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 */ |
64 | static 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 | |
90 | static 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 | |
102 | static 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 | |
109 | static 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 | |
117 | static 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 | |
124 | static 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 | |
138 | static void wslay_event_byte_chunk_free(struct wslay_event_byte_chunk *c) { |
139 | free(c); |
140 | } |
141 | |
142 | static 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 | |
148 | static 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 | |
156 | static 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 | |
165 | static 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 | |
171 | static 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 | |
187 | static 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 | |
208 | static 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 | |
224 | static void wslay_event_omsg_free(struct wslay_event_omsg *m) { free(m); } |
225 | |
226 | static 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 | |
250 | static 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 | |
254 | int 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 | |
287 | static 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 | |
300 | static 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 | |
305 | int 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 | |
310 | int 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 | |
337 | int 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 | |
342 | int 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 | |
363 | void wslay_event_config_set_callbacks( |
364 | wslay_event_context_ptr ctx, |
365 | const struct wslay_event_callbacks *callbacks) { |
366 | ctx->callbacks = *callbacks; |
367 | } |
368 | |
369 | static int |
370 | wslay_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 | |
407 | int 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 | |
418 | int 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 | |
429 | void 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 | |
460 | static 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 | |
472 | static 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 | |
482 | static void |
483 | wslay_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 | |
489 | static 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 | |
495 | static int wslay_event_config_get_no_buffering(wslay_event_context_ptr ctx) { |
496 | return (ctx->config & WSLAY_CONFIG_NO_BUFFERING) > 0; |
497 | } |
498 | |
499 | int 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 | |
709 | static void |
710 | wslay_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 | |
716 | static struct wslay_event_omsg * |
717 | wslay_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 | |
742 | int 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 | |
872 | ssize_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 | |
1011 | void wslay_event_set_error(wslay_event_context_ptr ctx, int val) { |
1012 | ctx->error = val; |
1013 | } |
1014 | |
1015 | int wslay_event_want_read(wslay_event_context_ptr ctx) { |
1016 | return ctx->read_enabled; |
1017 | } |
1018 | |
1019 | int 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 | |
1025 | void wslay_event_shutdown_read(wslay_event_context_ptr ctx) { |
1026 | ctx->read_enabled = 0; |
1027 | } |
1028 | |
1029 | void wslay_event_shutdown_write(wslay_event_context_ptr ctx) { |
1030 | ctx->write_enabled = 0; |
1031 | } |
1032 | |
1033 | int wslay_event_get_read_enabled(wslay_event_context_ptr ctx) { |
1034 | return ctx->read_enabled; |
1035 | } |
1036 | |
1037 | int wslay_event_get_write_enabled(wslay_event_context_ptr ctx) { |
1038 | return ctx->write_enabled; |
1039 | } |
1040 | |
1041 | int wslay_event_get_close_received(wslay_event_context_ptr ctx) { |
1042 | return (ctx->close_status & WSLAY_CLOSE_RECEIVED) > 0; |
1043 | } |
1044 | |
1045 | int wslay_event_get_close_sent(wslay_event_context_ptr ctx) { |
1046 | return (ctx->close_status & WSLAY_CLOSE_SENT) > 0; |
1047 | } |
1048 | |
1049 | void 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 | |
1055 | void 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 | |
1063 | void 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 | |
1068 | uint16_t wslay_event_get_status_code_received(wslay_event_context_ptr ctx) { |
1069 | return ctx->status_code_recv; |
1070 | } |
1071 | |
1072 | uint16_t wslay_event_get_status_code_sent(wslay_event_context_ptr ctx) { |
1073 | return ctx->status_code_sent; |
1074 | } |
1075 | |
1076 | size_t wslay_event_get_queued_msg_count(wslay_event_context_ptr ctx) { |
1077 | return ctx->queued_msg_count; |
1078 | } |
1079 | |
1080 | size_t wslay_event_get_queued_msg_length(wslay_event_context_ptr ctx) { |
1081 | return ctx->queued_msg_length; |
1082 | } |
1083 | |