updated spec enabled ssl
[profile/ivi/libwebsockets.git] / lib / libwebsockets.c
index ed0db66..0c85f0a 100644 (file)
 #ifdef WIN32
 #include <tchar.h>
 #include <io.h>
+#include <mstcpip.h>
 #else
 #ifdef LWS_BUILTIN_GETIFADDRS
 #include <getifaddrs.h>
 #else
 #include <ifaddrs.h>
 #endif
+#include <syslog.h>
 #include <sys/un.h>
 #include <sys/socket.h>
 #include <netdb.h>
@@ -47,10 +49,17 @@ int openssl_websocket_private_data_index;
 #endif
 #endif
 
+#ifndef LWS_BUILD_HASH
+#define LWS_BUILD_HASH "unknown-build-hash"
+#endif
+
 static int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE;
-static void lwsl_emit_stderr(const char *line);
-static void (*lwsl_emit)(const char *line) = lwsl_emit_stderr;
-static const char *log_level_names[] = {
+static void lwsl_emit_stderr(int level, const char *line);
+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 * const log_level_names[] = {
        "ERR",
        "WARN",
        "NOTICE",
@@ -60,25 +69,54 @@ static const char *log_level_names[] = {
        "HEADER",
        "EXTENSION",
        "CLIENT",
+       "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
+ *
+ *     returns a const char * to a string like "1.1 178d78c"
+ *     representing the library version followed by the git head hash it
+ *     was built from
+ */
+
+const char *
+lws_get_library_version(void)
+{
+       return library_version;
+}
+
 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;
@@ -89,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;
 
@@ -103,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;
 }
@@ -138,10 +185,12 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
        int old_state;
        unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 2 +
                                                  LWS_SEND_BUFFER_POST_PADDING];
+#ifndef LWS_NO_EXTENSIONS
        int ret;
        int m;
        struct lws_tokens eff_buf;
        struct libwebsocket_extension *ext;
+#endif
 
        if (!wsi)
                return;
@@ -151,14 +200,23 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
        if (old_state == WSI_STATE_DEAD_SOCKET)
                return;
 
-       wsi->close_reason = reason;
+       /* 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) {
+               close(wsi->u.http.fd);
+               wsi->u.http.fd = 0;
+       }
 
+#ifndef LWS_NO_EXTENSIONS
        /*
         * are his extensions okay with him closing?  Eg he might be a mux
         * parent and just his ch1 aspect is closing?
         */
 
-
        for (n = 0; n < wsi->count_active_extensions; n++) {
                if (!wsi->active_extensions[n]->callback)
                        continue;
@@ -180,8 +238,6 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
                }
        }
 
-
-
        /*
         * flush any tx pending from extensions, since we may send close packet
         * if there are problems with send, just nuke the connection
@@ -220,11 +276,12 @@ 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;
                        }
        }
+#endif
 
        /*
         * signal we are closing, libsocket_write will
@@ -243,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
@@ -253,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);
@@ -263,14 +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 */
        }
 
 just_kill_connection:
 
-       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
@@ -281,6 +344,20 @@ just_kill_connection:
 
        wsi->state = WSI_STATE_DEAD_SOCKET;
 
+       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 */
 
        if (wsi->protocol && wsi->protocol->callback &&
@@ -291,8 +368,9 @@ 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 */
 
        for (n = 0; n < wsi->count_active_extensions; n++) {
@@ -319,18 +397,7 @@ just_kill_connection:
                                       NULL, NULL, 0);
                ext++;
        }
-
-       /* free up his parsing allocations */
-
-       for (n = 0; n < WSI_TOKEN_COUNT; n++)
-               if (wsi->utf8_token[n].token)
-                       free(wsi->utf8_token[n].token);
-#ifndef LWS_NO_CLIENT
-       if (wsi->c_address)
-               free(wsi->c_address);
 #endif
-       if (wsi->rxflow_buffer)
-               free(wsi->rxflow_buffer);
 
 /*     lwsl_info("closing fd=%d\n", wsi->sock); */
 
