iodine 0.4.8 → 0.4.10

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +26 -0
  4. data/README.md +18 -12
  5. data/SPEC-Websocket-Draft.md +9 -5
  6. data/bin/ws-echo +3 -0
  7. data/examples/config.ru +0 -1
  8. data/examples/echo.ru +3 -1
  9. data/examples/redis.ru +0 -1
  10. data/ext/iodine/base64.c +97 -105
  11. data/ext/iodine/defer.c +16 -1
  12. data/ext/iodine/defer.h +10 -0
  13. data/ext/iodine/evio.c +35 -13
  14. data/ext/iodine/extconf.rb +1 -1
  15. data/ext/iodine/facil.c +12 -1
  16. data/ext/iodine/facil.h +3 -1
  17. data/ext/iodine/fio2resp.c +71 -0
  18. data/ext/iodine/fio2resp.h +50 -0
  19. data/ext/iodine/fio_cli_helper.c +404 -0
  20. data/ext/iodine/fio_cli_helper.h +152 -0
  21. data/ext/iodine/fiobj.h +631 -0
  22. data/ext/iodine/fiobj_alloc.c +81 -0
  23. data/ext/iodine/fiobj_ary.c +290 -0
  24. data/ext/iodine/fiobj_generic.c +260 -0
  25. data/ext/iodine/fiobj_hash.c +447 -0
  26. data/ext/iodine/fiobj_io.c +58 -0
  27. data/ext/iodine/fiobj_json.c +779 -0
  28. data/ext/iodine/fiobj_misc.c +213 -0
  29. data/ext/iodine/fiobj_numbers.c +113 -0
  30. data/ext/iodine/fiobj_primitives.c +98 -0
  31. data/ext/iodine/fiobj_str.c +261 -0
  32. data/ext/iodine/fiobj_sym.c +213 -0
  33. data/ext/iodine/fiobj_tests.c +474 -0
  34. data/ext/iodine/fiobj_types.h +290 -0
  35. data/ext/iodine/http1.c +54 -36
  36. data/ext/iodine/http1_parser.c +143 -35
  37. data/ext/iodine/http1_parser.h +6 -3
  38. data/ext/iodine/http1_response.c +0 -1
  39. data/ext/iodine/http_response.c +1 -1
  40. data/ext/iodine/iodine.c +20 -4
  41. data/ext/iodine/iodine_protocol.c +5 -4
  42. data/ext/iodine/iodine_pubsub.c +1 -1
  43. data/ext/iodine/random.c +5 -5
  44. data/ext/iodine/sha1.c +5 -8
  45. data/ext/iodine/sha2.c +8 -11
  46. data/ext/iodine/sha2.h +3 -3
  47. data/ext/iodine/sock.c +29 -31
  48. data/ext/iodine/websocket_parser.h +428 -0
  49. data/ext/iodine/websockets.c +112 -377
  50. data/ext/iodine/xor-crypt.c +16 -12
  51. data/lib/iodine/version.rb +1 -1
  52. metadata +21 -3
  53. data/ext/iodine/empty.h +0 -26
@@ -7,6 +7,7 @@ Feel free to copy, use and enjoy according to the license provided.
7
7
  #include "spnlock.inc"
8
8
 
9
9
  #include "fio_list.h"
10
+ #include "fiobj.h"
10
11
 
11
12
  #include "bscrypt.h"
12
13
  #include "pubsub.h"
@@ -18,6 +19,8 @@ Feel free to copy, use and enjoy according to the license provided.
18
19
  #include <string.h>
19
20
  #include <strings.h>
20
21
 
22
+ #include "websocket_parser.h"
23
+
21
24
  #if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
22
25
  #include <endian.h>
23
26
  #if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) && \
