updated spec enabled ssl
[profile/ivi/libwebsockets.git] / lib / libwebsockets.c
index 32f4a8d..0c85f0a 100644 (file)
@@ -24,6 +24,7 @@
 #ifdef WIN32
 #include <tchar.h>
 #include <io.h>
+#include <mstcpip.h>
 #else
 #ifdef LWS_BUILTIN_GETIFADDRS
 #include <getifaddrs.h>
@@ -58,7 +59,7 @@ static void (*lwsl_emit)(int level, const char *line) = lwsl_emit_stderr;
 
 static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
 
-static const char *log_level_names[] = {
+static const char * const log_level_names[] = {
        "ERR",
        "WARN",
        "NOTICE",
@@ -71,6 +72,17 @@ static const char *log_level_names[] = {
        "LATENCY",
 };
 
+#ifndef LWS_NO_CLIENT
+       extern int lws_client_socket_service(
+               struct libwebsocket_context *context,
+               struct libwebsocket *wsi, struct pollfd *pollfd);
+#endif
+#ifndef LWS_NO_SERVER
+       extern int lws_server_socket_service(
+               struct libwebsocket_context *context,
+               struct libwebsocket *wsi, struct pollfd *pollfd);
+#endif
+
 /**
  * lws_get_library_version: get version and git hash library built from
  *
@@ -86,22 +98,25 @@ lws_get_library_version(void)
 }
 
 int
-insert_wsi_socket_into_fds(struct libwebsocket_context *context, struct libwebsocket *wsi)
+insert_wsi_socket_into_fds(struct libwebsocket_context *context,
+                                                      struct libwebsocket *wsi)
 {
        if (context->fds_count >= context->max_fds) {
-               lwsl_err("Reached limit of fds tracking (%d)\n", context->max_fds);
+               lwsl_err("Too many fds (%d)\n", context->max_fds);
                return 1;
        }
 
        if (wsi->sock > context->max_fds) {
-               lwsl_err("Socket fd %d is beyond what we can index (%d)\n", wsi->sock, context->max_fds);
+               lwsl_err("Socket fd %d is too high (%d)\n",
+                                               wsi->sock, context->max_fds);
                return 1;
        }
 
        assert(wsi);
        assert(wsi->sock);
 
-       lwsl_info("insert_wsi_socket_into_fds: wsi=%p, sock=%d, fds pos=%d\n", wsi, wsi->sock, context->fds_count);
+       lwsl_info("insert_wsi_socket_into_fds: wsi=%p, sock=%d, fds pos=%d\n",
+                                           wsi, wsi->sock, context->fds_count);
 
        context->lws_lookup[wsi->sock] = wsi;
        wsi->position_in_fds_table = context->fds_count;
@@ -112,13 +127,14 @@ insert_wsi_socket_into_fds(struct libwebsocket_context *context, struct libwebso
        /* external POLL support via protocol 0 */
        context->protocols[0].callback(context, wsi,
                LWS_CALLBACK_ADD_POLL_FD,
-               (void *)(long)wsi->sock, NULL, POLLIN);
+               wsi->user_space, (void *)(long)wsi->sock, POLLIN);
 
        return 0;
 }
 
 static int
-remove_wsi_socket_from_fds(struct libwebsocket_context *context, struct libwebsocket *wsi)
+remove_wsi_socket_from_fds(struct libwebsocket_context *context,
+                                                     struct libwebsocket *wsi)
 {
        int m;
 
@@ -126,28 +142,36 @@ remove_wsi_socket_from_fds(struct libwebsocket_context *context, struct libwebso
                goto do_ext;
 
        if (wsi->sock > context->max_fds) {
-               lwsl_err("Socket fd %d is beyond what we can index (%d)\n", wsi->sock, context->max_fds);
+               lwsl_err("Socket fd %d too high (%d)\n",
+                                                  wsi->sock, context->max_fds);
                return 1;
        }
 
-       lwsl_info("remove_wsi_socket_from_fds: wsi=%p, sock=%d, fds pos=%d\n", wsi, wsi->sock, wsi->position_in_fds_table);
+       lwsl_info("remove_wsi_socket_from_fds: wsi=%p, sock=%d, fds pos=%d\n",
+                                   wsi, wsi->sock, wsi->position_in_fds_table);
 
        m = wsi->position_in_fds_table; /* replace the contents for this */
 
        /* have the last guy take up the vacant slot */
-       context->fds[m] = context->fds[context->fds_count]; /* vacant fds slot filled with end one */
-       /* end guy's fds_lookup entry remains unchanged (still same fd pointing to same wsi) */
+       context->fds[m] = context->fds[context->fds_count];
+       /*
+        * end guy's fds_lookup entry remains unchanged
+        * (still same fd pointing to same wsi)
+        */
        /* end guy's "position in fds table" changed */
-       context->lws_lookup[context->fds[context->fds_count].fd]->position_in_fds_table = m;
+       context->lws_lookup[context->fds[context->fds_count].fd]->
+                                               position_in_fds_table = m;
        /* deletion guy's lws_lookup entry needs nuking */
-       context->lws_lookup[wsi->sock] = NULL; /* no WSI for the socket of the wsi being removed*/
-       wsi->position_in_fds_table = -1; /* removed wsi has no position any more */
+       context->lws_lookup[wsi->sock] = NULL;
+       /* removed wsi has no position any more */
+       wsi->position_in_fds_table = -1;
 
 do_ext:
        /* remove also from external POLL support via protocol 0 */
        if (wsi->sock)
                context->protocols[0].callback(context, wsi,
-                   LWS_CALLBACK_DEL_POLL_FD, (void *)(long)wsi->sock, NULL, 0);
+                   LWS_CALLBACK_DEL_POLL_FD, wsi->user_space,
+                                                   (void *)(long)wsi->sock, 0);
 
        return 0;
 }
@@ -176,6 +200,10 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
        if (old_state == WSI_STATE_DEAD_SOCKET)
                return;
 