@@ -345,43 +412,28 @@ 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) {
-               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
  * @fd:                Connection socket descriptor
  * @name:      Buffer to take client address name
  * @name_len:  Length of client address name buffer
@@ -395,7 +447,8 @@ libwebsockets_hangup_on_client(struct libwebsocket_context *context, int fd)
  */
 
 void
-libwebsockets_get_peer_addresses(int fd, char *name, int name_len,
+libwebsockets_get_peer_addresses(struct libwebsocket_context *context,
+       struct libwebsocket *wsi, int fd, char *name, int name_len,
                                        char *rip, int rip_len)
 {
        unsigned int len;
@@ -405,24 +458,27 @@ libwebsockets_get_peer_addresses(int fd, char *name, int name_len,
        char ip[128];
        unsigned char *p;
        int n;
+       int ret = -1;
 #ifdef AF_LOCAL
-    struct sockaddr_un *un;
+       struct sockaddr_un *un;
 #endif
 
        rip[0] = '\0';
        name[0] = '\0';
 
-       len = sizeof sin;
+       lws_latency_pre(context, wsi);
+
+       len = sizeof(sin);
        if (getpeername(fd, (struct sockaddr *) &sin, &len) < 0) {
                perror("getpeername");
-               return;
+               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");
-               return;
+               goto bail;
        }
 
        strncpy(name, host->h_name, name_len);
@@ -430,7 +486,7 @@ libwebsockets_get_peer_addresses(int fd, char *name, int name_len,
 
        host1 = gethostbyname(host->h_name);
        if (host1 == NULL)
-               return;
+               goto bail;
        p = (unsigned char *)host1;
        n = 0;
        while (p != NULL) {
@@ -457,6 +513,10 @@ libwebsockets_get_peer_addresses(int fd, char *name, int name_len,
                strncpy(rip, ip, rip_len);
                rip[rip_len - 1] = '\0';
        }
+
+       ret = 0;
+bail:
+       lws_latency(context, wsi, "libwebsockets_get_peer_addresses", ret, 1);
 }
 
 int libwebsockets_get_random(struct libwebsocket_context *context,
@@ -475,10 +535,78 @@ int libwebsockets_get_random(struct libwebsocket_context *context,
        return n;
 }
 
-unsigned char *
-libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md)
+int lws_set_socket_options(struct libwebsocket_context *context, int fd)
 {
-       return SHA1(d, n, md);
+       int optval = 1;
+       socklen_t optlen = sizeof(optval);
+#ifdef WIN32
+       unsigned long optl = 0;
+#endif
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
+       struct protoent *tcp_proto;
+#endif
+
+       if (context->ka_time) {
+               /* enable keepalive on this socket */
+               optval = 1;
+               if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
+                                            (const void *)&optval, optlen) < 0)
+                       return 1;
+
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
+
+               /*
+                * 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;
+               if (setsockopt(fd, IPPROTO_IP, TCP_KEEPIDLE,
+                                            (const void *)&optval, optlen) < 0)
+                       return 1;
+
+               optval = context->ka_interval;
+               if (setsockopt(fd, IPPROTO_IP, TCP_KEEPINTVL,
+                                            (const void *)&optval, optlen) < 0)
+                       return 1;
+
+               optval = context->ka_probes;
+               if (setsockopt(fd, IPPROTO_IP, TCP_KEEPCNT,
+                                            (const void *)&optval, optlen) < 0)
+                       return 1;
+#endif
+       }
+
+       /* Disable Nagle */
+       optval = 1;
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
+       setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen);
+#else
+       tcp_proto = getprotobyname("TCP");
+       setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen);
+#endif
+
+       /* We are nonblocking... */
+#ifdef WIN32
+       ioctlsocket(fd, FIONBIO, &optl);
+#else
+       fcntl(fd, F_SETFL, O_NONBLOCK);
+#endif
+
+       return 0;
 }
 
 int lws_send_pipe_choked(struct libwebsocket *wsi)
@@ -504,8 +632,10 @@ int
 lws_handle_POLLOUT_event(struct libwebsocket_context *context,
                                struct libwebsocket *wsi, struct pollfd *pollfd)
 {
-       struct lws_tokens eff_buf;
        int n;
+
+#ifndef LWS_NO_EXTENSIONS
+       struct lws_tokens eff_buf;
        int ret;
        int m;
        int handled = 0;
@@ -568,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;
 
@@ -603,6 +742,7 @@ lws_handle_POLLOUT_event(struct libwebsocket_context *context,
        wsi->extension_data_pending = 0;
 
 user_service:
+#endif
        /* one shot */
 
        if (pollfd) {
@@ -611,28 +751,29 @@ 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:
+#endif
 
        if (wsi->mode == LWS_CONNMODE_WS_CLIENT)
                n = LWS_CALLBACK_CLIENT_WRITEABLE;
        else
                n = LWS_CALLBACK_SERVER_WRITEABLE;
 
-       user_callback_handle_rxflow(wsi->protocol->callback, context,
-               wsi, (enum libwebsocket_callback_reasons) n, wsi->user_space, NULL, 0);
-
-       return 0;
+       return user_callback_handle_rxflow(wsi->protocol->callback, context,
+                       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)
 {
+#ifndef LWS_NO_EXTENSIONS
        int n;
 
        /*
@@ -646,8 +787,9 @@ libwebsocket_service_timeout_check(struct libwebsocket_context *context,
                                    wsi, LWS_EXT_CALLBACK_1HZ,
                                    wsi->active_extensions_user[n], NULL, sec);
 
+#endif
        if (!wsi->pending_timeout)
-               return;
+               return 0;
 
        /*
         * if we went beyond the allowed time, kill the
@@ -658,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;
 }
 
 /**
@@ -667,9 +812,12 @@ libwebsocket_service_timeout_check(struct libwebsocket_context *context,
  * @pollfd:    The pollfd entry describing the socket fd and which events
  *             happened.
  *
- *     This function closes any active connections and then frees the
- *     context.  After calling this, any further use of the context is
- *     undefined.
+ *     This function takes a pollfd that has POLLIN or POLLOUT activity and
+ *     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.
  */
 
 int
@@ -677,19 +825,22 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
                                                          struct pollfd *pollfd)
 {
        struct libwebsocket *wsi;
-       unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1 +
-                        MAX_BROADCAST_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING];
        int n;
        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;
-       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
+       struct lws_tokens eff_buf;
+
+       if (context->listen_service_fd)
+               listen_socket_fds_index = context->lws_lookup[
+                            context->listen_service_fd]->position_in_fds_table;
+
        /*
         * you can call us with pollfd = NULL to just allow the once-per-second
         * global timeout checks; if less than a second since the last check
@@ -701,17 +852,37 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
        if (context->last_timeout_check_s != tv.tv_sec) {
                context->last_timeout_check_s = tv.tv_sec;
 
+               #ifndef WIN32
+               /* if our parent went down, don't linger around */
+               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)
@@ -728,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->fd != context->listen_service_fd) {
+       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[0], 1, 0);
-                               if (n > 0) { /* there's a connection waiting for us */
-                                       libwebsocket_service_fd(context, &context->fds[0]);
+                               /*
+                                * 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;
                                }
                        }
@@ -757,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;
        }
 
@@ -766,8 +947,7 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
 #ifndef LWS_NO_SERVER
        case LWS_CONNMODE_HTTP_SERVING:
        case LWS_CONNMODE_SERVER_LISTENER:
-       case LWS_CONNMODE_BROADCAST_PROXY_LISTENER:
-       case LWS_CONNMODE_BROADCAST_PROXY:
+       case LWS_CONNMODE_SSL_ACK_PENDING:
                return lws_server_socket_service(context, wsi, pollfd);
 #endif
 
@@ -776,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);
@@ -792,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;
                        }
 
@@ -805,12 +987,21 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
 
 #ifdef LWS_OPENSSL_SUPPORT
 read_pending:
-               if (wsi->ssl)
-                       eff_buf.token_len = SSL_read(wsi->ssl, buf, sizeof buf);
-               else
+               if (wsi->ssl) {
+                       eff_buf.token_len = SSL_read(wsi->ssl,
+                                       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));
+                       }
+               } else
 #endif
-                       eff_buf.token_len =
-                                          recv(pollfd->fd, buf, sizeof buf, 0);
+                       eff_buf.token_len = recv(pollfd->fd,
+                               context->service_buffer,
+                                           sizeof(context->service_buffer), 0);
 
                if (eff_buf.token_len < 0) {
                        lwsl_debug("Socket read returned %d\n",
@@ -821,6 +1012,7 @@ read_pending:
                        return 0;
                }
                if (!eff_buf.token_len) {
+                       lwsl_info("closing connection due to 0 length read\n");
                        libwebsocket_close_and_free_session(context, wsi,
                                                    LWS_CLOSE_STATUS_NOSTATUS);
                        return 0;
@@ -838,8 +1030,8 @@ read_pending:
                 * used then so it is efficient.
                 */
 
-               eff_buf.token = (char *)buf;
-
+               eff_buf.token = (char *)context->service_buffer;
+#ifndef LWS_NO_EXTENSIONS
                more = 1;
                while (more) {
 
@@ -862,7 +1054,7 @@ read_pending:
                                if (m)
                                        more = 1;
                        }
-
+#endif
                        /* service incoming data */
 
                        if (eff_buf.token_len) {
@@ -873,10 +1065,11 @@ read_pending:
                                        /* we closed wsi */
                                        return 0;
                        }
-
+#ifndef LWS_NO_EXTENSIONS
                        eff_buf.token = NULL;
                        eff_buf.token_len = 0;
                }
+#endif
 
 #ifdef LWS_OPENSSL_SUPPORT
                if (wsi->ssl && SSL_pending(wsi->ssl))
@@ -907,14 +1100,23 @@ read_pending:
 void
 libwebsocket_context_destroy(struct libwebsocket_context *context)
 {
+#ifndef LWS_NO_EXTENSIONS
        int n;
        int m;
        struct libwebsocket_extension *ext;
+       struct libwebsocket_protocols *protocol = context->protocols;
+
+#ifdef LWS_LATENCY
+       if (context->worst_latency_info[0])
+               lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
+#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--;
        }
 
        /*
@@ -927,10 +1129,25 @@ 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
 #else
        close(context->fd_random);
@@ -941,8 +1158,18 @@ 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)
+               free(context->fds);
+       if (context->lws_lookup)
+               free(context->lws_lookup);
+
        free(context);
 
 #ifdef WIN32
@@ -950,10 +1177,19 @@ libwebsocket_context_destroy(struct libwebsocket_context *context)
 #endif
 }
 
+/**
+ * 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
+ *     the context the sockets live in at context_create time.  It's a way
+ *     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;
 }
 
 /**
@@ -969,10 +1205,7 @@ libwebsocket_context_user(struct libwebsocket_context *context)
  *
  *     1) Accept new connections to our context's server
  *
- *     2) Perform pending broadcast writes initiated from other forked
- *        processes (effectively serializing asynchronous broadcasts)
- *
- *     3) Call the receive callback for incoming frame data received by
+ *     2) Call the receive callback for incoming frame data received by
  *         server or client connections.
  *
  *     You need to call this service function periodically to all the above
@@ -991,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)
 {
@@ -1021,6 +1253,7 @@ libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
        return 0;
 }
 
+#ifndef LWS_NO_EXTENSIONS
 int
 lws_any_extension_handled(struct libwebsocket_context *context,
                          struct libwebsocket *wsi,
@@ -1064,6 +1297,7 @@ lws_get_extension_user_matching_ext(struct libwebsocket *wsi,
 
        return NULL;
 }
+#endif
 
 /**
  * libwebsocket_callback_on_writable() - Request a callback when this socket
@@ -1078,6 +1312,7 @@ int
 libwebsocket_callback_on_writable(struct libwebsocket_context *context,
                                                      struct libwebsocket *wsi)
 {
+#ifndef LWS_NO_EXTENSIONS
        int n;
        int handled = 0;
 
@@ -1095,10 +1330,10 @@ libwebsocket_callback_on_writable(struct libwebsocket_context *context,
 
        if (handled)
                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;
        }
 
@@ -1107,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;
 }
@@ -1177,6 +1412,50 @@ libwebsocket_get_socket_fd(struct libwebsocket *wsi)
        return wsi->sock;
 }
 
+#ifdef LWS_LATENCY
+void
+lws_latency(struct libwebsocket_context *context, struct libwebsocket *wsi,
+                                    const char *action, int ret, int completed)
+{
+       struct timeval tv;
+       unsigned long u;
+       char buf[256];
+
+       gettimeofday(&tv, NULL);
+
+       u = (tv.tv_sec * 1000000) + tv.tv_usec;
+
+       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);
+                       else
+                               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);
+               if (u - wsi->latency_start > context->worst_latency) {
+                       context->worst_latency = u - wsi->latency_start;
+                       strcpy(context->worst_latency_info, buf);
+               }
+               lwsl_latency("%s", buf);
+       } else {
+               wsi->latency_start = u;
+               if (!wsi->action_start)
+                       wsi->action_start = u;
+       }
+}
+#endif
+
 #ifdef LWS_NO_SERVER
 int
 _libwebsocket_rx_flow_control(struct libwebsocket *wsi)
@@ -1190,18 +1469,19 @@ _libwebsocket_rx_flow_control(struct libwebsocket *wsi)
        struct libwebsocket_context *context = wsi->protocol->owning_server;
        int n;
 
-       if (!(wsi->rxflow_change_to & 2))
+       if (!(wsi->u.ws.rxflow_change_to & 2))
                return 0;
 
-       wsi->rxflow_change_to &= ~2;
+       wsi->u.ws.rxflow_change_to &= ~2;
 
-       lwsl_info("rxflow: wsi %p change_to %d\n", wsi, wsi->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->rxflow_change_to & 1) && wsi->rxflow_buffer) {
+       if ((wsi->u.ws.rxflow_change_to & 1) && wsi->u.ws.rxflow_buffer) {
                n = libwebsocket_interpret_incoming_packet(wsi, NULL, 0);
                if (n < 0) {
-                       libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
+                       lwsl_info("libwebsocket_rx_flow_control: close req\n");
                        return -1;
                }
                if (n)
@@ -1209,21 +1489,21 @@ _libwebsocket_rx_flow_control(struct libwebsocket *wsi)
                        return 0;
        }
 
-       if (wsi->rxflow_change_to & 1)
+       if (wsi->u.ws.rxflow_change_to & 1)
                context->fds[wsi->position_in_fds_table].events |= POLLIN;
        else
                context->fds[wsi->position_in_fds_table].events &= ~POLLIN;
 
-       if (wsi->rxflow_change_to & 1)
+       if (wsi->u.ws.rxflow_change_to & 1)
                /* 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;
 }
@@ -1243,7 +1523,7 @@ _libwebsocket_rx_flow_control(struct libwebsocket *wsi)
 int
 libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable)
 {
-       wsi->rxflow_change_to = 2 | !!enable;
+       wsi->u.ws.rxflow_change_to = 2 | !!enable;
 
        return 0;
 }
@@ -1305,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)
@@ -1313,41 +1593,18 @@ int user_callback_handle_rxflow(callback_function callback_function,
        int n;
 
        n = callback_function(context, wsi, reason, user, in, len);
-       if (n < 0)
-               return n;
-
-       _libwebsocket_rx_flow_control(wsi);
+       if (!n)
+               n = _libwebsocket_rx_flow_control(wsi);
 
-       return 0;
+       return n;
 }
 
 
 /**
  * libwebsocket_create_context() - Create the websocket handler
- * @port:      Port to listen on... you can use 0 to suppress listening on
- *             any port, that's what you want if you are not running a
- *             websocket server at all but just using it as a client
- * @interf:  NULL to bind the listen socket to all interfaces, or the
- *             interface name, eg, "eth2"
- * @protocols: Array of structures listing supported protocols and a protocol-
- *             specific callback for each one.  The list is ended with an
- *             entry that has a NULL callback pointer.
- *             It's not const because we write the owning_server member
- * @extensions: NULL or array of libwebsocket_extension structs listing the
- *             extensions this context supports
- * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want
- *                     to listen using SSL, set to the filepath to fetch the
- *                     server cert from, otherwise NULL for unencrypted
- * @ssl_private_key_filepath: filepath to private key if wanting SSL mode,
- *                     else ignored
- * @ssl_ca_filepath: CA certificate filepath or NULL
- * @gid:       group id to change to after setting listen socket, or -1.
- * @uid:       user id to change to after setting listen socket, or -1.
- * @options:   0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK
- * @user:      optional user pointer that can be recovered via the context
- *             pointer using libwebsocket_context_user 
+ * @info:      pointer to struct with parameters
  *
- *     This function creates the listening socket and takes care
+ *     This function creates the listening socket (if serving) and takes care
  *     of all initialization in one step.
  *
  *     After initialization, it returns a struct libwebsocket_context * that
@@ -1374,42 +1631,43 @@ int user_callback_handle_rxflow(callback_function callback_function,
  */
 
 struct libwebsocket_context *
-libwebsocket_create_context(int port, const char *interf,
-                              struct libwebsocket_protocols *protocols,
-                              struct libwebsocket_extension *extensions,
-                              const char *ssl_cert_filepath,
-                              const char *ssl_private_key_filepath,
-                              const char *ssl_ca_filepath,
-                              int gid, int uid, unsigned int options,
-                              void *user)
+libwebsocket_create_context(struct lws_context_creation_info *info)
 {
-       int n;
-       int m;
-       int fd;
-       struct sockaddr_in serv_addr, cli_addr;
-       int opt = 1;
        struct libwebsocket_context *context = NULL;
-       unsigned int slen;
        char *p;
+       int n;
+#ifndef LWS_NO_SERVER
+       int opt = 1;
        struct libwebsocket *wsi;
+       struct sockaddr_in serv_addr;
+#endif
+#ifndef LWS_NO_EXTENSIONS
+       int m;
+       struct libwebsocket_extension *ext;
+#endif
 
 #ifdef LWS_OPENSSL_SUPPORT
        SSL_METHOD *method;
-       char ssl_err_buf[512];
 #endif
 
-       lwsl_info("Initial logging level %d\n", log_level);
-       lwsl_info(" LWS_MAX_HEADER_NAME_LENGTH: %u\n", LWS_MAX_HEADER_NAME_LENGTH);
+#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);
        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(" MAX_USER_RX_BUFFER: %u\n", MAX_USER_RX_BUFFER);
-       lwsl_info(" MAX_BROADCAST_PAYLOAD: %u\n", MAX_BROADCAST_PAYLOAD);
        lwsl_info(" LWS_MAX_PROTOCOLS: %u\n", LWS_MAX_PROTOCOLS);
-       lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n", LWS_MAX_EXTENSIONS_ACTIVE);
+#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(" 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);
 
@@ -1438,51 +1696,75 @@ libwebsocket_create_context(int port, const char *interf,
                wsdll = GetModuleHandle(_T("Ws2_32.dll"));
                if (wsdll)
                        poll = (PFNWSAPOLL)GetProcAddress(wsdll, "WSAPoll");
+
+               /* Finally fall back to emulated poll if all else fails */
+               if (!poll)
+                       poll = emulated_poll;
        }
 #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;
        }
-       context->protocols = protocols;
-       context->listen_port = port;
+       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
+
+       context->listen_service_extraseen = 0;
+       context->protocols = info->protocols;
+       context->listen_port = info->port;
        context->http_proxy_port = 0;
        context->http_proxy_address[0] = '\0';
-       context->options = options;
+       context->options = info->options;
        /* to reduce this allocation, */
        context->max_fds = getdtablesize();
-       lwsl_info(" max fd tracked: %u\n", context->max_fds);
-
-       context->fds = (struct pollfd *)malloc(sizeof(struct pollfd) * context->max_fds);
+       lwsl_notice(" static allocation: %u + (%u x %u fds) = %u bytes\n",
+               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);
        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 libwebsocke *) * 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;
        }
+
        context->fds_count = 0;
-       context->extensions = extensions;
+#ifndef LWS_NO_EXTENSIONS
+       context->extensions = info->extensions;
+#endif
        context->last_timeout_check_s = 0;
-       context->user_space = user;
+       context->user_space = info->user;
 
 #ifdef WIN32
        context->fd_random = 0;
 #else
        context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
        if (context->fd_random < 0) {
-               free(context);
                lwsl_err("Unable to open random device %s %d\n",
                                    SYSTEM_RANDOM_FILEPATH, context->fd_random);
-               return NULL;
+               goto bail;
        }
 #endif
 
@@ -1496,37 +1778,13 @@ libwebsocket_create_context(int port, const char *interf,
        strcpy(context->canonical_hostname, "unknown");
 
 #ifndef LWS_NO_SERVER
-       if (!(options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME)) {
-               struct sockaddr sa;
-               char hostname[1024] = "";
-
+       if (!(info->options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME)) {
                /* find canonical hostname */
+               gethostname((char *)context->canonical_hostname,
+                                      sizeof(context->canonical_hostname) - 1);
 
-               hostname[(sizeof hostname) - 1] = '\0';
-               memset(&sa, 0, sizeof(sa));
-               sa.sa_family = AF_INET;
-               sa.sa_data[(sizeof sa.sa_data) - 1] = '\0';
-               gethostname(hostname, (sizeof hostname) - 1);
-
-               n = 0;
-
-               if (strlen(hostname) < sizeof(sa.sa_data) - 1) {
-                       strcpy(sa.sa_data, hostname);
-       //              lwsl_debug("my host name is %s\n", sa.sa_data);
-                       n = getnameinfo(&sa, sizeof(sa), hostname,
-                               (sizeof hostname) - 1, NULL, 0, 0);
-               }
-
-               if (!n) {
-                       strncpy(context->canonical_hostname, hostname,
-                                               sizeof context->canonical_hostname - 1);
-                       context->canonical_hostname[
-                                       sizeof context->canonical_hostname - 1] = '\0';
-               } else
-                       strncpy(context->canonical_hostname, hostname,
-                                               sizeof context->canonical_hostname - 1);
-
-               lwsl_info(" canonical_hostname = %s\n", context->canonical_hostname);
+               lwsl_notice(" canonical_hostname = %s\n",
+                                       context->canonical_hostname);
        }
 #endif
 
@@ -1535,43 +1793,52 @@ libwebsocket_create_context(int port, const char *interf,
        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) {
                        lwsl_err("http_proxy needs to be ads:port\n");
-                       return NULL;
+                       goto bail;
                }
                *p = '\0';
                context->http_proxy_port = atoi(p + 1);
 
-               lwsl_info(" Proxy %s:%u\n",
+               lwsl_notice(" Proxy %s:%u\n",
                                context->http_proxy_address,
                                                      context->http_proxy_port);
        }
 
 #ifndef LWS_NO_SERVER
-       if (port) {
+       if (info->port) {
 
 #ifdef LWS_OPENSSL_SUPPORT
-               context->use_ssl = ssl_cert_filepath != NULL &&
-                                              ssl_private_key_filepath != NULL;
+               context->use_ssl = info->ssl_cert_filepath != NULL &&
+                                        info->ssl_private_key_filepath != NULL;
+#ifdef USE_CYASSL
+               lwsl_notice(" Compiled with CYASSL support\n");
+#else
+               lwsl_notice(" Compiled with OpenSSL support\n");
+#endif
                if (context->use_ssl)
-                       lwsl_info(" Compiled with SSL support, using it\n");
+                       lwsl_notice(" Using SSL mode\n");
                else
-                       lwsl_info(" Compiled with SSL support, not using it\n");
+                       lwsl_notice(" Using non-SSL mode\n");
 
 #else
-               if (ssl_cert_filepath != NULL &&
-                                            ssl_private_key_filepath != NULL) {
-                       lwsl_info(" Not compiled for OpenSSl support!\n");
-                       return NULL;
+               if (info->ssl_cert_filepath != NULL &&
+                                      info->ssl_private_key_filepath != NULL) {
+                       lwsl_notice(" Not compiled for OpenSSl support!\n");
+                       goto bail;
                }
-               lwsl_info(" Compiled without SSL support, "
-                                                      "serving unencrypted\n");
+               lwsl_notice(" Compiled without SSL support\n");
 #endif
+
+               lwsl_notice(
+                       " per-conn mem: %u + %u headers + protocol rx buf\n",
+                               sizeof(struct libwebsocket),
+                                             sizeof(struct allocated_headers));
        }
 #endif
 
@@ -1601,66 +1868,80 @@ libwebsocket_create_context(int port, const char *interf,
 
        method = (SSL_METHOD *)SSLv23_server_method();
        if (!method) {
-               lwsl_err("problem creating ssl method: %s\n",
-                       ERR_error_string(ERR_get_error(), ssl_err_buf));
-               return NULL;
+               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(), ssl_err_buf));
-               return NULL;
+               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_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
 
        /* client context */
 
-       if (port == CONTEXT_PORT_NO_LISTEN) {
+       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(), ssl_err_buf));
-                       return NULL;
+                       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(), ssl_err_buf));
-                       return NULL;
+                       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 (!ssl_ca_filepath) {
+               if (!info->ssl_ca_filepath) {
                        if (!SSL_CTX_load_verify_locations(
                                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, ssl_ca_filepath,
+                               context->ssl_client_ctx, info->ssl_ca_filepath,
                                                                  NULL))
                                lwsl_err(
                                        "Unable to load SSL Client certs "
                                        "file from %s -- client ssl isn't "
-                                       "going to work", ssl_ca_filepath);
+                                       "going to work", info->ssl_ca_filepath);
 
                /*
                 * callback allowing user code to load extra verification certs
@@ -1675,7 +1956,8 @@ libwebsocket_create_context(int port, const char *interf,
 
        /* as a server, are we requiring clients to identify themselves? */
 
-       if (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 */
 
@@ -1699,25 +1981,30 @@ libwebsocket_create_context(int port, const char *interf,
 
                /* set the local certificate from CertFile */
                n = SSL_CTX_use_certificate_chain_file(context->ssl_ctx,
-                                       ssl_cert_filepath);
+                                       info->ssl_cert_filepath);
                if (n != 1) {
-                       lwsl_err("problem getting cert '%s': %s\n",
-                               ssl_cert_filepath,
-                               ERR_error_string(ERR_get_error(), ssl_err_buf));
-                       return NULL;
+                       lwsl_err("problem getting cert '%s' %lu: %s\n",
+                               info->ssl_cert_filepath,
+                               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,
-                            ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) {
-                       lwsl_err("ssl problem getting key '%s': %s\n",
-                                               ssl_private_key_filepath,
-                               ERR_error_string(ERR_get_error(), ssl_err_buf));
-                       return NULL;
+                            info->ssl_private_key_filepath,
+                                                      SSL_FILETYPE_PEM) != 1) {
+                       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 */
                if (!SSL_CTX_check_private_key(context->ssl_ctx)) {
                        lwsl_err("Private SSL key doesn't match cert\n");
-                       return NULL;
+                       goto bail;
                }
 
                /* SSL is happy and has a cert it's content with */
@@ -1727,57 +2014,74 @@ libwebsocket_create_context(int port, const char *interf,
        /* selftest */
 
        if (lws_b64_selftest())
-               return NULL;
+               goto bail;
 
 #ifndef LWS_NO_SERVER
        /* set up our external listening socket we serve on */
 
-       if (port) {
-               extern int interface_to_sa(const char *ifname, struct sockaddr_in *addr, size_t addrlen);
+       if (info->port) {
                int sockfd;
 
                sockfd = socket(AF_INET, SOCK_STREAM, 0);
                if (sockfd < 0) {
                        lwsl_err("ERROR opening socket\n");
-                       return NULL;
+                       goto bail;
                }
 
-               /* allow us to restart even if old sockets in TIME_WAIT */
+#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)
+                */
                setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
                                              (const void *)&opt, sizeof(opt));
+#endif
 
                /* Disable Nagle */
                opt = 1;
                setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
                                              (const void *)&opt, sizeof(opt));
 
+               #ifdef WIN32
+               opt = 0;
+               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 (interf == NULL)
+               if (info->iface == NULL)
                        serv_addr.sin_addr.s_addr = INADDR_ANY;
                else
-                       interface_to_sa(interf, &serv_addr,
+                       interface_to_sa(info->iface, &serv_addr,
                                                sizeof(serv_addr));
-               serv_addr.sin_port = htons(port);
+               serv_addr.sin_port = htons(info->port);
 
                n = bind(sockfd, (struct sockaddr *) &serv_addr,
                                                             sizeof(serv_addr));
                if (n < 0) {
                        lwsl_err("ERROR on binding to port %d (%d %d)\n",
-                                                               port, n, errno);
+                                                       info->port, n, errno);
                        close(sockfd);
-                       return NULL;
+                       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);
-                       return NULL;
+                       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;
+#endif
                wsi->mode = LWS_CONNMODE_SERVER_LISTENER;
 
                insert_wsi_socket_into_fds(context, wsi);
@@ -1787,7 +2091,7 @@ libwebsocket_create_context(int port, const char *interf,
                context->listen_service_fd = sockfd;
 
                listen(sockfd, LWS_SOMAXCONN);
-               lwsl_info(" Listening on port %d\n", port);
+               lwsl_notice(" Listening on port %d\n", info->port);
        }
 #endif
 
@@ -1798,199 +2102,72 @@ libwebsocket_create_context(int port, const char *interf,
         */
 #ifdef WIN32
 #else
-       if (gid != -1)
-               if (setgid(gid))
+       if (info->gid != -1)
+               if (setgid(info->gid))
                        lwsl_warn("setgid: %s\n", strerror(errno));
-       if (uid != -1)
-               if (setuid(uid))
+       if (info->uid != -1)
+               if (setuid(info->uid))
                        lwsl_warn("setuid: %s\n", strerror(errno));
 #endif
 
-       /* set up our internal broadcast trigger sockets per-protocol */
+       /* initialize supported protocols */
 
        for (context->count_protocols = 0;
-                       protocols[context->count_protocols].callback;
+               info->protocols[context->count_protocols].callback;
                                                   context->count_protocols++) {
 
                lwsl_parser("  Protocol: %s\n",
-                               protocols[context->count_protocols].name);
-
-               protocols[context->count_protocols].owning_server = context;
-               protocols[context->count_protocols].protocol_index =
-                                                      context->count_protocols;
-
-               fd = socket(AF_INET, SOCK_STREAM, 0);
-               if (fd < 0) {
-                       lwsl_err("ERROR opening socket\n");
-                       return NULL;
-               }
-
-               /* allow us to restart even if old sockets in TIME_WAIT */
-               setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt,
-                                                                 sizeof(opt));
-
-               bzero((char *) &serv_addr, sizeof(serv_addr));
-               serv_addr.sin_family = AF_INET;
-               serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-               serv_addr.sin_port = 0; /* pick the port for us */
-
-               n = bind(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
-               if (n < 0) {
-                       lwsl_err("ERROR on binding to port %d (%d %d)\n",
-                                                               port, n, errno);
-                       return NULL;
-               }
-
-               slen = sizeof cli_addr;
-               n = getsockname(fd, (struct sockaddr *)&cli_addr, &slen);
-               if (n < 0) {
-                       lwsl_err("getsockname failed\n");
-                       return NULL;
-               }
-               protocols[context->count_protocols].broadcast_socket_port =
-                                                      ntohs(cli_addr.sin_port);
-               listen(fd, 5);
-
-               lwsl_debug("  Protocol %s broadcast socket %d\n",
-                               protocols[context->count_protocols].name,
-                                                     ntohs(cli_addr.sin_port));
+                               info->protocols[context->count_protocols].name);
 
-               /* dummy wsi per broadcast proxy socket */
-
-               wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
-               if (wsi == NULL) {
-                       lwsl_err("Out of mem\n");
-                       close(fd);
-                       return NULL;
-               }
-               memset(wsi, 0, sizeof (struct libwebsocket));
-               wsi->sock = fd;
-               wsi->mode = LWS_CONNMODE_BROADCAST_PROXY_LISTENER;
-               wsi->count_active_extensions = 0;
-               /* note which protocol we are proxying */
-               wsi->protocol_index_for_broadcast_proxy =
+               info->protocols[context->count_protocols].owning_server =
+                                                                       context;
+               info->protocols[context->count_protocols].protocol_index =
                                                       context->count_protocols;
 
-               insert_wsi_socket_into_fds(context, wsi);
+               /*
+                * 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
        /*
         * give all extensions a chance to create any per-context
         * allocations they need
         */
 
        m = LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT;
-       if (port)
+       if (info->port)
                m = LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT;
-       
-       if (extensions) {
-           while (extensions->callback) {
-                   lwsl_ext("  Extension: %s\n", extensions->name);
-                   extensions->callback(context, extensions, NULL,
+
+       if (info->extensions) {
+               ext = info->extensions;
+               while (ext->callback) {
+                       lwsl_ext("  Extension: %s\n", ext->name);
+                       ext->callback(context, ext, NULL,
                        (enum libwebsocket_extension_callback_reasons)m,
                                                                NULL, NULL, 0);
-                   extensions++;
-           }
-       }
-
-       return context;
-}
-
-
-#ifndef LWS_NO_FORK
-
-/**
- * libwebsockets_fork_service_loop() - Optional helper function forks off
- *                               a process for the websocket server loop.
- *                             You don't have to use this but if not, you
- *                             have to make sure you are calling
- *                             libwebsocket_service periodically to service
- *                             the websocket traffic
- * @context:   server context returned by creation function
- */
-
-int
-libwebsockets_fork_service_loop(struct libwebsocket_context *context)
-{
-       int fd;
-       struct sockaddr_in cli_addr;
-       int n;
-       int p;
-
-       n = fork();
-       if (n < 0)
-               return n;
-
-       if (!n) {
-
-               /* main process context */
-
-               /*
-                * set up the proxy sockets to allow broadcast from
-                * service process context
-                */
-
-               for (p = 0; p < context->count_protocols; p++) {
-                       fd = socket(AF_INET, SOCK_STREAM, 0);
-                       if (fd < 0) {
-                               lwsl_err("Unable to create socket\n");
-                               return -1;
-                       }
-                       cli_addr.sin_family = AF_INET;
-                       cli_addr.sin_port = htons(
-                            context->protocols[p].broadcast_socket_port);
-                       cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-                       n = connect(fd, (struct sockaddr *)&cli_addr,
-                                                              sizeof cli_addr);
-                       if (n < 0) {
-                               lwsl_err("Unable to connect to "
-                                               "broadcast socket %d, %s\n",
-                                               n, strerror(errno));
-                               return -1;
-                       }
-
-                       context->protocols[p].broadcast_socket_user_fd = fd;
+                       ext++;
                }
-
-               return 0;
        }
-
-#ifdef HAVE_SYS_PRCTL_H
-       /* we want a SIGHUP when our parent goes down */
-       prctl(PR_SET_PDEATHSIG, SIGHUP);
 #endif
+       return context;
 
-       /* in this forked process, sit and service websocket connections */
-
-       while (1) {
-               if (libwebsocket_service(context, 1000))
-                       break;
-//#ifndef HAVE_SYS_PRCTL_H
-/*
- * on systems without prctl() (i.e. anything but linux) we can notice that our
- * parent is dead if getppid() returns 1. FIXME apparently this is not true for
- * solaris, could remember ppid right after fork and wait for it to change.
- */
-
-        if (getppid() == 1)
-            break;
-//#endif
-    }
-
-
-       return 1;
+bail:
+       libwebsocket_context_destroy(context);
+       return NULL;
 }
 
-#endif
-
 /**
  * libwebsockets_get_protocol() - Returns a protocol pointer from a websocket
  *                               connection.
  * @wsi:       pointer to struct websocket you want to know the protocol of
  *
  *
- *     This is useful to get the protocol to broadcast back to from inside
- * the callback.
+ *     Some apis can act on all live connections of a given protocol,
+ *     this is how you can get a pointer to the active protocol if needed.
  */
 
 const struct libwebsocket_protocols *
@@ -1999,110 +2176,24 @@ libwebsockets_get_protocol(struct libwebsocket *wsi)
        return wsi->protocol;
 }
 
-/**
- * libwebsockets_broadcast() - Sends a buffer to the callback for all active
- *                               connections of the given protocol.
- * @protocol:  pointer to the protocol you will broadcast to all members of
- * @buf:  buffer containing the data to be broadcase.  NOTE: this has to be
- *             allocated with LWS_SEND_BUFFER_PRE_PADDING valid bytes before
- *             the pointer and LWS_SEND_BUFFER_POST_PADDING afterwards in the
- *             case you are calling this function from callback context.
- * @len:       length of payload data in buf, starting from buf.
- *
- *     This function allows bulk sending of a packet to every connection using
- * the given protocol.  It does not send the data directly; instead it calls
- * the callback with a reason type of LWS_CALLBACK_BROADCAST.  If the callback
- * wants to actually send the data for that connection, the callback itself
- * should call libwebsocket_write().
- *
- * libwebsockets_broadcast() can be called from another fork context without
- * having to take any care about data visibility between the processes, it'll
- * "just work".
- */
-
-
-int
-libwebsockets_broadcast(const struct libwebsocket_protocols *protocol,
-                                                unsigned char *buf, size_t len)
-{
-       struct libwebsocket_context *context = protocol->owning_server;
-       int n;
-       struct libwebsocket *wsi;
-
-       if (!protocol->broadcast_socket_user_fd) {
-               /*
-                * We are either running unforked / flat, or we are being
-                * called from poll thread context
-                * eg, from a callback.  In that case don't use sockets for
-                * broadcast IPC (since we can't open a socket connection to
-                * a socket listening on our own thread) but directly do the
-                * send action.
-                *
-                * Locking is not needed because we are by definition being
-                * called in the poll thread context and are serialized.
-                */
-
-               for (n = 0; n < context->fds_count; n++) {
-
-                       wsi = context->lws_lookup[context->fds[n].fd];
-                       if (!wsi)
-                               continue;
-
-                       if (wsi->mode != LWS_CONNMODE_WS_SERVING)
-                               continue;
-
-                       /*
-                        * never broadcast to non-established connections
-                        */
-                       if (wsi->state != WSI_STATE_ESTABLISHED)
-                               continue;
-
-                       /* only broadcast to guys using
-                        * requested protocol
-                        */
-                       if (wsi->protocol != protocol)
-                               continue;
-
-                       user_callback_handle_rxflow(wsi->protocol->callback,
-                                context, wsi,
-                                LWS_CALLBACK_BROADCAST,
-                                wsi->user_space,
-                                buf, len);
-               }
-
-               return 0;
-       }
-
-       /*
-        * We're being called from a different process context than the server
-        * loop.  Instead of broadcasting directly, we send our
-        * payload on a socket to do the IPC; the server process will serialize
-        * the broadcast action in its main poll() loop.
-        *
-        * There's one broadcast socket listening for each protocol supported
-        * set up when the websocket server initializes
-        */
-
-       n = send(protocol->broadcast_socket_user_fd, buf, len, MSG_NOSIGNAL);
-
-       return n;
-}
-
 int
 libwebsocket_is_final_fragment(struct libwebsocket *wsi)
 {
-       return wsi->final;
+       return wsi->u.ws.final;
 }
 
 unsigned char
 libwebsocket_get_reserved_bits(struct libwebsocket *wsi)
 {
-       return wsi->rsv;
+       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) {
@@ -2110,44 +2201,11 @@ 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;
-}
-
-/**
- * lws_confirm_legit_wsi: returns nonzero if the wsi looks bad
- *
- * @wsi: struct libwebsocket to assess
- *
- * Performs consistecy checks on what the wsi claims and what the
- * polling arrays hold.  This'll catch a closed wsi still in use.
- * Don't try to use on the listen (nonconnection) wsi as it will
- * fail it.  Otherwise 0 return == wsi seems consistent.
- */
-
-int lws_confirm_legit_wsi(struct libwebsocket *wsi)
-{
-       struct libwebsocket_context *context;
-
-       if (!(wsi && wsi->protocol && wsi->protocol->owning_server))
-               return 1;
-
-       context = wsi->protocol->owning_server;
-
-       if (!context)
-               return 2;
-
-       if (!wsi->position_in_fds_table)
-               return 3; /* position in fds table looks bad */
-       if (context->fds[wsi->position_in_fds_table].fd != wsi->sock)
-               return 4; /* pollfd entry does not wait on our socket descriptor */
-       if (context->lws_lookup[wsi->sock] != wsi)
-               return 5; /* lookup table does not agree with wsi */
-
        return 0;
 }
 
@@ -2155,7 +2213,6 @@ static void lwsl_emit_stderr(int level, const char *line)
 {
        char buf[300];
        struct timeval tv;
-       int pos = 0;
        int n;
 
        gettimeofday(&tv, NULL);
@@ -2163,14 +2220,42 @@ static void lwsl_emit_stderr(int level, const char *line)
        buf[0] = '\0';
        for (n = 0; n < LLL_COUNT; n++)
                if (level == (1 << n)) {
-                       pos = sprintf(buf, "[%ld:%04d] %s: ", tv.tv_sec,
-                                       (int)(tv.tv_usec / 100), log_level_names[n]);
+                       sprintf(buf, "[%ld:%04d] %s: ", tv.tv_sec,
+                               (int)(tv.tv_usec / 100), log_level_names[n]);
                        break;
                }
-       
+
        fprintf(stderr, "%s%s", buf, line);
 }
 
+#ifdef WIN32
+void lwsl_emit_syslog(int level, const char *line)
+{
+       lwsl_emit_stderr(level, line);
+}
+#else
+void lwsl_emit_syslog(int level, const char *line)
+{
+       int syslog_level = LOG_DEBUG;
+
+       switch (level) {
+       case LLL_ERR:
+               syslog_level = LOG_ERR;
+               break;
+       case LLL_WARN:
+               syslog_level = LOG_WARNING;
+               break;
+       case LLL_NOTICE:
+               syslog_level = LOG_NOTICE;
+               break;
+       case LLL_INFO:
+               syslog_level = LOG_INFO;
+               break;
+       }
+       syslog(syslog_level, "%s", line);
+}
+#endif
+
 void _lws_log(int filter, const char *format, ...)
 {
        char buf[256];
@@ -2180,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);
@@ -2194,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)(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)