fix onopen browser context patch
[profile/ivi/libwebsockets.git] / lib / libwebsockets.c
index 0021eb4..b05f79e 100644 (file)
@@ -187,7 +187,7 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
                 */
 
                if (m) {
-                       fprintf(stderr, "extension vetoed close\n");
+                       debug("extension vetoed close\n");
                        return;
                }
        }
@@ -252,7 +252,7 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
        if (old_state == WSI_STATE_ESTABLISHED &&
                                          reason != LWS_CLOSE_STATUS_NOSTATUS) {
 
-               fprintf(stderr, "sending close indication...\n");
+               debug("sending close indication...\n");
 
                n = libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING],
                                                            0, LWS_WRITE_CLOSE);
@@ -269,7 +269,7 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
                        libwebsocket_set_timeout(wsi,
                                                  PENDING_TIMEOUT_CLOSE_ACK, 5);
 
-                       fprintf(stderr, "sent close indication, awaiting ack\n");
+                       debug("sent close indication, awaiting ack\n");
 
                        return;
                }
@@ -279,7 +279,7 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
 
 just_kill_connection:
 
-       fprintf(stderr, "libwebsocket_close_and_free_session: just_kill_connection\n");
+       debug("libwebsocket_close_and_free_session: just_kill_connection\n");
 
        /*
         * we won't be servicing or receiving anything further from this guy
@@ -316,12 +316,13 @@ just_kill_connection:
                                ((old_state == WSI_STATE_ESTABLISHED) ||
                                 (old_state == WSI_STATE_RETURNED_CLOSE_ALREADY) ||
                                 (old_state == WSI_STATE_AWAITING_CLOSE_ACK))) {
-               fprintf(stderr, "calling back CLOSED\n");
+               debug("calling back CLOSED\n");
                wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLOSED,
                                                      wsi->user_space, NULL, 0);
-       } else {
-               fprintf(stderr, "not calling back closed due to old_state=%d\n", old_state);
-       }
+       } else
+               debug("not calling back closed due to old_state=%d\n",
+                                                                    old_state);
+
 
        /* deallocate any active extension contexts */
 
@@ -657,7 +658,7 @@ lws_handle_POLLOUT_event(struct libwebsocket_context *context,
                        /* no we could add more */
                        continue;
 
-               fprintf(stderr, "choked in POLLOUT service\n");
+               debug("choked in POLLOUT service\n");
 
                /*
                 * Yes, he's choked.  Leave the POLLOUT masked on so we will
@@ -723,7 +724,7 @@ libwebsocket_service_timeout_check(struct libwebsocket_context *context,
         */
 
        if (sec > wsi->pending_timeout_limit) {
-               fprintf(stderr, "TIMEDOUT WAITING\n");
+               debug("TIMEDOUT WAITING\n");
                libwebsocket_close_and_free_session(context,
                                wsi, LWS_CLOSE_STATUS_NOSTATUS);
        }
@@ -784,6 +785,7 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
        char *p = pkt;
        int n;
        struct libwebsocket_extension *ext;
+       struct libwebsocket_extension *ext1;
        int ext_count = 0;
        unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1 + MAX_BROADCAST_PAYLOAD +
                                                  LWS_SEND_BUFFER_POST_PADDING];