+       /* we tried the polite way... */
+       if (old_state == WSI_STATE_AWAITING_CLOSE_ACK)
+               goto just_kill_connection;
+
        wsi->u.ws.close_reason = reason;
 
        if (wsi->mode == LWS_CONNMODE_HTTP_SERVING && wsi->u.http.fd) {
@@ -248,8 +276,8 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
 
                if (eff_buf.token_len)
                        if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
-                                                            eff_buf.token_len)) {
-                               lwsl_debug("close: sending final extension spill had problems\n");
+                                     eff_buf.token_len) != eff_buf.token_len) {
+                               lwsl_debug("close: ext spill failed\n");
                                goto just_kill_connection;
                        }
        }
@@ -272,9 +300,12 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
 
                lwsl_debug("sending close indication...\n");
 
-               n = libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING],
+               /* make valgrind happy */
+               memset(buf, 0, sizeof(buf));
+               n = libwebsocket_write(wsi,
+                               &buf[LWS_SEND_BUFFER_PRE_PADDING + 2],
                                                            0, LWS_WRITE_CLOSE);
-               if (!n) {
+               if (n >= 0) {
                        /*
                         * we have sent a nice protocol level indication we
                         * now wish to close, we should not send anything more
@@ -282,7 +313,10 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
 
                        wsi->state = WSI_STATE_AWAITING_CLOSE_ACK;
 
-                       /* and we should wait for a reply for a bit out of politeness */
+                       /*
+                        * ...and we should wait for a reply for a bit
+                        * out of politeness
+                        */
 
                        libwebsocket_set_timeout(wsi,
                                                  PENDING_TIMEOUT_CLOSE_ACK, 1);
@@ -292,16 +326,14 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
                        return;
                }
 
-               lwsl_info("close: sending the close packet failed, hanging up\n");
+               lwsl_info("close: sending close packet failed, hanging up\n");
 
                /* else, the send failed and we should just hang up */
        }
 
-#ifndef LWS_NO_EXTENSIONS
 just_kill_connection:
-#endif
 
-       lwsl_debug("libwebsocket_close_and_free_session: just_kill_connection\n");
+       lwsl_debug("close: just_kill_connection\n");
 
        /*
         * we won't be servicing or receiving anything further from this guy
@@ -312,9 +344,18 @@ just_kill_connection:
 
        wsi->state = WSI_STATE_DEAD_SOCKET;
 
-       if (old_state == WSI_STATE_ESTABLISHED && wsi->u.ws.rx_user_buffer) {
-               free(wsi->u.ws.rx_user_buffer);
-               wsi->u.ws.rx_user_buffer = NULL;
+       if ((old_state == WSI_STATE_ESTABLISHED ||
+            wsi->mode == LWS_CONNMODE_WS_SERVING ||
+            wsi->mode == LWS_CONNMODE_WS_CLIENT)) {
+
+               if (wsi->u.ws.rx_user_buffer) {
+                       free(wsi->u.ws.rx_user_buffer);
+                       wsi->u.ws.rx_user_buffer = NULL;
+               }
+               if (wsi->u.ws.rxflow_buffer) {
+                       free(wsi->u.ws.rxflow_buffer);
+                       wsi->u.ws.rxflow_buffer = NULL;
+               }
        }
 
        /* tell the user it's all over for this guy */
@@ -327,7 +368,7 @@ just_kill_connection:
                wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLOSED,
                                                      wsi->user_space, NULL, 0);
        } else
-               lwsl_debug("not calling back closed, old_state=%d\n", old_state);
+               lwsl_debug("not calling back closed\n");
 
 #ifndef LWS_NO_EXTENSIONS
        /* deallocate any active extension contexts */
@@ -358,13 +399,6 @@ just_kill_connection:
        }
 #endif
 
-#ifndef LWS_NO_CLIENT
-       if (wsi->c_address)
-               free(wsi->c_address);
-#endif
-       if (wsi->u.ws.rxflow_buffer)
-               free(wsi->u.ws.rxflow_buffer);
-
 /*     lwsl_info("closing fd=%d\n", wsi->sock); */
 
 #ifdef LWS_OPENSSL_SUPPORT
@@ -378,43 +412,25 @@ just_kill_connection:
                if (wsi->sock) {
                        n = shutdown(wsi->sock, SHUT_RDWR);
                        if (n)
-                               lwsl_debug("closing: shutdown returned %d\n", errno);
+                               lwsl_debug("closing: shutdown returned %d\n",
+                                                                       errno);
 
                        n = compatible_close(wsi->sock);
                        if (n)
-                               lwsl_debug("closing: close returned %d\n", errno);
+                               lwsl_debug("closing: close returned %d\n",
+                                                                       errno);
                }
 #ifdef LWS_OPENSSL_SUPPORT
        }
 #endif
-       if (wsi->protocol && wsi->protocol->per_session_data_size && wsi->user_space) /* user code may own */
+       if (wsi->protocol && wsi->protocol->per_session_data_size &&
+                                       wsi->user_space) /* user code may own */
                free(wsi->user_space);
 
        free(wsi);
 }
 
 /**
- * libwebsockets_hangup_on_client() - Server calls to terminate client
- *                                     connection
- * @context:   libwebsockets context
- * @fd:                Connection socket descriptor
- */
-
-void
-libwebsockets_hangup_on_client(struct libwebsocket_context *context, int fd)
-{
-       struct libwebsocket *wsi = context->lws_lookup[fd];
-
-       if (wsi) {
-               lwsl_info("closing connection at libwebsockets_hangup_on_client:\n");
-               libwebsocket_close_and_free_session(context,
-                       wsi, LWS_CLOSE_STATUS_NOSTATUS);
-       } else
-               close(fd);
-}
-
-
-/**
  * libwebsockets_get_peer_addresses() - Get client address information
  * @context:   Libwebsockets context
  * @wsi:       Local struct libwebsocket associated with
@@ -444,7 +460,7 @@ libwebsockets_get_peer_addresses(struct libwebsocket_context *context,
        int n;
        int ret = -1;
 #ifdef AF_LOCAL
-    struct sockaddr_un *un;
+       struct sockaddr_un *un;
 #endif
 
        rip[0] = '\0';
@@ -452,13 +468,13 @@ libwebsockets_get_peer_addresses(struct libwebsocket_context *context,
 
        lws_latency_pre(context, wsi);
 
-       len = sizeof sin;
+       len = sizeof(sin);
        if (getpeername(fd, (struct sockaddr *) &sin, &len) < 0) {
                perror("getpeername");
                goto bail;
        }
 
-       host = gethostbyaddr((char *) &sin.sin_addr, sizeof sin.sin_addr,
+       host = gethostbyaddr((char *) &sin.sin_addr, sizeof(sin.sin_addr),
                                                                       AF_INET);
        if (host == NULL) {
                perror("gethostbyaddr");
@@ -543,7 +559,18 @@ int lws_set_socket_options(struct libwebsocket_context *context, int fd)
                 * didn't find a way to set these per-socket, need to
                 * tune kernel systemwide values
                 */
