From 18db50c46a3839897b7a61c54e09b5c118ee79e3 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 25 Apr 2016 17:29:50 -0500 Subject: [PATCH] FS-9099 #resolve [Websocket raw frame read timeout is too short] --- libs/sofia-sip/.update | 2 +- .../libsofia-sip-ua/tport/tport_type_ws.c | 47 +++--- .../libsofia-sip-ua/tport/tport_ws.h | 3 +- libs/sofia-sip/libsofia-sip-ua/tport/ws.c | 156 +++++++++++------- libs/sofia-sip/libsofia-sip-ua/tport/ws.h | 19 ++- src/mod/endpoints/mod_verto/ws.c | 12 +- 6 files changed, 139 insertions(+), 100 deletions(-) diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index 971a2e93f3..768af17e16 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Mon Apr 18 10:41:03 CEST 2016 +Mon Apr 25 17:16:25 CDT 2016 diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c index 2866899fd3..8857515cb3 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c @@ -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; } diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_ws.h b/libs/sofia-sip/libsofia-sip-ua/tport/tport_ws.h index b4a5d42b5a..d48101e5cb 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_ws.h +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_ws.h @@ -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; diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/ws.c b/libs/sofia-sip/libsofia-sip-ua/tport/ws.c index 6e9a69d025..7fe9f182bf 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/ws.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/ws.c @@ -1,3 +1,4 @@ +#include #include "ws.h" #include @@ -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); + 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; + } + + + } + u64 = (uint64_t *) wsh->payload; wsh->payload += 8; - - wsh->plen = ntohl((u_long)*u64); - + 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; } + + *data = (uint8_t *)wsh->bbuffer; - - *(wsh->payload+wsh->rplen) = '\0'; - *data = (uint8_t *)wsh->payload; - - //printf("READ[%ld][%d]-----------------------------:\n[%s]\n-------------------------------\n", wsh->rplen, *oc, (char *)*data); + //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)) { diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/ws.h b/libs/sofia-sip/libsofia-sip-ua/tport/ws.h index 1751a96655..045ff32acc 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/ws.h +++ b/libs/sofia-sip/libsofia-sip-ua/tport/ws.h @@ -25,6 +25,17 @@ //#include "sha1.h" #include +#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; diff --git a/src/mod/endpoints/mod_verto/ws.c b/src/mod/endpoints/mod_verto/ws.c index 0731ac6915..265dd10d8e 100644 --- a/src/mod/endpoints/mod_verto/ws.c +++ b/src/mod/endpoints/mod_verto/ws.c @@ -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) {