]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-9099 #resolve [Websocket raw frame read timeout is too short]
authorAnthony Minessale <anthm@freeswitch.org>
Mon, 25 Apr 2016 22:29:50 +0000 (17:29 -0500)
committerAnthony Minessale <anthm@freeswitch.org>
Mon, 25 Apr 2016 22:29:50 +0000 (17:29 -0500)
libs/sofia-sip/.update
libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c
libs/sofia-sip/libsofia-sip-ua/tport/tport_ws.h
libs/sofia-sip/libsofia-sip-ua/tport/ws.c
libs/sofia-sip/libsofia-sip-ua/tport/ws.h
src/mod/endpoints/mod_verto/ws.c

index 971a2e93f3caba18c01bc23023b1875ed1750cf3..768af17e168bdb64589f5cb38600a964d6d7bc70 100644 (file)
@@ -1 +1 @@
-Mon Apr 18 10:41:03 CEST 2016
+Mon Apr 25 17:16:25 CDT 2016
index 2866899fd339b2d0346c80b570b9a096b0f1b717..8857515cb35816c139bbfc5af133cfe463d4c2d2 100644 (file)
@@ -267,26 +267,15 @@ ssize_t tport_send_stream_ws(tport_t const *self, msg_t *msg,
                          msg_iovec_t iov[],
                          size_t iovlen)
 {
-  size_t i, j, n, m, size = 0;
+  size_t i, j, m, size = 0;
   ssize_t nerror;
   tport_ws_t *wstp = (tport_ws_t *)self;
 
-  enum { WSBUFSIZE = 2048 };
+  wstp->wstp_buflen = 0;
 
   for (i = 0; i < iovlen; i = j) {
-    char *buf = wstp->wstp_buffer;
-    unsigned wsbufsize = WSBUFSIZE;
-
-    if (i + 1 == iovlen) {
-               buf = NULL;             /* Don't bother copying single chunk */
-       }
-
-    if (buf &&
-               (char *)iov[i].siv_base - buf < WSBUFSIZE &&
-               (char *)iov[i].siv_base - buf >= 0) {
-               wsbufsize = buf + WSBUFSIZE - (char *)iov[i].siv_base;
-               assert(wsbufsize <= WSBUFSIZE);
-    }
+       char *buf = NULL;
+    unsigned wsbufsize = sizeof(wstp->wstp_buffer);
 
     for (j = i, m = 0; buf && j < iovlen; j++) {
                if (m + iov[j].siv_len > wsbufsize) {
@@ -304,8 +293,20 @@ ssize_t tport_send_stream_ws(tport_t const *self, msg_t *msg,
       iov[j].siv_base = buf, iov[j].siv_len = m;
        }
 
-       nerror = ws_feed_buf(&wstp->ws, buf, m);
+       nerror = 0;
        
+       if (m + wstp->wstp_buflen >= wsbufsize) {
+               nerror = -1;
+               errno = ENOMEM;
+       } else {
+               if (memcpy(wstp->wstp_buffer + wstp->wstp_buflen, buf, m)) {
+                       wstp->wstp_buflen += m;
+               } else {
+                       nerror = -1;
+                       errno = ENOMEM;
+               }
+       }
+
     SU_DEBUG_9(("tport_ws_writevec: vec %p %p %lu ("MOD_ZD")\n",
                (void *)&wstp->ws, (void *)iov[i].siv_base, (LU)iov[i].siv_len,
                nerror));
@@ -317,17 +318,13 @@ ssize_t tport_send_stream_ws(tport_t const *self, msg_t *msg,
       SU_DEBUG_3(("ws_write: %s\n", strerror(err)));
       return -1;
     }
-
-    n = (size_t)nerror;
-    size += n;
-
-    /* Return if the write buffer is full for now */
-    if (n != m)
-      break;
   }
 
-  ws_send_buf(&wstp->ws, WSOC_TEXT);
-
+  if (wstp->wstp_buflen) {
+         *(wstp->wstp_buffer + wstp->wstp_buflen) = '\0';
+         ws_write_frame(&wstp->ws, WSOC_TEXT, wstp->wstp_buffer, wstp->wstp_buflen);
+         size = wstp->wstp_buflen;
+  }
 
   return size;
 }
index b4a5d42b5a0b1ad7a0c57abe98327d8b5df828bc..d48101e5cbe31a9f050401e103a0f28dad570735 100644 (file)
@@ -56,7 +56,8 @@ typedef enum {
 typedef struct tport_ws_s {
   tport_t  wstp_tp[1];
   wsh_t    ws;
-  char    *wstp_buffer;
+  char     wstp_buffer[65536];
+  size_t   wstp_buflen;
   SU_S8_T  ws_initialized;
   unsigned ws_secure:1;
   unsigned:0;
index 6e9a69d025713d64670ee8f61ccaf349413bbcac..7fe9f182bf5f4bc99048b028709d4273088c14e2 100644 (file)
@@ -1,3 +1,4 @@
+#include <switch.h>
 #include "ws.h"
 #include <pthread.h>
 
@@ -146,7 +147,7 @@ static int cheezy_get_var(char *data, char *name, char *buf, size_t buflen)
   } while((p = (strstr(p,"\n")+1))!=(char *)1);
 
 
-  if (p != (char *)1 && *p!='\0') {
+  if (p && p != (char *)1 && *p!='\0') {
     char *v, *e = 0;
 
     v = strchr(p, ':');
@@ -264,7 +265,7 @@ int ws_handshake(wsh_t *wsh)
                }
        }
 
-       if (bytes > sizeof(wsh->buffer) -1) {
+       if (bytes > wsh->buflen -1) {
                goto err;
        }
 
@@ -362,7 +363,7 @@ ssize_t ws_raw_read(wsh_t *wsh, void *data, size_t bytes, int block)
                                }
                        }
 
-               } while (r == -1 && err == SSL_ERROR_WANT_READ && wsh->x < 100);
+               } while (r == -1 && err == SSL_ERROR_WANT_READ && wsh->x < 1000);
 
                goto end;
        }
