refactor and introduce without server configure option
authorAndy Green <andy.green@linaro.org>
Fri, 18 Jan 2013 03:43:21 +0000 (11:43 +0800)
committerAndy Green <andy.green@linaro.org>
Fri, 18 Jan 2013 03:43:21 +0000 (11:43 +0800)
Move server-only stuff into their own files and make building
that depend on not having --without-server on the configure

Make fragments in other places conditional as well

Remove client-related members from struct libwebscket when
building LWS_NO_CLIENT

Apps:

normal: build test server, client, fraggle, ping
--without-client: build test server
--without-server: build test client, ping

Signed-off-by: Andy Green <andy.green@linaro.org>
README-test-server
configure.ac
lib/Makefile.am
lib/handshake.c
lib/libwebsockets.c
lib/parsers.c
lib/private-libwebsockets.h
lib/server-handshake.c [new file with mode: 0644]
lib/server.c [new file with mode: 0644]
test-server/Makefile.am

index 58a7123..fa61c10 100644 (file)
@@ -77,6 +77,11 @@ There are several other possible configure options
                        minimize library footprint for embedded server-only
                        case
 
+--without-server       Don't build the server part of the library nor the
+                       test apps that need the server part.  Useful to
+                       minimize library footprint for embedded client-only
+                       case
+
 --without-daemonize    Don't build daemonize.c / lws_daemonize
 
 --disable-debug                Remove all debug logging below lwsl_warn in severity
index 6e48e08..1b99ab6 100644 (file)
@@ -85,6 +85,21 @@ AM_CONDITIONAL(NO_CLIENT, test x$no_client = xyes)
 # 
 #
 #
