diff --git a/other/websocket.c b/other/websocket.c index 6f21eaa..5160bc7 100644 --- a/other/websocket.c +++ b/other/websocket.c @@ -105,14 +105,14 @@ ws_ctx_t *alloc_ws_ctx() { if (! (ctx = malloc(sizeof(ws_ctx_t))) ) { fatal("malloc()"); } - if (! (ctx->tbuf = malloc(BUFSIZE)) ) - { fatal("malloc of tbuf"); } - if (! (ctx->cbuf = malloc(BUFSIZE)) ) - { fatal("malloc of cbuf"); } - if (! (ctx->tbuf_tmp = malloc(BUFSIZE)) ) - { fatal("malloc of tbuf_tmp"); } - if (! (ctx->cbuf_tmp = malloc(BUFSIZE)) ) - { fatal("malloc of cbuf_tmp"); } + if (! (ctx->cin_buf = malloc(BUFSIZE)) ) + { fatal("malloc of cin_buf"); } + if (! (ctx->cout_buf = malloc(BUFSIZE)) ) + { fatal("malloc of cout_buf"); } + if (! (ctx->tin_buf = malloc(BUFSIZE)) ) + { fatal("malloc of tin_buf"); } + if (! (ctx->tout_buf = malloc(BUFSIZE)) ) + { fatal("malloc of tout_buf"); } ctx->headers = malloc(sizeof(headers_t)); ctx->ssl = NULL; @@ -121,10 +121,10 @@ ws_ctx_t *alloc_ws_ctx() { } int free_ws_ctx(ws_ctx_t *ctx) { - free(ctx->tbuf); - free(ctx->cbuf); - free(ctx->tbuf_tmp); - free(ctx->cbuf_tmp); + free(ctx->cin_buf); + free(ctx->cout_buf); + free(ctx->tin_buf); + free(ctx->tout_buf); free(ctx); } @@ -224,7 +224,8 @@ int encode_hixie(u_char const *src, size_t srclength, } int decode_hixie(char *src, size_t srclength, - u_char *target, size_t targsize, unsigned int *opcode) { + u_char *target, size_t targsize, + unsigned int *opcode, unsigned int *left) { char *start, *end, cntstr[4]; int i, len, framecount = 0, retlen = 0; unsigned char chr; @@ -232,6 +233,8 @@ int decode_hixie(char *src, size_t srclength, handler_emsg("WebSocket framing error\n"); return -1; } + *left = srclength; + if (srclength == 2 && (src[0] == '\xff') && (src[1] == '\x00')) { @@ -258,6 +261,7 @@ int decode_hixie(char *src, size_t srclength, snprintf(cntstr, 3, "%d", framecount); traffic(cntstr); } + *left = 0; return retlen; } @@ -300,43 +304,51 @@ int encode_hybi(u_char const *src, size_t srclength, } int decode_hybi(unsigned char *src, size_t srclength, - u_char *target, size_t targsize, unsigned int *opcode) + u_char *target, size_t targsize, + unsigned int *opcode, unsigned int *left) { unsigned char *frame, *mask, *payload, save_char, cntstr[4];; + int masked = 0; int i = 0, len, framecount = 0; + size_t remaining; unsigned int target_offset = 0, hdr_length = 0, payload_length = 0; - if ((unsigned int) srclength <= 0) - { - return 0; - } - + *left = srclength; frame = src; //printf("Deocde new frame\n"); - while (frame - src < srclength) { + while (1) { + // Need at least two bytes of the header + // Find beginning of next frame. First time hdr_length, masked and + // payload_length are zero + frame += hdr_length + 4*masked + payload_length; + //printf("frame[0..3]: 0x%x 0x%x 0x%x 0x%x (tot: %d)\n", + // (unsigned char) frame[0], + // (unsigned char) frame[1], + // (unsigned char) frame[2], + // (unsigned char) frame[3], srclength); + + if (frame > src + srclength) { + //printf("Truncated frame from client, need %d more bytes\n", frame - (src + srclength) ); + break; + } + remaining = (src + srclength) - frame; + if (remaining < 2) { + //printf("Truncated frame header from client\n"); + break; + } framecount ++; *opcode = frame[0] & 0x0f; + masked = (frame[1] & 0x80) >> 7; if (*opcode == 0x8) { // client sent orderly close frame break; } - //printf("opcode %d, frame[0..3]: 0x%x 0x%x 0x%x 0x%x\n", *opcode, - // (unsigned char) frame[0], - // (unsigned char) frame[1], - // (unsigned char) frame[2], - // (unsigned char) frame[3]); - payload_length = frame[1] & 0x7f; - if (payload_length == 0) { - // TODO: next frame - handler_msg("empty frame\n"); - frame += 6; - continue; - } else if (payload_length < 126) { + if (payload_length < 126) { hdr_length = 2; //frame += 2 * sizeof(char); } else if (payload_length == 126) { @@ -346,23 +358,24 @@ int decode_hybi(unsigned char *src, size_t srclength, handler_emsg("Receiving frames larger than 65535 bytes not supported\n"); return -1; } - //printf(" payload_length: %u, raw remaining: %u\n", payload_length, (unsigned int) srclength - target_offset); - payload = frame + hdr_length + 4; + if ((hdr_length + 4*masked + payload_length) > remaining) { + continue; + } + //printf(" payload_length: %u, raw remaining: %u\n", payload_length, remaining); + payload = frame + hdr_length + 4*masked; if (*opcode != 1 && *opcode != 2) { handler_msg("Ignoring non-data frame, opcode 0x%x\n", *opcode); - frame = frame + hdr_length + 4 + payload_length; continue; } - - if ((payload_length > 0) && (!(frame[1] & 0x80))) { - handler_emsg("Received unmasked payload from client\n"); - return -1; + if (payload_length == 0) { + handler_msg("Ignoring empty frame\n"); + continue; } - if ((hdr_length + 4 + payload_length) > (srclength - target_offset)) { - handler_emsg("Truncated frame received from client\n"); + if ((payload_length > 0) && (!masked)) { + handler_emsg("Received unmasked payload from client\n"); return -1; } @@ -385,11 +398,9 @@ int decode_hybi(unsigned char *src, size_t srclength, handler_emsg("Base64 decode error code %d", len); return len; } + target_offset += len; //printf(" len %d, raw %s\n", len, frame); - - target_offset += len; - frame = frame + hdr_length + 4 + payload_length; } if (framecount > 1) { @@ -397,6 +408,7 @@ int decode_hybi(unsigned char *src, size_t srclength, traffic(cntstr); } + *left = remaining; return target_offset; } @@ -557,7 +569,7 @@ ws_ctx_t *do_handshake(int sock) { char handshake[4096], response[4096], sha1[29], trailer[17]; char *scheme, *pre; headers_t *headers; - int len, ret; + int len, ret, i, offset; ws_ctx_t * ws_ctx; // Peek, but don't read the data @@ -598,12 +610,20 @@ ws_ctx_t *do_handshake(int sock) { scheme = "ws"; handler_msg("using plain (not SSL) socket\n"); } - len = ws_recv(ws_ctx, handshake, 4096); - if (len == 0) { - handler_emsg("Client closed during handshake\n"); - return NULL; + offset = 0; + for (i = 0; i < 10; i++) { + len = ws_recv(ws_ctx, handshake+offset, 4096); + if (len == 0) { + handler_emsg("Client closed during handshake\n"); + return NULL; + } + offset += len; + handshake[offset] = 0; + if (strstr(handshake, "\r\n\r\n")) { + break; + } + usleep(10); } - handshake[len] = 0; //handler_msg("handshake: %s\n", handshake); if (!parse_handshake(ws_ctx, handshake)) { diff --git a/other/websocket.h b/other/websocket.h index 5ac2936..8062da7 100644 --- a/other/websocket.h +++ b/other/websocket.h @@ -45,10 +45,10 @@ typedef struct { int hixie; int hybi; headers_t *headers; - char *tbuf; - char *cbuf; - char *tbuf_tmp; - char *cbuf_tmp; + char *cin_buf; + char *cout_buf; + char *tin_buf; + char *tout_buf; } ws_ctx_t; typedef struct { diff --git a/other/websockify.c b/other/websockify.c index fe130a5..f8e6bcb 100644 --- a/other/websockify.c +++ b/other/websockify.c @@ -54,10 +54,13 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) { fd_set rlist, wlist, elist; struct timeval tv; int i, maxfd, client = ws_ctx->sockfd; - unsigned int opcode, tstart, tend, cstart, cend, ret; + unsigned int opcode, left, ret; + unsigned int tout_start, tout_end, cout_start, cout_end; + unsigned int tin_start, tin_end; ssize_t len, bytes; - tstart = tend = cstart = cend = 0; + tout_start = tout_end = cout_start = cout_end; + tin_start = tin_end = 0; maxfd = client > target ? client+1 : target+1; while (1) { @@ -71,14 +74,14 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) { FD_SET(client, &elist); FD_SET(target, &elist); - if (tend == tstart) { + if (tout_end == tout_start) { // Nothing queued for target, so read from client FD_SET(client, &rlist); } else { // Data queued for target, so write to it FD_SET(target, &wlist); } - if (cend == cstart) { + if (cout_end == cout_start) { // Nothing queued for client, so read from target FD_SET(target, &rlist); } else { @@ -107,17 +110,17 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) { } if (FD_ISSET(target, &wlist)) { - len = tend-tstart; - bytes = send(target, ws_ctx->tbuf + tstart, len, 0); + len = tout_end-tout_start; + bytes = send(target, ws_ctx->tout_buf + tout_start, len, 0); if (pipe_error) { break; } if (bytes < 0) { handler_emsg("target connection error: %s\n", strerror(errno)); break; } - tstart += bytes; - if (tstart >= tend) { - tstart = tend = 0; + tout_start += bytes; + if (tout_start >= tout_end) { + tout_start = tout_end = 0; traffic(">"); } else { traffic(">."); @@ -125,17 +128,17 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) { } if (FD_ISSET(client, &wlist)) { - len = cend-cstart; - bytes = ws_send(ws_ctx, ws_ctx->cbuf + cstart, len); + len = cout_end-cout_start; + bytes = ws_send(ws_ctx, ws_ctx->cout_buf + cout_start, len); if (pipe_error) { break; } if (len < 3) { handler_emsg("len: %d, bytes: %d: %d\n", (int) len, (int) bytes, - (int) *(ws_ctx->cbuf + cstart)); + (int) *(ws_ctx->cout_buf + cout_start)); } - cstart += bytes; - if (cstart >= cend) { - cstart = cend = 0; + cout_start += bytes; + if (cout_start >= cout_end) { + cout_start = cout_end = 0; traffic("<"); } else { traffic("<."); @@ -143,28 +146,28 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) { } if (FD_ISSET(target, &rlist)) { - bytes = recv(target, ws_ctx->cbuf_tmp, DBUFSIZE , 0); + bytes = recv(target, ws_ctx->cin_buf, DBUFSIZE , 0); if (pipe_error) { break; } if (bytes <= 0) { handler_emsg("target closed connection\n"); break; } - cstart = 0; + cout_start = 0; if (ws_ctx->hybi) { - cend = encode_hybi(ws_ctx->cbuf_tmp, bytes, - ws_ctx->cbuf, BUFSIZE, 1); + cout_end = encode_hybi(ws_ctx->cin_buf, bytes, + ws_ctx->cout_buf, BUFSIZE, 1); } else { - cend = encode_hixie(ws_ctx->cbuf_tmp, bytes, - ws_ctx->cbuf, BUFSIZE); + cout_end = encode_hixie(ws_ctx->cin_buf, bytes, + ws_ctx->cout_buf, BUFSIZE); } /* printf("encoded: "); - for (i=0; i< cend; i++) { - printf("%u,", (unsigned char) *(ws_ctx->cbuf+i)); + for (i=0; i< cout_end; i++) { + printf("%u,", (unsigned char) *(ws_ctx->cout_buf+i)); } printf("\n"); */ - if (cend < 0) { + if (cout_end < 0) { handler_emsg("encoding error\n"); break; } @@ -172,25 +175,30 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) { } if (FD_ISSET(client, &rlist)) { - bytes = ws_recv(ws_ctx, ws_ctx->tbuf_tmp, BUFSIZE-1); + bytes = ws_recv(ws_ctx, ws_ctx->tin_buf + tin_end, BUFSIZE-1); if (pipe_error) { break; } if (bytes <= 0) { handler_emsg("client closed connection\n"); break; } + tin_end += bytes; /* printf("before decode: "); for (i=0; i< bytes; i++) { - printf("%u,", (unsigned char) *(ws_ctx->tbuf_tmp+i)); + printf("%u,", (unsigned char) *(ws_ctx->tin_buf+i)); } printf("\n"); */ if (ws_ctx->hybi) { - len = decode_hybi(ws_ctx->tbuf_tmp, bytes, - ws_ctx->tbuf, BUFSIZE-1, &opcode); + len = decode_hybi(ws_ctx->tin_buf + tin_start, + tin_end-tin_start, + ws_ctx->tout_buf, BUFSIZE-1, + &opcode, &left); } else { - len = decode_hixie(ws_ctx->tbuf_tmp, bytes, - ws_ctx->tbuf, BUFSIZE-1, &opcode); + len = decode_hixie(ws_ctx->tin_buf + tin_start, + tin_end-tin_start, + ws_ctx->tout_buf, BUFSIZE-1, + &opcode, &left); } if (opcode == 8) { @@ -201,7 +209,7 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) { /* printf("decoded: "); for (i=0; i< len; i++) { - printf("%u,", (unsigned char) *(ws_ctx->tbuf+i)); + printf("%u,", (unsigned char) *(ws_ctx->tout_buf+i)); } printf("\n"); */ @@ -209,9 +217,17 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) { handler_emsg("decoding error\n"); break; } + if (left) { + tin_start = tin_end - left; + //printf("partial frame from client"); + } else { + tin_start = 0; + tin_end = 0; + } + traffic("}"); - tstart = 0; - tend = len; + tout_start = 0; + tout_end = len; } } }