@@ -61,7 +64,7 @@ the code probably wouldn't offer a high performance boost.
61
64
  struct buffer_s create_ws_buffer(ws_s *owner) {
62
65
  (void)(owner);
63
66
  struct buffer_s buff;
64
- buff.size = round_up_buffer_size(WS_INITIAL_BUFFER_SIZE);
67
+ buff.size = WS_INITIAL_BUFFER_SIZE;
65
68
  buff.data = malloc(buff.size);
66
69
  return buff;
67
70
  }
@@ -111,40 +114,16 @@ struct Websocket {
111
114
  size_t max_msg_size;
112
115
  /** active pub/sub subscriptions */
113
116
  fio_list_s subscriptions;
114
- /** message buffer. */
117
+ /** socket buffer. */
115
118
  struct buffer_s buffer;
116
- /** message length (how much of the buffer actually used). */
119
+ /** data length (how much of the buffer actually used). */
117
120
  size_t length;
118
- /** parser. */
119
- struct {
120
- union {
121
- unsigned len1 : 16;
122
- unsigned long long len2 : 64;
123
- char bytes[8];
124
- } psize;
125
- size_t length;
126
- size_t received;
127
- char mask[4];
128
- struct {
129
- unsigned op_code : 4;
130
- unsigned rsv3 : 1;
131
- unsigned rsv2 : 1;
132
- unsigned rsv1 : 1;
133
- unsigned fin : 1;
134
- } head, head2;
135
- struct {
136
- unsigned size : 7;
137
- unsigned masked : 1;
138
- } sdata;
139
- struct {
140
- unsigned has_mask : 1;
141
- unsigned at_mask : 2;
142
- unsigned has_len : 1;
143
- unsigned at_len : 3;
144
- unsigned has_head : 1;
145
- } state;
146
- unsigned client : 1;
147
- } parser;
121
+ /** message buffer. */
122
+ fiobj_s *msg;
123
+ /** latest text state. */
124
+ uint8_t is_text;
125
+ /** websocket connection type. */
126
+ uint8_t is_client;
148
127
  };
149
128
 
150
129
  /**
@@ -152,15 +131,6 @@ The Websocket Protocol Identifying String. Used for the `each` function.
152
131
  */
153
132
  char *WEBSOCKET_ID_STR = "websockets";
154
133
 
155
- /**
156
- A thread localized buffer used for reading and parsing data from the socket.
157
- */
158
- #define WEBSOCKET_READ_MAX 4096
159
- static __thread struct {
160
- int pos;
161
- char buffer[WEBSOCKET_READ_MAX];
162
- } read_buffer;
163
-
164
134
  /* *****************************************************************************
165
135
  Create/Destroy the websocket subscription objects
166
136
  ***************************************************************************** */
@@ -190,6 +160,52 @@ static inline void clear_subscriptions(ws_s *ws) {
190
160
  }
191
161
  }
192
162
 
163
+ /* *****************************************************************************
164
+ Callbacks - Required functions for websocket_parser.h
165
+ ***************************************************************************** */
166
+
167
+ static void websocket_on_unwrapped(void *udata, void *msg, uint64_t len,
168
+ char first, char last, char text,
169
+ unsigned char rsv) {
170
+ ws_s *ws = udata;
171
+ if (last && first) {
172
+ ws->on_message(ws, msg, len, (uint8_t)text);
173
+ return;
174
+ }
175
+ if (first) {
176
+ ws->is_text = (uint8_t)text;
177
+ if (ws->msg == NULL)
178
+ ws->msg = fiobj_str_buf(len);
179
+ fiobj_str_resize(ws->msg, 0);
180
+ }
181
+ fiobj_str_write(ws->msg, msg, len);
182
+ if (last) {
183
+ fio_cstr_s s = fiobj_obj2cstr(ws->msg);
184
+ ws->on_message(ws, (char *)s.data, s.len, ws->is_text);
185
+ }
186
+
187
+ (void)rsv;
188
+ }
189
+ static void websocket_on_protocol_ping(void *udata, void *msg_, uint64_t len) {
190
+ ws_s *ws = udata;
191
+ uint16_t *msg = msg_;
192
+ msg[-1] = *((uint16_t *)"\x89\x00");
193
+ sock_write2(.uuid = ws->fd, .buffer = (void *)(msg - 1), .length = 2 + len);
194
+ }
195
+ static void websocket_on_protocol_pong(void *udata, void *msg, uint64_t len) {
196
+ (void)len;
197
+ (void)msg;
198
+ (void)udata;
199
+ }
200
+ static void websocket_on_protocol_close(void *udata) {
201
+ ws_s *ws = udata;
202
+ sock_close(ws->fd);
203
+ }
204
+ static void websocket_on_protocol_error(void *udata) {
205
+ ws_s *ws = udata;
206
+ sock_close(ws->fd);
207
+ }
208
+
193
209
  /*******************************************************************************
194
210
  The Websocket Protocol implementation
195
211
  */