+AC_ARG_WITH(server,
+ [  --without-server  dont build the client part of the library ],
+ [ no_server=yes
+ ])
+
+if test "x$no_server" = "xyes" ; then                                             
+CFLAGS="$CFLAGS -DLWS_NO_SERVER"                                          
+fi
+AM_CONDITIONAL(NO_SERVER, test x$no_server = xyes)
+
+
+
+# 
+#
+#
 AC_ARG_WITH(daemonize,
  [  --without-daemonize  dont build the daemonization api ],
  [ no_daemonize=yes
index f7af416..8b460bc 100644 (file)
@@ -1,8 +1,8 @@
 lib_LTLIBRARIES=libwebsockets.la
 include_HEADERS=libwebsockets.h
 dist_libwebsockets_la_SOURCES=libwebsockets.c \
-                               handshake.c \
                                parsers.c \
+                               handshake.c \
                                libwebsockets.h \
                                base64-decode.c \
                                output.c \
@@ -23,6 +23,12 @@ dist_libwebsockets_la_SOURCES+= client.c \
                                client-handshake.c
 endif
 
+if NO_SERVER
+else
+dist_libwebsockets_la_SOURCES+= server.c \
+                               server-handshake.c
+endif
+
 if USE_BUILTIN_GETIFADDRS
 dist_libwebsockets_la_SOURCES += getifaddrs.c
 endif
index 2b8c304..2b2765f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
 
 #include "private-libwebsockets.h"
 
-#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); }
-#define LWS_CPYAPP_TOKEN(ptr, tok) { strcpy(p, wsi->utf8_token[tok].token); \
-               p += wsi->utf8_token[tok].token_len; }
-
-static int
-interpret_key(const char *key, unsigned long *result)
-{
-       char digits[20];
-       int digit_pos = 0;
-       const char *p = key;
-       unsigned int spaces = 0;
-       unsigned long acc = 0;
-       int rem = 0;
-
-       while (*p) {
-               if (!isdigit(*p)) {
-                       p++;
-                       continue;
-               }
-               if (digit_pos == sizeof(digits) - 1)
-                       return -1;
-               digits[digit_pos++] = *p++;
-       }
-       digits[digit_pos] = '\0';
-       if (!digit_pos)
-               return -2;
-
-       while (*key) {
-               if (*key == ' ')
-                       spaces++;
-               key++;
-       }
-
-       if (!spaces)
-               return -3;
-
-       p = &digits[0];
-       while (*p) {
-               rem = (rem * 10) + ((*p++) - '0');
-               acc = (acc * 10) + (rem / spaces);
-               rem -= (rem / spaces) * spaces;
-       }
-
-       if (rem) {
-               lwsl_warn("nonzero handshake remainder\n");
-               return -1;
-       }
-
-       *result = acc;
-
-       return 0;
-}
-
-
-static int
-handshake_00(struct libwebsocket_context *context, struct libwebsocket *wsi)
-{
-       unsigned long key1, key2;
-       unsigned char sum[16];
-       char *response;
-       char *p;
-       int n;
-
-       /* Confirm we have all the necessary pieces */
-
-       if (!wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len ||
-               !wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
-               !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
-               !wsi->utf8_token[WSI_TOKEN_KEY1].token_len ||
-                            !wsi->utf8_token[WSI_TOKEN_KEY2].token_len)
-               /* completed header processing, but missing some bits */
-               goto bail;
-
-       /* allocate the per-connection user memory (if any) */
-       if (wsi->protocol->per_session_data_size &&
-                                         !libwebsocket_ensure_user_space(wsi))
-               goto bail;
-
-       /* create the response packet */
-
-       /* make a buffer big enough for everything */
-
-       response = (char *)malloc(256 +
-               wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
-               wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
-               wsi->utf8_token[WSI_TOKEN_HOST].token_len +
-               wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len +
-               wsi->utf8_token[WSI_TOKEN_GET_URI].token_len +
-               wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
-       if (!response) {
-               lwsl_err("Out of memory for response buffer\n");
-               goto bail;
-       }
-
-       p = response;
-       LWS_CPYAPP(p, "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
-                     "Upgrade: WebSocket\x0d\x0a"
-                     "Connection: Upgrade\x0d\x0a"
-                     "Sec-WebSocket-Origin: ");
-       strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
-       p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
-#ifdef LWS_OPENSSL_SUPPORT
-       if (wsi->ssl) {
-               LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: wss://");
-       } else {
-               LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://");
-       }
-#else
-       LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://");
-#endif
-
-       LWS_CPYAPP_TOKEN(p, WSI_TOKEN_HOST);
-       LWS_CPYAPP_TOKEN(p, WSI_TOKEN_GET_URI);
-
-       if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
-               LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
-               LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL);
-       }
-
-       LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
-
-       /* convert the two keys into 32-bit integers */
-
-       if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1))
-               goto bail;
-       if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2))
-               goto bail;
-
-       /* lay them out in network byte order (MSB first */
-
-       sum[0] = (unsigned char)(key1 >> 24);
-       sum[1] = (unsigned char)(key1 >> 16);
-       sum[2] = (unsigned char)(key1 >> 8);
-       sum[3] = (unsigned char)(key1);
-       sum[4] = (unsigned char)(key2 >> 24);
-       sum[5] = (unsigned char)(key2 >> 16);
-       sum[6] = (unsigned char)(key2 >> 8);
-       sum[7] = (unsigned char)(key2);
-
-       /* follow them with the challenge token we were sent */
-
-       memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8);
-
-       /*
-        * compute the md5sum of that 16-byte series and use as our
-        * payload after our headers
-        */
-
-       MD5(sum, 16, (unsigned char *)p);
-       p += 16;
-
-       /* it's complete: go ahead and send it */
-
-       lwsl_parser("issuing response packet %d len\n", (int)(p - response));
-#ifdef _DEBUG
-       fwrite(response, 1,  p - response, stderr);
-#endif
-       n = libwebsocket_write(wsi, (unsigned char *)response,
-                                         p - response, LWS_WRITE_HTTP);
-       if (n < 0) {
-               lwsl_debug("handshake_00: ERROR writing to socket\n");
-               goto bail;
-       }
-
-       /* alright clean up and set ourselves into established state */
-
-       free(response);
-       wsi->state = WSI_STATE_ESTABLISHED;
-       wsi->lws_rx_parse_state = LWS_RXPS_NEW;
-
-       /* notify user code that we're ready to roll */
-
-       if (wsi->protocol->callback)
-               wsi->protocol->callback(wsi->protocol->owning_server,
-                               wsi, LWS_CALLBACK_ESTABLISHED,
-                                         wsi->user_space, NULL, 0);
-
-       return 0;
-
-bail:
-       return -1;
-}
-
-/*
- * Perform the newer BASE64-encoded handshake scheme
- */
-
-static int
-handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi)
-{
-       static const char *websocket_magic_guid_04 =
-                                        "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
-       static const char *websocket_magic_guid_04_masking =
-                                        "61AC5F19-FBBA-4540-B96F-6561F1AB40A8";
-       char accept_buf[MAX_WEBSOCKET_04_KEY_LEN + 37];
-       char nonce_buf[256];
-       char mask_summing_buf[256 + MAX_WEBSOCKET_04_KEY_LEN + 37];
-       unsigned char hash[20];
-       int n;
-       char *response;
-       char *p;
-       char *m = mask_summing_buf;
-       int nonce_len = 0;
-       int accept_len;
-       char *c;
-       char ext_name[128];
-       struct libwebsocket_extension *ext;
-       int ext_count = 0;
-       int more = 1;
-
-       if (!wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
-           !wsi->utf8_token[WSI_TOKEN_KEY].token_len) {
-               lwsl_parser("handshake_04 missing pieces\n");
-               /* completed header processing, but missing some bits */
-               goto bail;
-       }
-
-       if (wsi->utf8_token[WSI_TOKEN_KEY].token_len >=
-                                                    MAX_WEBSOCKET_04_KEY_LEN) {
-               lwsl_warn("Client sent handshake key longer "
-                          "than max supported %d\n", MAX_WEBSOCKET_04_KEY_LEN);
-               goto bail;
-       }
-
-       strcpy(accept_buf, wsi->utf8_token[WSI_TOKEN_KEY].token);
-       strcpy(accept_buf + wsi->utf8_token[WSI_TOKEN_KEY].token_len,
-                                                      websocket_magic_guid_04);
-
-       SHA1((unsigned char *)accept_buf,
-                       wsi->utf8_token[WSI_TOKEN_KEY].token_len +
-                                        strlen(websocket_magic_guid_04), hash);
-
-       accept_len = lws_b64_encode_string((char *)hash, 20, accept_buf,
-                                                            sizeof accept_buf);
-       if (accept_len < 0) {
-               lwsl_warn("Base64 encoded hash too long\n");
-               goto bail;
-       }
-
-       /* allocate the per-connection user memory (if any) */
-       if (wsi->protocol->per_session_data_size &&
-                                         !libwebsocket_ensure_user_space(wsi))
-               goto bail;
-
-       /* create the response packet */
-
-       /* make a buffer big enough for everything */
-
-       response = (char *)malloc(256 +
-               wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
-               wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
-               wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
-       if (!response) {
-               lwsl_err("Out of memory for response buffer\n");
-               goto bail;
-       }
-
-       p = response;
-       LWS_CPYAPP(p, "HTTP/1.1 101 Switching Protocols\x0d\x0a"
-                     "Upgrade: WebSocket\x0d\x0a"
-                     "Connection: Upgrade\x0d\x0a"
-                     "Sec-WebSocket-Accept: ");
-       strcpy(p, accept_buf);
-       p += accept_len;
-
-       if (wsi->ietf_spec_revision == 4) {
-               LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Nonce: ");
-
-               /* select the nonce */
-
-               n = libwebsockets_get_random(wsi->protocol->owning_server,
-                                                                     hash, 16);
-               if (n != 16) {
-                       lwsl_err("Unable to read random device %s %d\n",
-                                                    SYSTEM_RANDOM_FILEPATH, n);
-                       if (wsi->user_space)
-                               free(wsi->user_space);
-                       goto bail;
-               }
-
-               /* encode the nonce */
-
-               nonce_len = lws_b64_encode_string((const char *)hash, 16,
-                                                  nonce_buf, sizeof nonce_buf);
-               if (nonce_len < 0) {
-                       lwsl_err("Failed to base 64 encode the nonce\n");
-                       if (wsi->user_space)
-                               free(wsi->user_space);
-                       goto bail;
-               }
-
-               /* apply the nonce */
-
-               strcpy(p, nonce_buf);
-               p += nonce_len;
-       }
-
-       if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
-               LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
-               LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL);
-       }
-
-       /*
-        * Figure out which extensions the client has that we want to
-        * enable on this connection, and give him back the list
-        */
-
-       if (wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token_len) {
-
-               /*
-                * break down the list of client extensions
-                * and go through them
-                */
-
-               c = wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token;
-               lwsl_parser("wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token = %s\n",
-                                 wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token);
-               wsi->count_active_extensions = 0;
-               n = 0;
-               while (more) {
-
-                       if (*c && (*c != ',' && *c != ' ' && *c != '\t')) {
-                               ext_name[n] = *c++;
-                               if (n < sizeof(ext_name) - 1)
-                                       n++;
-                               continue;
-                       }
-                       ext_name[n] = '\0';
-                       if (!*c)
-                               more = 0;
-                       else {
-                               c++;
-                               if (!n)
-                                       continue;
-                       }
-
-                       /* check a client's extension against our support */
-
-                       ext = wsi->protocol->owning_server->extensions;
-
-                       while (ext && ext->callback) {
-
-                               if (strcmp(ext_name, ext->name)) {
-                                       ext++;
-                                       continue;
-                               }
-
-                               /*
-                                * oh, we do support this one he
-                                * asked for... but let's ask user
-                                * code if it's OK to apply it on this
-                                * particular connection + protocol
-                                */
-
-                               n = wsi->protocol->owning_server->
-                                       protocols[0].callback(
-                                               wsi->protocol->owning_server,
-                                               wsi,
-                                         LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
-                                                 wsi->user_space, ext_name, 0);
-
-                               /*
-                                * zero return from callback means
-                                * go ahead and allow the extension,
-                                * it's what we get if the callback is
-                                * unhandled
-                                */
-
-                               if (n) {
-                                       ext++;
-                                       continue;
-                               }
-
-                               /* apply it */
-
-                               if (ext_count)
-                                       *p++ = ',';
-                               else
-                                       LWS_CPYAPP(p,
-                                        "\x0d\x0aSec-WebSocket-Extensions: ");
-                               p += sprintf(p, "%s", ext_name);
-                               ext_count++;
-
-                               /* instantiate the extension on this conn */
-
-                               wsi->active_extensions_user[
-                                       wsi->count_active_extensions] =
-                                            malloc(ext->per_session_data_size);
-                               if (wsi->active_extensions_user[
-                                        wsi->count_active_extensions] == NULL) {
-                                       lwsl_err("Out of mem\n");
-                                       free(response);
-                                       goto bail;
-                               }
-                               memset(wsi->active_extensions_user[
-                                       wsi->count_active_extensions], 0,
-                                                   ext->per_session_data_size);
-
-                               wsi->active_extensions[
-                                         wsi->count_active_extensions] = ext;
-
-                               /* allow him to construct his context */
-
-                               ext->callback(wsi->protocol->owning_server,
-                                               ext, wsi,
-                                               LWS_EXT_CALLBACK_CONSTRUCT,
-                                               wsi->active_extensions_user[
-                                       wsi->count_active_extensions], NULL, 0);
-
-                               wsi->count_active_extensions++;
-                               lwsl_parser("wsi->count_active_extensions <- %d\n",
-                                                 wsi->count_active_extensions);
-
-                               ext++;
-                       }
-
-                       n = 0;
-               }
-       }
-
-       /* end of response packet */
-
-       LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
-
-       if (wsi->ietf_spec_revision == 4) {
-
-               /*
-                * precompute the masking key the client will use from the SHA1
-                * hash of ( base 64 client key we were sent, concatenated with
-                * the bse 64 nonce we sent, concatenated with a magic constant
-                * guid specified by the 04 standard )
-                *
-                * We store the hash in the connection's wsi ready to use with
-                * undoing the masking the client has done on framed data it
-                * sends (we send our data to the client in clear).
-                */
-
-               strcpy(mask_summing_buf, wsi->utf8_token[WSI_TOKEN_KEY].token);
-               m += wsi->utf8_token[WSI_TOKEN_KEY].token_len;
-               strcpy(m, nonce_buf);
-               m += nonce_len;
-               strcpy(m, websocket_magic_guid_04_masking);
-               m += strlen(websocket_magic_guid_04_masking);
-
-               SHA1((unsigned char *)mask_summing_buf, m - mask_summing_buf,
-                                                          wsi->masking_key_04);
-       }
-
-       if (!lws_any_extension_handled(context, wsi,
-                       LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX,
-                                                    response, p - response)) {
-
-               /* okay send the handshake response accepting the connection */
-
-               lwsl_parser("issuing response packet %d len\n", (int)(p - response));
-       #ifdef DEBUG
-               fwrite(response, 1,  p - response, stderr);
-       #endif
-               n = libwebsocket_write(wsi, (unsigned char *)response,
-                                                 p - response, LWS_WRITE_HTTP);
-               if (n < 0) {
-                       lwsl_debug("handshake_0405: ERROR writing to socket\n");
-                       goto bail;
-               }
-
-       }
-
-       /* alright clean up and set ourselves into established state */
-
-       free(response);
-       wsi->state = WSI_STATE_ESTABLISHED;
-       wsi->lws_rx_parse_state = LWS_RXPS_NEW;
-       wsi->rx_packet_length = 0;
-
-       /* notify user code that we're ready to roll */
-
-       if (wsi->protocol->callback)
-               wsi->protocol->callback(wsi->protocol->owning_server,
-                               wsi, LWS_CALLBACK_ESTABLISHED,
-                                         wsi->user_space, NULL, 0);
-
-       return 0;
-
-
-bail:
-       return -1;
-}
-
-
 /*
  * -04 of the protocol (actually the 80th version) has a radically different
  * handshake.  The 04 spec gives the following idea
@@ -580,8 +91,12 @@ libwebsocket_read(struct libwebsocket_context *context,
                        break;
                }
 #endif
+#ifndef LWS_NO_SERVER
                /* LWS_CONNMODE_WS_SERVING */
 