@@ -957,6 +959,24 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
        while (ext && ext->callback) {
 
                n = 0;
+               ext1 = context->extensions;
+               while (ext1 && ext1->callback) {
+
+                       n |= ext1->callback(context, ext1, wsi,
+                               LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION,
+                                       NULL, (char *)ext->name, 0);
+
+                       ext1++;
+               }
+
+               if (n) {
+
+                       /* an extension vetos us */
+                       debug("ext %s vetoed\n", (char *)ext->name);
+                       ext++;
+                       continue;
+               }
+
                n = context->protocols[0].callback(context, wsi,
                        LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,
                                wsi->user_space, (char *)ext->name, 0);
@@ -1010,6 +1030,8 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
 
 issue_hdr:
 
+//     puts(pkt);
+
        /* done with these now */
 
        free(wsi->c_path);
@@ -1035,7 +1057,7 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context,
        char ext_name[128];
        struct libwebsocket_extension *ext;
        void *v;
-       int len;
+       int len = 0;
        int n;
        static const char magic_websocket_04_masking_guid[] =
                                         "61AC5F19-FBBA-4540-B96F-6561F1AB40A8";
@@ -1059,16 +1081,16 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context,
                        !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
                        (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len &&
                        wsi->c_protocol != NULL)) {
-                       fprintf(stderr, "libwebsocket_client_handshake "
+                       debug("libwebsocket_client_handshake "
                                        "missing required header(s)\n");
                        pkt[len] = '\0';
-                       fprintf(stderr, "%s", pkt);
+                       debug("%s", pkt);
                        goto bail3;
                }
 
                strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
-               if (strcmp(wsi->utf8_token[WSI_TOKEN_HTTP].token,
-                       "101 websocket protocol handshake")) {
+               if (strncmp(wsi->utf8_token[WSI_TOKEN_HTTP].token,
+                                                           "101", 3)) {
                        fprintf(stderr, "libwebsocket_client_handshake "
                                "server sent bad HTTP response '%s'\n",
                                wsi->utf8_token[WSI_TOKEN_HTTP].token);
@@ -1082,7 +1104,7 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context,
                                wsi->utf8_token[
                                        WSI_TOKEN_CHALLENGE].token_len);
                        pkt[len] = '\0';
-                       fprintf(stderr, "%s", pkt);
+                       debug("%s", pkt);
                        goto bail3;
 
                }
@@ -1110,10 +1132,10 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context,
                                   wsi->ietf_spec_revision == 4) ||
                (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len &&
                                                 wsi->c_protocol != NULL)) {
-               fprintf(stderr, "libwebsocket_client_handshake "
+                debug("libwebsocket_client_handshake "
                                        "missing required header(s)\n");
                pkt[len] = '\0';
-               fprintf(stderr, "%s", pkt);
+               debug("%s", pkt);
                goto bail3;
        }
 
@@ -1123,8 +1145,7 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context,
         */
 
        strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
-       if (strcmp(wsi->utf8_token[WSI_TOKEN_HTTP].token,
-                                          "101 switching protocols")) {
+       if (strncmp(wsi->utf8_token[WSI_TOKEN_HTTP].token, "101", 3)) {
                fprintf(stderr, "libwebsocket_client_handshake "
                                "server sent bad HTTP response '%s'\n",
                                 wsi->utf8_token[WSI_TOKEN_HTTP].token);
@@ -1154,7 +1175,7 @@ select_protocol:
        if (pc == NULL)
                fprintf(stderr, "lws_client_interpret_server_handshake: NULL c_protocol\n");
        else
-               fprintf(stderr, "lws_client_interpret_server_handshake: cPprotocol='%s'\n", pc);
+               debug("lws_client_interpret_server_handshake: cPprotocol='%s'\n", pc);
 
        /*
         * confirm the protocol the server wants to talk was in the list
@@ -1227,7 +1248,7 @@ select_protocol:
        /* instantiate the accepted extensions */
 
        if (!wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token_len) {
-               fprintf(stderr, "no client extenstions allowed by server \n");
+               debug("no client extenstions allowed by server \n");
                goto check_accept;
        }
 
@@ -1257,7 +1278,7 @@ select_protocol:
 
                /* check we actually support it */
 
-               fprintf(stderr, "checking client ext %s\n", ext_name);
+               debug("checking client ext %s\n", ext_name);
 
                n = 0;
                ext = wsi->protocol->owning_server->extensions;
@@ -1270,7 +1291,7 @@ select_protocol:
 
                        n = 1;
 
-                       fprintf(stderr, "instantiating client ext %s\n", ext_name);
+                       debug("instantiating client ext %s\n", ext_name);
 
                        /* instantiate the extension on this conn */
 
@@ -1352,17 +1373,8 @@ check_accept:
        accept_ok:
 
        /* allocate the per-connection user memory (if any) */
-
-       if (wsi->protocol->per_session_data_size) {
-               wsi->user_space = malloc(
-                                 wsi->protocol->per_session_data_size);
-               if (wsi->user_space  == NULL) {
-                       fprintf(stderr, "Out of memory for "
-                                                  "conn user space\n");
-                       goto bail2;
-               }
-       } else
-               wsi->user_space = NULL;
+       if (wsi->protocol->per_session_data_size && !libwebsocket_ensure_user_space(wsi))
+         goto bail2;
 
        /* clear his proxy connection timeout */
 
@@ -1436,7 +1448,7 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
        struct libwebsocket *new_wsi;
        int n;
        int m;
-       size_t len;
+       ssize_t len;
        int accept_fd;
        unsigned int clilen;
        struct sockaddr_in cli_addr;
@@ -1446,6 +1458,7 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
        int more = 1;
        struct lws_tokens eff_buf;
        int opt = 1;
+       char c;
 
 #ifdef LWS_OPENSSL_SUPPORT
        char ssl_err_buf[512];
@@ -1491,6 +1504,11 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
                if (!pollfd->revents & POLLIN)
                        break;
 
+               if (context->fds_count >= MAX_CLIENTS) {
+                       fprintf(stderr, "too busy to accept new client\n");
+                       break;
+               }
+
                /* listen socket got an unencrypted connection... */
 
                clilen = sizeof(cli_addr);
@@ -1503,19 +1521,9 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
 
                /* Disable Nagle */
                opt = 1;
-               setsockopt(accept_fd, IPPROTO_TCP, TCP_NODELAY, &opt,
+        setsockopt(accept_fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&opt,
                                sizeof(opt));
 
-               if (context->fds_count >= MAX_CLIENTS) {
-                       fprintf(stderr, "too busy to accept new client\n");
-#ifdef WIN32
-                       closesocket(accept_fd);
-#else
-                       close(accept_fd);
-#endif
-                       break;
-               }
-
                /*
                 * look at who we connected to and give user code a chance
                 * to reject based on client IP.  There's no protocol selected
@@ -1525,7 +1533,7 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
                if ((context->protocols[0].callback)(context, wsi,
                                LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
                                             (void*)(long)accept_fd, NULL, 0)) {
-                       fprintf(stderr, "Callback denied network connection\n");
+                       debug("Callback denied network connection\n");
 #ifdef WIN32
                        closesocket(accept_fd);
 #else
@@ -1870,25 +1878,29 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
                 *  Sec-WebSocket-Protocol: chat
                 */
 
-       #ifdef LWS_OPENSSL_SUPPORT
-               if (wsi->use_ssl)
-                       len = SSL_read(wsi->ssl, pkt, sizeof pkt);
-               else
-       #endif
-                       len = recv(wsi->sock, pkt, sizeof pkt, 0);
+               /*
+                * we have to take some care here to only take from the
+                * socket bytewise.  The browser may (and has been seen to
+                * in the case that onopen() performs websocket traffic)
+                * coalesce both handshake response and websocket traffic
+                * in one packet, since at that point the connection is
+                * definitively ready from browser pov.
+                */
 
-               if (len < 0) {
-                       fprintf(stderr,
-                                 "libwebsocket_client_handshake read error\n");
-                       goto bail3;
-               }
+               len = 1;
+               while (wsi->parser_state != WSI_PARSING_COMPLETE && len > 0) {
+#ifdef LWS_OPENSSL_SUPPORT
+                       if (wsi->use_ssl)
+                               len = SSL_read(wsi->ssl, &c, 1);
+                        else
+#endif
+                               len = recv(wsi->sock, &c, 1, 0);
 
-               p = pkt;
-               for (n = 0; n < len; n++)
-                       libwebsocket_parse(wsi, *p++);
+                       libwebsocket_parse(wsi, c);
+               }
 
                /*
-                * may be coming in multiple packets, there is a 5-second
+                * hs may also be coming in multiple packets, there is a 5-second
                 * libwebsocket timeout still active here too, so if parsing did
                 * not complete just wait for next packet coming in this state
                 */
@@ -1896,6 +1908,12 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
                if (wsi->parser_state != WSI_PARSING_COMPLETE)
                        break;
 
+               /*
+                * otherwise deal with the handshake.  If there's any
+                * packet traffic already arrived we'll trigger poll() again
+                * right away and deal with it that way
+                */
+
                return lws_client_interpret_server_handshake(context, wsi);
 
 bail3:
@@ -1957,7 +1975,10 @@ bail3:
                if (eff_buf.token_len < 0) {
                        fprintf(stderr, "Socket read returned %d\n",
                                                            eff_buf.token_len);
-                       break;
+                       if (errno != EINTR)
+                               libwebsocket_close_and_free_session(context, wsi,
+                                                                LWS_CLOSE_STATUS_NOSTATUS);
+                       return 1;
                }
                if (!eff_buf.token_len) {
                        libwebsocket_close_and_free_session(context, wsi,
@@ -2485,6 +2506,7 @@ libwebsocket_create_context(int port, const char *interf,
                WORD wVersionRequested;
                WSADATA wsaData;
                int err;
+        HMODULE wsdll;
 
                /* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */
                wVersionRequested = MAKEWORD(2, 2);
@@ -2497,6 +2519,17 @@ libwebsocket_create_context(int port, const char *interf,
                                                                           err);
                        return NULL;
                }
+
+        wsdll = GetModuleHandle("Ws2_32.dll");
+        if (wsdll)
+        {
+            poll = (PFNWSAPOLL)GetProcAddress(wsdll, "WSAPoll");
+        }
+
+        if (!poll)
+        {
+            poll = emulated_poll;
+        }
        }
 #endif
 
@@ -2736,12 +2769,12 @@ libwebsocket_create_context(int port, const char *interf,
                }
 
                /* allow us to restart even if old sockets in TIME_WAIT */
-               setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+               setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt));
 
 
                /* Disable Nagle */
                opt = 1;
-               setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
+               setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (const void *)&opt, sizeof(opt));
 
                bzero((char *) &serv_addr, sizeof(serv_addr));
                serv_addr.sin_family = AF_INET;
@@ -2812,7 +2845,7 @@ libwebsocket_create_context(int port, const char *interf,
                }
 
                /* allow us to restart even if old sockets in TIME_WAIT */
-               setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+               setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt));
 
                bzero((char *) &serv_addr, sizeof(serv_addr));
                serv_addr.sin_family = AF_INET;
@@ -3068,3 +3101,21 @@ libwebsocket_is_final_fragment(struct libwebsocket *wsi)
 {
        return wsi->final;
 }
+
+void *
+libwebsocket_ensure_user_space(struct libwebsocket *wsi)
+{
+       /* allocate the per-connection user memory (if any) */
+
+       if (wsi->protocol->per_session_data_size && !wsi->user_space) {
+               wsi->user_space = malloc(
+                                 wsi->protocol->per_session_data_size);
+               if (wsi->user_space  == NULL) {
+                       fprintf(stderr, "Out of memory for "
+                                                  "conn user space\n");
+                       return NULL;
+               }
+               memset(wsi->user_space, 0, wsi->protocol->per_session_data_size);
+       }
+       return wsi->user_space;
+}