Add the ability to handle the binary protocol

This commit is contained in:
Jeremy White 2012-05-11 07:56:30 -05:00
parent 63600bf422
commit 4909486139
3 changed files with 79 additions and 45 deletions

View File

@ -268,33 +268,43 @@ int decode_hixie(char *src, size_t srclength,
int encode_hybi(u_char const *src, size_t srclength,
char *target, size_t targsize, unsigned int opcode)
{
unsigned long long b64_sz, len_offset = 1, payload_offset = 2, len = 0;
unsigned long long pay_sz, len_offset = 1, payload_offset = 2, len = 0;
if ((int)srclength <= 0)
{
return 0;
}
b64_sz = ((srclength - 1) / 3) * 4 + 4;
if (opcode == 1)
pay_sz = ((srclength - 1) / 3) * 4 + 4;
if (opcode == 2)
pay_sz = srclength;
target[0] = (char)(opcode & 0x0F | 0x80);
if (b64_sz <= 125) {
target[1] = (char) b64_sz;
if (pay_sz <= 125) {
target[1] = (char) pay_sz;
payload_offset = 2;
} else if ((b64_sz > 125) && (b64_sz < 65536)) {
} else if ((pay_sz > 125) && (pay_sz < 65536)) {
target[1] = (char) 126;
*(u_short*)&(target[2]) = htons(b64_sz);
*(u_short*)&(target[2]) = htons(pay_sz);
payload_offset = 4;
} else {
handler_emsg("Sending frames larger than 65535 bytes not supported\n");
return -1;
//target[1] = (char) 127;
//*(u_long*)&(target[2]) = htonl(b64_sz);
//*(u_long*)&(target[2]) = htonl(pay_sz);
//payload_offset = 10;
}
len = b64_ntop(src, srclength, target+payload_offset, targsize-payload_offset);
if (opcode == 1) {
len = b64_ntop(src, srclength, target+payload_offset, targsize-payload_offset);
}
if (opcode == 2) {
len = srclength;
memcpy(target + payload_offset, src, len);
}
if (len < 0) {
return len;
@ -316,7 +326,7 @@ int decode_hybi(unsigned char *src, size_t srclength,
*left = srclength;
frame = src;
//printf("Deocde new frame\n");
//printf("Decode new frame\n");
while (1) {
// Need at least two bytes of the header
// Find beginning of next frame. First time hdr_length, masked and
@ -379,9 +389,11 @@ int decode_hybi(unsigned char *src, size_t srclength,
return -1;
}
// Terminate with a null for base64 decode
save_char = payload[payload_length];
payload[payload_length] = '\0';
if (*opcode == 1) {
// Terminate with a null for base64 decode
save_char = payload[payload_length];
payload[payload_length] = '\0';
}
// unmask the data
mask = payload - 4;
@ -389,15 +401,23 @@ int decode_hybi(unsigned char *src, size_t srclength,
payload[i] ^= mask[i%4];
}
// base64 decode the data
len = b64_pton((const char*)payload, target+target_offset, targsize);
if (*opcode == 1) {
// base64 decode the data
len = b64_pton((const char*)payload, target+target_offset, targsize);
// Restore the first character of the next frame
payload[payload_length] = save_char;
if (len < 0) {
handler_emsg("Base64 decode error code %d", len);
return len;
// Restore the first character of the next frame
payload[payload_length] = save_char;
if (len < 0) {
handler_emsg("Base64 decode error code %d", len);
return len;
}
}
if (*opcode == 2) {
len = payload_length;
memcpy(target + target_offset, payload, len);
}
target_offset += len;
//printf(" len %d, raw %s\n", len, frame);
@ -409,6 +429,7 @@ int decode_hybi(unsigned char *src, size_t srclength,
}
*left = remaining;
//printf(" returning %d, %d left\n", target_offset, *left);
return target_offset;
}
@ -481,6 +502,10 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
end = strstr(start, "\r\n");
strncpy(headers->protocols, start, end-start);
headers->protocols[end-start] = '\0';
if (strstr(headers->protocols, "binary"))
ws_ctx->binary = 1;
else
ws_ctx->binary = 0;
} else {
// Hixie 75 or 76
ws_ctx->hybi = 0;

View File

@ -44,6 +44,7 @@ typedef struct {
SSL *ssl;
int hixie;
int hybi;
int binary;
headers_t *headers;
char *cin_buf;
char *cout_buf;

View File

@ -112,6 +112,7 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) {
if (FD_ISSET(target, &wlist)) {
len = tout_end-tout_start;
bytes = send(target, ws_ctx->tout_buf + tout_start, len, 0);
//printf("wrote %d bytes of an intended %d bytes\n", bytes, len);
if (pipe_error) { break; }
if (bytes < 0) {
handler_emsg("target connection error: %s\n",
@ -149,29 +150,42 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) {
bytes = recv(target, ws_ctx->cin_buf, DBUFSIZE , 0);
if (pipe_error) { break; }
if (bytes <= 0) {
unsigned char term_buf[48];
unsigned char term_rc[2] = {0x0,0};
handler_emsg("target closed connection\n");
bytes = encode_hybi(term_rc, 2, term_buf, sizeof(term_buf), 2);
term_buf[0] |= 8;
send(ws_ctx->sockfd, term_buf, bytes, 0);
shutdown(ws_ctx->sockfd, SHUT_WR);
close(target);
close(ws_ctx->sockfd);
break;
}
cout_start = 0;
if (ws_ctx->hybi) {
cout_end = encode_hybi(ws_ctx->cin_buf, bytes,
ws_ctx->cout_buf, BUFSIZE, 1);
} else {
cout_end = encode_hixie(ws_ctx->cin_buf, bytes,
ws_ctx->cout_buf, BUFSIZE);
else {
cout_start = 0;
if (ws_ctx->hybi) {
cout_end = encode_hybi(ws_ctx->cin_buf, bytes,
ws_ctx->cout_buf, BUFSIZE, ws_ctx->binary ? 2 : 1);
} else {
cout_end = encode_hixie(ws_ctx->cin_buf, bytes,
ws_ctx->cout_buf, BUFSIZE);
}
/*
printf("encoded: ");
for (i=0; i< cout_end; i++) {
printf("%u,", (unsigned char) *(ws_ctx->cout_buf+i));
}
printf("\n");
*/
if (cout_end < 0) {
handler_emsg("encoding error\n");
break;
}
traffic("{");
}
/*
printf("encoded: ");
for (i=0; i< cout_end; i++) {
printf("%u,", (unsigned char) *(ws_ctx->cout_buf+i));
}
printf("\n");
*/
if (cout_end < 0) {
handler_emsg("encoding error\n");
break;
}
traffic("{");
}
if (FD_ISSET(client, &rlist)) {
@ -181,6 +195,7 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) {
handler_emsg("client closed connection\n");
break;
}
tin_end += bytes;
/*
printf("before decode: ");
@ -206,13 +221,6 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) {
break;
}
/*
printf("decoded: ");
for (i=0; i< len; i++) {
printf("%u,", (unsigned char) *(ws_ctx->tout_buf+i));
}
printf("\n");
*/
if (len < 0) {
handler_emsg("decoding error\n");
break;