-
+#elif WIN32
+               {
+                       DWORD dwBytesRet;
+                       struct tcp_keepalive alive;
+                       alive.onoff = TRUE;
+                       alive.keepalivetime = context->ka_time;
+                       alive.keepaliveinterval = context->ka_interval;
+
+                       if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive), 
+                                                                       NULL, 0, &dwBytesRet, NULL, NULL))
+                               return 1;
+               }
 #else
                /* set the keepalive conditions we want on it too */
                optval = context->ka_time;
@@ -551,12 +578,12 @@ int lws_set_socket_options(struct libwebsocket_context *context, int fd)
                                             (const void *)&optval, optlen) < 0)
                        return 1;
 
-               optval = context->ka_probes;
+               optval = context->ka_interval;
                if (setsockopt(fd, IPPROTO_IP, TCP_KEEPINTVL,
                                             (const void *)&optval, optlen) < 0)
                        return 1;
 
-               optval = context->ka_interval;
+               optval = context->ka_probes;
                if (setsockopt(fd, IPPROTO_IP, TCP_KEEPCNT,
                                             (const void *)&optval, optlen) < 0)
                        return 1;
@@ -671,9 +698,18 @@ lws_handle_POLLOUT_event(struct libwebsocket_context *context,
                /* assuming they gave us something to send, send it */
 
                if (eff_buf.token_len) {
-                       if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
-                                                            eff_buf.token_len))
+                       n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
+                                                            eff_buf.token_len);
+                       if (n < 0)
+                               return -1;
+                       /*
+                        * Keep amount spilled small to minimize chance of this
+                        */
+                       if (n != eff_buf.token_len) {
+                               lwsl_err("Unable to spill ext %d vs %s\n",
+                                                         eff_buf.token_len, n);
                                return -1;
+                       }
                } else
                        continue;
 
@@ -715,7 +751,7 @@ user_service:
                /* external POLL support via protocol 0 */
                context->protocols[0].callback(context, wsi,
                        LWS_CALLBACK_CLEAR_MODE_POLL_FD,
-                       (void *)(long)wsi->sock, NULL, POLLOUT);
+                       wsi->user_space, (void *)(long)wsi->sock, POLLOUT);
        }
 #ifndef LWS_NO_EXTENSIONS
 notify_action:
@@ -727,12 +763,13 @@ notify_action:
                n = LWS_CALLBACK_SERVER_WRITEABLE;
 
        return user_callback_handle_rxflow(wsi->protocol->callback, context,
-               wsi, (enum libwebsocket_callback_reasons) n, wsi->user_space, NULL, 0);
+                       wsi, (enum libwebsocket_callback_reasons) n,
+                                                     wsi->user_space, NULL, 0);
 }
 
 
 
