wsockd: implement reading of small and large frames (but not huge frames)

This commit is contained in:
William Pitcock 2016-04-02 23:56:18 -05:00
parent 53c0462146
commit d3f01ce7bf

View file

@ -521,6 +521,124 @@ cleanup_bad_message(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb)
rb_close(ctlb->F[i]); rb_close(ctlb->F[i]);
} }
static void
ws_frame_unmask(char *msg, int length, uint8_t maskval[WEBSOCKET_MASK_LENGTH])
{
int i;
for (i = 0; i < length; i++)
msg[i] = msg[i] ^ maskval[i % 4];
}
static void
conn_mod_process_frame(conn_t *conn, ws_frame_hdr_t *hdr, int masked)
{
char msg[WEBSOCKET_MAX_UNEXTENDED_PAYLOAD_DATA_LENGTH];
uint8_t maskval[WEBSOCKET_MASK_LENGTH];
int dolen;
/* if we're masked, we get to collect the masking key for this frame */
if (masked)
{
dolen = rb_rawbuf_get(conn->modbuf_in, maskval, sizeof(maskval));
if (!dolen)
{
close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking unmask key");
return;
}
}
dolen = rb_rawbuf_get(conn->modbuf_in, msg, hdr->payload_length_mask);
if (!dolen)
{
close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking message");
return;
}
if (masked)
ws_frame_unmask(msg, dolen, maskval);
rb_linebuf_parse(&conn->plainbuf_out, msg, dolen, 1);
}
static void
conn_mod_process_large(conn_t *conn, ws_frame_hdr_t *hdr, int masked)
{
char msg[READBUF_SIZE];
uint16_t msglen;
uint8_t maskval[WEBSOCKET_MASK_LENGTH];
int dolen;
memset(msg, 0, sizeof msg);
dolen = rb_rawbuf_get(conn->modbuf_in, &msglen, sizeof(msglen));
if (!dolen)
{
close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking message size");
return;
}
msglen = ntohs(msglen);
if (masked)
{
dolen = rb_rawbuf_get(conn->modbuf_in, maskval, sizeof(maskval));
if (!dolen)
{
close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking unmask key");
return;
}
}
dolen = rb_rawbuf_get(conn->modbuf_in, msg, msglen);
if (!dolen)
{
close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking message");
return;
}
if (masked)
ws_frame_unmask(msg, dolen, maskval);
rb_linebuf_parse(&conn->plainbuf_out, msg, dolen, 1);
}
static void
conn_mod_process_huge(conn_t *conn, ws_frame_hdr_t *hdr, int masked)
{
/* XXX implement me */
}
static void
conn_mod_process(conn_t *conn)
{
ws_frame_hdr_t hdr;
while (1)
{
int masked;
int dolen = rb_rawbuf_get(conn->modbuf_in, &hdr, sizeof(hdr));
if (dolen != sizeof(hdr))
break;
masked = (hdr.payload_length_mask >> 7) == 1;
hdr.payload_length_mask &= 0x7f;
switch (hdr.payload_length_mask)
{
case 126:
conn_mod_process_large(conn, &hdr, masked);
break;
case 127:
conn_mod_process_huge(conn, &hdr, masked);
break;
default:
conn_mod_process_frame(conn, &hdr, masked);
break;
}
}
}
static void static void
conn_mod_handshake_process(conn_t *conn) conn_mod_handshake_process(conn_t *conn)
{ {
@ -625,6 +743,8 @@ conn_mod_read_cb(rb_fde_t *fd, void *data)
rb_rawbuf_append(conn->modbuf_in, inbuf, length); rb_rawbuf_append(conn->modbuf_in, inbuf, length);
if (!IsKeyed(conn)) if (!IsKeyed(conn))
conn_mod_handshake_process(conn); conn_mod_handshake_process(conn);
else
conn_mod_process(conn);
if (length < sizeof(inbuf)) if (length < sizeof(inbuf))
{ {