@@ -382,9 +383,9 @@ ssize_t ws_raw_read(wsh_t *wsh, void *data, size_t bytes, int block)
                                ms_sleep(10);
                        }
                }
-       } while (r == -1 && xp_is_blocking(xp_errno()) && wsh->x < 100);
+       } while (r == -1 && xp_is_blocking(xp_errno()) && wsh->x < 1000);
        
-       if (wsh->x >= 1000 || (block && wsh->x >= 100)) {
+       if (wsh->x >= 10000 || (block && wsh->x >= 1000)) {
                r = -1;
        }
 
@@ -596,7 +597,15 @@ int ws_init(wsh_t *wsh, ws_socket_t sock, SSL_CTX *ssl_ctx, int close_sock, int
                wsh->close_sock = 1;
        }
 
-       wsh->buflen = sizeof(wsh->buffer);
+       wsh->buflen = 1024 * 64;
+       wsh->bbuflen = wsh->buflen;
+
+       wsh->buffer = malloc(wsh->buflen);
+       wsh->bbuffer = malloc(wsh->bbuflen);
+       //printf("init %p %ld\n", (void *) wsh->bbuffer, wsh->bbuflen);
+       //memset(wsh->buffer, 0, wsh->buflen);
+       //memset(wsh->bbuffer, 0, wsh->bbuflen);
+
        wsh->secure = ssl_ctx ? 1 : 0;
 
        setup_socket(sock);
@@ -644,6 +653,12 @@ void ws_destroy(wsh_t *wsh)
                SSL_free(wsh->ssl);
                wsh->ssl = NULL;
        }
+
+       if (wsh->buffer) free(wsh->buffer);
+       if (wsh->bbuffer) free(wsh->bbuffer);
+
+       wsh->buffer = wsh->bbuffer = NULL;
+
 }
 
 ssize_t ws_close(wsh_t *wsh, int16_t reason) 
@@ -685,6 +700,20 @@ ssize_t ws_close(wsh_t *wsh, int16_t reason)
        
 }
 