+               extern int handshake_00(struct libwebsocket_context *context, struct libwebsocket *wsi);
+               extern int handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi);
+
                for (n = 0; n < len; n++)
                        libwebsocket_parse(wsi, *buf++);
 
@@ -702,7 +217,7 @@ libwebsocket_read(struct libwebsocket_context *context,
 
                lwsl_parser("accepted v%02d connection\n",
                                                       wsi->ietf_spec_revision);
-
+#endif
                break;
 
        case WSI_STATE_AWAITING_CLOSE_ACK:
@@ -719,11 +234,12 @@ libwebsocket_read(struct libwebsocket_context *context,
                        break;
                }
 #endif
+#ifndef LWS_NO_SERVER
                /* LWS_CONNMODE_WS_SERVING */
 
                if (libwebsocket_interpret_incoming_packet(wsi, buf, len) < 0)
                        goto bail;
-
+#endif
                break;
        default:
                lwsl_err("libwebsocket_read: Unhandled state\n");
index 99ce9e8..000861c 100644 (file)
@@ -128,49 +128,6 @@ do_ext:
        return 0;
 }
 
-#ifdef LWS_OPENSSL_SUPPORT
-static void
-libwebsockets_decode_ssl_error(void)
-{
-       char buf[256];
-       u_long err;
-
-       while ((err = ERR_get_error()) != 0) {
-               ERR_error_string_n(err, buf, sizeof(buf));
-               lwsl_err("*** %s\n", buf);
-       }
-}
-#endif
-
-
-static int
-interface_to_sa(const char *ifname, struct sockaddr_in *addr, size_t addrlen)
-{
-       int rc = -1;
-#ifdef WIN32
-       /* TODO */
-#else
-       struct ifaddrs *ifr;
-       struct ifaddrs *ifc;
-       struct sockaddr_in *sin;
-
-       getifaddrs(&ifr);
-       for (ifc = ifr; ifc != NULL; ifc = ifc->ifa_next) {
-               if (strcmp(ifc->ifa_name, ifname))
-                       continue;
-               if (ifc->ifa_addr == NULL)
-                       continue;
-               sin = (struct sockaddr_in *)ifc->ifa_addr;
-               if (sin->sin_family != AF_INET)
-                       continue;
-               memcpy(addr, sin, addrlen);
-               rc = 0;
-       }
-
-       freeifaddrs(ifr);
-#endif
-       return rc;
-}
 
 void
 libwebsocket_close_and_free_session(struct libwebsocket_context *context,
@@ -367,10 +324,10 @@ just_kill_connection:
        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);
 
@@ -703,54 +660,6 @@ libwebsocket_service_timeout_check(struct libwebsocket_context *context,
        }
 }
 
-struct libwebsocket *
-libwebsocket_create_new_server_wsi(struct libwebsocket_context *context)
-{
-       struct libwebsocket *new_wsi;
-       int n;
-
-       new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
-       if (new_wsi == NULL) {
-               lwsl_err("Out of memory for new connection\n");
-               return NULL;
-       }
-
-       memset(new_wsi, 0, sizeof(struct libwebsocket));
-       new_wsi->count_active_extensions = 0;
-       new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
-
-       /* intialize the instance struct */
-
-       new_wsi->state = WSI_STATE_HTTP;
-       new_wsi->name_buffer_pos = 0;
-       new_wsi->mode = LWS_CONNMODE_HTTP_SERVING;
-
-       for (n = 0; n < WSI_TOKEN_COUNT; n++) {
-               new_wsi->utf8_token[n].token = NULL;
-               new_wsi->utf8_token[n].token_len = 0;
-       }
-
-       /*
-        * these can only be set once the protocol is known
-        * we set an unestablished connection's protocol pointer
-        * to the start of the supported list, so it can look
-        * for matching ones during the handshake
-        */
-       new_wsi->protocol = context->protocols;
-       new_wsi->user_space = NULL;
-
-       /*
-        * Default protocol is 76 / 00
-        * After 76, there's a header specified to inform which
-        * draft the client wants, when that's seen we modify
-        * the individual connection's spec revision accordingly
-        */
-       new_wsi->ietf_spec_revision = 0;
-
-       return new_wsi;
-}
-
-
 /**
  * libwebsocket_service_fd() - Service polled socket with something waiting
  * @context:   Websocket context
@@ -766,23 +675,20 @@ int
 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];
-       struct libwebsocket *wsi;
-       struct libwebsocket *new_wsi;
        int n;
        int m;
-       ssize_t len;
-       int accept_fd;
-       unsigned int clilen;
-       struct sockaddr_in cli_addr;
        struct timeval tv;
        int more = 1;
        struct lws_tokens eff_buf;
-       int opt = 1;
 #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
        /*
         * 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
@@ -856,278 +762,13 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
 
        switch (wsi->mode) {
 
+#ifndef LWS_NO_SERVER
        case LWS_CONNMODE_HTTP_SERVING:
-
-               /* handle http headers coming in */
-
-               /* any incoming data ready? */
-
-               if (pollfd->revents & POLLIN) {
-
-       #ifdef LWS_OPENSSL_SUPPORT
-                       if (wsi->ssl)
-                               len = SSL_read(wsi->ssl, buf, sizeof buf);
-                       else
-       #endif
-                               len = recv(pollfd->fd, buf, sizeof buf, 0);
-
-                       if (len < 0) {
-                               lwsl_debug("Socket read returned %d\n", len);
-                               if (errno != EINTR && errno != EAGAIN)
-                                       libwebsocket_close_and_free_session(context,
-                                                      wsi, LWS_CLOSE_STATUS_NOSTATUS);
-                               return 0;
-                       }
-                       if (!len) {
-                               libwebsocket_close_and_free_session(context, wsi,
-                                                           LWS_CLOSE_STATUS_NOSTATUS);
-                               return 0;
-                       }
-
-                       n = libwebsocket_read(context, wsi, buf, len);
-                       if (n < 0)
-                               /* we closed wsi */
-                               return 0;
-               }
-
-               /* this handles POLLOUT for http serving fragments */
-
-               if (!(pollfd->revents & POLLOUT))
-                       break;
-
-               /* one shot */
-               pollfd->events &= ~POLLOUT;
-               
-               if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE)
-                       break;
-
-               if (libwebsockets_serve_http_file_fragment(context, wsi) < 0)
-                       libwebsocket_close_and_free_session(context, wsi,
-                                              LWS_CLOSE_STATUS_NOSTATUS);
-               else
-                       if (wsi->state == WSI_STATE_HTTP && wsi->protocol->callback)
-                               if (user_callback_handle_rxflow(wsi->protocol->callback, context, wsi, LWS_CALLBACK_HTTP_FILE_COMPLETION, wsi->user_space,
-                                                               wsi->filepath, wsi->filepos))
-                                       libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
-               break;
-
        case LWS_CONNMODE_SERVER_LISTENER:
