void websock_text(struct websock *ws, const char *text, size_t length)
{
- websock_send(ws, OPCODE_TEXT, NULL, 0);
+ websock_send(ws, OPCODE_TEXT, text, length);
}
void websock_binary(struct websock *ws, const void *data, size_t length)
{
- websock_send(ws, OPCODE_BINARY, NULL, 0);
+ websock_send(ws, OPCODE_BINARY, data, length);
}
static int read_header(struct websock *ws)
return 0;
}
+static int check_control_header(struct websock *ws)
+{
+ /* sanity checks */
+ if (FRAME_GET_RSV1(ws->header[0]) != 0)
+ return 0;
+ if (FRAME_GET_RSV2(ws->header[0]) != 0)
+ return 0;
+ if (FRAME_GET_RSV3(ws->header[0]) != 0)
+ return 0;
+ if (FRAME_GET_OPCODE(ws->header[0]) == OPCODE_CLOSE)
+ return FRAME_GET_PAYLOAD_LEN(ws->header[1]) != 1;
+ if (FRAME_GET_MASK(ws->header[1]))
+ return 0;
+ return FRAME_GET_PAYLOAD_LEN(ws->header[1]) == 0;
+}
+
int websock_dispatch(struct websock *ws)
{
- loop:
+loop:
switch (ws->state) {
case STATE_INIT:
ws->lenhead = 0;
case STATE_START:
/* read the header */
- if (!read_header(ws))
+ if (read_header(ws))
return -1;
else if (ws->lenhead < ws->szhead)
return 0;
- /* sanity checks */
- if (FRAME_GET_RSV1(ws->header[0]) != 0)
- goto protocol_error;
- if (FRAME_GET_RSV2(ws->header[0]) != 0)
- goto protocol_error;
- if (FRAME_GET_RSV3(ws->header[0]) != 0)
- goto protocol_error;
/* fast track */
switch (FRAME_GET_OPCODE(ws->header[0])) {
case OPCODE_CONTINUATION:
case OPCODE_BINARY:
break;
case OPCODE_CLOSE:
- if (FRAME_GET_MASK(ws->header[1]))
- goto protocol_error;
- if (FRAME_GET_PAYLOAD_LEN(ws->header[1]) == 1)
+ if (!check_control_header(ws))
goto protocol_error;
if (FRAME_GET_PAYLOAD_LEN(ws->header[1]))
ws->szhead += 2;
break;
case OPCODE_PING:
- if (FRAME_GET_MASK(ws->header[1]))
- goto protocol_error;
- if (FRAME_GET_PAYLOAD_LEN(ws->header[1]) != 0)
+ if (!check_control_header(ws))
goto protocol_error;
if (ws->itf->on_ping)
ws->itf->on_ping(ws->closure);
ws->state = STATE_INIT;
goto loop;
case OPCODE_PONG:
- if (FRAME_GET_MASK(ws->header[1]))
- goto protocol_error;
- if (FRAME_GET_PAYLOAD_LEN(ws->header[1]) != 0)
+ if (!check_control_header(ws))
goto protocol_error;
if (ws->itf->on_pong)
ws->itf->on_pong(ws->closure);
ws->state = STATE_INIT;
goto loop;
default:
- goto protocol_error;
+ break;
}
/* update heading size */
switch (FRAME_GET_PAYLOAD_LEN(ws->header[1])) {
case STATE_LENGTH:
/* continue to read the header */
- if (!read_header(ws))
+ if (read_header(ws))
return -1;
else if (ws->lenhead < ws->szhead)
return 0;
((unsigned char *)&ws->mask)[3] = ws->header[ws->szhead - 1];
} else
ws->mask = 0;
+
+ /* all heading fields are known, process */
ws->state = STATE_DATA;
+ if (ws->itf->on_extension != NULL) {
+ if (ws->itf->on_extension(ws->closure,
+ FRAME_GET_FIN(ws->header[0]),
+ FRAME_GET_RSV1(ws->header[0]),
+ FRAME_GET_RSV2(ws->header[0]),
+ FRAME_GET_RSV3(ws->header[0]),
+ FRAME_GET_OPCODE(ws->header[0]),
+ (size_t) ws->length)) {
+ return 0;
+ }
+ }
+
+ /* not an extension case */
+ if (FRAME_GET_RSV1(ws->header[0]) != 0)
+ goto protocol_error;
+ if (FRAME_GET_RSV2(ws->header[0]) != 0)
+ goto protocol_error;
+ if (FRAME_GET_RSV3(ws->header[0]) != 0)
+ goto protocol_error;
+
+ /* handle */
switch (FRAME_GET_OPCODE(ws->header[0])) {
case OPCODE_CONTINUATION:
ws->itf->on_continue(ws->closure,
(size_t) ws->length);
else
ws->itf->on_close(ws->closure,
- STATUS_CODE_UNSET, 0);
+ WEBSOCKET_CODE_NOT_SET, 0);
ws->itf->disconnect(ws->closure);
return 0;
+ default:
+ goto protocol_error;
}
break;
goto loop;
too_long_error:
- websock_close_code(ws, STATUS_CODE_MESSAGE_TOO_LARGE);
+ websock_close_code(ws, WEBSOCKET_CODE_MESSAGE_TOO_LARGE);
return 0;
protocol_error:
- websock_close_code(ws, STATUS_CODE_PROTOCOL_ERROR);
+ websock_close_code(ws, WEBSOCKET_CODE_PROTOCOL_ERROR);
return 0;
}
void websock_drop(struct websock *ws)
{
- char buffer[4096];
+ char buffer[8000];
while (ws->length && ws_read(ws, buffer, sizeof buffer) >= 0) ;
}
-struct websock *websock_create(const struct websock_itf *itf, void *closure)
+struct websock *websock_create_v13(const struct websock_itf *itf, void *closure)
{
struct websock *result = calloc(1, sizeof *result);
if (result) {
result->itf = itf;
result->closure = closure;
+ result->maxlength = 65000;
}
return result;
}