iodine 0.4.2 → 0.4.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/ext/iodine/facil.c +18 -0
- data/ext/iodine/facil.h +8 -0
- data/ext/iodine/sock.c +1 -1
- data/ext/iodine/websockets.c +203 -217
- data/lib/iodine/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 56640878e0c4cc4794f8cf3747a398a51847b0ae
|
4
|
+
data.tar.gz: 0c58b292c6002ea03e068eba06f5aa75c449d236
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 193156a5098163d096af9c182ed20b7a6977234575d4fd49a81ba07d1f44dc677f8772bd6c873f79f0466b28037290463d070473eb057e4c522127e0a51d5e8a
|
7
|
+
data.tar.gz: ab58390cfd148cd7fa481cec9f3db47ccbe64188e993e9c34baaaab2b0eaaf51cb65c459d6a9ec0ee1315a0dcf0536d8931b72aae0d1fd2c0dd743216788aab0
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,15 @@ Please notice that this change log contains changes for upcoming releases as wel
|
|
6
6
|
|
7
7
|
## Changes:
|
8
8
|
|
9
|
+
***
|
10
|
+
|
11
|
+
#### Change log v.0.4.3
|
12
|
+
|
13
|
+
This release is a ghost hunt release, attempting to find an issue noticed only during when deploying in the Heroku production environment.
|
14
|
+
|
15
|
+
**Fix**: fixed a possible issue in fragmented pipelined Websocket messages. This
|
16
|
+
|
17
|
+
|
9
18
|
***
|
10
19
|
|
11
20
|
#### Change log v.0.4.2
|
data/ext/iodine/facil.c
CHANGED
@@ -170,6 +170,24 @@ void evio_on_close(void *arg) { sock_force_close((intptr_t)arg); }
|
|
170
170
|
void evio_on_error(void *arg) { sock_force_close((intptr_t)arg); }
|
171
171
|
void evio_on_data(void *arg) { defer(deferred_on_data, arg, NULL); }
|
172
172
|
|
173
|
+
/* *****************************************************************************
|
174
|
+
Forcing IO events
|
175
|
+
***************************************************************************** */
|
176
|
+
|
177
|
+
void facil_force_event(intptr_t uuid, enum facil_io_event ev) {
|
178
|
+
switch (ev) {
|
179
|
+
case FIO_EVENT_ON_DATA:
|
180
|
+
evio_on_data((void *)uuid);
|
181
|
+
break;
|
182
|
+
case FIO_EVENT_ON_TIMEOUT:
|
183
|
+
defer(deferred_ping, (void *)uuid, NULL);
|
184
|
+
break;
|
185
|
+
case FIO_EVENT_ON_READY:
|
186
|
+
evio_on_ready((void *)uuid);
|
187
|
+
break;
|
188
|
+
}
|
189
|
+
}
|
190
|
+
|
173
191
|
/* *****************************************************************************
|
174
192
|
Socket callbacks
|
175
193
|
***************************************************************************** */
|
data/ext/iodine/facil.h
CHANGED
@@ -303,6 +303,14 @@ void facil_set_timeout(intptr_t uuid, uint8_t timeout);
|
|
303
303
|
/** Gets a timeout for a specific connection. Returns 0 if none. */
|
304
304
|
uint8_t facil_get_timeout(intptr_t uuid);
|
305
305
|
|
306
|
+
enum facil_io_event {
|
307
|
+
FIO_EVENT_ON_DATA,
|
308
|
+
FIO_EVENT_ON_READY,
|
309
|
+
FIO_EVENT_ON_TIMEOUT,
|
310
|
+
};
|
311
|
+
/** Schedules an IO event, even id it did not occur. */
|
312
|
+
void facil_force_event(intptr_t uuid, enum facil_io_event);
|
313
|
+
|
306
314
|
/* *****************************************************************************
|
307
315
|
Helper API
|
308
316
|
***************************************************************************** */
|
data/ext/iodine/sock.c
CHANGED
@@ -1041,7 +1041,7 @@ after all the data was sent. This is a "busy" wait, polling isn't performed.
|
|
1041
1041
|
*/
|
1042
1042
|
void sock_flush_strong(intptr_t uuid) {
|
1043
1043
|
errno = 0;
|
1044
|
-
while (sock_flush(uuid) == 0 &&
|
1044
|
+
while (sock_flush(uuid) == 0 && errno == 0)
|
1045
1045
|
;
|
1046
1046
|
}
|
1047
1047
|
/**
|
data/ext/iodine/websockets.c
CHANGED
@@ -246,245 +246,231 @@ static void on_data(intptr_t sockfd, protocol_s *_ws) {
|
|
246
246
|
return;
|
247
247
|
ssize_t len = 0;
|
248
248
|
ssize_t data_len = 0;
|
249
|
-
if (
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
// collect the frame's head
|
262
|
-
if (!ws->parser.state.has_head) {
|
263
|
-
ws->parser.state.has_head = 1;
|
264
|
-
*((char *)(&(ws->parser.head))) = read_buffer.buffer[read_buffer.pos];
|
265
|
-
// save a copy if it's the first head in a fragmented message
|
266
|
-
if (!(*(char *)(&ws->parser.head2))) {
|
267
|
-
ws->parser.head2 = ws->parser.head;
|
268
|
-
}
|
269
|
-
// advance
|
270
|
-
read_buffer.pos++;
|
271
|
-
// go back to the `while` head, to review if there's more data
|
272
|
-
continue;
|
249
|
+
if ((len = sock_read(sockfd, read_buffer.buffer, WEBSOCKET_READ_MAX)) <= 0)
|
250
|
+
return;
|
251
|
+
data_len = 0;
|
252
|
+
read_buffer.pos = 0;
|
253
|
+
while (read_buffer.pos < len) {
|
254
|
+
// collect the frame's head
|
255
|
+
if (!ws->parser.state.has_head) {
|
256
|
+
ws->parser.state.has_head = 1;
|
257
|
+
*((char *)(&(ws->parser.head))) = read_buffer.buffer[read_buffer.pos];
|
258
|
+
// save a copy if it's the first head in a fragmented message
|
259
|
+
if (!(*(char *)(&ws->parser.head2))) {
|
260
|
+
ws->parser.head2 = ws->parser.head;
|
273
261
|
}
|
262
|
+
// advance
|
263
|
+
read_buffer.pos++;
|
264
|
+
// go back to the `while` head, to review if there's more data
|
265
|
+
continue;
|
266
|
+
}
|
274
267
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
}
|
288
|
-
read_buffer.pos++;
|
289
|
-
continue;
|
268
|
+
// save the mask and size information
|
269
|
+
if (!ws->parser.state.at_len && !ws->parser.state.has_len) {
|
270
|
+
// uint8_t tmp = ws->parser.sdata.masked;
|
271
|
+
*((char *)(&(ws->parser.sdata))) = read_buffer.buffer[read_buffer.pos];
|
272
|
+
// ws->parser.sdata.masked |= tmp;
|
273
|
+
// set length
|
274
|
+
ws->parser.state.at_len =
|
275
|
+
(ws->parser.sdata.size == 127 ? 7
|
276
|
+
: ws->parser.sdata.size == 126 ? 1 : 0);
|
277
|
+
if (!ws->parser.state.at_len) {
|
278
|
+
ws->parser.length = ws->parser.sdata.size;
|
279
|
+
ws->parser.state.has_len = 1;
|
290
280
|
}
|
281
|
+
read_buffer.pos++;
|
282
|
+
continue;
|
283
|
+
}
|
291
284
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
285
|
+
// check that if we need to collect the length data
|
286
|
+
if (!ws->parser.state.has_len) {
|
287
|
+
// avoiding a loop so we don't mixup the meaning of "continue" and
|
288
|
+
// "break"
|
289
|
+
collect_len:
|
297
290
|
////////// NOTICE: Network Byte Order requires us to translate the data
|
298
291
|
#ifdef __BIG_ENDIAN__
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
292
|
+
if ((ws->parser.state.at_len == 1 && ws->parser.sdata.size == 126) ||
|
293
|
+
(ws->parser.state.at_len == 7 && ws->parser.sdata.size == 127)) {
|
294
|
+
ws->parser.psize.bytes[ws->parser.state.at_len] =
|
295
|
+
read_buffer.buffer[read_buffer.pos++];
|
296
|
+
ws->parser.state.has_len = 1;
|
297
|
+
ws->parser.length = (ws->parser.sdata.size == 126)
|
298
|
+
? ws->parser.psize.len1
|
299
|
+
: ws->parser.psize.len2;
|
300
|
+
} else {
|
301
|
+
ws->parser.psize.bytes[ws->parser.state.at_len++] =
|
302
|
+
read_buffer.buffer[read_buffer.pos++];
|
303
|
+
if (read_buffer.pos < len)
|
304
|
+
goto collect_len;
|
305
|
+
}
|
313
306
|
#else
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
307
|
+
if (ws->parser.state.at_len == 0) {
|
308
|
+
ws->parser.psize.bytes[ws->parser.state.at_len] =
|
309
|
+
read_buffer.buffer[read_buffer.pos++];
|
310
|
+
ws->parser.state.has_len = 1;
|
311
|
+
ws->parser.length = (ws->parser.sdata.size == 126)
|
312
|
+
? ws->parser.psize.len1
|
313
|
+
: ws->parser.psize.len2;
|
314
|
+
} else {
|
315
|
+
ws->parser.psize.bytes[ws->parser.state.at_len--] =
|
316
|
+
read_buffer.buffer[read_buffer.pos++];
|
317
|
+
if (read_buffer.pos < len)
|
318
|
+
goto collect_len;
|
319
|
+
}
|
327
320
|
#endif
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
}
|
336
|
-
continue;
|
321
|
+
// check message size limit
|
322
|
+
if (ws->max_msg_size <
|
323
|
+
ws->length + (ws->parser.length - ws->parser.received)) {
|
324
|
+
// close connection!
|
325
|
+
fprintf(stderr, "ERROR Websocket: Payload too big, review limits.\n");
|
326
|
+
sock_close(sockfd);
|
327
|
+
return;
|
337
328
|
}
|
329
|
+
continue;
|
330
|
+
}
|
338
331
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
}
|
356
|
-
// since it's possible that there's no more data (0 length frame),
|
357
|
-
// we don't use `continue` (check while loop) and we process what we
|
358
|
-
// have.
|
332
|
+
// check that the data is masked and that we didn't colleced the mask yet
|
333
|
+
if (ws->parser.sdata.masked && !(ws->parser.state.has_mask)) {
|
334
|
+
// avoiding a loop so we don't mixup the meaning of "continue" and "break"
|
335
|
+
collect_mask:
|
336
|
+
if (ws->parser.state.at_mask == 3) {
|
337
|
+
ws->parser.mask[ws->parser.state.at_mask] =
|
338
|
+
read_buffer.buffer[read_buffer.pos++];
|
339
|
+
ws->parser.state.has_mask = 1;
|
340
|
+
ws->parser.state.at_mask = 0;
|
341
|
+
} else {
|
342
|
+
ws->parser.mask[ws->parser.state.at_mask++] =
|
343
|
+
read_buffer.buffer[read_buffer.pos++];
|
344
|
+
if (read_buffer.pos < len)
|
345
|
+
goto collect_mask;
|
346
|
+
else
|
347
|
+
continue;
|
359
348
|
}
|
349
|
+
// since it's possible that there's no more data (0 length frame),
|
350
|
+
// we don't use `continue` (check while loop) and we process what we
|
351
|
+
// have.
|
352
|
+
}
|
360
353
|
|
361
|
-
|
354
|
+
// Now that we know everything about the frame, let's collect the data
|
362
355
|
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
356
|
+
// How much data in the buffer is part of the frame?
|
357
|
+
data_len = len - read_buffer.pos;
|
358
|
+
if (data_len + ws->parser.received > ws->parser.length)
|
359
|
+
data_len = ws->parser.length - ws->parser.received;
|
367
360
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
}
|
376
|
-
} else if (ws->parser.client == 0) {
|
377
|
-
// enforce masking unless acting as client, also for security reasons...
|
378
|
-
fprintf(stderr, "ERROR Websockets: unmasked frame, disconnecting.\n");
|
379
|
-
sock_close(sockfd);
|
380
|
-
return;
|
361
|
+
// a note about unmasking: since ws->parser.state.at_mask is only 2 bits,
|
362
|
+
// it will wrap around (i.e. 3++ == 0), so no modulus is required :-)
|
363
|
+
// unmask:
|
364
|
+
if (ws->parser.sdata.masked) {
|
365
|
+
for (int i = 0; i < data_len; i++) {
|
366
|
+
read_buffer.buffer[i + read_buffer.pos] ^=
|
367
|
+
ws->parser.mask[ws->parser.state.at_mask++];
|
381
368
|
}
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
}
|
402
|
-
// set the frame's data received so far (copied or not)
|
403
|
-
ws->parser.received += data_len;
|
404
|
-
|
405
|
-
// check that we have collected the whole of the frame.
|
406
|
-
if (ws->parser.length > ws->parser.received) {
|
407
|
-
read_buffer.pos += data_len;
|
408
|
-
// fprintf(stderr, "%p websocket has %lu out of %lu\n", (void *)ws,
|
409
|
-
// ws->parser.received, ws->parser.length);
|
410
|
-
continue;
|
411
|
-
}
|
412
|
-
|
413
|
-
// we have the whole frame, time to process the data.
|
414
|
-
// pings, pongs and other non-user messages are handled independently.
|
415
|
-
if (ws->parser.head.op_code == 0 || ws->parser.head.op_code == 1 ||
|
416
|
-
ws->parser.head.op_code == 2) {
|
417
|
-
/* a user data frame - make sure we got the `fin` flag, or an error
|
418
|
-
* occured */
|
419
|
-
if (!ws->parser.head.fin) {
|
420
|
-
/* This frame was a partial message. */
|
421
|
-
goto reset_state;
|
369
|
+
} else if (ws->parser.client == 0) {
|
370
|
+
// enforce masking unless acting as client, also for security reasons...
|
371
|
+
fprintf(stderr, "ERROR Websockets: unmasked frame, disconnecting.\n");
|
372
|
+
sock_close(sockfd);
|
373
|
+
return;
|
374
|
+
}
|
375
|
+
// Copy the data to the Websocket buffer - only if it's a user message
|
376
|
+
if (data_len &&
|
377
|
+
(ws->parser.head.op_code == 1 || ws->parser.head.op_code == 2 ||
|
378
|
+
(!ws->parser.head.op_code &&
|
379
|
+
(ws->parser.head2.op_code == 1 || ws->parser.head2.op_code == 2)))) {
|
380
|
+
// review and resize the buffer's capacity - it can only grow.
|
381
|
+
if (ws->length + ws->parser.length - ws->parser.received >
|
382
|
+
ws->buffer.size) {
|
383
|
+
ws->buffer = resize_ws_buffer(ws, ws->buffer);
|
384
|
+
if (!ws->buffer.data) {
|
385
|
+
// no memory.
|
386
|
+
websocket_close(ws);
|
387
|
+
return;
|
422
388
|
}
|
423
|
-
/* This was the last frame */
|
424
|
-
if (ws->on_message) /* call the on_message callback */
|
425
|
-
ws->on_message(ws, ws->buffer.data, ws->length,
|
426
|
-
ws->parser.head2.op_code == 1);
|
427
|
-
goto reset_parser;
|
428
|
-
} else if (ws->parser.head.op_code == 8) {
|
429
|
-
/* op-code == close */
|
430
|
-
websocket_close(ws);
|
431
|
-
if (ws->parser.head2.op_code == ws->parser.head.op_code)
|
432
|
-
goto reset_parser;
|
433
|
-
} else if (ws->parser.head.op_code == 9) {
|
434
|
-
/* ping */
|
435
|
-
// write Pong - including ping data...
|
436
|
-
websocket_write_impl(sockfd, read_buffer.buffer + read_buffer.pos,
|
437
|
-
data_len, 10, 1, 1, ws->parser.client);
|
438
|
-
if (ws->parser.head2.op_code == ws->parser.head.op_code)
|
439
|
-
goto reset_parser;
|
440
|
-
} else if (ws->parser.head.op_code == 10) {
|
441
|
-
/* pong */
|
442
|
-
// do nothing... almost
|
443
|
-
if (ws->parser.head2.op_code == ws->parser.head.op_code)
|
444
|
-
goto reset_parser;
|
445
|
-
} else if (ws->parser.head.op_code > 2 && ws->parser.head.op_code < 8) {
|
446
|
-
/* future control frames. ignore. */
|
447
|
-
if (ws->parser.head2.op_code == ws->parser.head.op_code)
|
448
|
-
goto reset_parser;
|
449
|
-
} else {
|
450
|
-
/* WTF? */
|
451
|
-
// fprintf(stderr, "%p websocket reached a WTF?! state..."
|
452
|
-
// "op1: %i , op2: %i\n",
|
453
|
-
// (void *)ws, ws->parser.head.op_code,
|
454
|
-
// ws->parser.head2.op_code);
|
455
|
-
fprintf(stderr, "ERROR Websockets: protocol error, disconnecting.\n");
|
456
|
-
sock_close(sockfd);
|
457
|
-
return;
|
458
389
|
}
|
390
|
+
// copy here
|
391
|
+
memcpy((uint8_t *)ws->buffer.data + ws->length,
|
392
|
+
read_buffer.buffer + read_buffer.pos, data_len);
|
393
|
+
ws->length += data_len;
|
394
|
+
}
|
395
|
+
// set the frame's data received so far (copied or not)
|
396
|
+
ws->parser.received += data_len;
|
459
397
|
|
460
|
-
|
461
|
-
|
462
|
-
// clear the parser's multi-frame state
|
463
|
-
*((char *)(&(ws->parser.head2))) = 0;
|
464
|
-
ws->parser.sdata.masked = 0;
|
465
|
-
reset_state:
|
466
|
-
// move the pos marker along - in case we have more then one frame in the
|
467
|
-
// buffer
|
398
|
+
// check that we have collected the whole of the frame.
|
399
|
+
if (ws->parser.length > ws->parser.received) {
|
468
400
|
read_buffer.pos += data_len;
|
469
|
-
//
|
470
|
-
ws->parser.
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
.uuid = sockfd);
|
484
|
-
return;
|
401
|
+
// fprintf(stderr, "%p websocket has %lu out of %lu\n", (void *)ws,
|
402
|
+
// ws->parser.received, ws->parser.length);
|
403
|
+
continue;
|
404
|
+
}
|
405
|
+
|
406
|
+
// we have the whole frame, time to process the data.
|
407
|
+
// pings, pongs and other non-user messages are handled independently.
|
408
|
+
if (ws->parser.head.op_code == 0 || ws->parser.head.op_code == 1 ||
|
409
|
+
ws->parser.head.op_code == 2) {
|
410
|
+
/* a user data frame - make sure we got the `fin` flag, or an error
|
411
|
+
* occured */
|
412
|
+
if (!ws->parser.head.fin) {
|
413
|
+
/* This frame was a partial message. */
|
414
|
+
goto reset_state;
|
485
415
|
}
|
416
|
+
/* This was the last frame */
|
417
|
+
if (ws->on_message) /* call the on_message callback */
|
418
|
+
ws->on_message(ws, ws->buffer.data, ws->length,
|
419
|
+
ws->parser.head2.op_code == 1);
|
420
|
+
goto reset_parser;
|
421
|
+
} else if (ws->parser.head.op_code == 8) {
|
422
|
+
/* op-code == close */
|
423
|
+
websocket_close(ws);
|
424
|
+
if (ws->parser.head2.op_code == ws->parser.head.op_code)
|
425
|
+
goto reset_parser;
|
426
|
+
} else if (ws->parser.head.op_code == 9) {
|
427
|
+
/* ping */
|
428
|
+
// write Pong - including ping data...
|
429
|
+
websocket_write_impl(sockfd, read_buffer.buffer + read_buffer.pos,
|
430
|
+
data_len, 10, 1, 1, ws->parser.client);
|
431
|
+
if (ws->parser.head2.op_code == ws->parser.head.op_code)
|
432
|
+
goto reset_parser;
|
433
|
+
} else if (ws->parser.head.op_code == 10) {
|
434
|
+
/* pong */
|
435
|
+
// do nothing... almost
|
436
|
+
if (ws->parser.head2.op_code == ws->parser.head.op_code)
|
437
|
+
goto reset_parser;
|
438
|
+
} else if (ws->parser.head.op_code > 2 && ws->parser.head.op_code < 8) {
|
439
|
+
/* future control frames. ignore. */
|
440
|
+
if (ws->parser.head2.op_code == ws->parser.head.op_code)
|
441
|
+
goto reset_parser;
|
442
|
+
} else {
|
443
|
+
/* WTF? */
|
444
|
+
// fprintf(stderr, "%p websocket reached a WTF?! state..."
|
445
|
+
// "op1: %i , op2: %i\n",
|
446
|
+
// (void *)ws, ws->parser.head.op_code,
|
447
|
+
// ws->parser.head2.op_code);
|
448
|
+
fprintf(stderr, "ERROR Websockets: protocol error, disconnecting.\n");
|
449
|
+
sock_close(sockfd);
|
450
|
+
return;
|
486
451
|
}
|
452
|
+
|
453
|
+
reset_parser:
|
454
|
+
ws->length = 0;
|
455
|
+
// clear the parser's multi-frame state
|
456
|
+
*((char *)(&(ws->parser.head2))) = 0;
|
457
|
+
ws->parser.sdata.masked = 0;
|
458
|
+
reset_state:
|
459
|
+
// move the pos marker along - in case we have more then one frame in the
|
460
|
+
// buffer
|
461
|
+
read_buffer.pos += data_len;
|
462
|
+
// reset parser state
|
463
|
+
ws->parser.state.has_len = 0;
|
464
|
+
ws->parser.state.at_len = 0;
|
465
|
+
ws->parser.state.has_mask = 0;
|
466
|
+
ws->parser.state.at_mask = 0;
|
467
|
+
ws->parser.state.has_head = 0;
|
468
|
+
ws->parser.sdata.size = 0;
|
469
|
+
*((char *)(&(ws->parser.head))) = 0;
|
470
|
+
ws->parser.received = ws->parser.length = ws->parser.psize.len2 = data_len =
|
471
|
+
0;
|
487
472
|
}
|
473
|
+
facil_force_event(sockfd, FIO_EVENT_ON_DATA);
|
488
474
|
#undef ws
|
489
475
|
}
|
490
476
|
|
data/lib/iodine/version.rb
CHANGED