-
-               /* pollin means a client has connected to us then */
-
-               if (!(pollfd->revents & POLLIN))
-                       break;
-
-               /* listen socket got an unencrypted connection... */
-
-               clilen = sizeof(cli_addr);
-               accept_fd  = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
-                                                                      &clilen);
-               if (accept_fd < 0) {
-                       lwsl_warn("ERROR on accept: %s\n", strerror(errno));
-                       break;
-               }
-
-               /* Disable Nagle */
-               opt = 1;
-               setsockopt(accept_fd, IPPROTO_TCP, TCP_NODELAY,
-                                             (const void *)&opt, sizeof(opt));
-
-               /*
-                * look at who we connected to and give user code a chance
-                * to reject based on client IP.  There's no protocol selected
-                * yet so we issue this to protocols[0]
-                */
-
-               if ((context->protocols[0].callback)(context, wsi,
-                               LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
-                                          (void *)(long)accept_fd, NULL, 0)) {
-                       lwsl_debug("Callback denied network connection\n");
-                       compatible_close(accept_fd);
-                       break;
-               }
-
-               new_wsi = libwebsocket_create_new_server_wsi(context);
-               if (new_wsi == NULL) {
-                       compatible_close(accept_fd);
-                       break;
-               }
-
-               new_wsi->sock = accept_fd;
-
-
-#ifdef LWS_OPENSSL_SUPPORT
-               new_wsi->ssl = NULL;
-
-               if (context->use_ssl) {
-
-                       new_wsi->ssl = SSL_new(context->ssl_ctx);
-                       if (new_wsi->ssl == NULL) {
-                               lwsl_err("SSL_new failed: %s\n",
-                                   ERR_error_string(SSL_get_error(
-                                   new_wsi->ssl, 0), NULL));
-                                   libwebsockets_decode_ssl_error();
-                               free(new_wsi);
-                               compatible_close(accept_fd);
-                               break;
-                       }
-
-                       SSL_set_ex_data(new_wsi->ssl,
-                               openssl_websocket_private_data_index, context);
-
-                       SSL_set_fd(new_wsi->ssl, accept_fd);
-
-                       n = SSL_accept(new_wsi->ssl);
-                       if (n != 1) {
-                               /*
-                                * browsers seem to probe with various
-                                * ssl params which fail then retry
-                                * and succeed
-                                */
-                               lwsl_debug("SSL_accept failed skt %u: %s\n",
-                                     pollfd->fd,
-                                     ERR_error_string(SSL_get_error(
-                                     new_wsi->ssl, n), NULL));
-                               SSL_free(
-                                      new_wsi->ssl);
-                               free(new_wsi);
-                               compatible_close(accept_fd);
-                               break;
-                       }
-
-                       lwsl_debug("accepted new SSL conn  "
-                             "port %u on fd=%d SSL ver %s\n",
-                               ntohs(cli_addr.sin_port), accept_fd,
-                                 SSL_get_version(new_wsi->ssl));
-
-               } else
-#endif
-                       lwsl_debug("accepted new conn  port %u on fd=%d\n",
-                                         ntohs(cli_addr.sin_port), accept_fd);
-
-               insert_wsi_socket_into_fds(context, new_wsi);
-               break;
-
        case LWS_CONNMODE_BROADCAST_PROXY_LISTENER:
-
-               /* as we are listening, POLLIN means accept() is needed */
-
-               if (!(pollfd->revents & POLLIN))
-                       break;
-
-               /* listen socket got an unencrypted connection... */
-
-               clilen = sizeof(cli_addr);
-               accept_fd  = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
-                                                                      &clilen);
-               if (accept_fd < 0) {
-                       lwsl_warn("ERROR on accept %d\n", accept_fd);
-                       return 0;
-               }
-
-               /* create a dummy wsi for the connection and add it */
-
-               new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
-               if (new_wsi == NULL) {
-                       lwsl_err("Out of mem\n");
-                       goto bail_prox_listener;
-               }
-               memset(new_wsi, 0, sizeof (struct libwebsocket));
-               new_wsi->sock = accept_fd;
-               new_wsi->mode = LWS_CONNMODE_BROADCAST_PROXY;
-               new_wsi->state = WSI_STATE_ESTABLISHED;
-               new_wsi->count_active_extensions = 0;
-               /* note which protocol we are proxying */
-               new_wsi->protocol_index_for_broadcast_proxy =
-                                       wsi->protocol_index_for_broadcast_proxy;
-
-               insert_wsi_socket_into_fds(context, new_wsi);
-               break;
-
-bail_prox_listener:
-               compatible_close(accept_fd);
-               break;
-
        case LWS_CONNMODE_BROADCAST_PROXY:
-
-               /* handle session socket closed */
-
-               if (pollfd->revents & (POLLERR | POLLHUP)) {
-
-                       lwsl_debug("Session Socket %p (fd=%d) dead\n",
-                               (void *)wsi, pollfd->fd);
-
-                       libwebsocket_close_and_free_session(context, wsi,
-                                                      LWS_CLOSE_STATUS_NORMAL);
-                       return 0;
-               }
-
-               /*
-                * either extension code with stuff to spill, or the user code,
-                * requested a callback when it was OK to write
-                */
-
-               if (pollfd->revents & POLLOUT)
-                       if (lws_handle_POLLOUT_event(context, wsi,
-                                                                pollfd) < 0) {
-                               libwebsocket_close_and_free_session(
-                                       context, wsi, LWS_CLOSE_STATUS_NORMAL);
-                               return 0;
-                       }
-
-               /* any incoming data ready? */
-
-               if (!(pollfd->revents & POLLIN))
-                       break;
-
-               /* get the issued broadcast payload from the socket */
-
-               len = read(pollfd->fd, buf + LWS_SEND_BUFFER_PRE_PADDING,
-                                                        MAX_BROADCAST_PAYLOAD);
-               if (len < 0) {
-                       lwsl_err("Error reading broadcast payload\n");
-                       break;
-               }
-
-               /* broadcast it to all guys with this protocol index */
-
-               for (n = 0; n < context->fds_count; n++) {
-
-                       new_wsi = context->lws_lookup[context->fds[n].fd];
-                       if (new_wsi == NULL)
-                               continue;
-
-                       /* only to clients we are serving to */
-
-                       if (new_wsi->mode != LWS_CONNMODE_WS_SERVING)
-                               continue;
-
-                       /*
-                        * never broadcast to non-established
-                        * connection
-                        */
-
-                       if (new_wsi->state != WSI_STATE_ESTABLISHED)
-                               continue;
-
-                       /*
-                        * only broadcast to connections using
-                        * the requested protocol
-                        */
-
-                       if (new_wsi->protocol->protocol_index !=
-                               wsi->protocol_index_for_broadcast_proxy)
-                               continue;
-
-                       /* broadcast it to this connection */
-
-                       user_callback_handle_rxflow(new_wsi->protocol->callback, context, new_wsi,
-                               LWS_CALLBACK_BROADCAST,
-                               new_wsi->user_space,
-                               buf + LWS_SEND_BUFFER_PRE_PADDING, len);
-               }
-               break;
-
+               return lws_server_socket_service(context, wsi, pollfd);
+#endif
 
        case LWS_CONNMODE_WS_SERVING:
        case LWS_CONNMODE_WS_CLIENT:
@@ -1535,7 +1176,13 @@ libwebsocket_get_socket_fd(struct libwebsocket *wsi)
        return wsi->sock;
 }
 
-
+#ifdef LWS_NO_SERVER
+int
+_libwebsocket_rx_flow_control(struct libwebsocket *wsi)
+{
+       return 0;
+}
+#else
 int
 _libwebsocket_rx_flow_control(struct libwebsocket *wsi)
 {
@@ -1579,6 +1226,7 @@ _libwebsocket_rx_flow_control(struct libwebsocket *wsi)
 
        return 1;
 }
+#endif
 
 /**
  * libwebsocket_rx_flow_control() - Enable and disable socket servicing for
@@ -1736,17 +1384,13 @@ libwebsocket_create_context(int port, const char *interf,
 {
        int n;
        int m;
-       int sockfd = 0;
        int fd;
        struct sockaddr_in serv_addr, cli_addr;
        int opt = 1;
        struct libwebsocket_context *context = NULL;
        unsigned int slen;
        char *p;
-       char hostname[1024] = "";
-//     struct hostent *he;
        struct libwebsocket *wsi;
-       struct sockaddr sa;
 
 #ifdef LWS_OPENSSL_SUPPORT
        SSL_METHOD *method;
@@ -1848,11 +1492,12 @@ libwebsocket_create_context(int port, const char *interf,
        openssl_websocket_private_data_index = 0;
 #endif
 
-       if (options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME) {
-
-               strcpy(context->canonical_hostname, "unknown");
+       strcpy(context->canonical_hostname, "unknown");
 
-       } else {
+#ifndef LWS_NO_SERVER
+       if (!(options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME)) {
+               struct sockaddr sa;
+               char hostname[1024] = "";
 
                /* find canonical hostname */
 
@@ -1880,9 +1525,9 @@ libwebsocket_create_context(int port, const char *interf,
                        strncpy(context->canonical_hostname, hostname,
                                                sizeof context->canonical_hostname - 1);
 
-       //      lwsl_debug("context->canonical_hostname = %s\n",
-       //                                              context->canonical_hostname);
+               lwsl_info(" canonical_hostname = %s\n", context->canonical_hostname);
        }
+#endif
 
        /* split the proxy ads:port if given */
 
