1/*
2 * Wslay - The WebSocket Library
3 *
4 * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25#include "wslay_event.h"
26
27#include <string.h>
28#include <assert.h>
29#include <stdio.h>
30
31#include "wslay_frame.h"
32#include "wslay_net.h"
33#include "wslay_macro.h"
34/* Start of utf8 dfa */
35/* Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
36 * See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
37 *
38 * Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
39 *
40 * Permission is hereby granted, free of charge, to any person
41 * obtaining a copy of this software and associated documentation
42 * files (the "Software"), to deal in the Software without
43 * restriction, including without limitation the rights to use, copy,
44 * modify, merge, publish, distribute, sublicense, and/or sell copies
45 * of the Software, and to permit persons to whom the Software is
46 * furnished to do so, subject to the following conditions:
47 *
48 * The above copyright notice and this permission notice shall be
49 * included in all copies or substantial portions of the Software.
50 *
51 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
52 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
53 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
54 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
55 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
56 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
57 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
58 * SOFTWARE.
59 */
60#define UTF8_ACCEPT 0
61#define UTF8_REJECT 12
62
63/* clang-format off */
64static const uint8_t utf8d[] = {
65 /*
66 * The first part of the table maps bytes to character classes that
67 * to reduce the size of the transition table and create bitmasks.
68 */
69 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
70 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
71 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
72 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
73 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
74 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
75 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
76 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
77
78 /*
79 * The second part is a transition table that maps a combination
80 * of a state of the automaton and a character class to a state.
81 */
82 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
83 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
84 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
85 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
86 12,36,12,12,12,12,12,12,12,12,12,12,
87};
88/* clang-format on */
89
90static uint32_t decode(uint32_t *state, uint32_t *codep, uint32_t byte) {
91 uint32_t type = utf8d[byte];
92
93 *codep = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*codep << 6)
94 : (0xff >> type) & (byte);
95
96 *state = utf8d[256 + *state + type];
97 return *state;
98}
99
100/* End of utf8 dfa */
101
102static ssize_t wslay_event_frame_recv_callback(uint8_t *buf, size_t len,
103 int flags, void *user_data) {
104 struct wslay_event_frame_user_data *e =
105 (struct wslay_event_frame_user_data *)user_data;
106 return e->ctx->callbacks.recv_callback(e->ctx, buf, len, flags, e->user_data);
107}
108
109static ssize_t wslay_event_frame_send_callback(const uint8_t *data, size_t len,
110 int flags, void *user_data) {
111 struct wslay_event_frame_user_data *e =
112 (struct wslay_event_frame_user_data *)user_data;
113 return e->ctx->callbacks.send_callback(e->ctx, data, len, flags,
114 e->user_data);
115}
116
117static int wslay_event_frame_genmask_callback(uint8_t *buf, size_t len,
118 void *user_data) {
119 struct wslay_event_frame_user_data *e =
120 (struct wslay_event_frame_user_data *)user_data;
121 return e->ctx->callbacks.genmask_callback(e->ctx, buf, len, e->user_data);
122}
123
124static int wslay_event_byte_chunk_init(struct wslay_event_byte_chunk **chunk,
125 size_t len) {
126 *chunk = malloc(sizeof(struct wslay_event_byte_chunk) + len);
127 if (*chunk == NULL) {
128 return WSLAY_ERR_NOMEM;
129 }
130 memset(*chunk, 0, sizeof(struct wslay_event_byte_chunk));
131 if (len) {
132 (*chunk)->data = (uint8_t *)(*chunk) + sizeof(**chunk);
133 (*chunk)->data_length = len;
134 }
135 return 0;
136}
137
138static void wslay_event_byte_chunk_free(struct wslay_event_byte_chunk *c) {
139 free(c);
140}
141
142static void wslay_event_byte_chunk_copy(struct wslay_event_byte_chunk *c,
143 size_t off, const uint8_t *data,
144 size_t data_length) {
145 memcpy(c->data + off, data, data_length);
146}
147
148static void wslay_event_imsg_set(struct wslay_event_imsg *m, uint8_t fin,
149 uint8_t rsv, uint8_t opcode) {
150 m->fin = fin;
151 m->rsv = rsv;
152 m->opcode = opcode;
153 m->msg_length = 0;
154}
155
156static void wslay_event_imsg_chunks_free(struct wslay_event_imsg *m) {
157 while (!wslay_queue_empty(&m->chunks)) {
158 struct wslay_event_byte_chunk *chunk = wslay_struct_of(
159 wslay_queue_top(&m->chunks), struct wslay_event_byte_chunk, qe);
160 wslay_queue_pop(&m->chunks);
161 wslay_event_byte_chunk_free(chunk);
162 }
163}
164
165static void wslay_event_imsg_reset(struct wslay_event_imsg *m) {
166 m->opcode = 0xffu;
167 m->utf8state = UTF8_ACCEPT;
168 wslay_event_imsg_chunks_free(m);
169}
170
171static int wslay_event_imsg_append_chunk(struct wslay_event_imsg *m,
172 size_t len) {
173 if (len == 0) {
174 return 0;
175 } else {
176 int r;
177 struct wslay_event_byte_chunk *chunk;
178 if ((r = wslay_event_byte_chunk_init(&chunk, len)) != 0) {
179 return r;
180 }
181 wslay_queue_push(&m->chunks, &chunk->qe);
182 m->msg_length += len;
183 return 0;
184 }
185}
186
187static int wslay_event_omsg_non_fragmented_init(struct wslay_event_omsg **m,
188 uint8_t opcode, uint8_t rsv,
189 const uint8_t *msg,
190 size_t msg_length) {
191 *m = malloc(sizeof(struct wslay_event_omsg) + msg_length);
192 if (!*m) {
193 return WSLAY_ERR_NOMEM;
194 }
195 memset(*m, 0, sizeof(struct wslay_event_omsg));
196 (*m)->fin = 1;
197 (*m)->opcode = opcode;
198 (*m)->rsv = rsv;
199 (*m)->type = WSLAY_NON_FRAGMENTED;
200 if (msg_length) {
201 (*m)->data = (uint8_t *)(*m) + sizeof(**m);
202 memcpy((*m)->data, msg, msg_length);
203 (*m)->data_length = msg_length;
204 }
205 return 0;
206}
207
208static int wslay_event_omsg_fragmented_init(
209 struct wslay_event_omsg **m, uint8_t opcode, uint8_t rsv,
210 const union wslay_event_msg_source source,
211 wslay_event_fragmented_msg_callback read_callback) {
212 *m = calloc(1, sizeof(struct wslay_event_omsg));
213 if (!*m) {
214 return WSLAY_ERR_NOMEM;
215 }
216 (*m)->opcode = opcode;
217 (*m)->rsv = rsv;
218 (*m)->type = WSLAY_FRAGMENTED;
219 (*m)->source = source;
220 (*m)->read_callback = read_callback;
221 return 0;
222}
223
224static void wslay_event_omsg_free(struct wslay_event_omsg *m) { free(m); }
225
226static uint8_t *wslay_event_flatten_queue(struct wslay_queue *queue,
227 size_t len) {
228 if (len == 0) {
229 return NULL;
230 } else {
231 size_t off = 0;
232 uint8_t *buf = malloc(len);
233 if (!buf) {
234 return NULL;
235 }
236 while (!wslay_queue_empty(queue)) {
237 struct wslay_event_byte_chunk *chunk = wslay_struct_of(
238 wslay_queue_top(queue), struct wslay_event_byte_chunk, qe);
239 wslay_queue_pop(queue);
240 memcpy(buf + off, chunk->data, chunk->data_length);
241 off += chunk->data_length;
242 wslay_event_byte_chunk_free(chunk);
243 assert(off <= len);
244 }
245 assert(len == off);
246 return buf;
247 }
248}
249
250static int wslay_event_is_msg_queueable(wslay_event_context_ptr ctx) {
251 return ctx->write_enabled && (ctx->close_status & WSLAY_CLOSE_QUEUED) == 0;
252}
253
254int wslay_event_queue_close(wslay_event_context_ptr ctx, uint16_t status_code,
255 const uint8_t *reason, size_t reason_length) {
256 if (!wslay_event_is_msg_queueable(ctx)) {
257 return WSLAY_ERR_NO_MORE_MSG;
258 } else if (reason_length > 123) {
259 return WSLAY_ERR_INVALID_ARGUMENT;
260 } else {
261 uint8_t msg[128];
262 size_t msg_length;
263 struct wslay_event_msg arg;
264 uint16_t ncode;
265 int r;
266 if (status_code == 0) {
267 msg_length = 0;
268 } else {
269 ncode = htons(status_code);
270 memcpy(msg, &ncode, 2);
271 if (reason_length) {
272 memcpy(msg + 2, reason, reason_length);
273 }
274 msg_length = reason_length + 2;
275 }
276 arg.opcode = WSLAY_CONNECTION_CLOSE;
277 arg.msg = msg;
278 arg.msg_length = msg_length;
279 r = wslay_event_queue_msg(ctx, &arg);
280 if (r == 0) {
281 ctx->close_status |= WSLAY_CLOSE_QUEUED;
282 }
283 return r;
284 }
285}
286
287static int wslay_event_queue_close_wrapper(wslay_event_context_ptr ctx,
288 uint16_t status_code,
289 const uint8_t *reason,
290 size_t reason_length) {
291 int r;
292 ctx->read_enabled = 0;
293 if ((r = wslay_event_queue_close(ctx, status_code, reason, reason_length)) &&
294 r != WSLAY_ERR_NO_MORE_MSG) {
295 return r;
296 }
297 return 0;
298}
299
300static int wslay_event_verify_rsv_bits(wslay_event_context_ptr ctx,
301 uint8_t rsv) {
302 return ((rsv & ~ctx->allowed_rsv_bits) == 0);
303}
304
305int wslay_event_queue_msg(wslay_event_context_ptr ctx,
306 const struct wslay_event_msg *arg) {
307 return wslay_event_queue_msg_ex(ctx, arg, WSLAY_RSV_NONE);
308}
309
310int wslay_event_queue_msg_ex(wslay_event_context_ptr ctx,
311 const struct wslay_event_msg *arg, uint8_t rsv) {
312 int r;
313 struct wslay_event_omsg *omsg;
314 if (!wslay_event_is_msg_queueable(ctx)) {
315 return WSLAY_ERR_NO_MORE_MSG;
316 }
317 /* RSV1 is not allowed for control frames */
318 if ((wslay_is_ctrl_frame(arg->opcode) &&
319 (arg->msg_length > 125 || wslay_get_rsv1(rsv))) ||
320 !wslay_event_verify_rsv_bits(ctx, rsv)) {
321 return WSLAY_ERR_INVALID_ARGUMENT;
322 }
323 if ((r = wslay_event_omsg_non_fragmented_init(
324 &omsg, arg->opcode, rsv, arg->msg, arg->msg_length)) != 0) {
325 return r;
326 }
327 if (wslay_is_ctrl_frame(arg->opcode)) {
328 wslay_queue_push(&ctx->send_ctrl_queue, &omsg->qe);
329 } else {
330 wslay_queue_push(&ctx->send_queue, &omsg->qe);
331 }
332 ++ctx->queued_msg_count;
333 ctx->queued_msg_length += arg->msg_length;
334 return 0;
335}
336
337int wslay_event_queue_fragmented_msg(
338 wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg) {
339 return wslay_event_queue_fragmented_msg_ex(ctx, arg, WSLAY_RSV_NONE);
340}
341
342int wslay_event_queue_fragmented_msg_ex(
343 wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg,
344 uint8_t rsv) {
345 int r;
346 struct wslay_event_omsg *omsg;
347 if (!wslay_event_is_msg_queueable(ctx)) {
348 return WSLAY_ERR_NO_MORE_MSG;
349 }
350 if (wslay_is_ctrl_frame(arg->opcode) ||
351 !wslay_event_verify_rsv_bits(ctx, rsv)) {
352 return WSLAY_ERR_INVALID_ARGUMENT;
353 }
354 if ((r = wslay_event_omsg_fragmented_init(
355 &omsg, arg->opcode, rsv, arg->source, arg->read_callback)) != 0) {
356 return r;
357 }
358 wslay_queue_push(&ctx->send_queue, &omsg->qe);
359 ++ctx->queued_msg_count;
360 return 0;
361}
362
363void wslay_event_config_set_callbacks(
364 wslay_event_context_ptr ctx,
365 const struct wslay_event_callbacks *callbacks) {
366 ctx->callbacks = *callbacks;
367}
368
369static int
370wslay_event_context_init(wslay_event_context_ptr *ctx,
371 const struct wslay_event_callbacks *callbacks,
372 void *user_data) {
373 int i, r;
374 struct wslay_frame_callbacks frame_callbacks = {
375 wslay_event_frame_send_callback, wslay_event_frame_recv_callback,
376 wslay_event_frame_genmask_callback};
377 *ctx = calloc(1, sizeof(struct wslay_event_context));
378 if (!*ctx) {
379 return WSLAY_ERR_NOMEM;
380 }
381 wslay_event_config_set_callbacks(*ctx, callbacks);
382 (*ctx)->user_data = user_data;
383 (*ctx)->frame_user_data.ctx = *ctx;
384 (*ctx)->frame_user_data.user_data = user_data;
385 if ((r = wslay_frame_context_init(&(*ctx)->frame_ctx, &frame_callbacks,
386 &(*ctx)->frame_user_data)) != 0) {
387 wslay_event_context_free(*ctx);
388 return r;
389 }
390 (*ctx)->read_enabled = (*ctx)->write_enabled = 1;
391 wslay_queue_init(&(*ctx)->send_queue);
392 wslay_queue_init(&(*ctx)->send_ctrl_queue);
393 (*ctx)->queued_msg_count = 0;
394 (*ctx)->queued_msg_length = 0;
395 for (i = 0; i < 2; ++i) {
396 wslay_queue_init(&(*ctx)->imsgs[i].chunks);
397 wslay_event_imsg_reset(&(*ctx)->imsgs[i]);
398 }
399 (*ctx)->imsg = &(*ctx)->imsgs[0];
400 (*ctx)->obufmark = (*ctx)->obuflimit = (*ctx)->obuf;
401 (*ctx)->status_code_sent = WSLAY_CODE_ABNORMAL_CLOSURE;
402 (*ctx)->status_code_recv = WSLAY_CODE_ABNORMAL_CLOSURE;
403 (*ctx)->max_recv_msg_length = (1u << 31) - 1;
404 return 0;
405}
406
407int wslay_event_context_server_init(
408 wslay_event_context_ptr *ctx, const struct wslay_event_callbacks *callbacks,
409 void *user_data) {
410 int r;
411 if ((r = wslay_event_context_init(ctx, callbacks, user_data)) != 0) {
412 return r;
413 }
414 (*ctx)->server = 1;
415 return 0;
416}
417
418int wslay_event_context_client_init(
419 wslay_event_context_ptr *ctx, const struct wslay_event_callbacks *callbacks,
420 void *user_data) {
421 int r;
422 if ((r = wslay_event_context_init(ctx, callbacks, user_data)) != 0) {
423 return r;
424 }
425 (*ctx)->server = 0;
426 return 0;
427}
428
429void wslay_event_context_free(wslay_event_context_ptr ctx) {
430 int i;
431 if (!ctx) {
432 return;
433 }
434 for (i = 0; i < 2; ++i) {
435 wslay_event_imsg_chunks_free(&ctx->imsgs[i]);
436 wslay_queue_deinit(&ctx->imsgs[i].chunks);
437 }
438
439 while (!wslay_queue_empty(&ctx->send_queue)) {
440 struct wslay_event_omsg *omsg = wslay_struct_of(
441 wslay_queue_top(&ctx->send_queue), struct wslay_event_omsg, qe);
442 wslay_queue_pop(&ctx->send_queue);
443 wslay_event_omsg_free(omsg);
444 }
445 wslay_queue_deinit(&ctx->send_queue);
446
447 while (!wslay_queue_empty(&ctx->send_ctrl_queue)) {
448 struct wslay_event_omsg *omsg = wslay_struct_of(
449 wslay_queue_top(&ctx->send_ctrl_queue), struct wslay_event_omsg, qe);
450 wslay_queue_pop(&ctx->send_ctrl_queue);
451 wslay_event_omsg_free(omsg);
452 }
453 wslay_queue_deinit(&ctx->send_ctrl_queue);
454
455 wslay_frame_context_free(ctx->frame_ctx);
456 wslay_event_omsg_free(ctx->omsg);
457 free(ctx);
458}
459
460static void wslay_event_call_on_frame_recv_start_callback(
461 wslay_event_context_ptr ctx, const struct wslay_frame_iocb *iocb) {
462 if (ctx->callbacks.on_frame_recv_start_callback) {
463 struct wslay_event_on_frame_recv_start_arg arg;
464 arg.fin = iocb->fin;
465 arg.rsv = iocb->rsv;
466 arg.opcode = iocb->opcode;
467 arg.payload_length = iocb->payload_length;
468 ctx->callbacks.on_frame_recv_start_callback(ctx, &arg, ctx->user_data);
469 }
470}
471
472static void wslay_event_call_on_frame_recv_chunk_callback(
473 wslay_event_context_ptr ctx, const struct wslay_frame_iocb *iocb) {
474 if (ctx->callbacks.on_frame_recv_chunk_callback) {
475 struct wslay_event_on_frame_recv_chunk_arg arg;
476 arg.data = iocb->data;
477 arg.data_length = iocb->data_length;
478 ctx->callbacks.on_frame_recv_chunk_callback(ctx, &arg, ctx->user_data);
479 }
480}
481
482static void
483wslay_event_call_on_frame_recv_end_callback(wslay_event_context_ptr ctx) {
484 if (ctx->callbacks.on_frame_recv_end_callback) {
485 ctx->callbacks.on_frame_recv_end_callback(ctx, ctx->user_data);
486 }
487}
488
489static int wslay_event_is_valid_status_code(uint16_t status_code) {
490 return (1000 <= status_code && status_code <= 1011 && status_code != 1004 &&
491 status_code != 1005 && status_code != 1006) ||
492 (3000 <= status_code && status_code <= 4999);
493}
494
495static int wslay_event_config_get_no_buffering(wslay_event_context_ptr ctx) {
496 return (ctx->config & WSLAY_CONFIG_NO_BUFFERING) > 0;
497}
498
499int wslay_event_recv(wslay_event_context_ptr ctx) {
500 struct wslay_frame_iocb iocb;
501 ssize_t r;
502 while (ctx->read_enabled) {
503 memset(&iocb, 0, sizeof(iocb));
504 r = wslay_frame_recv(ctx->frame_ctx, &iocb);
505 if (r >= 0) {
506 int new_frame = 0;
507 /* RSV1 is not allowed on control and continuation frames */
508 if ((!wslay_event_verify_rsv_bits(ctx, iocb.rsv)) ||
509 (wslay_get_rsv1(iocb.rsv) &&
510 (wslay_is_ctrl_frame(iocb.opcode) ||
511 iocb.opcode == WSLAY_CONTINUATION_FRAME)) ||
512 (ctx->server && !iocb.mask) || (!ctx->server && iocb.mask)) {
513 if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_PROTOCOL_ERROR,
514 NULL, 0)) != 0) {
515 return (int)r;
516 }
517 break;
518 }
519 if (ctx->imsg->opcode == 0xffu) {
520 if (iocb.opcode == WSLAY_TEXT_FRAME ||
521 iocb.opcode == WSLAY_BINARY_FRAME ||
522 iocb.opcode == WSLAY_CONNECTION_CLOSE ||
523 iocb.opcode == WSLAY_PING || iocb.opcode == WSLAY_PONG) {
524 wslay_event_imsg_set(ctx->imsg, iocb.fin, iocb.rsv, iocb.opcode);
525 new_frame = 1;
526 } else {
527 if ((r = wslay_event_queue_close_wrapper(
528 ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
529 return (int)r;
530 }
531 break;
532 }
533 } else if (ctx->ipayloadlen == 0 && ctx->ipayloadoff == 0) {
534 if (iocb.opcode == WSLAY_CONTINUATION_FRAME) {
535 ctx->imsg->fin = iocb.fin;
536 } else if (iocb.opcode == WSLAY_CONNECTION_CLOSE ||
537 iocb.opcode == WSLAY_PING || iocb.opcode == WSLAY_PONG) {
538 ctx->imsg = &ctx->imsgs[1];
539 wslay_event_imsg_set(ctx->imsg, iocb.fin, iocb.rsv, iocb.opcode);
540 } else {
541 if ((r = wslay_event_queue_close_wrapper(
542 ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
543 return (int)r;
544 }
545 break;
546 }
547 new_frame = 1;
548 }
549 if (new_frame) {
550 if (ctx->imsg->msg_length + iocb.payload_length >
551 ctx->max_recv_msg_length) {
552 if ((r = wslay_event_queue_close_wrapper(
553 ctx, WSLAY_CODE_MESSAGE_TOO_BIG, NULL, 0)) != 0) {
554 return (int)r;
555 }
556 break;
557 }
558 ctx->ipayloadlen = iocb.payload_length;
559 wslay_event_call_on_frame_recv_start_callback(ctx, &iocb);
560 if (!wslay_event_config_get_no_buffering(ctx) ||
561 wslay_is_ctrl_frame(iocb.opcode)) {
562 if ((r = wslay_event_imsg_append_chunk(ctx->imsg,
563 iocb.payload_length)) != 0) {
564 ctx->read_enabled = 0;
565 return (int)r;
566 }
567 }
568 }
569 /* If RSV1 bit is set then it is too early for utf-8 validation */
570 if ((!wslay_get_rsv1(ctx->imsg->rsv) &&
571 ctx->imsg->opcode == WSLAY_TEXT_FRAME) ||
572 ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
573 size_t i;
574 if (ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
575 i = 2;
576 } else {
577 i = 0;
578 }
579 for (; i < iocb.data_length; ++i) {
580 uint32_t codep;
581 if (decode(&ctx->imsg->utf8state, &codep, iocb.data[i]) ==
582 UTF8_REJECT) {
583 if ((r = wslay_event_queue_close_wrapper(
584 ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) !=
585 0) {
586 return (int)r;
587 }
588 break;
589 }
590 }
591 }
592 if (ctx->imsg->utf8state == UTF8_REJECT) {
593 break;
594 }
595 wslay_event_call_on_frame_recv_chunk_callback(ctx, &iocb);
596 if (iocb.data_length > 0) {
597 if (!wslay_event_config_get_no_buffering(ctx) ||
598 wslay_is_ctrl_frame(iocb.opcode)) {
599 struct wslay_event_byte_chunk *chunk;
600 chunk = wslay_struct_of(wslay_queue_tail(&ctx->imsg->chunks),
601 struct wslay_event_byte_chunk, qe);
602 wslay_event_byte_chunk_copy(chunk, ctx->ipayloadoff, iocb.data,
603 iocb.data_length);
604 }
605 ctx->ipayloadoff += iocb.data_length;
606 }
607 if (ctx->ipayloadoff == ctx->ipayloadlen) {
608 if (ctx->imsg->fin &&
609 (ctx->imsg->opcode == WSLAY_TEXT_FRAME ||
610 ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) &&
611 ctx->imsg->utf8state != UTF8_ACCEPT) {
612 if ((r = wslay_event_queue_close_wrapper(
613 ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) != 0) {
614 return (int)r;
615 }
616 break;
617 }
618 wslay_event_call_on_frame_recv_end_callback(ctx);
619 if (ctx->imsg->fin) {
620 if (ctx->callbacks.on_msg_recv_callback ||
621 ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE ||
622 ctx->imsg->opcode == WSLAY_PING) {
623 struct wslay_event_on_msg_recv_arg arg;
624 uint16_t status_code = 0;
625 uint8_t *msg = NULL;
626 size_t msg_length = 0;
627 if (!wslay_event_config_get_no_buffering(ctx) ||
628 wslay_is_ctrl_frame(iocb.opcode)) {
629 msg = wslay_event_flatten_queue(&ctx->imsg->chunks,
630 ctx->imsg->msg_length);
631 if (ctx->imsg->msg_length && !msg) {
632 ctx->read_enabled = 0;
633 return WSLAY_ERR_NOMEM;
634 }
635 msg_length = ctx->imsg->msg_length;
636 }
637 if (ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
638 const uint8_t *reason;
639 size_t reason_length;
640 if (ctx->imsg->msg_length >= 2) {
641 memcpy(&status_code, msg, 2);
642 status_code = ntohs(status_code);
643 if (!wslay_event_is_valid_status_code(status_code)) {
644 free(msg);
645 if ((r = wslay_event_queue_close_wrapper(
646 ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
647 return (int)r;
648 }
649 break;
650 }
651 reason = msg + 2;
652 reason_length = ctx->imsg->msg_length - 2;
653 } else {
654 reason = NULL;
655 reason_length = 0;
656 }
657 ctx->close_status |= WSLAY_CLOSE_RECEIVED;
658 ctx->status_code_recv =
659 status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code;
660 if ((r = wslay_event_queue_close_wrapper(ctx, status_code, reason,
661 reason_length)) != 0) {
662 free(msg);
663 return (int)r;
664 }
665 } else if (ctx->imsg->opcode == WSLAY_PING) {
666 struct wslay_event_msg pong_arg;
667 pong_arg.opcode = WSLAY_PONG;
668 pong_arg.msg = msg;
669 pong_arg.msg_length = ctx->imsg->msg_length;
670 if ((r = wslay_event_queue_msg(ctx, &pong_arg)) &&
671 r != WSLAY_ERR_NO_MORE_MSG) {
672 ctx->read_enabled = 0;
673 free(msg);
674 return (int)r;
675 }
676 }
677 if (ctx->callbacks.on_msg_recv_callback) {
678 arg.rsv = ctx->imsg->rsv;
679 arg.opcode = ctx->imsg->opcode;
680 arg.msg = msg;
681 arg.msg_length = msg_length;
682 arg.status_code = status_code;
683 ctx->error = 0;
684 ctx->callbacks.on_msg_recv_callback(ctx, &arg, ctx->user_data);
685 }
686 free(msg);
687 }
688 wslay_event_imsg_reset(ctx->imsg);
689 if (ctx->imsg == &ctx->imsgs[1]) {
690 ctx->imsg = &ctx->imsgs[0];
691 }
692 }
693 ctx->ipayloadlen = ctx->ipayloadoff = 0;
694 }
695 } else {
696 if (r != WSLAY_ERR_WANT_READ ||
697 (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
698 if ((r = wslay_event_queue_close_wrapper(ctx, 0, NULL, 0)) != 0) {
699 return (int)r;
700 }
701 return WSLAY_ERR_CALLBACK_FAILURE;
702 }
703 break;
704 }
705 }
706 return 0;
707}
708
709static void
710wslay_event_on_non_fragmented_msg_popped(wslay_event_context_ptr ctx) {
711 ctx->omsg->fin = 1;
712 ctx->opayloadlen = ctx->omsg->data_length;
713 ctx->opayloadoff = 0;
714}
715
716static struct wslay_event_omsg *
717wslay_event_send_ctrl_queue_pop(wslay_event_context_ptr ctx) {
718 /*
719 * If Close control frame is queued, we don't send any control frame
720 * other than Close.
721 */
722 if (ctx->close_status & WSLAY_CLOSE_QUEUED) {
723 while (!wslay_queue_empty(&ctx->send_ctrl_queue)) {
724 struct wslay_event_omsg *msg = wslay_struct_of(
725 wslay_queue_top(&ctx->send_ctrl_queue), struct wslay_event_omsg, qe);
726 wslay_queue_pop(&ctx->send_ctrl_queue);
727 if (msg->opcode == WSLAY_CONNECTION_CLOSE) {
728 return msg;
729 } else {
730 wslay_event_omsg_free(msg);
731 }
732 }
733 return NULL;
734 } else {
735 struct wslay_event_omsg *msg = wslay_struct_of(
736 wslay_queue_top(&ctx->send_ctrl_queue), struct wslay_event_omsg, qe);
737 wslay_queue_pop(&ctx->send_ctrl_queue);
738 return msg;
739 }
740}
741
742int wslay_event_send(wslay_event_context_ptr ctx) {
743 struct wslay_frame_iocb iocb;
744 ssize_t r;
745 while (ctx->write_enabled &&
746 (!wslay_queue_empty(&ctx->send_queue) ||
747 !wslay_queue_empty(&ctx->send_ctrl_queue) || ctx->omsg)) {
748 if (!ctx->omsg) {
749 if (wslay_queue_empty(&ctx->send_ctrl_queue)) {
750 ctx->omsg = wslay_struct_of(wslay_queue_top(&ctx->send_queue),
751 struct wslay_event_omsg, qe);
752 wslay_queue_pop(&ctx->send_queue);
753 } else {
754 ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
755 if (ctx->omsg == NULL) {
756 break;
757 }
758 }
759 if (ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
760 wslay_event_on_non_fragmented_msg_popped(ctx);
761 }
762 } else if (!wslay_is_ctrl_frame(ctx->omsg->opcode) &&
763 ctx->frame_ctx->ostate == PREP_HEADER &&
764 !wslay_queue_empty(&ctx->send_ctrl_queue)) {
765 wslay_queue_push_front(&ctx->send_queue, &ctx->omsg->qe);
766 ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
767 if (ctx->omsg == NULL) {
768 break;
769 }
770 /* ctrl message has WSLAY_NON_FRAGMENTED */
771 wslay_event_on_non_fragmented_msg_popped(ctx);
772 }
773 if (ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
774 memset(&iocb, 0, sizeof(iocb));
775 iocb.fin = 1;
776 iocb.opcode = ctx->omsg->opcode;
777 iocb.rsv = ctx->omsg->rsv;
778 iocb.mask = ctx->server ^ 1;
779 iocb.data = ctx->omsg->data;
780 iocb.data_length = ctx->opayloadlen;
781 if (ctx->opayloadoff) {
782 iocb.data += ctx->opayloadoff;
783 iocb.data_length -= ctx->opayloadoff;
784 }
785 iocb.payload_length = ctx->opayloadlen;
786 r = wslay_frame_send(ctx->frame_ctx, &iocb);
787 if (r >= 0) {
788 ctx->opayloadoff += (uint64_t)r;
789 if (ctx->opayloadoff == ctx->opayloadlen) {
790 --ctx->queued_msg_count;
791 ctx->queued_msg_length -= ctx->omsg->data_length;
792 if (ctx->omsg->opcode == WSLAY_CONNECTION_CLOSE) {
793 uint16_t status_code = 0;
794 ctx->write_enabled = 0;
795 ctx->close_status |= WSLAY_CLOSE_SENT;
796 if (ctx->omsg->data_length >= 2) {
797 memcpy(&status_code, ctx->omsg->data, 2);
798 status_code = ntohs(status_code);
799 }
800 ctx->status_code_sent =
801 status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code;
802 }
803 wslay_event_omsg_free(ctx->omsg);
804 ctx->omsg = NULL;
805 } else {
806 break;
807 }
808 } else {
809 if (r != WSLAY_ERR_WANT_WRITE ||
810 (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
811 ctx->write_enabled = 0;
812 return WSLAY_ERR_CALLBACK_FAILURE;
813 }
814 break;
815 }
816 } else {
817 if (ctx->omsg->fin == 0 && ctx->obuflimit == ctx->obufmark) {
818 int eof = 0;
819 r = ctx->omsg->read_callback(ctx, ctx->obuf, sizeof(ctx->obuf),
820 &ctx->omsg->source, &eof, ctx->user_data);
821 if (r == 0 && eof == 0) {
822 break;
823 } else if (r < 0) {
824 ctx->write_enabled = 0;
825 return WSLAY_ERR_CALLBACK_FAILURE;
826 }
827 ctx->obuflimit = ctx->obuf + r;
828 if (eof) {
829 ctx->omsg->fin = 1;
830 }
831 ctx->opayloadlen = (uint64_t)r;
832 ctx->opayloadoff = 0;
833 }
834 memset(&iocb, 0, sizeof(iocb));
835 iocb.fin = ctx->omsg->fin;
836 iocb.opcode = ctx->omsg->opcode;
837 iocb.rsv = ctx->omsg->rsv;
838 iocb.mask = ctx->server ? 0 : 1;
839 iocb.data = ctx->obufmark;
840 iocb.data_length = (size_t)(ctx->obuflimit - ctx->obufmark);
841 iocb.payload_length = ctx->opayloadlen;
842 r = wslay_frame_send(ctx->frame_ctx, &iocb);
843 if (r >= 0) {
844 ctx->obufmark += r;
845 if (ctx->obufmark == ctx->obuflimit) {
846 ctx->obufmark = ctx->obuflimit = ctx->obuf;
847 if (ctx->omsg->fin) {
848 --ctx->queued_msg_count;
849 wslay_event_omsg_free(ctx->omsg);
850 ctx->omsg = NULL;
851 } else {
852 ctx->omsg->opcode = WSLAY_CONTINUATION_FRAME;
853 /* RSV1 is not set on continuation frames */
854 ctx->omsg->rsv = (uint8_t)(ctx->omsg->rsv & ~WSLAY_RSV1_BIT);
855 }
856 } else {
857 break;
858 }
859 } else {
860 if (r != WSLAY_ERR_WANT_WRITE ||
861 (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
862 ctx->write_enabled = 0;
863 return WSLAY_ERR_CALLBACK_FAILURE;
864 }
865 break;
866 }
867 }
868 }
869 return 0;
870}
871
872ssize_t wslay_event_write(wslay_event_context_ptr ctx, uint8_t *buf,
873 size_t buflen) {
874 struct wslay_frame_iocb iocb;
875 ssize_t r;
876 uint8_t *buf_last = buf;
877 size_t wpayloadlen;
878 while (ctx->write_enabled &&
879 (!wslay_queue_empty(&ctx->send_queue) ||
880 !wslay_queue_empty(&ctx->send_ctrl_queue) || ctx->omsg)) {
881 if (!ctx->omsg) {
882 if (wslay_queue_empty(&ctx->send_ctrl_queue)) {
883 ctx->omsg = wslay_struct_of(wslay_queue_top(&ctx->send_queue),
884 struct wslay_event_omsg, qe);
885 wslay_queue_pop(&ctx->send_queue);
886 } else {
887 ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
888 if (ctx->omsg == NULL) {
889 break;
890 }
891 }
892 if (ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
893 wslay_event_on_non_fragmented_msg_popped(ctx);
894 }
895 } else if (!wslay_is_ctrl_frame(ctx->omsg->opcode) &&
896 ctx->frame_ctx->ostate == PREP_HEADER &&
897 !wslay_queue_empty(&ctx->send_ctrl_queue)) {
898 wslay_queue_push_front(&ctx->send_queue, &ctx->omsg->qe);
899 ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
900 if (ctx->omsg == NULL) {
901 break;
902 }
903 /* ctrl message has WSLAY_NON_FRAGMENTED */
904 wslay_event_on_non_fragmented_msg_popped(ctx);
905 }
906 if (ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
907 memset(&iocb, 0, sizeof(iocb));
908 iocb.fin = 1;
909 iocb.opcode = ctx->omsg->opcode;
910 iocb.rsv = ctx->omsg->rsv;
911 iocb.mask = ctx->server ^ 1;
912 iocb.data = ctx->omsg->data;
913 iocb.data_length = ctx->opayloadlen;
914 if (ctx->opayloadoff) {
915 iocb.data += ctx->opayloadoff;
916 iocb.data_length -= ctx->opayloadoff;
917 }
918 iocb.payload_length = ctx->opayloadlen;
919 r = wslay_frame_write(ctx->frame_ctx, &iocb, buf_last, buflen,
920 &wpayloadlen);
921 if (r > 0) {
922 assert((size_t)r <= buflen);
923
924 buf_last += r;
925 buflen -= (size_t)r;
926
927 ctx->opayloadoff += wpayloadlen;
928 if (ctx->opayloadoff == ctx->opayloadlen) {
929 --ctx->queued_msg_count;
930 ctx->queued_msg_length -= ctx->omsg->data_length;
931 if (ctx->omsg->opcode == WSLAY_CONNECTION_CLOSE) {
932 uint16_t status_code = 0;
933 ctx->write_enabled = 0;
934 ctx->close_status |= WSLAY_CLOSE_SENT;
935 if (ctx->omsg->data_length >= 2) {
936 memcpy(&status_code, ctx->omsg->data, 2);
937 status_code = ntohs(status_code);
938 }
939 ctx->status_code_sent =
940 status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code;
941 }
942 wslay_event_omsg_free(ctx->omsg);
943 ctx->omsg = NULL;
944 } else {
945 break;
946 }
947 } else if (r == 0) {
948 return buf_last - buf;
949 } else {
950 return WSLAY_ERR_CALLBACK_FAILURE;
951 }
952 } else {
953 if (ctx->omsg->fin == 0 && ctx->obuflimit == ctx->obufmark) {
954 int eof = 0;
955 r = ctx->omsg->read_callback(ctx, ctx->obuf, sizeof(ctx->obuf),
956 &ctx->omsg->source, &eof, ctx->user_data);
957 if (r == 0 && eof == 0) {
958 break;
959 } else if (r < 0) {
960 ctx->write_enabled = 0;
961 return WSLAY_ERR_CALLBACK_FAILURE;
962 }
963 ctx->obuflimit = ctx->obuf + r;
964 if (eof) {
965 ctx->omsg->fin = 1;
966 }
967 ctx->opayloadlen = (uint64_t)r;
968 ctx->opayloadoff = 0;
969 }
970 memset(&iocb, 0, sizeof(iocb));
971 iocb.fin = ctx->omsg->fin;
972 iocb.opcode = ctx->omsg->opcode;
973 iocb.rsv = ctx->omsg->rsv;
974 iocb.mask = ctx->server ? 0 : 1;
975 iocb.data = ctx->obufmark;
976 iocb.data_length = (size_t)(ctx->obuflimit - ctx->obufmark);
977 iocb.payload_length = ctx->opayloadlen;
978 r = wslay_frame_write(ctx->frame_ctx, &iocb, buf_last, buflen,
979 &wpayloadlen);
980 if (r > 0) {
981 assert((size_t)r <= buflen);
982
983 buf_last += r;
984 buflen -= (size_t)r;
985
986 ctx->obufmark += wpayloadlen;
987 if (ctx->obufmark == ctx->obuflimit) {
988 ctx->obufmark = ctx->obuflimit = ctx->obuf;
989 if (ctx->omsg->fin) {
990 --ctx->queued_msg_count;
991 wslay_event_omsg_free(ctx->omsg);
992 ctx->omsg = NULL;
993 } else {
994 ctx->omsg->opcode = WSLAY_CONTINUATION_FRAME;
995 /* RSV1 is not set on continuation frames */
996 ctx->omsg->rsv = (uint8_t)(ctx->omsg->rsv & ~WSLAY_RSV1_BIT);
997 }
998 } else {
999 break;
1000 }
1001 } else if (r == 0) {
1002 return buf_last - buf;
1003 } else {
1004 return WSLAY_ERR_CALLBACK_FAILURE;
1005 }
1006 }
1007 }
1008 return buf_last - buf;
1009}
1010
1011void wslay_event_set_error(wslay_event_context_ptr ctx, int val) {
1012 ctx->error = val;
1013}
1014
1015int wslay_event_want_read(wslay_event_context_ptr ctx) {
1016 return ctx->read_enabled;
1017}
1018
1019int wslay_event_want_write(wslay_event_context_ptr ctx) {
1020 return ctx->write_enabled &&
1021 (!wslay_queue_empty(&ctx->send_queue) ||
1022 !wslay_queue_empty(&ctx->send_ctrl_queue) || ctx->omsg);
1023}
1024
1025void wslay_event_shutdown_read(wslay_event_context_ptr ctx) {
1026 ctx->read_enabled = 0;
1027}
1028
1029void wslay_event_shutdown_write(wslay_event_context_ptr ctx) {
1030 ctx->write_enabled = 0;
1031}
1032
1033int wslay_event_get_read_enabled(wslay_event_context_ptr ctx) {
1034 return ctx->read_enabled;
1035}
1036
1037int wslay_event_get_write_enabled(wslay_event_context_ptr ctx) {
1038 return ctx->write_enabled;
1039}
1040
1041int wslay_event_get_close_received(wslay_event_context_ptr ctx) {
1042 return (ctx->close_status & WSLAY_CLOSE_RECEIVED) > 0;
1043}
1044
1045int wslay_event_get_close_sent(wslay_event_context_ptr ctx) {
1046 return (ctx->close_status & WSLAY_CLOSE_SENT) > 0;
1047}
1048
1049void wslay_event_config_set_allowed_rsv_bits(wslay_event_context_ptr ctx,
1050 uint8_t rsv) {
1051 /* We currently only allow WSLAY_RSV1_BIT or WSLAY_RSV_NONE */
1052 ctx->allowed_rsv_bits = rsv & WSLAY_RSV1_BIT;
1053}
1054
1055void wslay_event_config_set_no_buffering(wslay_event_context_ptr ctx, int val) {
1056 if (val) {
1057 ctx->config |= WSLAY_CONFIG_NO_BUFFERING;
1058 } else {
1059 ctx->config &= (uint32_t)~WSLAY_CONFIG_NO_BUFFERING;
1060 }
1061}
1062
1063void wslay_event_config_set_max_recv_msg_length(wslay_event_context_ptr ctx,
1064 uint64_t val) {
1065 ctx->max_recv_msg_length = val;
1066}
1067
1068uint16_t wslay_event_get_status_code_received(wslay_event_context_ptr ctx) {
1069 return ctx->status_code_recv;
1070}
1071
1072uint16_t wslay_event_get_status_code_sent(wslay_event_context_ptr ctx) {
1073 return ctx->status_code_sent;
1074}
1075
1076size_t wslay_event_get_queued_msg_count(wslay_event_context_ptr ctx) {
1077 return ctx->queued_msg_count;
1078}
1079
1080size_t wslay_event_get_queued_msg_length(wslay_event_context_ptr ctx) {
1081 return ctx->queued_msg_length;
1082}
1083