From 6781cf6b45f377f309c86d1ce1ee6296125f4c30 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Mon, 28 Jan 2013 12:19:10 +0800 Subject: [PATCH] break up ssl accept action Signed-off-by: Andy Green --- lib/libwebsockets.c | 5 ++ lib/private-libwebsockets.h | 5 +- lib/server.c | 128 ++++++++++++++++++++++++++++++-------------- 3 files changed, 98 insertions(+), 40 deletions(-) diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index b2f4e91..728d5e9 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -783,6 +783,9 @@ libwebsocket_service_fd(struct libwebsocket_context *context, case LWS_CONNMODE_SERVER_LISTENER: case LWS_CONNMODE_BROADCAST_PROXY_LISTENER: case LWS_CONNMODE_BROADCAST_PROXY: + case LWS_CONNMODE_SSL_ACK_PENDING: + +lwsl_debug("*\n"); return lws_server_socket_service(context, wsi, pollfd); #endif @@ -1806,6 +1809,8 @@ libwebsocket_create_context(int port, const char *interf, setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (const void *)&opt, sizeof(opt)); + fcntl(sockfd, F_SETFL, O_NONBLOCK); + bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; if (interf == NULL) diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 664f188..b34e840 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -1,7 +1,7 @@ /* * libwebsockets - small server side websockets and web server implementation * - * Copyright (C) 2010 Andy Green + * Copyright (C) 2010 - 2013 Andy Green * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -205,6 +205,9 @@ enum connection_mode { LWS_CONNMODE_WS_SERVING, LWS_CONNMODE_WS_CLIENT, + /* transient, ssl delay hiding */ + LWS_CONNMODE_SSL_ACK_PENDING, + /* transient modes */ LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY, LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE, diff --git a/lib/server.c b/lib/server.c index 54a5405..5fdccbb 100644 --- a/lib/server.c +++ b/lib/server.c @@ -140,6 +140,7 @@ int lws_server_socket_service(struct libwebsocket_context *context, unsigned int clilen; struct sockaddr_in cli_addr; int n; + int m; int opt = 1; ssize_t len; @@ -213,6 +214,10 @@ int lws_server_socket_service(struct libwebsocket_context *context, accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr, &clilen); if (accept_fd < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + lwsl_debug("accept asks to try again\n"); + break; + } lwsl_warn("ERROR on accept: %s\n", strerror(errno)); break; } @@ -247,58 +252,103 @@ int lws_server_socket_service(struct libwebsocket_context *context, new_wsi->sock = accept_fd; - #ifdef LWS_OPENSSL_SUPPORT new_wsi->ssl = NULL; + if (!context->use_ssl) { +#endif + + 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); + + /* + * 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); + + lwsl_info("inserted SSL acceipt into fds, trying actual SSL_accept\n"); + + /* fallthru */ + + case LWS_CONNMODE_SSL_ACK_PENDING: + + pollfd->events &= ~POLLOUT; + + /* external POLL support via protocol 0 */ + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_CLEAR_MODE_POLL_FD, + (void *)(long)wsi->sock, NULL, POLLOUT); + + //lwsl_notice("LWS_CONNMODE_SSL_ACK_PENDING: pre\n"); + n = SSL_accept(wsi->ssl); + //lwsl_notice("LWS_CONNMODE_SSL_ACK_PENDING: post %d\n", n); - if (context->use_ssl) { + if (n != 1) { + m = SSL_get_error(wsi->ssl, n); + lwsl_debug("SSL_accept failed %d / %s\n", m, ERR_error_string(m, NULL)); - 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); + if (m == SSL_ERROR_WANT_READ) { + context->fds[wsi->position_in_fds_table].events |= POLLIN; + + /* external POLL support via protocol 0 */ + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_SET_MODE_POLL_FD, + (void *)(long)wsi->sock, NULL, POLLIN); + lwsl_info("SSL_ERROR_WANT_READ\n"); break; } + if (m == SSL_ERROR_WANT_WRITE) { + context->fds[wsi->position_in_fds_table].events |= POLLOUT; - SSL_set_ex_data(new_wsi->ssl, - openssl_websocket_private_data_index, context); - - SSL_set_fd(new_wsi->ssl, accept_fd); - - n = SSL_accept(new_wsi->ssl); - if (n != 1) { - /* - * browsers seem to probe with various - * ssl params which fail then retry - * and succeed - */ - lwsl_debug("SSL_accept failed skt %u: %s\n", - pollfd->fd, - ERR_error_string(SSL_get_error( - new_wsi->ssl, n), NULL)); - SSL_free( - new_wsi->ssl); - free(new_wsi); - compatible_close(accept_fd); + /* external POLL support via protocol 0 */ + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_SET_MODE_POLL_FD, + (void *)(long)wsi->sock, NULL, POLLOUT); 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; + } - lwsl_debug("accepted new SSL conn " - "port %u on fd=%d SSL ver %s\n", - ntohs(cli_addr.sin_port), accept_fd, - SSL_get_version(new_wsi->ssl)); + /* OK, we are accepted */ - } else -#endif - lwsl_debug("accepted new conn port %u on fd=%d\n", - ntohs(cli_addr.sin_port), accept_fd); + wsi->mode = LWS_CONNMODE_HTTP_SERVING; - insert_wsi_socket_into_fds(context, new_wsi); + lwsl_debug("accepted new SSL conn " + "port %u on fd=%d SSL ver %s\n", + ntohs(cli_addr.sin_port), + SSL_get_version(wsi->ssl)); break; +#endif + #ifndef LWS_NO_FORK case LWS_CONNMODE_BROADCAST_PROXY_LISTENER: -- 2.7.4