@@ -1901,11 +1546,12 @@ libwebsocket_create_context(int port, const char *interf,
                *p = '\0';
                context->http_proxy_port = atoi(p + 1);
 
-               lwsl_debug("Using proxy %s:%u\n",
+               lwsl_info(" Proxy %s:%u\n",
                                context->http_proxy_address,
                                                      context->http_proxy_port);
        }
 
+#ifndef LWS_NO_SERVER
        if (port) {
 
 #ifdef LWS_OPENSSL_SUPPORT
@@ -1926,6 +1572,7 @@ libwebsocket_create_context(int port, const char *interf,
                                                       "serving unencrypted\n");
 #endif
        }
+#endif
 
        /* ignore SIGPIPE */
 #ifdef WIN32
@@ -1970,6 +1617,8 @@ libwebsocket_create_context(int port, const char *interf,
        SSL_CTX_set_options(context->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
        SSL_CTX_set_cipher_list(context->ssl_ctx, CIPHERS_LIST_STRING);
 
+#ifndef LWS_NO_CLIENT
+
        /* client context */
 
        if (port == CONTEXT_PORT_NO_LISTEN) {
@@ -2021,6 +1670,7 @@ libwebsocket_create_context(int port, const char *interf,
                        LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,
                        context->ssl_client_ctx, NULL, 0);
        }
+#endif
 
        /* as a server, are we requiring clients to identify themselves? */
 
@@ -2078,9 +1728,12 @@ libwebsocket_create_context(int port, const char *interf,
        if (lws_b64_selftest())
                return NULL;
 
+#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);
+               int sockfd;
 
                sockfd = socket(AF_INET, SOCK_STREAM, 0);
                if (sockfd < 0) {
@@ -2135,6 +1788,7 @@ libwebsocket_create_context(int port, const char *interf,
                listen(sockfd, LWS_SOMAXCONN);
                lwsl_info(" Listening on port %d\n", port);
        }
+#endif
 
        /*
         * drop any root privs for this process
index a1e4a48..b2d40f2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
 #include <io.h>
 #endif
 
-static const struct lws_tokens lws_tokens[WSI_TOKEN_COUNT] = {
-
-       /* win32 can't do C99 */
-
-/*     [WSI_TOKEN_GET_URI]     =       */{ "GET ",                      4 },
-/*     [WSI_TOKEN_HOST]        =       */{ "Host:",                     5 },
-/*     [WSI_TOKEN_CONNECTION]  =       */{ "Connection:",              11 },
-/*     [WSI_TOKEN_KEY1]        =       */{ "Sec-WebSocket-Key1:",      19 },
-/*     [WSI_TOKEN_KEY2]        =       */{ "Sec-WebSocket-Key2:",      19 },
-/*     [WSI_TOKEN_PROTOCOL]    =       */{ "Sec-WebSocket-Protocol:",  23 },
-/*     [WSI_TOKEN_UPGRADE]     =       */{ "Upgrade:",                  8 },
-/*     [WSI_TOKEN_ORIGIN]      =       */{ "Origin:",                   7 },
-/*     [WSI_TOKEN_DRAFT]       =       */{ "Sec-WebSocket-Draft:",     20 },
-/*     [WSI_TOKEN_CHALLENGE]   =       */{ "\x0d\x0a",                  2 },
-
-/*     [WSI_TOKEN_KEY]         =       */{ "Sec-WebSocket-Key:",       18 },
-/*     [WSI_TOKEN_VERSION]     =       */{ "Sec-WebSocket-Version:",   22 },
-/*     [WSI_TOKEN_SWORIGIN]=           */{ "Sec-WebSocket-Origin:",    21 },
-
-/*     [WSI_TOKEN_EXTENSIONS]  =       */{ "Sec-WebSocket-Extensions:", 25 },
-
-/*     [WSI_TOKEN_ACCEPT]      =       */{ "Sec-WebSocket-Accept:",    21 },
-/*     [WSI_TOKEN_NONCE]       =       */{ "Sec-WebSocket-Nonce:",     20 },
-/*     [WSI_TOKEN_HTTP]        =       */{ "HTTP/1.1 ",                 9 },
-/*     [WSI_TOKEN_MUXURL]      =       */{ "",          -1 },
-
-};
 
 unsigned char lextable[] = {
 /* pos 0: state 0 */
@@ -626,7 +599,6 @@ int lws_frame_is_binary(struct libwebsocket *wsi)
        return wsi->frame_is_binary;
 }
 
-
 int
 libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
 {
@@ -1191,8 +1163,6 @@ illegal_ctl_length:
 }
 
 
-
-
 int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,
                                                 unsigned char *buf, size_t len)
 {
index 8c52c81..4f6400d 100644 (file)
@@ -378,9 +378,11 @@ struct libwebsocket {
        /* 07 specific */
        char this_frame_masked;
 
+       enum connection_mode mode;
+
+#ifndef LWS_NO_CLIENT
        /* client support */
        char initial_handshake_hash_base64[30];
-       enum connection_mode mode;
        char *c_path;
        char *c_host;
        char *c_origin;
@@ -389,7 +391,7 @@ struct libwebsocket {
 
        char *c_address;
        int c_port;
-
+#endif
 
 #ifdef LWS_OPENSSL_SUPPORT
        SSL *ssl;
diff --git a/lib/server-handshake.c b/lib/server-handshake.c
new file mode 100644 (file)
index 0000000..b91769e
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+
+#include "private-libwebsockets.h"
+
+#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); }
+#define LWS_CPYAPP_TOKEN(ptr, tok) { strcpy(p, wsi->utf8_token[tok].token); \
+               p += wsi->utf8_token[tok].token_len; }
+
+static int
+interpret_key(const char *key, unsigned long *result)
+{
+       char digits[20];
+       int digit_pos = 0;
+       const char *p = key;
+       unsigned int spaces = 0;
+       unsigned long acc = 0;
+       int rem = 0;
+
+       while (*p) {
+               if (!isdigit(*p)) {
+                       p++;
+                       continue;
+               }
+               if (digit_pos == sizeof(digits) - 1)
+                       return -1;
+               digits[digit_pos++] = *p++;
+       }
+       digits[digit_pos] = '\0';
+       if (!digit_pos)
+               return -2;
+
+       while (*key) {
+               if (*key == ' ')
+                       spaces++;
+               key++;
+       }
+
+       if (!spaces)
+               return -3;
+
+       p = &digits[0];
+       while (*p) {
+               rem = (rem * 10) + ((*p++) - '0');
+               acc = (acc * 10) + (rem / spaces);
+               rem -= (rem / spaces) * spaces;
+       }
+
+       if (rem) {
+               lwsl_warn("nonzero handshake remainder\n");
+               return -1;
+       }
+
+       *result = acc;
+
+       return 0;
+}
+
+
+int handshake_00(struct libwebsocket_context *context, struct libwebsocket *wsi)
+{
+       unsigned long key1, key2;
+       unsigned char sum[16];
+       char *response;
+       char *p;
+       int n;
+
+       /* Confirm we have all the necessary pieces */
+
+       if (!wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len ||
+               !wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
+               !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
+               !wsi->utf8_token[WSI_TOKEN_KEY1].token_len ||
+                            !wsi->utf8_token[WSI_TOKEN_KEY2].token_len)
+               /* completed header processing, but missing some bits */
+               goto bail;
+
+       /* allocate the per-connection user memory (if any) */
+       if (wsi->protocol->per_session_data_size &&
+                                         !libwebsocket_ensure_user_space(wsi))
+               goto bail;
+
+       /* create the response packet */
+
+       /* make a buffer big enough for everything */
+
+       response = (char *)malloc(256 +
+               wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
+               wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
+               wsi->utf8_token[WSI_TOKEN_HOST].token_len +
+               wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len +
+               wsi->utf8_token[WSI_TOKEN_GET_URI].token_len +
+               wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
+       if (!response) {
+               lwsl_err("Out of memory for response buffer\n");
+               goto bail;
+       }
+
+       p = response;
+       LWS_CPYAPP(p, "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
+                     "Upgrade: WebSocket\x0d\x0a"
+                     "Connection: Upgrade\x0d\x0a"
+                     "Sec-WebSocket-Origin: ");
+       strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
+       p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
+#ifdef LWS_OPENSSL_SUPPORT
+       if (wsi->ssl) {
+               LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: wss://");
+       } else {
+               LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://");
+       }
+#else
+       LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://");
+#endif
+
+       LWS_CPYAPP_TOKEN(p, WSI_TOKEN_HOST);
+       LWS_CPYAPP_TOKEN(p, WSI_TOKEN_GET_URI);
+
+       if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
+               LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
+               LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL);
+       }
+
+       LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
+
+       /* convert the two keys into 32-bit integers */
+
+       if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1))
+               goto bail;
+       if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2))
+               goto bail;
+
+       /* lay them out in network byte order (MSB first */
+
+       sum[0] = (unsigned char)(key1 >> 24);
+       sum[1] = (unsigned char)(key1 >> 16);
+       sum[2] = (unsigned char)(key1 >> 8);
+       sum[3] = (unsigned char)(key1);
+       sum[4] = (unsigned char)(key2 >> 24);
+       sum[5] = (unsigned char)(key2 >> 16);
+       sum[6] = (unsigned char)(key2 >> 8);
+       sum[7] = (unsigned char)(key2);
+
+       /* follow them with the challenge token we were sent */
+
+       memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8);
+
+       /*
+        * compute the md5sum of that 16-byte series and use as our
+        * payload after our headers
+        */
+
+       MD5(sum, 16, (unsigned char *)p);
+       p += 16;
+
+       /* it's complete: go ahead and send it */
+
+       lwsl_parser("issuing response packet %d len\n", (int)(p - response));
+#ifdef _DEBUG
+       fwrite(response, 1,  p - response, stderr);
+#endif
+       n = libwebsocket_write(wsi, (unsigned char *)response,
+                                         p - response, LWS_WRITE_HTTP);
+       if (n < 0) {
+               lwsl_debug("handshake_00: ERROR writing to socket\n");
+               goto bail;
+       }
+
+       /* alright clean up and set ourselves into established state */
+
+       free(response);
+       wsi->state = WSI_STATE_ESTABLISHED;
+       wsi->lws_rx_parse_state = LWS_RXPS_NEW;
+
+       /* notify user code that we're ready to roll */
+
+       if (wsi->protocol->callback)
+               wsi->protocol->callback(wsi->protocol->owning_server,
+                               wsi, LWS_CALLBACK_ESTABLISHED,
+                                         wsi->user_space, NULL, 0);
+
+       return 0;
+
+bail:
+       return -1;
+}
+
+/*
+ * Perform the newer BASE64-encoded handshake scheme
+ */
+
+int
+handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi)
+{
+       static const char *websocket_magic_guid_04 =
+                                        "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+       static const char *websocket_magic_guid_04_masking =
+                                        "61AC5F19-FBBA-4540-B96F-6561F1AB40A8";
+       char accept_buf[MAX_WEBSOCKET_04_KEY_LEN + 37];
+       char nonce_buf[256];
+       char mask_summing_buf[256 + MAX_WEBSOCKET_04_KEY_LEN + 37];
+       unsigned char hash[20];
+       int n;
+       char *response;
+       char *p;
+       char *m = mask_summing_buf;
+       int nonce_len = 0;
+       int accept_len;
+       char *c;
+       char ext_name[128];
+       struct libwebsocket_extension *ext;
+       int ext_count = 0;
+       int more = 1;
+
+       if (!wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
+           !wsi->utf8_token[WSI_TOKEN_KEY].token_len) {
+               lwsl_parser("handshake_04 missing pieces\n");
+               /* completed header processing, but missing some bits */
+               goto bail;
+       }
+
+       if (wsi->utf8_token[WSI_TOKEN_KEY].token_len >=
+                                                    MAX_WEBSOCKET_04_KEY_LEN) {
+               lwsl_warn("Client sent handshake key longer "
+                          "than max supported %d\n", MAX_WEBSOCKET_04_KEY_LEN);
+               goto bail;
+       }
+
+       strcpy(accept_buf, wsi->utf8_token[WSI_TOKEN_KEY].token);
+       strcpy(accept_buf + wsi->utf8_token[WSI_TOKEN_KEY].token_len,
+                                                      websocket_magic_guid_04);
+
+       SHA1((unsigned char *)accept_buf,
+                       wsi->utf8_token[WSI_TOKEN_KEY].token_len +
+                                        strlen(websocket_magic_guid_04), hash);
+
+       accept_len = lws_b64_encode_string((char *)hash, 20, accept_buf,
+                                                            sizeof accept_buf);
+       if (accept_len < 0) {
+               lwsl_warn("Base64 encoded hash too long\n");
+               goto bail;
+       }
+
+       /* allocate the per-connection user memory (if any) */
+       if (wsi->protocol->per_session_data_size &&
+                                         !libwebsocket_ensure_user_space(wsi))
+               goto bail;
+
+       /* create the response packet */
+
+       /* make a buffer big enough for everything */
+
+       response = (char *)malloc(256 +
+               wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
+               wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
+               wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
+       if (!response) {
+               lwsl_err("Out of memory for response buffer\n");
+               goto bail;
+       }
+
+       p = response;
+       LWS_CPYAPP(p, "HTTP/1.1 101 Switching Protocols\x0d\x0a"
+                     "Upgrade: WebSocket\x0d\x0a"
+                     "Connection: Upgrade\x0d\x0a"
+                     "Sec-WebSocket-Accept: ");
+       strcpy(p, accept_buf);
+       p += accept_len;
+
+       if (wsi->ietf_spec_revision == 4) {
+               LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Nonce: ");
+
+               /* select the nonce */
+
+               n = libwebsockets_get_random(wsi->protocol->owning_server,
+                                                                     hash, 16);
+               if (n != 16) {
+                       lwsl_err("Unable to read random device %s %d\n",
+                                                    SYSTEM_RANDOM_FILEPATH, n);
+                       if (wsi->user_space)
+                               free(wsi->user_space);
+                       goto bail;
+               }
+
+               /* encode the nonce */
+
+               nonce_len = lws_b64_encode_string((const char *)hash, 16,
+                                                  nonce_buf, sizeof nonce_buf);
+               if (nonce_len < 0) {
+                       lwsl_err("Failed to base 64 encode the nonce\n");
+                       if (wsi->user_space)
+                               free(wsi->user_space);
+                       goto bail;
+               }
+
+               /* apply the nonce */
+
+               strcpy(p, nonce_buf);
+               p += nonce_len;
+       }
+
+       if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
+               LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
+               LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL);
+       }
+
+       /*
+        * Figure out which extensions the client has that we want to
+        * enable on this connection, and give him back the list
+        */
+
+       if (wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token_len) {
+
+               /*
+                * break down the list of client extensions
+                * and go through them
+                */
+
+               c = wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token;
+               lwsl_parser("wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token = %s\n",
+                                 wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token);
+               wsi->count_active_extensions = 0;
+               n = 0;
+               while (more) {
+
+                       if (*c && (*c != ',' && *c != ' ' && *c != '\t')) {
+                               ext_name[n] = *c++;
+                               if (n < sizeof(ext_name) - 1)
+                                       n++;
+                               continue;
+                       }
+                       ext_name[n] = '\0';
+                       if (!*c)
+                               more = 0;
+                       else {
+                               c++;
+                               if (!n)
+                                       continue;
+                       }
+
+                       /* check a client's extension against our support */
+
+                       ext = wsi->protocol->owning_server->extensions;
+
+                       while (ext && ext->callback) {
+
+                               if (strcmp(ext_name, ext->name)) {
+                                       ext++;
+                                       continue;
+                               }
+
+                               /*
+                                * oh, we do support this one he
+                                * asked for... but let's ask user
+                                * code if it's OK to apply it on this
+                                * particular connection + protocol
+                                */
+
+                               n = wsi->protocol->owning_server->
+                                       protocols[0].callback(
+                                               wsi->protocol->owning_server,
+                                               wsi,
+                                         LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
+                                                 wsi->user_space, ext_name, 0);
+
+                               /*
+                                * zero return from callback means
+                                * go ahead and allow the extension,
+                                * it's what we get if the callback is
+                                * unhandled
+                                */
+
+                               if (n) {
+                                       ext++;
+                                       continue;
+                               }
+
+                               /* apply it */
+
+                               if (ext_count)
+                                       *p++ = ',';
+                               else
+                                       LWS_CPYAPP(p,
+                                        "\x0d\x0aSec-WebSocket-Extensions: ");
+                               p += sprintf(p, "%s", ext_name);
+                               ext_count++;
+
+                               /* instantiate the extension on this conn */
+
+                               wsi->active_extensions_user[
+                                       wsi->count_active_extensions] =
+                                            malloc(ext->per_session_data_size);
+                               if (wsi->active_extensions_user[
+                                        wsi->count_active_extensions] == NULL) {
+                                       lwsl_err("Out of mem\n");
+                                       free(response);
+                                       goto bail;
+                               }
+                               memset(wsi->active_extensions_user[
+                                       wsi->count_active_extensions], 0,
+                                                   ext->per_session_data_size);
+
+                               wsi->active_extensions[
+                                         wsi->count_active_extensions] = ext;
+
+                               /* allow him to construct his context */
+
+                               ext->callback(wsi->protocol->owning_server,
+                                               ext, wsi,
+                                               LWS_EXT_CALLBACK_CONSTRUCT,
+                                               wsi->active_extensions_user[
+                                       wsi->count_active_extensions], NULL, 0);
+
+                               wsi->count_active_extensions++;
+                               lwsl_parser("wsi->count_active_extensions <- %d\n",
+                                                 wsi->count_active_extensions);
+
+                               ext++;
+                       }
+
+                       n = 0;
+               }
+       }
+
+       /* end of response packet */
+
+       LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
+
+       if (wsi->ietf_spec_revision == 4) {
+
+               /*
+                * precompute the masking key the client will use from the SHA1
+                * hash of ( base 64 client key we were sent, concatenated with
+                * the bse 64 nonce we sent, concatenated with a magic constant
+                * guid specified by the 04 standard )
+                *
+                * We store the hash in the connection's wsi ready to use with
+                * undoing the masking the client has done on framed data it
+                * sends (we send our data to the client in clear).
+                */
+
+               strcpy(mask_summing_buf, wsi->utf8_token[WSI_TOKEN_KEY].token);
+               m += wsi->utf8_token[WSI_TOKEN_KEY].token_len;
+               strcpy(m, nonce_buf);
+               m += nonce_len;
+               strcpy(m, websocket_magic_guid_04_masking);
+               m += strlen(websocket_magic_guid_04_masking);
+
+               SHA1((unsigned char *)mask_summing_buf, m - mask_summing_buf,
+                                                          wsi->masking_key_04);
+       }
+
+       if (!lws_any_extension_handled(context, wsi,
+                       LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX,
+                                                    response, p - response)) {
+
+               /* okay send the handshake response accepting the connection */
+
+               lwsl_parser("issuing response packet %d len\n", (int)(p - response));
+       #ifdef DEBUG
+               fwrite(response, 1,  p - response, stderr);
+       #endif
+               n = libwebsocket_write(wsi, (unsigned char *)response,
+                                                 p - response, LWS_WRITE_HTTP);
+               if (n < 0) {
+                       lwsl_debug("handshake_0405: ERROR writing to socket\n");
+                       goto bail;
+               }
+
+       }
+
+       /* alright clean up and set ourselves into established state */
+
+       free(response);
+       wsi->state = WSI_STATE_ESTABLISHED;
+       wsi->lws_rx_parse_state = LWS_RXPS_NEW;
+       wsi->rx_packet_length = 0;
+
+       /* notify user code that we're ready to roll */
+
+       if (wsi->protocol->callback)
+               wsi->protocol->callback(wsi->protocol->owning_server,
+                               wsi, LWS_CALLBACK_ESTABLISHED,
+                                         wsi->user_space, NULL, 0);
+
+       return 0;
+
+
+bail:
+       return -1;
+}
+
diff --git a/lib/server.c b/lib/server.c
new file mode 100644 (file)
index 0000000..17f83ae
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+
+
+#include "private-libwebsockets.h"
+
+#ifdef WIN32
+#include <tchar.h>
+#include <io.h>
+#else
+#ifdef LWS_BUILTIN_GETIFADDRS
+#include <getifaddrs.h>
+#else
+#include <ifaddrs.h>
+#endif
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#endif
+
+#ifdef LWS_OPENSSL_SUPPORT
+extern int openssl_websocket_private_data_index;
+
+static void
+libwebsockets_decode_ssl_error(void)
+{
+       char buf[256];
+       u_long err;
+
+       while ((err = ERR_get_error()) != 0) {
+               ERR_error_string_n(err, buf, sizeof(buf));
+               lwsl_err("*** %s\n", buf);
+       }
+}
+#endif
+
+int
+interface_to_sa(const char *ifname, struct sockaddr_in *addr, size_t addrlen)
+{
+       int rc = -1;
+#ifdef WIN32
+       /* TODO */
+#else
+       struct ifaddrs *ifr;
+       struct ifaddrs *ifc;
+       struct sockaddr_in *sin;
+
+       getifaddrs(&ifr);
+       for (ifc = ifr; ifc != NULL; ifc = ifc->ifa_next) {
+               if (strcmp(ifc->ifa_name, ifname))
+                       continue;
+               if (ifc->ifa_addr == NULL)
+                       continue;
+               sin = (struct sockaddr_in *)ifc->ifa_addr;
+               if (sin->sin_family != AF_INET)
+                       continue;
+               memcpy(addr, sin, addrlen);
+               rc = 0;
+       }
+
+       freeifaddrs(ifr);
+#endif
+       return rc;
+}
+
+struct libwebsocket *
+libwebsocket_create_new_server_wsi(struct libwebsocket_context *context)
+{
+       struct libwebsocket *new_wsi;
+       int n;
+
+       new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
+       if (new_wsi == NULL) {
+               lwsl_err("Out of memory for new connection\n");
+               return NULL;
+       }
+
+       memset(new_wsi, 0, sizeof(struct libwebsocket));
+       new_wsi->count_active_extensions = 0;
+       new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
+
+       /* intialize the instance struct */
+
+       new_wsi->state = WSI_STATE_HTTP;
+       new_wsi->name_buffer_pos = 0;
+       new_wsi->mode = LWS_CONNMODE_HTTP_SERVING;
+
+       for (n = 0; n < WSI_TOKEN_COUNT; n++) {
+               new_wsi->utf8_token[n].token = NULL;
+               new_wsi->utf8_token[n].token_len = 0;
+       }
+
+       /*
+        * these can only be set once the protocol is known
+        * we set an unestablished connection's protocol pointer
+        * to the start of the supported list, so it can look
+        * for matching ones during the handshake
+        */
+       new_wsi->protocol = context->protocols;
+       new_wsi->user_space = NULL;
+
+       /*
+        * Default protocol is 76 / 00
+        * After 76, there's a header specified to inform which
+        * draft the client wants, when that's seen we modify
+        * the individual connection's spec revision accordingly
+        */
+       new_wsi->ietf_spec_revision = 0;
+
+       return new_wsi;
+}
+
+int lws_server_socket_service(struct libwebsocket_context *context,
+                       struct libwebsocket *wsi, struct pollfd *pollfd)
+{
+       unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1 +
+                        MAX_BROADCAST_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING];
+       struct libwebsocket *new_wsi;
+       int accept_fd;
+       unsigned int clilen;
+       struct sockaddr_in cli_addr;
+       int n;
+       int opt = 1;
+       ssize_t len;
+
+       switch (wsi->mode) {
+
+       case LWS_CONNMODE_HTTP_SERVING:
+
+               /* handle http headers coming in */
+
+               /* any incoming data ready? */
+
+               if (pollfd->revents & POLLIN) {
+
+       #ifdef LWS_OPENSSL_SUPPORT
+                       if (wsi->ssl)
+                               len = SSL_read(wsi->ssl, buf, sizeof buf);
+                       else
+       #endif
+                               len = recv(pollfd->fd, buf, sizeof buf, 0);
+
+                       if (len < 0) {
+                               lwsl_debug("Socket read returned %d\n", len);
+                               if (errno != EINTR && errno != EAGAIN)
+                                       libwebsocket_close_and_free_session(context,
+                                                      wsi, LWS_CLOSE_STATUS_NOSTATUS);
+                               return 0;
+                       }
+                       if (!len) {
+                               libwebsocket_close_and_free_session(context, wsi,
+                                                           LWS_CLOSE_STATUS_NOSTATUS);
+                               return 0;
+                       }
+
+                       n = libwebsocket_read(context, wsi, buf, len);
+                       if (n < 0)
+                               /* we closed wsi */
+                               return 0;
+               }
+
+               /* this handles POLLOUT for http serving fragments */
+
+               if (!(pollfd->revents & POLLOUT))
+                       break;
+
+               /* one shot */
+               pollfd->events &= ~POLLOUT;
+               
+               if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE)
+                       break;
+
+               if (libwebsockets_serve_http_file_fragment(context, wsi) < 0)
+                       libwebsocket_close_and_free_session(context, wsi,
+                                              LWS_CLOSE_STATUS_NOSTATUS);
+               else
+                       if (wsi->state == WSI_STATE_HTTP && wsi->protocol->callback)
+                               if (user_callback_handle_rxflow(wsi->protocol->callback, context, wsi, LWS_CALLBACK_HTTP_FILE_COMPLETION, wsi->user_space,
+                                                               wsi->filepath, wsi->filepos))
+                                       libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
+               break;
+
+       case LWS_CONNMODE_SERVER_LISTENER:
+
+               /* pollin means a client has connected to us then */
+
+               if (!(pollfd->revents & POLLIN))
+                       break;
+
+               /* listen socket got an unencrypted connection... */
+
+               clilen = sizeof(cli_addr);
+               accept_fd  = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
+                                                                      &clilen);
+               if (accept_fd < 0) {
+                       lwsl_warn("ERROR on accept: %s\n", strerror(errno));
+                       break;
+               }
+
+               /* Disable Nagle */
+               opt = 1;
+               setsockopt(accept_fd, IPPROTO_TCP, TCP_NODELAY,
+                                             (const void *)&opt, sizeof(opt));
+
+               /*
+                * look at who we connected to and give user code a chance
+                * to reject based on client IP.  There's no protocol selected
+                * yet so we issue this to protocols[0]
+                */
+
+               if ((context->protocols[0].callback)(context, wsi,
+                               LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
+                                          (void *)(long)accept_fd, NULL, 0)) {
+                       lwsl_debug("Callback denied network connection\n");
+                       compatible_close(accept_fd);
+                       break;
+               }
+
+               new_wsi = libwebsocket_create_new_server_wsi(context);
+               if (new_wsi == NULL) {
+                       compatible_close(accept_fd);
+                       break;
+               }
+
+               new_wsi->sock = accept_fd;
+
+
+#ifdef LWS_OPENSSL_SUPPORT
+               new_wsi->ssl = NULL;
+
+               if (context->use_ssl) {
+
+                       new_wsi->ssl = SSL_new(context->ssl_ctx);
+                       if (new_wsi->ssl == NULL) {
+                               lwsl_err("SSL_new failed: %s\n",
+                                   ERR_error_string(SSL_get_error(
+                                   new_wsi->ssl, 0), NULL));
+                                   libwebsockets_decode_ssl_error();
+                               free(new_wsi);
+                               compatible_close(accept_fd);
+                               break;
+                       }
+
+                       SSL_set_ex_data(new_wsi->ssl,
+                               openssl_websocket_private_data_index, context);
+
+                       SSL_set_fd(new_wsi->ssl, accept_fd);
+
+                       n = SSL_accept(new_wsi->ssl);
+                       if (n != 1) {
+                               /*
+                                * browsers seem to probe with various
+                                * ssl params which fail then retry
+                                * and succeed
+                                */
+                               lwsl_debug("SSL_accept failed skt %u: %s\n",
+                                     pollfd->fd,
+                                     ERR_error_string(SSL_get_error(
+                                     new_wsi->ssl, n), NULL));
+                               SSL_free(
+                                      new_wsi->ssl);
+                               free(new_wsi);
+                               compatible_close(accept_fd);
+                               break;
+                       }
+
+                       lwsl_debug("accepted new SSL conn  "
+                             "port %u on fd=%d SSL ver %s\n",
+                               ntohs(cli_addr.sin_port), accept_fd,
+                                 SSL_get_version(new_wsi->ssl));
+
+               } else
+#endif
+                       lwsl_debug("accepted new conn  port %u on fd=%d\n",
+                                         ntohs(cli_addr.sin_port), accept_fd);
+
+               insert_wsi_socket_into_fds(context, new_wsi);
+               break;
+
+       case LWS_CONNMODE_BROADCAST_PROXY_LISTENER:
+
+               /* as we are listening, POLLIN means accept() is needed */
+
+               if (!(pollfd->revents & POLLIN))
+                       break;
+
+               /* listen socket got an unencrypted connection... */
+
+               clilen = sizeof(cli_addr);
+               accept_fd  = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
+                                                                      &clilen);
+               if (accept_fd < 0) {
+                       lwsl_warn("ERROR on accept %d\n", accept_fd);
+                       return 0;
+               }
+
+               /* create a dummy wsi for the connection and add it */
+
+               new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
+               if (new_wsi == NULL) {
+                       lwsl_err("Out of mem\n");
+                       goto bail_prox_listener;
+               }
+               memset(new_wsi, 0, sizeof (struct libwebsocket));
+               new_wsi->sock = accept_fd;
+               new_wsi->mode = LWS_CONNMODE_BROADCAST_PROXY;
+               new_wsi->state = WSI_STATE_ESTABLISHED;
+               new_wsi->count_active_extensions = 0;
+               /* note which protocol we are proxying */
+               new_wsi->protocol_index_for_broadcast_proxy =
+                                       wsi->protocol_index_for_broadcast_proxy;
+
+               insert_wsi_socket_into_fds(context, new_wsi);
+               break;
+
+bail_prox_listener:
+               compatible_close(accept_fd);
+               break;
+
+       case LWS_CONNMODE_BROADCAST_PROXY:
+
+               /* handle session socket closed */
+
+               if (pollfd->revents & (POLLERR | POLLHUP)) {
+
+                       lwsl_debug("Session Socket %p (fd=%d) dead\n",
+                               (void *)wsi, pollfd->fd);
+
+                       libwebsocket_close_and_free_session(context, wsi,
+                                                      LWS_CLOSE_STATUS_NORMAL);
+                       return 0;
+               }
+
+               /*
+                * either extension code with stuff to spill, or the user code,
+                * requested a callback when it was OK to write
+                */
+
+               if (pollfd->revents & POLLOUT)
+                       if (lws_handle_POLLOUT_event(context, wsi,
+                                                                pollfd) < 0) {
+                               libwebsocket_close_and_free_session(
+                                       context, wsi, LWS_CLOSE_STATUS_NORMAL);
+                               return 0;
+                       }
+
+               /* any incoming data ready? */
+
+               if (!(pollfd->revents & POLLIN))
+                       break;
+
+               /* get the issued broadcast payload from the socket */
+
+               len = read(pollfd->fd, buf + LWS_SEND_BUFFER_PRE_PADDING,
+                                                        MAX_BROADCAST_PAYLOAD);
+               if (len < 0) {
+                       lwsl_err("Error reading broadcast payload\n");
+                       break;
+               }
+
+               /* broadcast it to all guys with this protocol index */
+
+               for (n = 0; n < context->fds_count; n++) {
+
+                       new_wsi = context->lws_lookup[context->fds[n].fd];
+                       if (new_wsi == NULL)
+                               continue;
+
+                       /* only to clients we are serving to */
+
+                       if (new_wsi->mode != LWS_CONNMODE_WS_SERVING)
+                               continue;
+
+                       /*
+                        * never broadcast to non-established
+                        * connection
+                        */
+
+                       if (new_wsi->state != WSI_STATE_ESTABLISHED)
+                               continue;
+
+                       /*
+                        * only broadcast to connections using
+                        * the requested protocol
+                        */
+
+                       if (new_wsi->protocol->protocol_index !=
+                               wsi->protocol_index_for_broadcast_proxy)
+                               continue;
+
+                       /* broadcast it to this connection */
+
+                       user_callback_handle_rxflow(new_wsi->protocol->callback, context, new_wsi,
+                               LWS_CALLBACK_BROADCAST,
+                               new_wsi->user_space,
+                               buf + LWS_SEND_BUFFER_PRE_PADDING, len);
+               }
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
index de0a2a2..4dda770 100644 (file)
@@ -1,60 +1,99 @@
-bin_PROGRAMS=libwebsockets-test-server libwebsockets-test-server-extpoll
+bin_PROGRAMS=
 
 if NO_CLIENT
 else
