diff --git a/lib/context.c b/lib/context.c index fd89ae3e..2c283d76 100644 --- a/lib/context.c +++ b/lib/context.c @@ -77,9 +77,7 @@ libwebsocket_create_context(struct lws_context_creation_info *info) struct libwebsocket_context *context = NULL; char *p; -#ifndef LWS_NO_DAEMONIZE int pid_daemon = get_daemonize_pid(); -#endif lwsl_notice("Initial logging level %d\n", log_level); lwsl_notice("Library version: %s\n", library_version); @@ -94,12 +92,7 @@ libwebsocket_create_context(struct lws_context_creation_info *info) lws_feature_status_libev(info); lwsl_info(" LWS_MAX_HEADER_LEN: %u\n", LWS_MAX_HEADER_LEN); lwsl_info(" LWS_MAX_PROTOCOLS: %u\n", LWS_MAX_PROTOCOLS); -#ifndef LWS_NO_EXTENSIONS - lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n", - LWS_MAX_EXTENSIONS_ACTIVE); -#else - lwsl_notice(" Configured without extension support\n"); -#endif + lwsl_info(" SPEC_LATEST_SUPPORTED: %u\n", SPEC_LATEST_SUPPORTED); lwsl_info(" AWAITING_TIMEOUT: %u\n", AWAITING_TIMEOUT); lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH); @@ -115,10 +108,11 @@ libwebsocket_create_context(struct lws_context_creation_info *info) return NULL; } memset(context, 0, sizeof(*context)); -#ifndef LWS_NO_DAEMONIZE - context->started_with_parent = pid_daemon; - lwsl_notice(" Started with daemon pid %d\n", pid_daemon); -#endif + + if (pid_daemon) { + context->started_with_parent = pid_daemon; + lwsl_notice(" Started with daemon pid %d\n", pid_daemon); + } context->listen_service_extraseen = 0; context->protocols = info->protocols; @@ -169,23 +163,13 @@ libwebsocket_create_context(struct lws_context_creation_info *info) return NULL; } -#ifndef LWS_NO_EXTENSIONS - context->extensions = info->extensions; -#endif + lws_context_init_extensions(info, context); + context->user_space = info->user; strcpy(context->canonical_hostname, "unknown"); -#ifndef LWS_NO_SERVER - if (!(info->options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME)) { - /* find canonical hostname */ - gethostname((char *)context->canonical_hostname, - sizeof(context->canonical_hostname) - 1); - - lwsl_notice(" canonical_hostname = %s\n", - context->canonical_hostname); - } -#endif + lws_server_get_canonical_hostname(context, info); /* split the proxy ads:port if given */ @@ -300,6 +284,8 @@ libwebsocket_context_destroy(struct libwebsocket_context *context) int n; struct libwebsocket_protocols *protocol = context->protocols; + lwsl_notice("%s\n", __func__); + #ifdef LWS_LATENCY if (context->worst_latency_info[0]) lwsl_notice("Worst latency: %s\n", context->worst_latency_info); @@ -341,24 +327,14 @@ libwebsocket_context_destroy(struct libwebsocket_context *context) lws_plat_context_early_destroy(context); -#ifdef LWS_OPENSSL_SUPPORT - if (context->ssl_ctx) - SSL_CTX_free(context->ssl_ctx); - if (context->ssl_client_ctx) - SSL_CTX_free(context->ssl_client_ctx); - - ERR_remove_state(0); - ERR_free_strings(); - EVP_cleanup(); - CRYPTO_cleanup_all_ex_data(); -#endif + lws_ssl_context_destroy(context); if (context->fds) free(context->fds); if (context->lws_lookup) free(context->lws_lookup); - free(context); - lws_plat_context_late_destroy(context); + + free(context); } diff --git a/lib/extension.c b/lib/extension.c index 176faf0e..52510a91 100644 --- a/lib/extension.c +++ b/lib/extension.c @@ -27,6 +27,14 @@ struct libwebsocket_extension libwebsocket_internal_extensions[] = { } }; +LWS_VISIBLE void +lws_context_init_extensions(struct lws_context_creation_info *info, + struct libwebsocket_context *context) +{ + context->extensions = info->extensions; + lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n", LWS_MAX_EXTENSIONS_ACTIVE); +} + LWS_VISIBLE struct libwebsocket_extension *libwebsocket_get_internal_extensions() { return libwebsocket_internal_extensions; diff --git a/lib/libev.c b/lib/libev.c index b75c5ec4..04a4b5be 100644 --- a/lib/libev.c +++ b/lib/libev.c @@ -135,10 +135,10 @@ lws_libev_io(struct libwebsocket_context *context, { if (!LWS_LIBEV_ENABLED(context)) return; - + if (!context->io_loop) return; - + assert((flags & (LWS_EV_START | LWS_EV_STOP)) && (flags & (LWS_EV_READ | LWS_EV_WRITE))); diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index d2f06af8..40a56e83 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -264,28 +264,15 @@ just_kill_connection: /* lwsl_info("closing fd=%d\n", wsi->sock); */ -#ifdef LWS_OPENSSL_SUPPORT - if (wsi->ssl) { - n = SSL_get_fd(wsi->ssl); - SSL_shutdown(wsi->ssl); - compatible_close(n); - SSL_free(wsi->ssl); - } else { -#endif - if (wsi->sock) { - n = shutdown(wsi->sock, SHUT_RDWR); - if (n) - lwsl_debug("closing: shutdown returned %d\n", - LWS_ERRNO); + if (!lws_ssl_close(wsi) && wsi->sock >= 0) { + n = shutdown(wsi->sock, SHUT_RDWR); + if (n) + lwsl_debug("closing: shutdown ret %d\n", LWS_ERRNO); - n = compatible_close(wsi->sock); - if (n) - lwsl_debug("closing: close returned %d\n", - LWS_ERRNO); - } -#ifdef LWS_OPENSSL_SUPPORT + n = compatible_close(wsi->sock); + if (n) + lwsl_debug("closing: close ret %d\n", LWS_ERRNO); } -#endif /* outermost destroy notification for wsi (user_space still intact) */ context->protocols[0].callback(context, wsi, diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 8cfab08b..c65d3652 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -678,7 +678,14 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context, LWS_EXTERN int lws_handle_POLLOUT_event(struct libwebsocket_context *context, struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd); +/* + * EXTENSIONS + */ + #ifndef LWS_NO_EXTENSIONS +LWS_VISIBLE void +lws_context_init_extensions(struct lws_context_creation_info *info, + struct libwebsocket_context *context); LWS_EXTERN int lws_any_extension_handled(struct libwebsocket_context *context, struct libwebsocket *wsi, @@ -697,6 +704,7 @@ lws_ext_callback_for_each_extension_type( #define lws_ext_callback_for_each_active(_a, _b, _c, _d) (0) #define lws_ext_callback_for_each_extension_type(_a, _b, _c, _d, _e) (0) #define lws_issue_raw_ext_access lws_issue_raw +#define lws_context_init_extensions(_a, _b) #endif LWS_EXTERN int @@ -747,13 +755,19 @@ LWS_EXTERN int handshake_0405(struct libwebsocket_context *context, LWS_EXTERN int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi, unsigned char *buf, size_t len); +LWS_EXTERN void +lws_server_get_canonical_hostname(struct libwebsocket_context *context, + struct lws_context_creation_info *info); #else #define lws_context_init_server(_a, _b) (0) #define libwebsocket_interpret_incoming_packet(_a, _b, _c) (0) +#define lws_server_get_canonical_hostname(_a, _b) #endif #ifndef LWS_NO_DAEMONIZE LWS_EXTERN int get_daemonize_pid(); +#else +#define get_daemonize_pid() (0) #endif LWS_EXTERN int interface_to_sa(struct libwebsocket_context *context, @@ -773,7 +787,7 @@ enum lws_ssl_capable_status { }; #ifndef LWS_OPENSSL_SUPPORT - +#define LWS_SSL_ENABLED(context) (0) unsigned char * SHA1(const unsigned char *d, size_t n, unsigned char *md); #define lws_context_init_server_ssl(_a, _b) (0) @@ -782,7 +796,11 @@ SHA1(const unsigned char *d, size_t n, unsigned char *md); #define lws_ssl_pending(_a) (0) #define lws_ssl_capable_read lws_ssl_capable_read_no_ssl #define lws_ssl_capable_write lws_ssl_capable_write_no_ssl +#define lws_server_socket_service_ssl(_a, _b, _c, _d, _e) (0) +#define lws_ssl_close(_a) (0) +#define lws_ssl_context_destroy(_a) #else +#define LWS_SSL_ENABLED(context) (context->use_ssl) LWS_EXTERN int lws_ssl_pending(struct libwebsocket *wsi); LWS_EXTERN int openssl_websocket_private_data_index; LWS_EXTERN int @@ -790,7 +808,14 @@ lws_ssl_capable_read(struct libwebsocket *wsi, unsigned char *buf, int len); LWS_EXTERN int lws_ssl_capable_write(struct libwebsocket *wsi, unsigned char *buf, int len); - +LWS_EXTERN int +lws_server_socket_service_ssl(struct libwebsocket_context *context, + struct libwebsocket **wsi, struct libwebsocket *new_wsi, + int accept_fd, struct libwebsocket_pollfd *pollfd); +LWS_EXTERN int +lws_ssl_close(struct libwebsocket *wsi); +LWS_EXTERN void +lws_ssl_context_destroy(struct libwebsocket_context *context); #ifndef LWS_NO_SERVER LWS_EXTERN int lws_context_init_server_ssl(struct lws_context_creation_info *info, diff --git a/lib/server.c b/lib/server.c index e58632a7..e358719d 100644 --- a/lib/server.c +++ b/lib/server.c @@ -484,18 +484,12 @@ libwebsocket_create_new_server_wsi(struct libwebsocket_context *context) int lws_server_socket_service(struct libwebsocket_context *context, struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd) { - struct libwebsocket *new_wsi; - int accept_fd; + struct libwebsocket *new_wsi = NULL; + int accept_fd = 0; socklen_t clilen; struct sockaddr_in cli_addr; int n; int len; -#ifdef LWS_OPENSSL_SUPPORT - int m; -#ifndef USE_CYASSL - BIO *bio; -#endif -#endif switch (wsi->mode) { @@ -656,157 +650,21 @@ int lws_server_socket_service(struct libwebsocket_context *context, lws_libev_accept(context, new_wsi, accept_fd); -#ifdef LWS_OPENSSL_SUPPORT - new_wsi->ssl = NULL; - if (!context->use_ssl) { -#endif - + if (!LWS_SSL_ENABLED(context)) { lwsl_debug("accepted new conn port %u on fd=%d\n", ntohs(cli_addr.sin_port), accept_fd); insert_wsi_socket_into_fds(context, new_wsi); - break; -#ifdef LWS_OPENSSL_SUPPORT } - - new_wsi->ssl = SSL_new(context->ssl_ctx); - if (new_wsi->ssl == NULL) { - lwsl_err("SSL_new failed: %s\n", - ERR_error_string(SSL_get_error( - new_wsi->ssl, 0), NULL)); - libwebsockets_decode_ssl_error(); - free(new_wsi); - compatible_close(accept_fd); - break; - } - - SSL_set_ex_data(new_wsi->ssl, - openssl_websocket_private_data_index, context); - - SSL_set_fd(new_wsi->ssl, accept_fd); -#ifndef USE_CYASSL - SSL_set_mode(new_wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); -#endif - #ifdef USE_CYASSL - CyaSSL_set_using_nonblock(new_wsi->ssl, 1); - #else - bio = SSL_get_rbio(new_wsi->ssl); - if (bio) - BIO_set_nbio(bio, 1); /* nonblocking */ - else - lwsl_notice("NULL rbio\n"); - bio = SSL_get_wbio(new_wsi->ssl); - if (bio) - BIO_set_nbio(bio, 1); /* nonblocking */ - else - lwsl_notice("NULL rbio\n"); - #endif - - /* - * we are not accepted yet, but we need to enter ourselves - * as a live connection. That way we can retry when more - * pieces come if we're not sorted yet - */ - - wsi = new_wsi; - wsi->mode = LWS_CONNMODE_SSL_ACK_PENDING; - insert_wsi_socket_into_fds(context, wsi); - - libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT, - AWAITING_TIMEOUT); - - lwsl_info("inserted SSL accept into fds, trying SSL_accept\n"); - - /* fallthru */ - - case LWS_CONNMODE_SSL_ACK_PENDING: - - if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) - goto fail; - - lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE); - - lws_latency_pre(context, wsi); - - n = recv(wsi->sock, context->service_buffer, - sizeof(context->service_buffer), MSG_PEEK); - - /* - * optionally allow non-SSL connect on SSL listening socket - * This is disabled by default, if enabled it goes around any - * SSL-level access control (eg, client-side certs) so leave - * it disabled unless you know it's not a problem for you - */ - - if (context->allow_non_ssl_on_ssl_port && n >= 1 && - context->service_buffer[0] >= ' ') { - /* - * TLS content-type for Handshake is 0x16 - * TLS content-type for ChangeCipherSpec Record is 0x14 - * - * A non-ssl session will start with the HTTP method in - * ASCII. If we see it's not a legit SSL handshake - * kill the SSL for this connection and try to handle - * as a HTTP connection upgrade directly. - */ - wsi->use_ssl = 0; - SSL_shutdown(wsi->ssl); - SSL_free(wsi->ssl); - wsi->ssl = NULL; - goto accepted; - } - - /* normal SSL connection processing path */ - - n = SSL_accept(wsi->ssl); - lws_latency(context, wsi, - "SSL_accept LWS_CONNMODE_SSL_ACK_PENDING\n", n, n == 1); - - if (n != 1) { - m = SSL_get_error(wsi->ssl, n); - lwsl_debug("SSL_accept failed %d / %s\n", - m, ERR_error_string(m, NULL)); - - if (m == SSL_ERROR_WANT_READ) { - if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) - goto fail; - - lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ); - - lwsl_info("SSL_ERROR_WANT_READ\n"); - break; - } - if (m == SSL_ERROR_WANT_WRITE) { - if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) - goto fail; - - lws_libev_io(context, wsi, - LWS_EV_START | LWS_EV_WRITE); - break; - } - lwsl_debug("SSL_accept failed skt %u: %s\n", - pollfd->fd, - ERR_error_string(m, NULL)); - libwebsocket_close_and_free_session(context, wsi, - LWS_CLOSE_STATUS_NOSTATUS); - break; - } - -accepted: - /* OK, we are accepted... give him some time to negotiate */ - libwebsocket_set_timeout(wsi, - PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, - AWAITING_TIMEOUT); - - wsi->mode = LWS_CONNMODE_HTTP_SERVING; - - lwsl_debug("accepted new SSL conn\n"); break; -#endif default: break; } + + if (lws_server_socket_service_ssl(context, &wsi, new_wsi, accept_fd, pollfd)) + goto fail; + return 0; fail: @@ -993,4 +851,18 @@ int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi, } return 0; +} + +LWS_VISIBLE void +lws_server_get_canonical_hostname(struct libwebsocket_context *context, + struct lws_context_creation_info *info) +{ + if (info->options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME) + return; + + /* find canonical hostname */ + gethostname((char *)context->canonical_hostname, + sizeof(context->canonical_hostname) - 1); + + lwsl_notice(" canonical_hostname = %s\n", context->canonical_hostname); } \ No newline at end of file diff --git a/lib/ssl.c b/lib/ssl.c index f0a9a326..d2200007 100644 --- a/lib/ssl.c +++ b/lib/ssl.c @@ -380,4 +380,191 @@ lws_ssl_pending(struct libwebsocket *wsi) if (wsi->ssl) return SSL_pending(wsi->ssl); return 0; +} + +LWS_VISIBLE int +lws_ssl_close(struct libwebsocket *wsi) +{ + int n; + + if (!wsi->ssl) + return 0; /* not handled */ + + n = SSL_get_fd(wsi->ssl); + SSL_shutdown(wsi->ssl); + compatible_close(n); + SSL_free(wsi->ssl); + + return 1; /* handled */ +} + +LWS_VISIBLE int +lws_server_socket_service_ssl(struct libwebsocket_context *context, + struct libwebsocket **pwsi, struct libwebsocket *new_wsi, + int accept_fd, struct libwebsocket_pollfd *pollfd) +{ + int n, m; + struct libwebsocket *wsi = *pwsi; +#ifndef USE_CYASSL + BIO *bio; +#endif + + if (!LWS_SSL_ENABLED(context)) + return 0; + + switch (wsi->mode) { + case LWS_CONNMODE_SERVER_LISTENER: + + new_wsi->ssl = SSL_new(context->ssl_ctx); + if (new_wsi->ssl == NULL) { + lwsl_err("SSL_new failed: %s\n", + ERR_error_string(SSL_get_error( + new_wsi->ssl, 0), NULL)); + libwebsockets_decode_ssl_error(); + free(new_wsi); + compatible_close(accept_fd); + break; + } + + SSL_set_ex_data(new_wsi->ssl, + openssl_websocket_private_data_index, context); + + SSL_set_fd(new_wsi->ssl, accept_fd); + +#ifdef USE_CYASSL + CyaSSL_set_using_nonblock(new_wsi->ssl, 1); +#else + SSL_set_mode(new_wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + bio = SSL_get_rbio(new_wsi->ssl); + if (bio) + BIO_set_nbio(bio, 1); /* nonblocking */ + else + lwsl_notice("NULL rbio\n"); + bio = SSL_get_wbio(new_wsi->ssl); + if (bio) + BIO_set_nbio(bio, 1); /* nonblocking */ + else + lwsl_notice("NULL rbio\n"); +#endif + + /* + * we are not accepted yet, but we need to enter ourselves + * as a live connection. That way we can retry when more + * pieces come if we're not sorted yet + */ + + *pwsi = new_wsi; + wsi = *pwsi; + wsi->mode = LWS_CONNMODE_SSL_ACK_PENDING; + insert_wsi_socket_into_fds(context, wsi); + + libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT, + AWAITING_TIMEOUT); + + lwsl_info("inserted SSL accept into fds, trying SSL_accept\n"); + + /* fallthru */ + + case LWS_CONNMODE_SSL_ACK_PENDING: + + if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) + goto fail; + + lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE); + + lws_latency_pre(context, wsi); + + n = recv(wsi->sock, context->service_buffer, + sizeof(context->service_buffer), MSG_PEEK); + + /* + * optionally allow non-SSL connect on SSL listening socket + * This is disabled by default, if enabled it goes around any + * SSL-level access control (eg, client-side certs) so leave + * it disabled unless you know it's not a problem for you + */ + + if (context->allow_non_ssl_on_ssl_port && n >= 1 && + context->service_buffer[0] >= ' ') { + /* + * TLS content-type for Handshake is 0x16 + * TLS content-type for ChangeCipherSpec Record is 0x14 + * + * A non-ssl session will start with the HTTP method in + * ASCII. If we see it's not a legit SSL handshake + * kill the SSL for this connection and try to handle + * as a HTTP connection upgrade directly. + */ + wsi->use_ssl = 0; + SSL_shutdown(wsi->ssl); + SSL_free(wsi->ssl); + wsi->ssl = NULL; + goto accepted; + } + + /* normal SSL connection processing path */ + + n = SSL_accept(wsi->ssl); + lws_latency(context, wsi, + "SSL_accept LWS_CONNMODE_SSL_ACK_PENDING\n", n, n == 1); + + if (n == 1) + goto accepted; + + m = SSL_get_error(wsi->ssl, n); + lwsl_debug("SSL_accept failed %d / %s\n", + m, ERR_error_string(m, NULL)); + + if (m == SSL_ERROR_WANT_READ) { + if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) + goto fail; + + lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ); + + lwsl_info("SSL_ERROR_WANT_READ\n"); + break; + } + if (m == SSL_ERROR_WANT_WRITE) { + if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) + goto fail; + + lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_WRITE); + break; + } + lwsl_debug("SSL_accept failed skt %u: %s\n", + pollfd->fd, ERR_error_string(m, NULL)); + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + break; + +accepted: + /* OK, we are accepted... give him some time to negotiate */ + libwebsocket_set_timeout(wsi, + PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, + AWAITING_TIMEOUT); + + wsi->mode = LWS_CONNMODE_HTTP_SERVING; + + lwsl_debug("accepted new SSL conn\n"); + break; + } + + return 0; + +fail: + return 1; +} + +LWS_VISIBLE void +lws_ssl_context_destroy(struct libwebsocket_context *context) +{ + if (context->ssl_ctx) + SSL_CTX_free(context->ssl_ctx); + if (context->ssl_client_ctx) + SSL_CTX_free(context->ssl_client_ctx); + + ERR_remove_state(0); + ERR_free_strings(); + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); } \ No newline at end of file