/*
* Soft: Perform a GET query to a remote HTTP/HTTPS server.
* Set a timer to compute global remote server response
* time.
*
* Part: SSL engine. 'Semi' asyncrhonous stream handling.
*
* Version: $Id: ssl.c,v 1.1.1.1 2005/02/14 15:44:19 clement Exp $
*
* Authors: Alexandre Cassen, <acassen@linux-vs.org>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Copyright (C) 2001-2005 Alexandre Cassen, <acassen@linux-vs.org>
*/
#include <openssl/err.h>
#include "main.h"
#include "sock.h"
#include "http.h"
#include "ssl.h"
#include "utils.h"
#include "html.h"
/* extern variables */
extern REQ *req;
/*
* Initialize the SSL context, with or without specific
* configuration files.
*/
static BIO *bio_err = 0;
void
init_ssl(void)
{
/* Library initialization */
SSL_library_init();
SSL_load_error_strings();
bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
/* Initialize SSL context for SSL v2/3 */
req->meth = SSLv23_method();
req->ctx = SSL_CTX_new(req->meth);
#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
SSL_CTX_set_verify_depth(req->ctx, 1);
#endif
}
/* Display SSL error to readable string */
int
ssl_printerr(int err)
{
unsigned long extended_error = 0;
char *ssl_strerr;
switch (err) {
case SSL_ERROR_ZERO_RETURN:
fprintf(stderr, " SSL error: (zero return)\n");
break;
case SSL_ERROR_WANT_READ:
fprintf(stderr, " SSL error: (read error)\n");
break;
case SSL_ERROR_WANT_WRITE:
fprintf(stderr, " SSL error: (write error)\n");
break;
case SSL_ERROR_WANT_CONNECT:
fprintf(stderr, " SSL error: (connect error)\n");
break;
case SSL_ERROR_WANT_X509_LOOKUP:
fprintf(stderr, " SSL error: (X509 lookup error)\n");
break;
case SSL_ERROR_SYSCALL:
fprintf(stderr, " SSL error: (syscall error)\n");
break;
case SSL_ERROR_SSL:{
ssl_strerr = (char *) MALLOC(500);
extended_error = ERR_get_error();
ERR_error_string(extended_error, ssl_strerr);
fprintf(stderr, " SSL error: (%s)\n", ssl_strerr);
FREE(ssl_strerr);
break;
}
}
return 0;
}
int
ssl_connect(thread * thread_obj)
{
SOCK *sock_obj = THREAD_ARG(thread_obj);
int ret;
sock_obj->ssl = SSL_new(req->ctx);
sock_obj->bio = BIO_new_socket(sock_obj->fd, BIO_NOCLOSE);
BIO_set_nbio(sock_obj->bio, 1); /* Set the Non-Blocking flag */
SSL_set_bio(sock_obj->ssl, sock_obj->bio, sock_obj->bio);
ret = SSL_connect(sock_obj->ssl);
DBG(" SSL_connect return code = %d on fd:%d\n", ret, thread_obj->u.fd);
ssl_printerr(SSL_get_error(sock_obj->ssl, ret));
return (ret > 0) ? 1 : 0;
}
int
ssl_send_request(SSL * ssl, char *str_request, int request_len)
{
int err, r = 0;
while (1) {
err = 1;
r = SSL_write(ssl, str_request, request_len);
if (SSL_ERROR_NONE != SSL_get_error(ssl, r))
break;
err++;
if (request_len != r)
break;
err++;
break;
}
return (err == 3) ? 1 : 0;
}
/* Asynchronous SSL stream reader */
int
ssl_read_thread(thread * thread_obj)
{
SOCK *sock_obj = THREAD_ARG(thread_obj);
int r = 0;
int error;
/* Handle read timeout */
if (thread_obj->type == THREAD_READ_TIMEOUT)
return epilog(thread_obj);
/*
* The design implemented here is a workaround for use
* with OpenSSL. This goto loop is a 'read until not
* end of stream'. But this break a little our global
* I/O multiplexer thread framework because it enter
* a synchronous read process for each GET reply.
* Sound a little nasty !.
*
* Why OpenSSL doesn t handle underlying fd. This
* break the I/O (select()) approach !...
* If you read this and know the answer, please reply
* I am probably missing something... :)
* My test show that sometime it return from select,
* and sometime not...
*/
read_stream:
/* read the SSL stream */
memset(sock_obj->buffer, 0, MAX_BUFFER_LENGTH);
r = SSL_read(sock_obj->ssl, sock_obj->buffer, MAX_BUFFER_LENGTH);
error = SSL_get_error(sock_obj->ssl, r);
DBG(" [l:%d,fd:%d]\n", r, sock_obj->fd);
if (error) {
/* All the SSL streal has been parsed */
/* Handle response stream */
if (error != SSL_ERROR_NONE)
return finalize(thread_obj);
} else if (r > 0 && error == 0) {
/* Handle the response stream */
http_process_stream(sock_obj, r);
/*
* Register next ssl stream reader.
* Register itself to not perturbe global I/O multiplexer.
*/
goto read_stream;
}
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1