-bin_PROGRAMS+=libwebsockets-test-client libwebsockets-test-fraggle
+bin_PROGRAMS+= libwebsockets-test-client
+if NO_SERVER
+else
+bin_PROGRAMS+= libwebsockets-test-fraggle
+endif
 endif
 
+if NO_SERVER
+else
+bin_PROGRAMS+=libwebsockets-test-server libwebsockets-test-server-extpoll
+endif
+
+if NO_SERVER
+else
 libwebsockets_test_server_SOURCES=test-server.c
 libwebsockets_test_server_CFLAGS=
 libwebsockets_test_server_LDADD=-L../lib -lwebsockets -lz
 libwebsockets_test_server_extpoll_SOURCES=test-server.c
 libwebsockets_test_server_extpoll_CFLAGS=$(AM_CFLAGS) -DEXTERNAL_POLL
 libwebsockets_test_server_extpoll_LDADD=-L../lib -lwebsockets -lz
+endif
 if NO_CLIENT
 else
 libwebsockets_test_client_SOURCES=test-client.c
 libwebsockets_test_client_CFLAGS=
 libwebsockets_test_client_LDADD=-L../lib -lwebsockets -lz
+if NO_SERVER
+else
 libwebsockets_test_fraggle_SOURCES=test-fraggle.c
 libwebsockets_test_fraggle_CFLAGS=
 libwebsockets_test_fraggle_LDADD=-L../lib -lwebsockets -lz
 endif