@@ -225,247 +241,45 @@ static void on_shutdown(intptr_t fd, protocol_s *ws) {
225
241
  ((ws_s *)ws)->on_shutdown((ws_s *)ws);
226
242
  }
227
243
 
228
- /* later */
229
- static void websocket_write_impl(intptr_t fd, void *data, size_t len, char text,
230
- char first, char last, char client);
231
- static size_t websocket_encode(void *buff, void *data, size_t len, char text,
232
- char first, char last, char client);
244
+ /************** new implementation */
233
245
 
234
- /* read data from the socket, parse it and invoke the websocket events. */
235
- static void on_data(intptr_t sockfd, protocol_s *_ws) {
236
- #define ws ((ws_s *)_ws)
246
+ static void on_data(intptr_t sockfd, protocol_s *ws_) {
247
+ ws_s *const ws = (ws_s *)ws_;
237
248
  if (ws == NULL || ws->protocol.service != WEBSOCKET_ID_STR)
238
249
  return;
239
- ssize_t len = 0;
240
- ssize_t data_len = 0;
241
- read_buffer.pos = 0;
242
-
243
- if ((len = sock_read(sockfd, read_buffer.buffer, WEBSOCKET_READ_MAX)) <= 0)
250
+ struct websocket_packet_info_s info =
251
+ websocket_buffer_peek(ws->buffer.data, ws->length);
252
+ const uint64_t raw_length = info.packet_length + info.head_length;
253
+ /* test expected data amount */
254
+ if (ws->max_msg_size < raw_length) {
255
+ /* too big */
256
+ websocket_close(ws);
244
257
  return;
245
-
246
- while (read_buffer.pos < len) {
247
- // collect the frame's head
248
- if (!ws->parser.state.has_head) {
249
- ws->parser.state.has_head = 1;
250
- *((char *)(&(ws->parser.head))) = read_buffer.buffer[read_buffer.pos];
251
- // save a copy if it's the first head in a fragmented message
252
- if (!(*(char *)(&ws->parser.head2))) {
253
- ws->parser.head2 = ws->parser.head;
254
- }
255
- // advance
256
- read_buffer.pos++;
257
- // go back to the `while` head, to review if there's more data
258
- continue;
259
- }
260
-
261
- // save the mask and size information
262
- if (!ws->parser.state.at_len && !ws->parser.state.has_len) {
263
- // uint8_t tmp = ws->parser.sdata.masked;
264
- *((char *)(&(ws->parser.sdata))) = read_buffer.buffer[read_buffer.pos];
265
- // ws->parser.sdata.masked |= tmp;
266
- // set length
267
- ws->parser.state.at_len =
268
- (ws->parser.sdata.size == 127 ? 7
269
- : ws->parser.sdata.size == 126 ? 1 : 0);
270
- if (!ws->parser.state.at_len) {
271
- ws->parser.length = ws->parser.sdata.size;
272
- ws->parser.state.has_len = 1;
273
- }
274
- read_buffer.pos++;
275
- continue;
276
- }
277
-
278
- // check that if we need to collect the length data
279
- if (!ws->parser.state.has_len) {
280
- // avoiding a loop so we don't mixup the meaning of "continue" and
281
- // "break"
282
- collect_len:
283
- ////////// NOTICE: Network Byte Order requires us to translate the data
284
- #ifdef __BIG_ENDIAN__
285
- if ((ws->parser.state.at_len == 1 && ws->parser.sdata.size == 126) ||
286
- (ws->parser.state.at_len == 7 && ws->parser.sdata.size == 127)) {
287
- ws->parser.psize.bytes[ws->parser.state.at_len] =
288
- read_buffer.buffer[read_buffer.pos++];
289
- ws->parser.state.has_len = 1;
290
- ws->parser.length = (ws->parser.sdata.size == 126)
291
- ? ws->parser.psize.len1
292
- : ws->parser.psize.len2;
293
- } else {
294
- ws->parser.psize.bytes[ws->parser.state.at_len++] =
295
- read_buffer.buffer[read_buffer.pos++];
296
- if (read_buffer.pos < len)
297
- goto collect_len;
298
- }
299
- #else
300
- if (ws->parser.state.at_len == 0) {
301
- ws->parser.psize.bytes[ws->parser.state.at_len] =
302
- read_buffer.buffer[read_buffer.pos++];
303
- ws->parser.state.has_len = 1;
304
- ws->parser.length = (ws->parser.sdata.size == 126)
305
- ? ws->parser.psize.len1
306
- : ws->parser.psize.len2;
307
- } else {
308
- ws->parser.psize.bytes[ws->parser.state.at_len--] =
309
- read_buffer.buffer[read_buffer.pos++];
310
- if (read_buffer.pos < len)
311
- goto collect_len;
312
- }
313
- #endif
314
- // check message size limit
315
- if (ws->max_msg_size <
316
- ws->length + (ws->parser.length - ws->parser.received)) {
317
- // close connection!
318
- fprintf(stderr, "ERROR Websocket: Payload too big, review limits.\n");
319
- sock_close(sockfd);
320
- return;
321
- }
322
- continue;
323
- }
324
-
325
- // check that the data is masked and that we didn't colleced the mask yet
326
- if (ws->parser.sdata.masked && !(ws->parser.state.has_mask)) {
327
- // avoiding a loop so we don't mixup the meaning of "continue" and "break"
328
- collect_mask:
329
- if (ws->parser.state.at_mask == 3) {
330
- ws->parser.mask[ws->parser.state.at_mask] =
331
- read_buffer.buffer[read_buffer.pos++];
332
- ws->parser.state.has_mask = 1;
333
- ws->parser.state.at_mask = 0;
334
- } else {
335
- ws->parser.mask[ws->parser.state.at_mask++] =
336
- read_buffer.buffer[read_buffer.pos++];
337
- if (read_buffer.pos < len)
338
- goto collect_mask;
339
- else
340
- continue;
341
- }
342
- // since it's possible that there's no more data (0 length frame),
343
- // we don't use `continue` (check while loop) and we process what we
344
- // have.
345
- }
346
-
347
- // Now that we know everything about the frame, let's collect the data
348
-
349
- // How much data in the buffer is part of the frame?
350
- data_len = len - read_buffer.pos;
351
- if (data_len + ws->parser.received > ws->parser.length)
352
- data_len = ws->parser.length - ws->parser.received;
353
-
354
- // a note about unmasking: since ws->parser.state.at_mask is only 2 bits,
355
- // it will wrap around (i.e. 3++ == 0), so no modulus is required :-)
356
- // unmask:
357
- if (ws->parser.sdata.masked) {
358
- for (int i = 0; i < data_len; i++) {
359
- read_buffer.buffer[i + read_buffer.pos] ^=
360
- ws->parser.mask[ws->parser.state.at_mask++];
361
- }
362
- } else if (ws->parser.client == 0) {
363
- // enforce masking unless acting as client, also for security reasons...
364
- fprintf(stderr, "ERROR Websockets: unmasked frame, disconnecting.\n");
365
- sock_close(sockfd);
366
- return;
367
- }
368
- // Copy the data to the Websocket buffer - only if it's a user message
369
- if (data_len &&
370
- (ws->parser.head.op_code == 1 || ws->parser.head.op_code == 2 ||
371
- (!ws->parser.head.op_code &&
372
- (ws->parser.head2.op_code == 1 || ws->parser.head2.op_code == 2)))) {
373
- // review and resize the buffer's capacity - it can only grow.
374
- if (ws->length + ws->parser.length - ws->parser.received >
375
- ws->buffer.size) {
376
- ws->buffer = resize_ws_buffer(ws, ws->buffer);
377
- if (!ws->buffer.data) {
378
- // no memory.
379
- websocket_close(ws);
380
- return;
381
- }
382
- }
383
- // copy here
384
- memcpy((uint8_t *)ws->buffer.data + ws->length,
385
- read_buffer.buffer + read_buffer.pos, data_len);
386
- ws->length += data_len;
387
- }
388
- // set the frame's data received so far (copied or not)
389
- ws->parser.received += data_len;
390
-
391
- // check that we have collected the whole of the frame.
392
- if (ws->parser.length > ws->parser.received) {
393
- read_buffer.pos += data_len;
394
- // fprintf(stderr, "%p websocket has %lu out of %lu\n", (void *)ws,
395
- // ws->parser.received, ws->parser.length);
396
- continue;
397
- }
398
-
399
- // we have the whole frame, time to process the data.
400
- // pings, pongs and other non-user messages are handled independently.
401
- if (ws->parser.head.op_code == 0 || ws->parser.head.op_code == 1 ||
402
- ws->parser.head.op_code == 2) {
403
- /* a user data frame - make sure we got the `fin` flag, or an error
404
- * occured */
405
- if (!ws->parser.head.fin) {
406
- /* This frame was a partial message. */
407
- goto reset_state;
408
- }
409
- /* This was the last frame */
410
- if (ws->on_message) /* call the on_message callback */
411
- ws->on_message(ws, ws->buffer.data, ws->length,
412
- ws->parser.head2.op_code == 1);
413
- goto reset_parser;
414
- } else if (ws->parser.head.op_code == 8) {
415
- /* op-code == close */
258
+ }
259
+ /* test buffer capacity */
260
+ if (raw_length >= ws->buffer.size) {
261
+ ws->buffer.size = (size_t)raw_length;
262
+ ws->buffer = resize_ws_buffer(ws, ws->buffer);
263
+ if (!ws->buffer.data) {
264
+ // no memory.
416
265
  websocket_close(ws);
417
- if (ws->parser.head2.op_code == ws->parser.head.op_code)
418
- goto reset_parser;
419
- } else if (ws->parser.head.op_code == 9) {
420
- /* ping */
421
- // write Pong - including ping data...
422
- websocket_write_impl(sockfd, read_buffer.buffer + read_buffer.pos,
423
- data_len, 10, 1, 1, ws->parser.client);
424
- if (ws->parser.head2.op_code == ws->parser.head.op_code)
425
- goto reset_parser;
426
- } else if (ws->parser.head.op_code == 10) {
427
- /* pong */
428
- // do nothing... almost
429
- if (ws->parser.head2.op_code == ws->parser.head.op_code)
430
- goto reset_parser;
431
- } else if (ws->parser.head.op_code > 2 && ws->parser.head.op_code < 8) {
432
- /* future control frames. ignore. */
433
- if (ws->parser.head2.op_code == ws->parser.head.op_code)
434
- goto reset_parser;
435
- } else {
436
- /* WTF? */
437
- // fprintf(stderr, "%p websocket reached a WTF?! state..."
438
- // "op1: %i , op2: %i\n",
439
- // (void *)ws, ws->parser.head.op_code,
440
- // ws->parser.head2.op_code);
441
- fprintf(stderr, "ERROR Websockets: protocol error, disconnecting.\n");
442
- sock_close(sockfd);
443
266
  return;
444
267
  }
268
+ }
445
269
 
446
- reset_parser:
447
- ws->length = 0;
448
- // clear the parser's multi-frame state
449
- *((char *)(&(ws->parser.head2))) = 0;
450
- ws->parser.sdata.masked = 0;
451
- reset_state:
452
- // move the pos marker along - in case we have more then one frame in the
453
- // buffer
454
- read_buffer.pos += data_len;
455
- // reset parser state
456
- ws->parser.state.has_len = 0;
457
- ws->parser.state.at_len = 0;
458
- ws->parser.state.has_mask = 0;
459
- ws->parser.state.at_mask = 0;
460
- ws->parser.state.has_head = 0;
461
- ws->parser.sdata.size = 0;
462
- *((char *)(&(ws->parser.head))) = 0;
463
- ws->parser.received = ws->parser.length = ws->parser.psize.len2 = data_len =
464
- 0;
270
+ ssize_t len = sock_read(sockfd, (uint8_t *)ws->buffer.data + ws->length,
271
+ ws->buffer.size - ws->length);
272
+ if (len <= 0) {
273
+ return;
465
274
  }
275
+ ws->length += len;
276
+ ws->length = websocket_consume(ws->buffer.data, ws->length, ws, 1);
277
+
466
278
  facil_force_event(sockfd, FIO_EVENT_ON_DATA);
467
- #undef ws
468
279
  }
280
+ /* later */
281
+ static void websocket_write_impl(intptr_t fd, void *data, size_t len, char text,
282
+ char first, char last, char client);
469
283
 
470
284
  /*******************************************************************************
471
285
  Create/Destroy the websocket object
@@ -482,6 +296,7 @@ static ws_s *new_websocket() {
482
296
  .protocol.on_ready = on_ready,
483
297
  .protocol.on_shutdown = on_shutdown,
484
298
  .subscriptions = FIO_LIST_INIT_STATIC(ws->subscriptions),
299
+ .is_client = 0,
485
300
  };
486
301
  return ws;
487
302
  }
@@ -489,6 +304,8 @@ static void destroy_ws(ws_s *ws) {
489
304
  clear_subscriptions(ws);
490
305
  if (ws->on_close)
491
306
  ws->on_close(ws);
307
+ if (ws->msg)
308
+ fiobj_free(ws->msg);
492
309
  free_ws_buffer(ws, ws->buffer);
493
310
  free(ws);
494
311
  }
@@ -526,115 +343,27 @@ Writing to the Websocket
526
343
  (((i)&0xFF0000ULL) << 24) | (((i)&0xFF000000ULL) << 8) | \
527
344
  (((i)&0xFF00000000ULL) >> 8) | (((i)&0xFF0000000000ULL) >> 24) | \
528
345
  (((i)&0xFF000000000000ULL) >> 40) | (((i)&0xFF00000000000000ULL) >> 56))
529
-
530
346
  #endif
531
347
 
532
- static void websocket_mask(void *dest, void *data, size_t len) {
533
- /* a semi-random 4 byte mask */
534
- uint32_t mask = ((rand() << 7) ^ ((uintptr_t)dest >> 13));
535
- /* place mask at head of data */
536
- dest = (uint8_t *)dest + 4;
537
- memcpy(dest, &mask, 4);
538
- /* TODO: optimize this */
539
- for (size_t i = 0; i < len; i++) {
540
- ((uint8_t *)dest)[i] = ((uint8_t *)data)[i] ^ ((uint8_t *)(&mask))[i & 3];
541
- }
542
- }
543
- static size_t websocket_encode(void *buff, void *data, size_t len, char text,
544
- char first, char last, char client) {
545
- if (len < 126) {
546
- struct {
547
- unsigned op_code : 4;
548
- unsigned rsv3 : 1;
549
- unsigned rsv2 : 1;
550
- unsigned rsv1 : 1;
551
- unsigned fin : 1;
552
- unsigned size : 7;
553
- unsigned masked : 1;
554
- } head = {.op_code = (first ? (!text ? 2 : text) : 0),
555
- .fin = last,
556
- .size = len,
557
- .masked = client};
558
- memcpy(buff, &head, 2);
559
- if (client) {
560
- websocket_mask((uint8_t *)buff + 2, data, len);
561
- len += 4;
562
- } else
563
- memcpy((uint8_t *)buff + 2, data, len);
564
- return len + 2;
565
- } else if (len < (1UL << 16)) {
566
- /* head is 4 bytes */
567
- struct {
568
- unsigned op_code : 4;
569
- unsigned rsv3 : 1;
570
- unsigned rsv2 : 1;
571
- unsigned rsv1 : 1;
572
- unsigned fin : 1;
573
- unsigned size : 7;
574
- unsigned masked : 1;
575
- unsigned length : 16;
576
- } head = {.op_code = (first ? (text ? 1 : 2) : 0),
577
- .fin = last,
578
- .size = 126,
579
- .masked = client,
580
- .length = htons(len)};
581
- memcpy(buff, &head, 4);
582
- if (client) {
583
- websocket_mask((uint8_t *)buff + 4, data, len);
584
- len += 4;
585
- } else
586
- memcpy((uint8_t *)buff + 4, data, len);
587
- return len + 4;
588
- }
589
- /* Really Long Message */
590
- struct {
591
- unsigned op_code : 4;
592
- unsigned rsv3 : 1;
593
- unsigned rsv2 : 1;
594
- unsigned rsv1 : 1;
595
- unsigned fin : 1;
596
- unsigned size : 7;
597
- unsigned masked : 1;
598
- } head = {
599
- .op_code = (first ? (text ? 1 : 2) : 0),
600
- .fin = last,
601
- .size = 127,
602
- .masked = client,
603
- };
604
- memcpy(buff, &head, 2);
605
- ((size_t *)((uint8_t *)buff + 2))[0] = bswap64(len);
606
- if (client) {
607
- websocket_mask((uint8_t *)buff + 10, data, len);
608
- len += 4;
609
- } else
610
- memcpy((uint8_t *)buff + 10, data, len);
611
- return len + 10;
612
- }
613
-
614
348
  static void websocket_write_impl(intptr_t fd, void *data, size_t len,
615
349
  char text, /* TODO: add client masking */
616
350
  char first, char last, char client) {
617
- if (len < 126) {
351
+ if (len < (BUFFER_PACKET_SIZE - 16)) {
618
352
  sock_buffer_s *sbuff = sock_buffer_checkout();
353
+
619
354
  sbuff->len =
620
- websocket_encode(sbuff->buf, data, len, text, first, last, client);
355
+ (client ? websocket_client_wrap(sbuff->buf, data, len, (text ? 1 : 2),
356
+ first, last, 0)
357
+ : websocket_server_wrap(sbuff->buf, data, len, (text ? 1 : 2),
358
+ first, last, 0));
621
359
  sock_buffer_send(fd, sbuff);
622
- // // was:
623
- // char buff[len + (client ? 6 : 2)];
624
- // len = websocket_encode(buff, data, len, text, first, last, client);
625
- // sock_write(fd, buff, len);
626
360
  } else if (len <= WS_MAX_FRAME_SIZE) {
627
- if (len >= BUFFER_PACKET_SIZE - 8) { // can't feet in sock buffer
628
- /* head MUST be 4 bytes */
629
- void *buff = malloc(len + 4);
630
- len = websocket_encode(buff, data, len, text, first, last, client);
631
- sock_write2(.uuid = fd, .buffer = buff, .length = len, .move = 1);
632
- } else {
633
- sock_buffer_s *sbuff = sock_buffer_checkout();
634
- sbuff->len =
635
- websocket_encode(sbuff->buf, data, len, text, first, last, client);
636
- sock_buffer_send(fd, sbuff);
637
- }
361
+ void *buff = malloc(len + 16);
362
+ len = (client ? websocket_client_wrap(buff, data, len, (text ? 1 : 2),
363
+ first, last, 0)
364
+ : websocket_server_wrap(buff, data, len, (text ? 1 : 2),
365
+ first, last, 0));
366
+ sock_write2(.uuid = fd, .buffer = buff, .length = len, .move = 1);
638
367
  } else {
639
368
  /* frame fragmentation is better for large data then large frames */
640
369
  while (len > WS_MAX_FRAME_SIZE) {
@@ -989,6 +718,8 @@ cleanup:
989
718
  // call the on_open callback
990
719
  if (settings.on_open) {
991
720
  defer(deferred_on_open, (void *)settings.on_open, ws);
721
+ } else {
722
+ facil_protocol_unlock(&ws->protocol, FIO_PR_LOCK_TASK);
992
723
  }
993
724
  return 0;
994
725
  }
@@ -1013,7 +744,7 @@ void *websocket_udata_set(ws_s *ws, void *udata) {
1013
744
  /** Writes data to the websocket. Returns -1 on failure (0 on success). */
1014
745
  int websocket_write(ws_s *ws, void *data, size_t size, uint8_t is_text) {
1015
746
  if (sock_isvalid(ws->fd)) {
1016
- websocket_write_impl(ws->fd, data, size, is_text, 1, 1, ws->parser.client);
747
+ websocket_write_impl(ws->fd, data, size, is_text, 1, 1, ws->is_client);
1017
748
  return 0;
1018
749
  }
1019
750
  return -1;
@@ -1135,7 +866,7 @@ static void ws_finish_multi_write(intptr_t fd, void *arg) {
1135
866
 
1136
867
  static void ws_direct_multi_write(intptr_t fd, protocol_s *_ws, void *arg) {
1137
868
  struct websocket_multi_write *multi = arg;
1138
- if (((ws_s *)(_ws))->parser.client != multi->as_client)
869
+ if (((ws_s *)(_ws))->is_client != multi->as_client)
1139
870
  return;
1140
871
  spn_lock(&multi->lock);
1141
872
  multi->count += 1;
@@ -1146,7 +877,7 @@ static void ws_direct_multi_write(intptr_t fd, protocol_s *_ws, void *arg) {
1146
877
 
1147
878
  static void ws_check_multi_write(intptr_t fd, protocol_s *_ws, void *arg) {
1148
879
  struct websocket_multi_write *multi = arg;
1149
- if (((ws_s *)(_ws))->parser.client != multi->as_client)
880
+ if (((ws_s *)(_ws))->is_client != multi->as_client)
1150
881
  return;
1151
882
  if (multi->if_callback((void *)_ws, multi->arg))
1152
883
  ws_direct_multi_write(fd, _ws, arg);
@@ -1164,8 +895,12 @@ int websocket_write_each(struct websocket_write_each_args_s args) {
1164
895
  return -1;
1165
896
  }
1166
897
  *multi = (struct websocket_multi_write){
1167
- .length = websocket_encode(multi->buffer, args.data, args.length,
1168
- args.is_text, 1, 1, args.as_client),
898
+ .length =
899
+ (args.as_client
900
+ ? websocket_client_wrap(multi->buffer, args.data, args.length,
901
+ args.is_text ? 1 : 2, 1, 1, 0)
902
+ : websocket_server_wrap(multi->buffer, args.data, args.length,
903
+ args.is_text ? 1 : 2, 1, 1, 0)),
1169
904
  .if_callback = args.filter,
1170
905
  .on_finished = args.on_finished,
1171
906
  .arg = args.arg,