--- embedaddon/lighttpd/src/network_openssl.c 2014/06/15 20:20:06 1.1.1.2 +++ embedaddon/lighttpd/src/network_openssl.c 2016/11/02 10:35:00 1.1.1.3 @@ -1,36 +1,25 @@ +#include "first.h" + #include "network_backends.h" -#ifdef USE_OPENSSL +#if defined(USE_OPENSSL) #include "network.h" -#include "fdevent.h" #include "log.h" -#include "stat_cache.h" -#include -#include -#include -#include -#include +#include +#include -#include -#include - #include -#include -#include -#include #include -#include -#include # include # include -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes) { - int ssl_r; - chunk *c; +static int load_next_chunk(server *srv, connection *con, chunkqueue *cq, off_t max_bytes, const char **data, size_t *data_len) { + chunk * const c = cq->first; +#define LOCAL_SEND_BUFSIZE (64 * 1024) /* this is a 64k sendbuffer * * it has to stay at the same location all the time to satisfy the needs @@ -38,260 +27,161 @@ int network_write_chunkqueue_openssl(server *srv, conn * * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown * -> we expect a 64k block to 'leak' in valgrind - * - * - * In reality we would like to use mmap() but we don't have a guarantee that - * we get the same mmap() address for each call. On openbsd the mmap() address - * even randomized. - * That means either we keep the mmap() open or we do a read() into a - * constant buffer * */ -#define LOCAL_SEND_BUFSIZE (64 * 1024) static char *local_send_buffer = NULL; - /* the remote side closed the connection before without shutdown request - * - IE - * - wget - * if keep-alive is disabled */ + force_assert(NULL != c); - if (con->keep_alive == 0) { - SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); - } + switch (c->type) { + case MEM_CHUNK: + { + size_t have; - for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) { - int chunk_finished = 0; + force_assert(c->offset >= 0 && c->offset <= (off_t)buffer_string_length(c->mem)); - switch(c->type) { - case MEM_CHUNK: { - char * offset; - off_t toSend; - ssize_t r; + have = buffer_string_length(c->mem) - c->offset; + if ((off_t) have > max_bytes) have = max_bytes; - if (c->mem->used == 0 || c->mem->used == 1) { - chunk_finished = 1; - break; - } + *data = c->mem->ptr + c->offset; + *data_len = have; + } + return 0; - offset = c->mem->ptr + c->offset; - toSend = c->mem->used - 1 - c->offset; - if (toSend > max_bytes) toSend = max_bytes; + case FILE_CHUNK: + if (NULL == local_send_buffer) { + local_send_buffer = malloc(LOCAL_SEND_BUFSIZE); + force_assert(NULL != local_send_buffer); + } - /** - * SSL_write man-page - * - * WARNING - * When an SSL_write() operation has to be repeated because of - * SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be - * repeated with the same arguments. - * - */ + if (0 != network_open_file_chunk(srv, con, cq)) return -1; - ERR_clear_error(); - r = SSL_write(ssl, offset, toSend); + { + off_t offset, toSend; - if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) { - log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection"); - return -1; - } + force_assert(c->offset >= 0 && c->offset <= c->file.length); + offset = c->file.start + c->offset; + toSend = c->file.length - c->offset; - if (r <= 0) { - unsigned long err; + if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE; + if (toSend > max_bytes) toSend = max_bytes; - switch ((ssl_r = SSL_get_error(ssl, r))) { - case SSL_ERROR_WANT_WRITE: - break; - case SSL_ERROR_SYSCALL: - /* perhaps we have error waiting in our error-queue */ - if (0 != (err = ERR_get_error())) { - do { - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", - ssl_r, r, - ERR_error_string(err, NULL)); - } while((err = ERR_get_error())); - } else if (r == -1) { - /* no, but we have errno */ - switch(errno) { - case EPIPE: - case ECONNRESET: - return -2; - default: - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", - ssl_r, r, errno, - strerror(errno)); - break; - } - } else { - /* neither error-queue nor errno ? */ - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", - ssl_r, r, errno, - strerror(errno)); - } - - return -1; - case SSL_ERROR_ZERO_RETURN: - /* clean shutdown on the remote side */ - - if (r == 0) return -2; - - /* fall through */ - default: - while((err = ERR_get_error())) { - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", - ssl_r, r, - ERR_error_string(err, NULL)); - } - - return -1; - } - } else { - c->offset += r; - cq->bytes_out += r; - max_bytes -= r; + if (-1 == lseek(c->file.fd, offset, SEEK_SET)) { + log_error_write(srv, __FILE__, __LINE__, "ss", "lseek: ", strerror(errno)); + return -1; } - - if (c->offset == (off_t)c->mem->used - 1) { - chunk_finished = 1; + if (-1 == (toSend = read(c->file.fd, local_send_buffer, toSend))) { + log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno)); + return -1; } - break; + *data = local_send_buffer; + *data_len = toSend; } - case FILE_CHUNK: { - char *s; - ssize_t r; - stat_cache_entry *sce = NULL; - int ifd; - int write_wait = 0; + return 0; + } - if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { - log_error_write(srv, __FILE__, __LINE__, "sb", - strerror(errno), c->file.name); - return -1; - } + return -1; +} - if (NULL == local_send_buffer) { - local_send_buffer = malloc(LOCAL_SEND_BUFSIZE); - force_assert(local_send_buffer); - } - do { - off_t offset = c->file.start + c->offset; - off_t toSend = c->file.length - c->offset; - if (toSend > max_bytes) toSend = max_bytes; +int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes) { + /* the remote side closed the connection before without shutdown request + * - IE + * - wget + * if keep-alive is disabled */ - if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE; + if (con->keep_alive == 0) { + SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); + } - if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) { - log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno)); + chunkqueue_remove_finished_chunks(cq); - return -1; - } + while (max_bytes > 0 && NULL != cq->first) { + const char *data; + size_t data_len; + int r; + if (0 != load_next_chunk(srv, con, cq, max_bytes, &data, &data_len)) return -1; - if (-1 == lseek(ifd, offset, SEEK_SET)) { - log_error_write(srv, __FILE__, __LINE__, "ss", "lseek failed:", strerror(errno)); - close(ifd); - return -1; - } - if (-1 == (toSend = read(ifd, local_send_buffer, toSend))) { - log_error_write(srv, __FILE__, __LINE__, "ss", "read failed:", strerror(errno)); - close(ifd); - return -1; - } + /** + * SSL_write man-page + * + * WARNING + * When an SSL_write() operation has to be repeated because of + * SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be + * repeated with the same arguments. + */ - s = local_send_buffer; + ERR_clear_error(); + r = SSL_write(ssl, data, data_len); - close(ifd); + if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) { + log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection"); + return -1; + } - ERR_clear_error(); - r = SSL_write(ssl, s, toSend); + if (r <= 0) { + int ssl_r; + unsigned long err; - if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) { - log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection"); - return -1; - } - - if (r <= 0) { - unsigned long err; - - switch ((ssl_r = SSL_get_error(ssl, r))) { - case SSL_ERROR_WANT_WRITE: - write_wait = 1; - break; - case SSL_ERROR_SYSCALL: - /* perhaps we have error waiting in our error-queue */ - if (0 != (err = ERR_get_error())) { - do { - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", - ssl_r, r, - ERR_error_string(err, NULL)); - } while((err = ERR_get_error())); - } else if (r == -1) { - /* no, but we have errno */ - switch(errno) { - case EPIPE: - case ECONNRESET: - return -2; - default: - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", - ssl_r, r, errno, - strerror(errno)); - break; - } - } else { - /* neither error-queue nor errno ? */ - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", - ssl_r, r, errno, - strerror(errno)); - } - - return -1; - case SSL_ERROR_ZERO_RETURN: - /* clean shutdown on the remote side */ - - if (r == 0) return -2; - - /* fall thourgh */ + switch ((ssl_r = SSL_get_error(ssl, r))) { + case SSL_ERROR_WANT_READ: + con->is_readable = -1; + return 0; /* try again later */ + case SSL_ERROR_WANT_WRITE: + con->is_writable = -1; + return 0; /* try again later */ + case SSL_ERROR_SYSCALL: + /* perhaps we have error waiting in our error-queue */ + if (0 != (err = ERR_get_error())) { + do { + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", + ssl_r, r, + ERR_error_string(err, NULL)); + } while((err = ERR_get_error())); + } else if (r == -1) { + /* no, but we have errno */ + switch(errno) { + case EPIPE: + case ECONNRESET: + return -2; default: - while((err = ERR_get_error())) { - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", - ssl_r, r, - ERR_error_string(err, NULL)); - } - - return -1; + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", + ssl_r, r, errno, + strerror(errno)); + break; } } else { - c->offset += r; - cq->bytes_out += r; - max_bytes -= r; + /* neither error-queue nor errno ? */ + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", + ssl_r, r, errno, + strerror(errno)); } + break; - if (c->offset == c->file.length) { - chunk_finished = 1; - } - } while (!chunk_finished && !write_wait && max_bytes > 0); + case SSL_ERROR_ZERO_RETURN: + /* clean shutdown on the remote side */ - break; - } - default: - log_error_write(srv, __FILE__, __LINE__, "s", "type not known"); + if (r == 0) return -2; + /* fall through */ + default: + while((err = ERR_get_error())) { + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", + ssl_r, r, + ERR_error_string(err, NULL)); + } + break; + } return -1; } - if (!chunk_finished) { - /* not finished yet */ + chunkqueue_mark_written(cq, r); + max_bytes -= r; - break; - } + if ((size_t) r < data_len) break; /* try again later */ } return 0; } -#endif - -#if 0 -network_openssl_init(void) { - p->write_ssl = network_openssl_write_chunkset; -} -#endif +#endif /* USE_OPENSSL */