+endif
 
-if MINGW                                                                        
+if MINGW
+if NO_SERVER
+else
 libwebsockets_test_server_CFLAGS+= -w  -I../win32port/win32helpers
 libwebsockets_test_server_extpoll_CFLAGS+= -w  -I../win32port/win32helpers
+endif
 if NO_CLIENT
 else
 libwebsockets_test_client_CFLAGS+= -w   -I../win32port/win32helpers
+if NO_SERVER
+else
 libwebsockets_test_fraggle_CFLAGS+= -w   -I../win32port/win32helpers
 endif
+endif
 
+if NO_SERVER
+else
 libwebsockets_test_server_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz
 libwebsockets_test_server_extpoll_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz
+endif
 if NO_CLIENT
 else
 libwebsockets_test_client_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz 
+if NO_SERVER
+else
 libwebsockets_test_fraggle_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz
 endif
+endif
 
 else
+if NO_SERVER
+else
 libwebsockets_test_server_CFLAGS+= -Werror
 libwebsockets_test_server_extpoll_CFLAGS+= -Werror
+endif
 if NO_CLIENT
 else
 libwebsockets_test_client_CFLAGS+= -Werror
+if NO_SERVER
+else
 libwebsockets_test_fraggle_CFLAGS+= -Werror
 endif
+endif
 endif   
 
+if NO_SERVER
+else
 libwebsockets_test_server_CFLAGS+= -Wall -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
 libwebsockets_test_server_extpoll_CFLAGS+= -Wall -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
+endif
 if NO_CLIENT
 else
 libwebsockets_test_client_CFLAGS+= -Wall -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
+if NO_SERVER
+else
 libwebsockets_test_fraggle_CFLAGS+= -Wall -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
 endif
+endif
 
 if NOPING
 else