+
+uint64_t hton64(uint64_t val)
+{
+       if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
+       else return __bswap_64(val);
+}
+
+uint64_t ntoh64(uint64_t val)
+{
+       if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
+       else return __bswap_64(val);
+}
+
+
 ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
 {
        
@@ -692,6 +721,10 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
        char *maskp;
        int ll = 0;
        int frag = 0;
+       int blen;
+
+       wsh->body = wsh->bbuffer;
+       wsh->packetlen = 0;
 
  again:
        need = 2;
@@ -745,12 +778,11 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
                        int fin = (wsh->buffer[0] >> 7) & 1;
                        int mask = (wsh->buffer[1] >> 7) & 1;
                        
-                       if (fin) {
-                               if (*oc == WSOC_CONTINUATION) {
-                                       frag = 1;
-                               } else {
-                                       frag = 0;
-                               }
+
+                       if (!fin && *oc != WSOC_CONTINUATION) {
+                               frag = 1;
+                       } else if (fin && *oc == WSOC_CONTINUATION) {
+                               frag = 0;
                        }
 
                        if (mask) {
@@ -765,23 +797,33 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
 
                        wsh->plen = wsh->buffer[1] & 0x7f;
                        wsh->payload = &wsh->buffer[2];
-
+                       
                        if (wsh->plen == 127) {
                                uint64_t *u64;
+                               int more = 0;
 
                                need += 8;
 
                                if (need > wsh->datalen) {
                                        /* too small - protocol err */
-                                       *oc = WSOC_CLOSE;
-                                       return ws_close(wsh, WS_PROTO_ERR);
-                               }
+                                       //*oc = WSOC_CLOSE;
+                                       //return ws_close(wsh, WS_PROTO_ERR);
 
-                               u64 = (uint64_t *) wsh->payload;
-                               wsh->payload += 8;
+                                       more = ws_raw_read(wsh, wsh->buffer + wsh->datalen, need - wsh->datalen, WS_BLOCK);
+
+                                       if (more < need - wsh->datalen) {
+                                               *oc = WSOC_CLOSE;
+                                               return ws_close(wsh, WS_PROTO_ERR);
+                                       } else {
+                                               wsh->datalen += more;
+                                       }
 
-                               wsh->plen = ntohl((u_long)*u64);
 
+                               }
+                               
+                               u64 = (uint64_t *) wsh->payload;
+                               wsh->payload += 8;
+                               wsh->plen = ntoh64(*u64);
                        } else if (wsh->plen == 126) {
                                uint16_t *u16;
 
@@ -811,16 +853,30 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
                                return ws_close(wsh, WS_PROTO_ERR);
                        }
 
-                       if ((need + wsh->datalen) > (ssize_t)wsh->buflen) {
-                               /* too big - Ain't nobody got time fo' dat */
-                               *oc = WSOC_CLOSE;
-                               return ws_close(wsh, WS_DATA_TOO_BIG);                          
+                       blen = wsh->body - wsh->bbuffer;
+
+                       if (need + blen > (ssize_t)wsh->bbuflen) {
+                               void *tmp;
+                               
+                               wsh->bbuflen = need + blen + wsh->rplen;
+
+                               if ((tmp = realloc(wsh->bbuffer, wsh->bbuflen))) {
+                                       wsh->bbuffer = tmp;
+                               } else {
+                                       abort();
+                               }
+
+                               wsh->body = wsh->bbuffer + blen;
                        }
 
                        wsh->rplen = wsh->plen - need;
-
+                       
+                       if (wsh->rplen) {
+                               memcpy(wsh->body, wsh->payload, wsh->rplen);
+                       }
+                       
                        while(need) {
-                               ssize_t r = ws_raw_read(wsh, wsh->payload + wsh->rplen, need, WS_BLOCK);
+                               ssize_t r = ws_raw_read(wsh, wsh->body + wsh->rplen, need, WS_BLOCK);
 
                                if (r < 1) {
                                        /* invalid read - protocol err .. */
@@ -837,28 +893,30 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
                                ssize_t i;
 
                                for (i = 0; i < wsh->datalen; i++) {
-                                       wsh->payload[i] ^= maskp[i % 4];
+                                       wsh->body[i] ^= maskp[i % 4];
                                }
                        }
                        
 
                        if (*oc == WSOC_PING) {
-                               ws_write_frame(wsh, WSOC_PONG, wsh->payload, wsh->rplen);
+                               ws_write_frame(wsh, WSOC_PONG, wsh->body, wsh->rplen);
                                goto again;
                        }
 
+                       *(wsh->body+wsh->rplen) = '\0';
+                       wsh->packetlen += wsh->rplen;
+                       wsh->body += wsh->rplen;
+
                        if (frag) {
                                goto again;
                        }
-                       
-
-                       *(wsh->payload+wsh->rplen) = '\0';
-                       *data = (uint8_t *)wsh->payload;
 
-                       //printf("READ[%ld][%d]-----------------------------:\n[%s]\n-------------------------------\n", wsh->rplen, *oc, (char *)*data);
+                       *data = (uint8_t *)wsh->bbuffer;
+                       
+                       //printf("READ[%ld][%d]-----------------------------:\n[%s]\n-------------------------------\n", wsh->packetlen, *oc, (char *)*data);
 
 
-                       return wsh->rplen;
+                       return wsh->packetlen;
                }
                break;
        default:
@@ -871,36 +929,6 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
        }
 }
 
-ssize_t ws_feed_buf(wsh_t *wsh, void *data, size_t bytes)
-{
-
-       if (bytes + wsh->wdatalen > wsh->buflen) {
-               return -1;
-       }
-
-       memcpy(wsh->wbuffer + wsh->wdatalen, data, bytes);
-       
-       wsh->wdatalen += bytes;
-
-       return bytes;
-}
-
-ssize_t ws_send_buf(wsh_t *wsh, ws_opcode_t oc)
-{
-       ssize_t r = 0;
-
-       if (!wsh->wdatalen) {
-               return -1;
-       }
-       
-       r = ws_write_frame(wsh, oc, wsh->wbuffer, wsh->wdatalen);
-       
-       wsh->wdatalen = 0;
-
-       return r;
-}
-
-
 ssize_t ws_write_frame(wsh_t *wsh, ws_opcode_t oc, void *data, size_t bytes)
 {
        uint8_t hdr[14] = { 0 };
@@ -934,7 +962,7 @@ ssize_t ws_write_frame(wsh_t *wsh, ws_opcode_t oc, void *data, size_t bytes)
                hlen += 8;
                
                u64 = (uint64_t *) &hdr[2];
-               *u64 = htonl(bytes);
+               *u64 = hton64(bytes);
        }
 
        if (wsh->write_buffer_len < (hlen + bytes + 1)) {
index 1751a96655df2d6663f9c325513c7d80121a168d..045ff32accbc610062caf7b172f21870dc880162 100644 (file)
 //#include "sha1.h"
 #include <openssl/ssl.h>
 
+#if defined(_MSC_VER) || defined(__APPLE__) || defined(__FreeBSD__) || (defined(__SVR4) && defined(__sun)) 
+#define __bswap_64(x) \
+  x = (x>>56) | \
+    ((x<<40) & 0x00FF000000000000) | \
+    ((x<<24) & 0x0000FF0000000000) | \
+    ((x<<8)  & 0x000000FF00000000) | \
+    ((x>>8)  & 0x00000000FF000000) | \
+    ((x>>24) & 0x0000000000FF0000) | \
+    ((x>>40) & 0x000000000000FF00) | \
+    (x<<56)
+#endif
 #ifdef _MSC_VER
 #ifndef strncasecmp
 #define strncasecmp _strnicmp
@@ -78,15 +89,17 @@ typedef enum {
 
 typedef struct wsh_s {
        ws_socket_t sock;
-       char buffer[65536];
-       char wbuffer[65536];
+       char *buffer;
+       char *bbuffer;
+       char *body;
        char *uri;
        size_t buflen;
+       size_t bbuflen;
        ssize_t datalen;
-       ssize_t wdatalen;
        char *payload;
        ssize_t plen;
        ssize_t rplen;
+       ssize_t packetlen;
        SSL *ssl;
        int handshake;
        uint8_t down;
index 0731ac6915dde61a3969c02fbd75197d2c778752..265dd10d8e3741de635dc265f8d99dcc5c9a8fca 100644 (file)
@@ -385,7 +385,7 @@ ssize_t ws_raw_read(wsh_t *wsh, void *data, size_t bytes, int block)
                }
        } while (r == -1 && xp_is_blocking(xp_errno()) && wsh->x < 1000);
        
-       if (wsh->x >= 1000 || (block && wsh->x >= 100)) {
+       if (wsh->x >= 10000 || (block && wsh->x >= 1000)) {
                r = -1;
        }
 
@@ -929,7 +929,7 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
        }
 }
 
-#if 0
+
 ssize_t ws_feed_buf(wsh_t *wsh, void *data, size_t bytes)
 {
 
@@ -937,9 +937,9 @@ ssize_t ws_feed_buf(wsh_t *wsh, void *data, size_t bytes)
                return -1;
        }
 
-       memcpy(wsh->wbuffer + wsh->wdatalen, data, bytes);
+       memcpy((unsigned char *)wsh->write_buffer + wsh->write_buffer_len, data, bytes);
        
-       wsh->wdatalen += bytes;
+       wsh->write_buffer_len += bytes;
 
        return bytes;
 }
@@ -953,13 +953,13 @@ ssize_t ws_send_buf(wsh_t *wsh, ws_opcode_t oc)
                return -1;
        }
        
-       r = ws_write_frame(wsh, oc, wsh->wbuffer, wsh->wdatalen);
+       r = ws_write_frame(wsh, oc, wsh->write_buffer, wsh->write_buffer_len);
        
        wsh->wdatalen = 0;
 
        return r;
 }
-#endif 
+
 
 ssize_t ws_write_frame(wsh_t *wsh, ws_opcode_t oc, void *data, size_t bytes)
 {