diff --git a/src/uhttp.c b/src/uhttp.c index 9a63542..2cfb9bc 100755 --- a/src/uhttp.c +++ b/src/uhttp.c @@ -196,6 +196,18 @@ static void connection_read_cb(struct ev_loop *loop, ev_io *w, int revents) struct uh_buf *buf = &con->read_buf; char *base; int len, parsered; + +#if (UHTTP_SSL_ENABLED) + if (con->flags & UH_CON_SSL_HANDSHAKE_DONE) + goto handshake_done; + + uh_ssl_handshake(con); + if (con->flags & UH_CON_CLOSE) + uh_connection_destroy(con); + return; + +handshake_done: +#endif if (uh_buf_available(buf) < UH_BUFFER_SIZE) uh_buf_grow(buf, UH_BUFFER_SIZE); @@ -203,16 +215,9 @@ static void connection_read_cb(struct ev_loop *loop, ev_io *w, int revents) base = buf->base + buf->len; len = uh_ssl_read(con, base, UH_BUFFER_SIZE); - if (unlikely(len < 0)) { - if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) - return; - uh_log_err("read"); - uh_send_error(con, 500, NULL); - return; - } - - if (len == 0) { - uh_connection_destroy(con); + if (unlikely(len <= 0)) { + if (con->flags & UH_CON_CLOSE) + uh_connection_destroy(con); return; } @@ -236,17 +241,18 @@ static void connection_write_cb(struct ev_loop *loop, ev_io *w, int revents) if (buf->len > 0) { int len = uh_ssl_write(con, buf->base, buf->len); - uh_buf_remove(buf, len); + if (len > 0) + uh_buf_remove(buf, len); } if (buf->len == 0) { ev_io_stop(loop, w); if (!http_should_keep_alive(&con->parser)) - con->flags |= UH_CONNECTION_CLOSE; + con->flags |= UH_CON_CLOSE; } - if (con->flags & UH_CONNECTION_CLOSE) + if (con->flags & UH_CON_CLOSE) uh_connection_destroy(con); } @@ -267,12 +273,9 @@ static void uh_accept_cb(struct ev_loop *loop, ev_io *w, int revents) con->srv = srv; list_add(&con->list, &srv->connections); - sock = uh_ssl_accept(srv, con); - if (unlikely(sock < 0)) { - if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) - uh_log_err("accept"); + sock = uh_ssl_accept(con); + if (unlikely(sock < 0)) goto err; - } read_watcher = &con->read_watcher; ev_io_init(read_watcher, connection_read_cb, sock, EV_READ); @@ -443,7 +446,7 @@ void uh_send_error(struct uh_connection *con, int code, const char *reason) if (parser->method != HTTP_HEAD) uh_send(con, reason, strlen(reason)); - con->flags |= UH_CONNECTION_CLOSE; + con->flags |= UH_CON_CLOSE; } void uh_redirect(struct uh_connection *con, int code, const char *location) diff --git a/src/uhttp_internal.h b/src/uhttp_internal.h index a5029bf..c06509b 100755 --- a/src/uhttp_internal.h +++ b/src/uhttp_internal.h @@ -1,64 +1,65 @@ -#ifndef _UHTTP_INTERNAL_H -#define _UHTTP_INTERNAL_H - -#include - -#include "list.h" -#include "uhttp.h" - -#define UH_BUFFER_SIZE 2048 -#define UH_CONNECTION_TIMEOUT 30 -#define UH_MAX_HTTP_HEADERS 20 - -#define UH_CONNECTION_CLOSE (1 << 0) - -#define likely(x) (__builtin_expect(!!(x), 1)) -#define unlikely(x) (__builtin_expect(!!(x), 0)) - -struct uh_route { - char *path; - uh_route_handler_t cb; - struct list_head list; -}; - -struct uh_server { - int sock; -#if (UHTTP_SSL_ENABLED) - void *ssl_ctx; -#endif - ev_io read_watcher; - struct ev_loop *loop; - struct list_head routes; - struct list_head connections; -}; - -struct uh_header { - struct uh_value field; - struct uh_value value; -}; - -struct uh_request { - struct uh_value url; - struct uh_value body; - int header_num; - struct uh_header header[UH_MAX_HTTP_HEADERS]; -}; - -struct uh_connection { - int sock; -#if (UHTTP_SSL_ENABLED) - void *ssl; -#endif - unsigned char flags; - struct uh_buf read_buf; - struct uh_buf write_buf; - ev_io read_watcher; - ev_io write_watcher; - ev_timer timer_watcher; - struct uh_request req; - http_parser parser; - struct list_head list; - struct uh_server *srv; -}; - +#ifndef _UHTTP_INTERNAL_H +#define _UHTTP_INTERNAL_H + +#include + +#include "list.h" +#include "uhttp.h" + +#define UH_BUFFER_SIZE 2048 +#define UH_CONNECTION_TIMEOUT 30 +#define UH_MAX_HTTP_HEADERS 20 + +#define UH_CON_CLOSE (1 << 0) +#define UH_CON_SSL_HANDSHAKE_DONE (1 << 1) /* SSL hanshake has completed */ + +#define likely(x) (__builtin_expect(!!(x), 1)) +#define unlikely(x) (__builtin_expect(!!(x), 0)) + +struct uh_route { + char *path; + uh_route_handler_t cb; + struct list_head list; +}; + +struct uh_server { + int sock; +#if (UHTTP_SSL_ENABLED) + void *ssl_ctx; +#endif + ev_io read_watcher; + struct ev_loop *loop; + struct list_head routes; + struct list_head connections; +}; + +struct uh_header { + struct uh_value field; + struct uh_value value; +}; + +struct uh_request { + struct uh_value url; + struct uh_value body; + int header_num; + struct uh_header header[UH_MAX_HTTP_HEADERS]; +}; + +struct uh_connection { + int sock; +#if (UHTTP_SSL_ENABLED) + void *ssl; +#endif + unsigned char flags; + struct uh_buf read_buf; + struct uh_buf write_buf; + ev_io read_watcher; + ev_io write_watcher; + ev_timer timer_watcher; + struct uh_request req; + http_parser parser; + struct list_head list; + struct uh_server *srv; +}; + #endif \ No newline at end of file diff --git a/src/uhttp_ssl.c b/src/uhttp_ssl.c index 36ab163..2c1da72 100755 --- a/src/uhttp_ssl.c +++ b/src/uhttp_ssl.c @@ -20,6 +20,9 @@ int uh_ssl_init(struct uh_server *srv, const char *cert, const char *key) #if (UHTTP_USE_OPENSSL) SSL_library_init(); + /* registers the error strings for all libssl functions */ + SSL_load_error_strings(); + /* creates a new SSL_CTX object */ ctx = SSL_CTX_new(SSLv23_server_method()); if (!ctx) { @@ -115,45 +118,115 @@ void uh_ssl_free(struct uh_connection *con) #endif } +#if (UHTTP_SSL_ENABLED) +static int uh_ssl_err(struct uh_connection *con, int ret, const char *fun) +{ + int err; +#if (UHTTP_USE_OPENSSL) + err = SSL_get_error(con->ssl, ret); + if (err == SSL_ERROR_ZERO_RETURN || ERR_peek_error()) { + con->flags |= UH_CON_CLOSE; + return 0; + } + + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) + return -1; + + if (err == SSL_ERROR_SYSCALL) { + if (errno > 0) + uh_log_err("%s", fun); + con->flags |= UH_CON_CLOSE; + return -1; + } + + con->flags |= UH_CON_CLOSE; + uh_log_err("%s() Error: %s", fun, ERR_reason_error_string(err)); + return -1; +#elif (UHTTP_USE_CYASSL) +#endif +} +#endif + int uh_ssl_read(struct uh_connection *con, void *buf, int count) { + int ret = -1; #if (UHTTP_SSL_ENABLED) if (!con->ssl) - return read(con->sock, buf, count); + goto no_ssl; #endif #if (UHTTP_USE_OPENSSL) - return SSL_read(con->ssl, buf, count); + ret = SSL_read(con->ssl, buf, count); + if (ret > 0) + return ret; + + return uh_ssl_err(con, ret, "SSL_read"); + #elif (UHTTP_USE_CYASSL) return wolfSSL_read(con->ssl, buf, count); #endif - return read(con->sock, buf, count); +#if (UHTTP_SSL_ENABLED) +no_ssl: +#endif + ret = read(con->sock, buf, count); + if (ret <= 0) { + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) + return ret; + + if (ret != 0) { + con->flags |= UH_CON_CLOSE; + uh_log_err("read"); + } + } + return ret; } int uh_ssl_write(struct uh_connection *con, void *buf, int count) { + int ret = -1; #if (UHTTP_SSL_ENABLED) if (!con->ssl) - return write(con->sock, buf, count); + goto no_ssl; #endif #if (UHTTP_USE_OPENSSL) - return SSL_write(con->ssl, buf, count); + ret = SSL_write(con->ssl, buf, count); + if (ret > 0) + return ret; + + return uh_ssl_err(con, ret, "SSL_write"); + #elif (UHTTP_USE_CYASSL) return wolfSSL_write(con->ssl, buf, count); #endif - return write(con->sock, buf, count); +#if (UHTTP_SSL_ENABLED) + no_ssl: +#endif + ret = write(con->sock, buf, count); + if (ret <= 0) { + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) + return ret; + if (ret != 0) { + con->flags |= UH_CON_CLOSE; + uh_log_err("write"); + } + } + return ret; } -int uh_ssl_accept(struct uh_server *srv, struct uh_connection *con) +int uh_ssl_accept(struct uh_connection *con) { int sock = -1; + struct uh_server *srv = con->srv; sock = accept4(srv->sock, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC); - if (sock < 0) - return sock; + if (unlikely(sock < 0)) { + if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) + uh_log_err("accept4"); + return -1; + } con->sock = sock; @@ -162,17 +235,18 @@ int uh_ssl_accept(struct uh_server *srv, struct uh_connection *con) return sock; #endif -#if (UHTTP_USE_OPENSSL) +#if (UHTTP_USE_OPENSSL) con->ssl = SSL_new(srv->ssl_ctx); if (!con->ssl) return -1; - SSL_set_fd(con->ssl, sock); - - if (!SSL_accept(con->ssl)) { - uh_log_err("SSL_accept Error: %s", ERR_reason_error_string(ERR_get_error())); + if (!SSL_set_fd(con->ssl, sock)) { + uh_log_err("SSL_set_fd() failed"); return -1; } + + SSL_set_accept_state(con->ssl); + #elif (UHTTP_USE_CYASSL) con->ssl = wolfSSL_new(srv->ssl_ctx); if (!con->ssl) @@ -184,3 +258,21 @@ int uh_ssl_accept(struct uh_server *srv, struct uh_connection *con) return sock; } +void uh_ssl_handshake(struct uh_connection *con) +{ +#if (UHTTP_SSL_ENABLED) + int ret; +#if (UHTTP_USE_OPENSSL) + ret = SSL_do_handshake(con->ssl); + if (ret == 1) { + con->flags |= UH_CON_SSL_HANDSHAKE_DONE; + return; + } + + uh_ssl_err(con, ret, "SSL_do_handshake"); + +#elif (UHTTP_USE_CYASSL) +#endif +#endif +} + diff --git a/src/uhttp_ssl.h b/src/uhttp_ssl.h index 05203a3..2f9dc2e 100755 --- a/src/uhttp_ssl.h +++ b/src/uhttp_ssl.h @@ -7,6 +7,7 @@ void uh_ssl_ctx_free(struct uh_server *srv); void uh_ssl_free(struct uh_connection *con); int uh_ssl_read(struct uh_connection *con, void *buf, int count); int uh_ssl_write(struct uh_connection *con, void *buf, int count); -int uh_ssl_accept(struct uh_server *srv, struct uh_connection *con); +int uh_ssl_accept(struct uh_connection *con); +void uh_ssl_handshake(struct uh_connection *con); #endif