-void
+int
 libwebsocket_service_timeout_check(struct libwebsocket_context *context,
                                     struct libwebsocket *wsi, unsigned int sec)
 {
@@ -752,7 +789,7 @@ libwebsocket_service_timeout_check(struct libwebsocket_context *context,
 
 #endif
        if (!wsi->pending_timeout)
-               return;
+               return 0;
 
        /*
         * if we went beyond the allowed time, kill the
@@ -763,7 +800,10 @@ libwebsocket_service_timeout_check(struct libwebsocket_context *context,
                lwsl_info("TIMEDOUT WAITING\n");
                libwebsocket_close_and_free_session(context,
                                wsi, LWS_CLOSE_STATUS_NOSTATUS);
+               return 1;
        }
+
+       return 0;
 }
 
 /**
@@ -773,7 +813,8 @@ libwebsocket_service_timeout_check(struct libwebsocket_context *context,
  *             happened.
  *
  *     This function takes a pollfd that has POLLIN or POLLOUT activity and
- *     services it according to the state of the associated struct libwebsocket.
+ *     services it according to the state of the associated
+ *     struct libwebsocket.
  *
  *     The one call deals with all "service" that might happen on a socket
  *     including listen accepts, http files as well as websocket protocol.
@@ -788,17 +829,13 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
        int m;
        int listen_socket_fds_index = 0;
        struct timeval tv;
+       int timed_out = 0;
+       int our_fd = 0;
 
 #ifndef LWS_NO_EXTENSIONS
        int more = 1;
 #endif
        struct lws_tokens eff_buf;
-#ifndef LWS_NO_CLIENT
-       extern int lws_client_socket_service(struct libwebsocket_context *context, struct libwebsocket *wsi, struct pollfd *pollfd);
-#endif
-#ifndef LWS_NO_SERVER
-       extern int lws_server_socket_service(struct libwebsocket_context *context, struct libwebsocket *wsi, struct pollfd *pollfd);
-#endif
 
        if (context->listen_service_fd)
                listen_socket_fds_index = context->lws_lookup[
@@ -817,21 +854,35 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
 
                #ifndef WIN32
                /* if our parent went down, don't linger around */
-               if (context->started_with_parent && kill(context->started_with_parent, 0) < 0)
+               if (context->started_with_parent &&
+                                     kill(context->started_with_parent, 0) < 0)
                        kill(getpid(), SIGTERM);
                #endif
 
                /* global timeout check once per second */
 
+               if (pollfd)
+                       our_fd = pollfd->fd;
+
                for (n = 0; n < context->fds_count; n++) {
-                       struct libwebsocket *new_wsi = context->lws_lookup[context->fds[n].fd];
-                       if (!new_wsi)
+                       m = context->fds[n].fd;
+                       wsi = context->lws_lookup[m];
+                       if (!wsi)
                                continue;
-                       libwebsocket_service_timeout_check(context,
-                               new_wsi, tv.tv_sec);
+
+                       if (libwebsocket_service_timeout_check(context, wsi,
+                                                                    tv.tv_sec))
+                               /* he did time out... */
+                               if (m == our_fd)
+                                       /* it was the guy we came to service! */
+                                       timed_out = 1;
                }
        }
 
+       /* the socket we came to service timed out, nothing to do */
+       if (timed_out)
+               return 0;
+
        /* just here for timeout management? */
 
        if (pollfd == NULL)
@@ -848,23 +899,32 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
         * pending connection here, it causes us to check again next time.
         */
 
-       if (context->listen_service_fd && pollfd != &context->fds[listen_socket_fds_index]) {
+       if (context->listen_service_fd && pollfd !=
+                                      &context->fds[listen_socket_fds_index]) {
                context->listen_service_count++;
                if (context->listen_service_extraseen ||
-                               context->listen_service_count == context->listen_service_modulo) {
+                               context->listen_service_count ==
+                                              context->listen_service_modulo) {
                        context->listen_service_count = 0;
                        m = 1;
                        if (context->listen_service_extraseen > 5)
                                m = 2;
                        while (m--) {
-                               /* even with extpoll, we prepared this internal fds for listen */
-                               n = poll(&context->fds[listen_socket_fds_index], 1, 0);
-                               if (n > 0) { /* there's a connection waiting for us */
-                                       libwebsocket_service_fd(context, &context->fds[listen_socket_fds_index]);
+                               /*
+                                * even with extpoll, we prepared this
+                                * internal fds for listen
+                                */
+                               n = poll(&context->fds[listen_socket_fds_index],
+                                                                         1, 0);
+                               if (n > 0) { /* there's a conn waiting for us */
+                                       libwebsocket_service_fd(context,
+                                               &context->
+                                                 fds[listen_socket_fds_index]);
                                        context->listen_service_extraseen++;
                                } else {
                                        if (context->listen_service_extraseen)
-                                               context->listen_service_extraseen--;
+                                               context->
+                                                    listen_service_extraseen--;
                                        break;
                                }
                        }
@@ -877,7 +937,8 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
        wsi = context->lws_lookup[pollfd->fd];
        if (wsi == NULL) {
                if (pollfd->fd > 11)
-                       lwsl_err("unexpected NULL wsi fd=%d fds_count=%d\n", pollfd->fd, context->fds_count);
+                       lwsl_err("unexpected NULL wsi fd=%d fds_count=%d\n",
+                                               pollfd->fd, context->fds_count);
                return 0;
        }
 
@@ -895,7 +956,8 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
 
                /* handle session socket closed */
 
-               if (pollfd->revents & (POLLERR | POLLHUP)) {
+               if ((!pollfd->revents & POLLIN) &&
+                               (pollfd->revents & (POLLERR | POLLHUP))) {
 
                        lwsl_debug("Session Socket %p (fd=%d) dead\n",
                                (void *)wsi, pollfd->fd);
@@ -911,8 +973,9 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
                                            wsi->state == WSI_STATE_ESTABLISHED)
                        if (lws_handle_POLLOUT_event(context, wsi,
                                                                  pollfd) < 0) {
+                               lwsl_info("libwebsocket_service_fd: closing\n");
                                libwebsocket_close_and_free_session(
-                                        context, wsi, LWS_CLOSE_STATUS_NORMAL);
+                                      context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
                                return 0;
                        }
 
@@ -927,17 +990,18 @@ read_pending:
                if (wsi->ssl) {
                        eff_buf.token_len = SSL_read(wsi->ssl,
                                        context->service_buffer,
-                                               sizeof context->service_buffer);
+                                              sizeof(context->service_buffer));
                        if (!eff_buf.token_len) {
                                n = SSL_get_error(wsi->ssl, eff_buf.token_len);
                                lwsl_err("SSL_read returned 0 with reason %s\n",
-                                 ERR_error_string(n, (char *)context->service_buffer));
+                                 ERR_error_string(n,
+                                             (char *)context->service_buffer));
                        }
                } else
 #endif
                        eff_buf.token_len = recv(pollfd->fd,
-                                       context->service_buffer,
-                                            sizeof context->service_buffer, 0);
+                               context->service_buffer,
+                                           sizeof(context->service_buffer), 0);
 
                if (eff_buf.token_len < 0) {
                        lwsl_debug("Socket read returned %d\n",
@@ -948,7 +1012,7 @@ read_pending:
                        return 0;
                }
                if (!eff_buf.token_len) {
-                       lwsl_info("closing connection due to zero length read\n");
+                       lwsl_info("closing connection due to 0 length read\n");
                        libwebsocket_close_and_free_session(context, wsi,
                                                    LWS_CLOSE_STATUS_NOSTATUS);
                        return 0;
@@ -1040,6 +1104,7 @@ libwebsocket_context_destroy(struct libwebsocket_context *context)
        int n;
        int m;
        struct libwebsocket_extension *ext;
+       struct libwebsocket_protocols *protocol = context->protocols;
 
 #ifdef LWS_LATENCY
        if (context->worst_latency_info[0])
@@ -1047,9 +1112,11 @@ libwebsocket_context_destroy(struct libwebsocket_context *context)
 #endif
 
        for (n = 0; n < context->fds_count; n++) {
-               struct libwebsocket *wsi = context->lws_lookup[context->fds[n].fd];
+               struct libwebsocket *wsi =
+                                       context->lws_lookup[context->fds[n].fd];
                libwebsocket_close_and_free_session(context,
-                       wsi, LWS_CLOSE_STATUS_GOINGAWAY);
+                       wsi, LWS_CLOSE_STATUS_NOSTATUS /* no protocol close */);
+               n--;
        }
 
        /*
@@ -1062,9 +1129,23 @@ libwebsocket_context_destroy(struct libwebsocket_context *context)
        if (context->listen_port)
                m = LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT;
        while (ext && ext->callback) {
-               ext->callback(context, ext, NULL, (enum libwebsocket_extension_callback_reasons)m, NULL, NULL, 0);
+               ext->callback(context, ext, NULL,
+                       (enum libwebsocket_extension_callback_reasons)m,
+                                                                NULL, NULL, 0);
                ext++;
        }
+
+       /*
+        * inform all the protocols that they are done and will have no more
+        * callbacks
+        */
+
+       while (protocol->callback) {
+               protocol->callback(context, NULL, LWS_CALLBACK_PROTOCOL_DESTROY,
+                               NULL, NULL, 0);
+               protocol++;
+       }
+
 #endif
 
 #ifdef WIN32
@@ -1077,6 +1158,11 @@ libwebsocket_context_destroy(struct libwebsocket_context *context)
                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
 
        if (context->fds)
@@ -1092,7 +1178,7 @@ libwebsocket_context_destroy(struct libwebsocket_context *context)
 }
 
 /**
- * libwebsocket_context_user() - get the user data associated with the whole context
+ * libwebsocket_context_user() - get the user data associated with the context
  * @context: Websocket context
  *
  *     This returns the optional user allocation that can be attached to
@@ -1100,12 +1186,10 @@ libwebsocket_context_destroy(struct libwebsocket_context *context)
  *     to let all sockets serviced in the same context share data without
  *     using globals statics in the user code.
  */
-
-
 LWS_EXTERN void *
 libwebsocket_context_user(struct libwebsocket_context *context)
 {
-    return context->user_space;
+       return context->user_space;
 }
 
 /**
@@ -1140,7 +1224,6 @@ libwebsocket_context_user(struct libwebsocket_context *context)
  *     nothing is pending, or as soon as it services whatever was pending.
  */
 
-
 int
 libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
 {
@@ -1249,8 +1332,8 @@ libwebsocket_callback_on_writable(struct libwebsocket_context *context,
                return 1;
 #endif
        if (wsi->position_in_fds_table < 0) {
-               lwsl_err("libwebsocket_callback_on_writable: "
-                                     "failed to find socket %d\n", wsi->sock);
+               lwsl_err("libwebsocket_callback_on_writable: failed to find socket %d\n",
+                                                                    wsi->sock);
                return -1;
        }
 
@@ -1259,7 +1342,7 @@ libwebsocket_callback_on_writable(struct libwebsocket_context *context,
        /* external POLL support via protocol 0 */
        context->protocols[0].callback(context, wsi,
                LWS_CALLBACK_SET_MODE_POLL_FD,
-               (void *)(long)wsi->sock, NULL, POLLOUT);
+               wsi->user_space, (void *)(long)wsi->sock, POLLOUT);
 
        return 1;
 }
@@ -1331,7 +1414,8 @@ libwebsocket_get_socket_fd(struct libwebsocket *wsi)
 
 #ifdef LWS_LATENCY
 void
-lws_latency(struct libwebsocket_context *context, struct libwebsocket *wsi, const char *action, int ret, int completed)
+lws_latency(struct libwebsocket_context *context, struct libwebsocket *wsi,
+                                    const char *action, int ret, int completed)
 {
        struct timeval tv;
        unsigned long u;
@@ -1344,12 +1428,21 @@ lws_latency(struct libwebsocket_context *context, struct libwebsocket *wsi, cons
        if (action) {
                if (completed) {
                        if (wsi->action_start == wsi->latency_start)
-                               sprintf(buf, "Completion first try lat %luus: %p: ret %d: %s\n", u - wsi->latency_start, (void *)wsi, ret, action);
+                               sprintf(buf,
+                       "Completion first try lat %luus: %p: ret %d: %s\n",
+                                       u - wsi->latency_start,
+                                       (void *)wsi, ret, action);
                        else
-                               sprintf(buf, "Completion %luus: lat %luus: %p: ret %d: %s\n", u - wsi->action_start, u - wsi->latency_start, (void *)wsi, ret, action);
+                               sprintf(buf,
+                       "Completion %luus: lat %luus: %p: ret %d: %s\n",
+                                       u - wsi->action_start,
+                                       u - wsi->latency_start,
+                                       (void *)wsi, ret, action);
                        wsi->action_start = 0;
                } else
-                       sprintf(buf, "lat %luus: %p: ret %d: %s\n", u - wsi->latency_start, (void *)wsi, ret, action);
+                       sprintf(buf, "lat %luus: %p: ret %d: %s\n",
+                                       u - wsi->latency_start,
+                                                     (void *)wsi, ret, action);
                if (u - wsi->latency_start > context->worst_latency) {
                        context->worst_latency = u - wsi->latency_start;
                        strcpy(context->worst_latency_info, buf);
@@ -1381,13 +1474,14 @@ _libwebsocket_rx_flow_control(struct libwebsocket *wsi)
 
        wsi->u.ws.rxflow_change_to &= ~2;
 
-       lwsl_info("rxflow: wsi %p change_to %d\n", wsi, wsi->u.ws.rxflow_change_to);
+       lwsl_info("rxflow: wsi %p change_to %d\n",
+                                       wsi, wsi->u.ws.rxflow_change_to);
 
        /* if we're letting it come again, did we interrupt anything? */
        if ((wsi->u.ws.rxflow_change_to & 1) && wsi->u.ws.rxflow_buffer) {
                n = libwebsocket_interpret_incoming_packet(wsi, NULL, 0);
                if (n < 0) {
-                       lwsl_info("returning that we want to close connection at libwebsocket_rx_flow_control:\n");
+                       lwsl_info("libwebsocket_rx_flow_control: close req\n");
                        return -1;
                }
                if (n)
@@ -1404,12 +1498,12 @@ _libwebsocket_rx_flow_control(struct libwebsocket *wsi)
                /* external POLL support via protocol 0 */
                context->protocols[0].callback(context, wsi,
                        LWS_CALLBACK_SET_MODE_POLL_FD,
-                       (void *)(long)wsi->sock, NULL, POLLIN);
+                       wsi->user_space, (void *)(long)wsi->sock, POLLIN);
        else
                /* external POLL support via protocol 0 */
                context->protocols[0].callback(context, wsi,
                        LWS_CALLBACK_CLEAR_MODE_POLL_FD,
-                       (void *)(long)wsi->sock, NULL, POLLIN);
+                       wsi->user_space, (void *)(long)wsi->sock, POLLIN);
 
        return 1;
 }
@@ -1491,7 +1585,7 @@ OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
 #endif
 
 int user_callback_handle_rxflow(callback_function callback_function,
-               struct libwebsocket_context * context,
+               struct libwebsocket_context *context,
                        struct libwebsocket *wsi,
                         enum libwebsocket_callback_reasons reason, void *user,
                                                          void *in, size_t len)
@@ -1539,9 +1633,9 @@ int user_callback_handle_rxflow(callback_function callback_function,
 struct libwebsocket_context *
 libwebsocket_create_context(struct lws_context_creation_info *info)
 {
-       int n;
        struct libwebsocket_context *context = NULL;
        char *p;
+       int n;
 #ifndef LWS_NO_SERVER
        int opt = 1;
        struct libwebsocket *wsi;
@@ -1557,25 +1651,23 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
 #endif
 
 #ifndef LWS_NO_DAEMONIZE
-       extern int get_daemonize_pid();
        int pid_daemon = get_daemonize_pid();
 #endif
 
        lwsl_notice("Initial logging level %d\n", log_level);
        lwsl_notice("Library version: %s\n", library_version);
-       lwsl_info(" LWS_MAX_HEADER_NAME_LENGTH: %u\n", LWS_MAX_HEADER_NAME_LENGTH);
        lwsl_info(" LWS_MAX_HEADER_LEN: %u\n", LWS_MAX_HEADER_LEN);
-       lwsl_info(" LWS_INITIAL_HDR_ALLOC: %u\n", LWS_INITIAL_HDR_ALLOC);
-       lwsl_info(" LWS_ADDITIONAL_HDR_ALLOC: %u\n", LWS_ADDITIONAL_HDR_ALLOC);
        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);
+       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(" CIPHERS_LIST_STRING: '%s'\n", CIPHERS_LIST_STRING);
+       if (info->ssl_cipher_list)
+               lwsl_info(" SSL ciphers: '%s'\n", info->ssl_cipher_list);
        lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
        lwsl_info(" LWS_MAX_ZLIB_CONN_BUFFER: %u\n", LWS_MAX_ZLIB_CONN_BUFFER);
 
@@ -1611,7 +1703,8 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
        }
 #endif
 
-       context = (struct libwebsocket_context *) malloc(sizeof(struct libwebsocket_context));
+       context = (struct libwebsocket_context *)
+                               malloc(sizeof(struct libwebsocket_context));
        if (!context) {
                lwsl_err("No memory for websocket context\n");
                return NULL;
@@ -1621,7 +1714,7 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
        context->started_with_parent = pid_daemon;
        lwsl_notice(" Started with daemon pid %d\n", pid_daemon);
 #endif
-       
+
        context->listen_service_extraseen = 0;
        context->protocols = info->protocols;
        context->listen_port = info->port;
@@ -1634,17 +1727,24 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
                sizeof(struct libwebsocket_context),
                sizeof(struct pollfd) + sizeof(struct libwebsocket *),
                context->max_fds,
-               sizeof(struct libwebsocket_context) + ((sizeof(struct pollfd) + sizeof(struct libwebsocket *)) * context->max_fds));
+               sizeof(struct libwebsocket_context) +
+               ((sizeof(struct pollfd) + sizeof(struct libwebsocket *)) *
+                                                            context->max_fds));
 
-       context->fds = (struct pollfd *)malloc(sizeof(struct pollfd) * context->max_fds);
+       context->fds = (struct pollfd *)malloc(sizeof(struct pollfd) *
+                                                             context->max_fds);
        if (context->fds == NULL) {
-               lwsl_err("Unable to allocate fds array for %d connections\n", context->max_fds);
+               lwsl_err("Unable to allocate fds array for %d connections\n",
+                                                             context->max_fds);
                free(context);
                return NULL;
        }
-       context->lws_lookup = (struct libwebsocket **)malloc(sizeof(struct libwebsocket *) * context->max_fds);
+       context->lws_lookup = (struct libwebsocket **)
+                     malloc(sizeof(struct libwebsocket *) * context->max_fds);
        if (context->lws_lookup == NULL) {
-               lwsl_err("Unable to allocate lws_lookup array for %d connections\n", context->max_fds);
+               lwsl_err(
+                 "Unable to allocate lws_lookup array for %d connections\n",
+                                                             context->max_fds);
                free(context->fds);
                free(context);
                return NULL;
@@ -1679,36 +1779,12 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
 
 #ifndef LWS_NO_SERVER
        if (!(info->options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME)) {
-               struct sockaddr sa;
-               context->service_buffer[0] = '\0';
-
                /* find canonical hostname */
+               gethostname((char *)context->canonical_hostname,
+                                      sizeof(context->canonical_hostname) - 1);
 
-               context->service_buffer[(sizeof context->service_buffer) - 1] = '\0';
-               memset(&sa, 0, sizeof(sa));
-               sa.sa_family = AF_INET;
-               sa.sa_data[(sizeof sa.sa_data) - 1] = '\0';
-               gethostname((char *)context->service_buffer, (sizeof context->service_buffer) - 1);
-
-               n = 0;
-
-               if (strlen((char *)context->service_buffer) < sizeof(sa.sa_data) - 1) {
-                       strcpy(sa.sa_data, (char *)context->service_buffer);
-                       lwsl_debug("my host name is %s\n", sa.sa_data);
-                       n = getnameinfo(&sa, sizeof(sa), (char *)context->service_buffer,
-                               (sizeof context->service_buffer) - 1, NULL, 0, NI_NAMEREQD);
-               }
-
-               if (!n) {
-                       strncpy(context->canonical_hostname, (char *)context->service_buffer,
-                                               sizeof context->canonical_hostname - 1);
-                       context->canonical_hostname[
-                                       sizeof context->canonical_hostname - 1] = '\0';
-               } else
-                       strncpy(context->canonical_hostname, (char *)context->service_buffer,
-                                               sizeof context->canonical_hostname - 1);
-
-               lwsl_notice(" canonical_hostname = %s\n", context->canonical_hostname);
+               lwsl_notice(" canonical_hostname = %s\n",
+                                       context->canonical_hostname);
        }
 #endif
 
@@ -1717,9 +1793,9 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
        p = getenv("http_proxy");
        if (p) {
                strncpy(context->http_proxy_address, p,
-                                      sizeof context->http_proxy_address - 1);
+                                     sizeof(context->http_proxy_address) - 1);
                context->http_proxy_address[
-                                sizeof context->http_proxy_address - 1] = '\0';
+                               sizeof(context->http_proxy_address) - 1] = '\0';
 
                p = strchr(context->http_proxy_address, ':');
                if (p == NULL) {
@@ -1756,11 +1832,13 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
                        lwsl_notice(" Not compiled for OpenSSl support!\n");
                        goto bail;
                }
-               lwsl_notice(" Compiled without SSL support, "
-                                                      "serving unencrypted\n");
+               lwsl_notice(" Compiled without SSL support\n");
 #endif
 
-               lwsl_notice(" per-connection allocation: %u + headers during handshake + frame buffer set by protocol\n", sizeof(struct libwebsocket));
+               lwsl_notice(
+                       " per-conn mem: %u + %u headers + protocol rx buf\n",
+                               sizeof(struct libwebsocket),
+                                             sizeof(struct allocated_headers));
        }
 #endif
 
@@ -1790,14 +1868,18 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
 
        method = (SSL_METHOD *)SSLv23_server_method();
        if (!method) {
-               lwsl_err("problem creating ssl method: %s\n",
-                       ERR_error_string(ERR_get_error(), (char *)context->service_buffer));
+               lwsl_err("problem creating ssl method %lu: %s\n", 
+                       ERR_get_error(),
+                       ERR_error_string(ERR_get_error(),
+                                             (char *)context->service_buffer));
                goto bail;
        }
        context->ssl_ctx = SSL_CTX_new(method); /* create context */
        if (!context->ssl_ctx) {
-               lwsl_err("problem creating ssl context: %s\n",
-                       ERR_error_string(ERR_get_error(), (char *)context->service_buffer));
+               lwsl_err("problem creating ssl context %lu: %s\n",
+                       ERR_get_error(),
+                       ERR_error_string(ERR_get_error(),
+                                             (char *)context->service_buffer));
                goto bail;
        }
 
@@ -1805,7 +1887,9 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
        SSL_CTX_set_options(context->ssl_ctx, SSL_OP_NO_COMPRESSION);
 #endif
        SSL_CTX_set_options(context->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
-       SSL_CTX_set_cipher_list(context->ssl_ctx, CIPHERS_LIST_STRING);
+       if (info->ssl_cipher_list)
+               SSL_CTX_set_cipher_list(context->ssl_ctx,
+                                               info->ssl_cipher_list);
 
 #ifndef LWS_NO_CLIENT
 
@@ -1814,23 +1898,31 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
        if (info->port == CONTEXT_PORT_NO_LISTEN) {
                method = (SSL_METHOD *)SSLv23_client_method();
                if (!method) {
-                       lwsl_err("problem creating ssl method: %s\n",
-                               ERR_error_string(ERR_get_error(), (char *)context->service_buffer));
+                       lwsl_err("problem creating ssl method %lu: %s\n",
+                               ERR_get_error(),
+                               ERR_error_string(ERR_get_error(),
+                                             (char *)context->service_buffer));
                        goto bail;
                }
                /* create context */
                context->ssl_client_ctx = SSL_CTX_new(method);
                if (!context->ssl_client_ctx) {
-                       lwsl_err("problem creating ssl context: %s\n",
-                               ERR_error_string(ERR_get_error(), (char *)context->service_buffer));
+                       lwsl_err("problem creating ssl context %lu: %s\n",
+                               ERR_get_error(),
+                               ERR_error_string(ERR_get_error(),
+                                             (char *)context->service_buffer));
                        goto bail;
                }
 
 #ifdef SSL_OP_NO_COMPRESSION
-               SSL_CTX_set_options(context->ssl_client_ctx, SSL_OP_NO_COMPRESSION);
+               SSL_CTX_set_options(context->ssl_client_ctx,
+                                                        SSL_OP_NO_COMPRESSION);
 #endif
-               SSL_CTX_set_options(context->ssl_client_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
-               SSL_CTX_set_cipher_list(context->ssl_client_ctx, CIPHERS_LIST_STRING);
+               SSL_CTX_set_options(context->ssl_client_ctx,
+                                              SSL_OP_CIPHER_SERVER_PREFERENCE);
+               if (info->ssl_cipher_list)
+                       SSL_CTX_set_cipher_list(context->ssl_client_ctx,
+                                                       info->ssl_cipher_list);
 
                /* openssl init for cert verification (for client sockets) */
                if (!info->ssl_ca_filepath) {
@@ -1838,10 +1930,10 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
                                context->ssl_client_ctx, NULL,
                                                     LWS_OPENSSL_CLIENT_CERTS))
                                lwsl_err(
-                                       "Unable to load SSL Client certs from %s "
-                                       "(set by --with-client-cert-dir= in configure) -- "
-                                       " client ssl isn't going to work",
-                                                    LWS_OPENSSL_CLIENT_CERTS);
+                                   "Unable to load SSL Client certs from %s "
+                                   "(set by --with-client-cert-dir= "
+                                   "in configure) --  client ssl isn't "
+                                   "going to work", LWS_OPENSSL_CLIENT_CERTS);
                } else
                        if (!SSL_CTX_load_verify_locations(
                                context->ssl_client_ctx, info->ssl_ca_filepath,
@@ -1864,7 +1956,8 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
 
        /* as a server, are we requiring clients to identify themselves? */
 
-       if (info->options & LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT) {
+       if (info->options &
+                       LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT) {
 
                /* absolutely require the client cert */
 
@@ -1890,18 +1983,22 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
                n = SSL_CTX_use_certificate_chain_file(context->ssl_ctx,
                                        info->ssl_cert_filepath);
                if (n != 1) {
-                       lwsl_err("problem getting cert '%s': %s\n",
+                       lwsl_err("problem getting cert '%s' %lu: %s\n",
                                info->ssl_cert_filepath,
-                               ERR_error_string(ERR_get_error(), (char *)context->service_buffer));
+                               ERR_get_error(),
+                               ERR_error_string(ERR_get_error(),
+                                             (char *)context->service_buffer));
                        goto bail;
                }
                /* set the private key from KeyFile */
                if (SSL_CTX_use_PrivateKey_file(context->ssl_ctx,
                             info->ssl_private_key_filepath,
                                                       SSL_FILETYPE_PEM) != 1) {
-                       lwsl_err("ssl problem getting key '%s': %s\n",
-                                               info->ssl_private_key_filepath,
-                               ERR_error_string(ERR_get_error(), (char *)context->service_buffer));
+                       lwsl_err("ssl problem getting key '%s' %lu: %s\n",
+                               info->ssl_private_key_filepath,
+                                       ERR_get_error(),
+                                       ERR_error_string(ERR_get_error(),
+                                             (char *)context->service_buffer));
                        goto bail;
                }
                /* verify private key */
@@ -1923,7 +2020,6 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
        /* set up our external listening socket we serve on */
 
        if (info->port) {
-               extern int interface_to_sa(const char *ifname, struct sockaddr_in *addr, size_t addrlen);
                int sockfd;
 
                sockfd = socket(AF_INET, SOCK_STREAM, 0);
@@ -1933,10 +2029,13 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
                }
 
 #ifndef WIN32
-               /* allow us to restart even if old sockets in TIME_WAIT
-                * (REUSEADDR on Unix means, "don't hang on to this address after the
-                * listener is closed."  On Windows, though, it means "don't keep other
-                * processes from binding to this address while we're using it) */
+               /*
+                * allow us to restart even if old sockets in TIME_WAIT
+                * (REUSEADDR on Unix means, "don't hang on to this
+                * address after the listener is closed."  On Windows, though,
+                * it means "don't keep other processes from binding to
+                * this address while we're using it)
+                */
                setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
                                              (const void *)&opt, sizeof(opt));
 #endif
@@ -1948,17 +2047,17 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
 
                #ifdef WIN32
                opt = 0;
-               ioctlsocket(sockfd, FIONBIO, (unsigned long *)&opt );
+               ioctlsocket(sockfd, FIONBIO, (unsigned long *)&opt);
                #else
                fcntl(sockfd, F_SETFL, O_NONBLOCK);
                #endif
 
                bzero((char *) &serv_addr, sizeof(serv_addr));
                serv_addr.sin_family = AF_INET;
-               if (info->interface == NULL)
+               if (info->iface == NULL)
                        serv_addr.sin_addr.s_addr = INADDR_ANY;
                else
-                       interface_to_sa(info->interface, &serv_addr,
+                       interface_to_sa(info->iface, &serv_addr,
                                                sizeof(serv_addr));
                serv_addr.sin_port = htons(info->port);
 
@@ -1971,13 +2070,14 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
                        goto bail;
                }
 
-               wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
+               wsi = (struct libwebsocket *)malloc(
+                                       sizeof(struct libwebsocket));
                if (wsi == NULL) {
                        lwsl_err("Out of mem\n");
                        close(sockfd);
                        goto bail;
                }
-               memset(wsi, 0, sizeof (struct libwebsocket));
+               memset(wsi, 0, sizeof(struct libwebsocket));
                wsi->sock = sockfd;
 #ifndef LWS_NO_EXTENSIONS
                wsi->count_active_extensions = 0;
@@ -2023,6 +2123,13 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
                                                                        context;
                info->protocols[context->count_protocols].protocol_index =
                                                       context->count_protocols;
+
+               /*
+                * inform all the protocols that they are doing their one-time
+                * initialization if they want to
+                */
+               info->protocols[context->count_protocols].callback(context,
+                              NULL, LWS_CALLBACK_PROTOCOL_INIT, NULL, NULL, 0);
        }
 
 #ifndef LWS_NO_EXTENSIONS
@@ -2034,7 +2141,7 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
        m = LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT;
        if (info->port)
                m = LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT;
-       
+
        if (info->extensions) {
                ext = info->extensions;
                while (ext->callback) {
@@ -2081,9 +2188,12 @@ libwebsocket_get_reserved_bits(struct libwebsocket *wsi)
        return wsi->u.ws.rsv;
 }
 
-void *
+int
 libwebsocket_ensure_user_space(struct libwebsocket *wsi)
 {
+       if (!wsi->protocol)
+               return 1;
+
        /* allocate the per-connection user memory (if any) */
 
        if (wsi->protocol->per_session_data_size && !wsi->user_space) {
@@ -2091,12 +2201,12 @@ libwebsocket_ensure_user_space(struct libwebsocket *wsi)
                                  wsi->protocol->per_session_data_size);
                if (wsi->user_space  == NULL) {
                        lwsl_err("Out of memory for conn user space\n");
-                       return NULL;
+                       return 1;
                }
                memset(wsi->user_space, 0,
                                         wsi->protocol->per_session_data_size);
        }
-       return wsi->user_space;
+       return 0;
 }
 
 static void lwsl_emit_stderr(int level, const char *line)
@@ -2111,10 +2221,10 @@ static void lwsl_emit_stderr(int level, const char *line)
        for (n = 0; n < LLL_COUNT; n++)
                if (level == (1 << n)) {
                        sprintf(buf, "[%ld:%04d] %s: ", tv.tv_sec,
-                                       (int)(tv.tv_usec / 100), log_level_names[n]);
+                               (int)(tv.tv_usec / 100), log_level_names[n]);
                        break;
                }
-       
+
        fprintf(stderr, "%s%s", buf, line);
 }
 
@@ -2155,8 +2265,8 @@ void _lws_log(int filter, const char *format, ...)
                return;
 
        va_start(ap, format);
-       vsnprintf(buf, (sizeof buf), format, ap);
-       buf[(sizeof buf) - 1] = '\0';
+       vsnprintf(buf, sizeof(buf), format, ap);
+       buf[sizeof(buf) - 1] = '\0';
        va_end(ap);
 
        lwsl_emit(filter, buf);
@@ -2169,11 +2279,12 @@ void _lws_log(int filter, const char *format, ...)
  *                     function to perform log string emission instead of
  *                     the default stderr one.
  *
- *     log level defaults to "err" and "warn" contexts enabled only and
+ *     log level defaults to "err", "warn" and "notice" contexts enabled and
  *     emission on stderr.
  */
 
-void lws_set_log_level(int level, void (*log_emit_function)(int level, const char *line))
+void lws_set_log_level(int level, void (*log_emit_function)(int level,
+                                                             const char *line))
 {
        log_level = level;
        if (log_emit_function)