iodine 0.2.17 → 0.3.0
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 +6 -0
- data/README.md +36 -3
- data/bin/config.ru +23 -2
- data/bin/http-hello +1 -1
- data/bin/ws-shootout +5 -0
- data/ext/iodine/defer.c +468 -0
- data/ext/iodine/defer.h +105 -0
- data/ext/iodine/evio.c +263 -0
- data/ext/iodine/evio.h +133 -0
- data/ext/iodine/extconf.rb +2 -1
- data/ext/iodine/facil.c +958 -0
- data/ext/iodine/facil.h +423 -0
- data/ext/iodine/http.c +90 -0
- data/ext/iodine/http.h +50 -12
- data/ext/iodine/http1.c +200 -267
- data/ext/iodine/http1.h +17 -26
- data/ext/iodine/http1_request.c +81 -0
- data/ext/iodine/http1_request.h +58 -0
- data/ext/iodine/http1_response.c +403 -0
- data/ext/iodine/http1_response.h +90 -0
- data/ext/iodine/http1_simple_parser.c +124 -108
- data/ext/iodine/http1_simple_parser.h +8 -3
- data/ext/iodine/http_request.c +104 -0
- data/ext/iodine/http_request.h +58 -102
- data/ext/iodine/http_response.c +212 -208
- data/ext/iodine/http_response.h +89 -252
- data/ext/iodine/iodine_core.c +57 -46
- data/ext/iodine/iodine_core.h +3 -1
- data/ext/iodine/iodine_http.c +105 -81
- data/ext/iodine/iodine_websocket.c +17 -13
- data/ext/iodine/iodine_websocket.h +1 -0
- data/ext/iodine/rb-call.c +9 -7
- data/ext/iodine/{rb-libasync.h → rb-defer.c} +57 -49
- data/ext/iodine/rb-rack-io.c +12 -6
- data/ext/iodine/rb-rack-io.h +1 -1
- data/ext/iodine/rb-registry.c +5 -2
- data/ext/iodine/sock.c +1159 -0
- data/ext/iodine/{libsock.h → sock.h} +138 -142
- data/ext/iodine/spnlock.inc +77 -0
- data/ext/iodine/websockets.c +101 -112
- data/ext/iodine/websockets.h +38 -19
- data/iodine.gemspec +3 -3
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +6 -6
- metadata +23 -19
- data/ext/iodine/http_response_http1.h +0 -382
- data/ext/iodine/libasync.c +0 -570
- data/ext/iodine/libasync.h +0 -122
- data/ext/iodine/libreact.c +0 -350
- data/ext/iodine/libreact.h +0 -244
- data/ext/iodine/libserver.c +0 -957
- data/ext/iodine/libserver.h +0 -481
- data/ext/iodine/libsock.c +0 -1025
- data/ext/iodine/spnlock.h +0 -243
data/ext/iodine/iodine_core.h
CHANGED
@@ -17,9 +17,11 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
17
17
|
#include <ruby/io.h>
|
18
18
|
// clang-format on
|
19
19
|
|
20
|
-
#include "libserver.h"
|
21
20
|
#include "rb-call.h"
|
22
21
|
#include "rb-registry.h"
|
22
|
+
|
23
|
+
#include "facil.h"
|
24
|
+
|
23
25
|
#include <stdio.h>
|
24
26
|
#include <stdlib.h>
|
25
27
|
#include <string.h>
|
data/ext/iodine/iodine_http.c
CHANGED
@@ -8,6 +8,9 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
8
8
|
#include "iodine_websocket.h"
|
9
9
|
#include "websockets.h"
|
10
10
|
|
11
|
+
#include <arpa/inet.h>
|
12
|
+
#include <sys/socket.h>
|
13
|
+
|
11
14
|
/* the Iodine::Rack HTTP server class*/
|
12
15
|
VALUE IodineHttp;
|
13
16
|
/* these three are used also by rb-rack-io.c */
|
@@ -38,6 +41,8 @@ static _Bool iodine_http_static_file_server = 0;
|
|
38
41
|
|
39
42
|
#define rack_autoset(rack_name) rack_set((rack_name), #rack_name)
|
40
43
|
|
44
|
+
static uint8_t IODINE_IS_DEVELOPMENT_MODE = 0;
|
45
|
+
|
41
46
|
static VALUE ENV_TEMPLATE;
|
42
47
|
|
43
48
|
rack_declare(HTTP_SCHEME);
|
@@ -80,8 +85,9 @@ static inline VALUE copy2env(http_request_s *request) {
|
|
80
85
|
env, REQUEST_METHOD,
|
81
86
|
rb_enc_str_new(request->method, request->method_len, BinaryEncoding));
|
82
87
|
|
83
|
-
rb_hash_aset(
|
84
|
-
|
88
|
+
rb_hash_aset(
|
89
|
+
env, PATH_INFO,
|
90
|
+
rb_enc_str_new(request->path, request->path_len, BinaryEncoding));
|
85
91
|
rb_hash_aset(
|
86
92
|
env, QUERY_STRING,
|
87
93
|
(request->query
|
@@ -98,10 +104,22 @@ static inline VALUE copy2env(http_request_s *request) {
|
|
98
104
|
rb_hash_aset(env, SERVER_PROTOCOL, hname);
|
99
105
|
rb_hash_aset(env, HTTP_VERSION, hname);
|
100
106
|
|
101
|
-
//
|
107
|
+
// Suppoer for Ruby web-console.
|
108
|
+
hname = rb_str_buf_new(64);
|
109
|
+
sock_peer_addr_s addrinfo = sock_peer_addr(request->fd);
|
110
|
+
if (addrinfo.addrlen &&
|
111
|
+
inet_ntop(
|
112
|
+
addrinfo.addr->sa_family,
|
113
|
+
addrinfo.addr->sa_family == AF_INET
|
114
|
+
? (void *)&((struct sockaddr_in *)addrinfo.addr)->sin_addr
|
115
|
+
: (void *)&((struct sockaddr_in6 *)addrinfo.addr)->sin6_addr,
|
116
|
+
RSTRING_PTR(hname), 64)) {
|
117
|
+
rb_str_set_len(hname, strlen(RSTRING_PTR(hname)));
|
118
|
+
rb_hash_aset(env, REMOTE_ADDR, hname);
|
119
|
+
}
|
102
120
|
|
103
121
|
/* setup input IO + hijack support */
|
104
|
-
rb_hash_aset(env, R_INPUT, (hname = RackIO.
|
122
|
+
rb_hash_aset(env, R_INPUT, (hname = RackIO.create(request, env)));
|
105
123
|
|
106
124
|
/* publish upgrade support */
|
107
125
|
if (request->upgrade) {
|
@@ -135,36 +153,37 @@ static inline VALUE copy2env(http_request_s *request) {
|
|
135
153
|
rb_hash_aset(env, R_URL_SCHEME, HTTP_SCHEME);
|
136
154
|
|
137
155
|
/* add all headers, exclude special cases */
|
138
|
-
|
139
|
-
|
140
|
-
if (header
|
141
|
-
strncasecmp("content-length", header
|
156
|
+
http_header_s header = http_request_header_first(request);
|
157
|
+
while (header.name) {
|
158
|
+
if (header.name_len == 14 &&
|
159
|
+
strncasecmp("content-length", header.name, 14) == 0) {
|
142
160
|
rb_hash_aset(
|
143
161
|
env, CONTENT_LENGTH,
|
144
|
-
rb_enc_str_new(header
|
162
|
+
rb_enc_str_new(header.value, header.value_len, BinaryEncoding));
|
163
|
+
header = http_request_header_next(request);
|
145
164
|
continue;
|
146
|
-
} else if (header
|
147
|
-
strncasecmp("content-type", header
|
165
|
+
} else if (header.name_len == 12 &&
|
166
|
+
strncasecmp("content-type", header.name, 12) == 0) {
|
148
167
|
rb_hash_aset(
|
149
168
|
env, CONTENT_TYPE,
|
150
|
-
rb_enc_str_new(header
|
169
|
+
rb_enc_str_new(header.value, header.value_len, BinaryEncoding));
|
170
|
+
header = http_request_header_next(request);
|
151
171
|
continue;
|
152
|
-
} else if (header
|
153
|
-
strncasecmp("x-forwarded-proto", header
|
154
|
-
if (header
|
155
|
-
!strncasecmp(header->value, "https", 5)) {
|
172
|
+
} else if (header.name_len == 27 &&
|
173
|
+
strncasecmp("x-forwarded-proto", header.name, 27) == 0) {
|
174
|
+
if (header.value_len >= 5 && !strncasecmp(header.value, "https", 5)) {
|
156
175
|
rb_hash_aset(env, R_URL_SCHEME, HTTPS_SCHEME);
|
157
|
-
} else if (header
|
158
|
-
*((uint32_t *)header
|
176
|
+
} else if (header.value_len == 4 &&
|
177
|
+
*((uint32_t *)header.value) == *((uint32_t *)"http")) {
|
159
178
|
rb_hash_aset(env, R_URL_SCHEME, HTTP_SCHEME);
|
160
179
|
} else {
|
161
|
-
rb_hash_aset(
|
162
|
-
|
163
|
-
|
180
|
+
rb_hash_aset(
|
181
|
+
env, R_URL_SCHEME,
|
182
|
+
rb_enc_str_new(header.value, header.value_len, BinaryEncoding));
|
164
183
|
}
|
165
|
-
} else if (header
|
166
|
-
strncasecmp("forwarded", header
|
167
|
-
pos = (char *)header
|
184
|
+
} else if (header.name_len == 9 &&
|
185
|
+
strncasecmp("forwarded", header.name, 9) == 0) {
|
186
|
+
pos = (char *)header.value;
|
168
187
|
if (pos) {
|
169
188
|
while (*pos) {
|
170
189
|
if (((*(pos++) | 32) == 'p') && ((*(pos++) | 32) == 'r') &&
|
@@ -189,18 +208,20 @@ static inline VALUE copy2env(http_request_s *request) {
|
|
189
208
|
}
|
190
209
|
}
|
191
210
|
|
192
|
-
hname = rb_str_buf_new(6 + header
|
211
|
+
hname = rb_str_buf_new(6 + header.name_len);
|
193
212
|
memcpy(RSTRING_PTR(hname), "HTTP_", 5);
|
194
213
|
pos = RSTRING_PTR(hname) + 5;
|
195
|
-
reader = header
|
214
|
+
reader = header.name;
|
196
215
|
while (*reader) {
|
197
216
|
*(pos++) = *reader == '-' ? '_' : to_upper(*reader);
|
198
217
|
++reader;
|
199
218
|
}
|
200
219
|
*pos = 0;
|
201
|
-
rb_str_set_len(hname, 5 + header
|
202
|
-
rb_hash_aset(
|
203
|
-
|
220
|
+
rb_str_set_len(hname, 5 + header.name_len);
|
221
|
+
rb_hash_aset(
|
222
|
+
env, hname,
|
223
|
+
rb_enc_str_new(header.value, header.value_len, BinaryEncoding));
|
224
|
+
header = http_request_header_next(request);
|
204
225
|
}
|
205
226
|
return env;
|
206
227
|
}
|
@@ -227,8 +248,8 @@ static int for_each_header_data(VALUE key, VALUE val, VALUE _res) {
|
|
227
248
|
while (pos_e < val_len && val_s[pos_e] != '\n')
|
228
249
|
pos_e++;
|
229
250
|
http_response_write_header(
|
230
|
-
(void *)_res, .name = RSTRING_PTR(key), .
|
231
|
-
.value = val_s + pos_s, .
|
251
|
+
(void *)_res, .name = RSTRING_PTR(key), .name_len = RSTRING_LEN(key),
|
252
|
+
.value = val_s + pos_s, .value_len = pos_e - pos_s);
|
232
253
|
// fprintf(stderr, "For_each - headers: wrote header\n");
|
233
254
|
// move forward (skip the '\n' if exists)
|
234
255
|
pos_s = pos_e + 1;
|
@@ -258,7 +279,6 @@ static VALUE for_each_body_string(VALUE str, VALUE _res, int argc, VALUE argv) {
|
|
258
279
|
return Qfalse;
|
259
280
|
}
|
260
281
|
} else {
|
261
|
-
http_response_finish((void *)_res);
|
262
282
|
return Qfalse;
|
263
283
|
}
|
264
284
|
return Qtrue;
|
@@ -285,24 +305,19 @@ static inline int ruby2c_response_send(http_response_s *response,
|
|
285
305
|
// fprintf(stderr, "Review body as String\n");
|
286
306
|
if (RSTRING_LEN(body))
|
287
307
|
http_response_write_body(response, RSTRING_PTR(body), RSTRING_LEN(body));
|
288
|
-
http_response_finish(response);
|
289
308
|
return 0;
|
290
309
|
} else if (body == Qnil) {
|
291
|
-
http_response_finish(response);
|
292
310
|
return 0;
|
293
311
|
} else if (rb_respond_to(body, each_method_id)) {
|
294
312
|
// fprintf(stderr, "Review body as for-each ...\n");
|
295
|
-
if (!response->
|
296
|
-
!response->metadata.content_length_written) {
|
313
|
+
if (!response->connection_written && !response->content_length_written) {
|
297
314
|
// close the connection to indicate message length...
|
298
315
|
// protection from bad code
|
299
|
-
response->
|
316
|
+
response->should_close = 1;
|
300
317
|
response->content_length = -1;
|
301
318
|
}
|
302
319
|
rb_block_call(body, each_method_id, 0, NULL, for_each_body_string,
|
303
320
|
(VALUE)response);
|
304
|
-
// make sure the response is sent even if it was an empty collection
|
305
|
-
http_response_finish(response);
|
306
321
|
// we need to call `close` in case the object is an IO / BodyProxy
|
307
322
|
if (rb_respond_to(body, close_method_id))
|
308
323
|
RubyCaller.call(body, close_method_id);
|
@@ -318,24 +333,22 @@ static inline int ruby2c_review_upgrade(http_response_s *response,
|
|
318
333
|
// send headers
|
319
334
|
http_response_finish(response);
|
320
335
|
// remove socket from libsock and libserver
|
321
|
-
|
336
|
+
facil_attach(response->fd, NULL);
|
322
337
|
// call the callback
|
323
338
|
VALUE io_ruby = RubyCaller.call(rb_hash_aref(env, R_HIJACK), call_proc_id);
|
324
339
|
RubyCaller.call2(handler, call_proc_id, 1, &io_ruby);
|
325
340
|
} else if ((handler = rb_hash_aref(env, R_HIJACK_IO)) != Qnil) {
|
326
341
|
// send nothing.
|
327
|
-
if (iodine_http_request_logging)
|
328
|
-
http_response_log_finish(response);
|
329
342
|
http_response_destroy(response);
|
330
343
|
// remove socket from libsock and libserver
|
331
|
-
|
344
|
+
facil_attach(response->fd, NULL);
|
332
345
|
} else if ((handler = rb_hash_aref(env, UPGRADE_WEBSOCKET)) != Qnil ||
|
333
346
|
(handler = rb_hash_aref(env, IODINE_WEBSOCKET)) != Qnil) {
|
334
347
|
// use response as existing base for native websocket upgrade
|
335
|
-
iodine_websocket_upgrade(response->
|
348
|
+
iodine_websocket_upgrade(response->request, response, handler);
|
336
349
|
} else if ((handler = rb_hash_aref(env, UPGRADE_TCP)) != Qnil ||
|
337
350
|
(handler = rb_hash_aref(env, IODINE_UPGRADE)) != Qnil) {
|
338
|
-
intptr_t fduuid = response->
|
351
|
+
intptr_t fduuid = response->fd;
|
339
352
|
// send headers
|
340
353
|
http_response_finish(response);
|
341
354
|
// upgrade protocol
|
@@ -353,9 +366,9 @@ static inline int ruby2c_review_upgrade(http_response_s *response,
|
|
353
366
|
}
|
354
367
|
|
355
368
|
static void *on_rack_request_in_GVL(http_request_s *request) {
|
356
|
-
http_response_s response =
|
369
|
+
http_response_s *response = http_response_create(request);
|
357
370
|
if (iodine_http_request_logging)
|
358
|
-
http_response_log_start(
|
371
|
+
http_response_log_start(response);
|
359
372
|
// create /register env variable
|
360
373
|
VALUE env = copy2env(request);
|
361
374
|
// will be used later
|
@@ -371,7 +384,7 @@ static void *on_rack_request_in_GVL(http_request_s *request) {
|
|
371
384
|
tmp = rb_funcall2(tmp, to_fixnum_func_id, 0, NULL);
|
372
385
|
if (TYPE(tmp) != T_FIXNUM)
|
373
386
|
goto internal_error;
|
374
|
-
response
|
387
|
+
response->status = FIX2ULONG(tmp);
|
375
388
|
// handle header copy from ruby land to C land.
|
376
389
|
VALUE response_headers = rb_ary_entry(rbresponse, 1);
|
377
390
|
if (TYPE(response_headers) != T_HASH)
|
@@ -386,35 +399,37 @@ static void *on_rack_request_in_GVL(http_request_s *request) {
|
|
386
399
|
rb_hash_delete(response_headers, CONTENT_LENGTH_HEADER);
|
387
400
|
}
|
388
401
|
// review each header and write it to the response.
|
389
|
-
rb_hash_foreach(response_headers, for_each_header_data, (VALUE)(
|
402
|
+
rb_hash_foreach(response_headers, for_each_header_data, (VALUE)(response));
|
390
403
|
// If the X-Sendfile header was provided, send the file directly and finish
|
391
404
|
if (xfiles != Qnil &&
|
392
|
-
http_response_sendfile2(
|
393
|
-
RSTRING_LEN(xfiles), NULL, 0, 1) == 0)
|
394
|
-
goto
|
395
|
-
}
|
405
|
+
http_response_sendfile2(response, request, RSTRING_PTR(xfiles),
|
406
|
+
RSTRING_LEN(xfiles), NULL, 0, 1) == 0)
|
407
|
+
goto external_done;
|
396
408
|
// review for belated (post response headers) upgrade.
|
397
|
-
if (ruby2c_review_upgrade(
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
409
|
+
if (ruby2c_review_upgrade(response, rbresponse, env))
|
410
|
+
goto external_done;
|
411
|
+
// send the request body.
|
412
|
+
if (ruby2c_response_send(response, rbresponse, env))
|
413
|
+
goto internal_error;
|
414
|
+
|
415
|
+
Registry.remove(rbresponse);
|
416
|
+
Registry.remove(env);
|
417
|
+
http_response_finish(response);
|
418
|
+
return NULL;
|
419
|
+
external_done:
|
404
420
|
Registry.remove(rbresponse);
|
405
421
|
Registry.remove(env);
|
406
|
-
http_response_destroy(&response);
|
407
422
|
return NULL;
|
408
423
|
internal_error:
|
409
424
|
Registry.remove(rbresponse);
|
410
425
|
Registry.remove(env);
|
411
|
-
http_response_destroy(
|
412
|
-
response =
|
426
|
+
http_response_destroy(response);
|
427
|
+
response = http_response_create(request);
|
413
428
|
if (iodine_http_request_logging)
|
414
|
-
http_response_log_start(
|
415
|
-
response
|
416
|
-
http_response_write_body(
|
417
|
-
http_response_finish(
|
429
|
+
http_response_log_start(response);
|
430
|
+
response->status = 500;
|
431
|
+
http_response_write_body(response, "Error 500, Internal error.", 26);
|
432
|
+
http_response_finish(response);
|
418
433
|
return NULL;
|
419
434
|
}
|
420
435
|
|
@@ -484,6 +499,10 @@ Rack object API
|
|
484
499
|
*/
|
485
500
|
|
486
501
|
int iodine_http_review(void) {
|
502
|
+
if ((getenv("RACK_ENV") && !strcasecmp(getenv("RACK_ENV"), "development")) ||
|
503
|
+
(getenv("RAILS_ENV") && !strcasecmp(getenv("RAILS_ENV"), "development")))
|
504
|
+
IODINE_IS_DEVELOPMENT_MODE = 1;
|
505
|
+
|
487
506
|
rack_app_handler = rb_iv_get(IodineHttp, "@app");
|
488
507
|
if (rack_app_handler != Qnil &&
|
489
508
|
rb_respond_to(rack_app_handler, call_proc_id)) {
|
@@ -504,8 +523,11 @@ int iodine_http_review(void) {
|
|
504
523
|
TYPE(rbport) != Qnil)
|
505
524
|
rb_raise(rb_eTypeError,
|
506
525
|
"The port variable must be either a Fixnum or a String.");
|
507
|
-
if (TYPE(rbport) == T_FIXNUM)
|
526
|
+
if (TYPE(rbport) == T_FIXNUM) {
|
508
527
|
rbport = rb_funcall2(rbport, rb_intern("to_s"), 0, NULL);
|
528
|
+
// rb_ivar_set(self, rb_intern("_port"), port);
|
529
|
+
rb_iv_set(IodineHttp, "@port", rbport);
|
530
|
+
}
|
509
531
|
if (TYPE(rbport) == T_STRING)
|
510
532
|
port = StringValueCStr(rbport);
|
511
533
|
// review address
|
@@ -554,26 +576,28 @@ int iodine_http_review(void) {
|
|
554
576
|
VALUE iodine_version = rb_const_get(Iodine, rb_intern("VERSION"));
|
555
577
|
VALUE ruby_version = rb_const_get(Iodine, rb_intern("RUBY_VERSION"));
|
556
578
|
if (public_folder)
|
557
|
-
fprintf(stderr,
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
579
|
+
fprintf(stderr,
|
580
|
+
"Starting up Iodine HTTP Server:\n"
|
581
|
+
" * Ruby v.%s\n * Iodine v.%s \n"
|
582
|
+
" * %lu max concurrent connections / open files\n"
|
583
|
+
" * Serving static files from:\n"
|
584
|
+
" %s\n\n",
|
562
585
|
StringValueCStr(ruby_version), StringValueCStr(iodine_version),
|
563
586
|
(size_t)sock_max_capacity(), public_folder);
|
564
587
|
else
|
565
|
-
fprintf(stderr,
|
566
|
-
|
567
|
-
|
568
|
-
|
588
|
+
fprintf(stderr,
|
589
|
+
"Starting up Iodine HTTP Server:\n"
|
590
|
+
" * Ruby v.%s\n * Iodine v.%s \n"
|
591
|
+
" * %lu max concurrent connections / open files\n"
|
592
|
+
"\n",
|
569
593
|
StringValueCStr(ruby_version), StringValueCStr(iodine_version),
|
570
594
|
(size_t)sock_max_capacity());
|
571
595
|
|
572
596
|
// listen
|
573
|
-
return
|
574
|
-
|
575
|
-
|
576
|
-
|
597
|
+
return http_listen(port, address, .on_request = on_rack_request,
|
598
|
+
.log_static = iodine_http_request_logging,
|
599
|
+
.max_body_size = max_body_size,
|
600
|
+
.public_folder = public_folder, .timeout = timeout);
|
577
601
|
}
|
578
602
|
return 0;
|
579
603
|
}
|
@@ -25,7 +25,7 @@ size_t iodine_websocket_max_msg_size = 0;
|
|
25
25
|
uint8_t iodine_websocket_timeout = 0;
|
26
26
|
|
27
27
|
#define set_uuid(object, request) \
|
28
|
-
rb_ivar_set((object), fd_var_id, ULONG2NUM((request)->
|
28
|
+
rb_ivar_set((object), fd_var_id, ULONG2NUM((request)->fd))
|
29
29
|
|
30
30
|
inline static intptr_t get_uuid(VALUE obj) {
|
31
31
|
VALUE i = rb_ivar_get(obj, fd_var_id);
|
@@ -42,8 +42,8 @@ inline static ws_s *get_ws(VALUE obj) {
|
|
42
42
|
return (ws_s *)FIX2ULONG(i);
|
43
43
|
}
|
44
44
|
|
45
|
-
#define set_handler(ws, handler)
|
46
|
-
#define get_handler(ws) ((VALUE)
|
45
|
+
#define set_handler(ws, handler) websocket_udata_set((ws), (VALUE)handler)
|
46
|
+
#define get_handler(ws) ((VALUE)websocket_udata((ws_s *)(ws)))
|
47
47
|
|
48
48
|
/*******************************************************************************
|
49
49
|
Buffer management - update to change the way the buffer is handled.
|
@@ -154,8 +154,8 @@ static VALUE iodine_ws_write(VALUE self, VALUE data) {
|
|
154
154
|
/** Returns the number of active websocket connections (including connections
|
155
155
|
* that are in the process of closing down). */
|
156
156
|
static VALUE iodine_ws_count(VALUE self) {
|
157
|
-
|
158
|
-
|
157
|
+
return LONG2FIX(websocket_count());
|
158
|
+
(void)self;
|
159
159
|
}
|
160
160
|
|
161
161
|
/**
|
@@ -165,7 +165,7 @@ return `true`, otherwise `false` will be returned.
|
|
165
165
|
*/
|
166
166
|
static VALUE iodine_ws_has_pending(VALUE self) {
|
167
167
|
intptr_t uuid = get_uuid(self);
|
168
|
-
return
|
168
|
+
return sock_has_pending(uuid) ? Qtrue : Qfalse;
|
169
169
|
}
|
170
170
|
|
171
171
|
/**
|
@@ -236,7 +236,8 @@ static VALUE iodine_defer(int argc, VALUE *argv, VALUE self) {
|
|
236
236
|
return Qfalse;
|
237
237
|
Registry.add(block);
|
238
238
|
|
239
|
-
|
239
|
+
facil_defer(.uuid = fd, .task = iodine_perform_defer, .arg = (void *)block,
|
240
|
+
.fallback = iodine_defer_fallback);
|
240
241
|
return block;
|
241
242
|
}
|
242
243
|
|
@@ -245,6 +246,8 @@ Websocket Multi-Write
|
|
245
246
|
*/
|
246
247
|
|
247
248
|
static uint8_t iodine_ws_if_callback(ws_s *ws, void *block) {
|
249
|
+
if (!ws)
|
250
|
+
return 0;
|
248
251
|
VALUE handler = get_handler(ws);
|
249
252
|
uint8_t ret = 0;
|
250
253
|
if (handler)
|
@@ -305,16 +308,15 @@ static void iodine_ws_perform_each_task(intptr_t fd, protocol_s *protocol,
|
|
305
308
|
if (handler)
|
306
309
|
RubyCaller.call2((VALUE)data, call_proc_id, 1, &handler);
|
307
310
|
}
|
308
|
-
static void iodine_ws_finish_each_task(intptr_t fd,
|
309
|
-
void *data) {
|
311
|
+
static void iodine_ws_finish_each_task(intptr_t fd, void *data) {
|
310
312
|
(void)(fd);
|
311
|
-
(void)(protocol);
|
312
313
|
Registry.remove((VALUE)data);
|
313
314
|
}
|
314
315
|
|
315
316
|
inline static void iodine_ws_run_each(intptr_t origin, VALUE block) {
|
316
|
-
|
317
|
-
|
317
|
+
facil_each(.origin = origin, .service = WEBSOCKET_ID_STR,
|
318
|
+
.task = iodine_ws_perform_each_task, .arg = (void *)block,
|
319
|
+
.on_complete = iodine_ws_finish_each_task);
|
318
320
|
}
|
319
321
|
|
320
322
|
/** Performs a block of code for each websocket connection. The function returns
|
@@ -395,7 +397,8 @@ static VALUE iodine_class_defer(VALUE self, VALUE ws_uuid) {
|
|
395
397
|
return Qfalse;
|
396
398
|
Registry.add(block);
|
397
399
|
|
398
|
-
|
400
|
+
facil_defer(.uuid = fd, .task = iodine_perform_defer, .arg = (void *)block,
|
401
|
+
.fallback = iodine_defer_fallback);
|
399
402
|
return block;
|
400
403
|
}
|
401
404
|
|
@@ -413,6 +416,7 @@ void ws_on_close(ws_s *ws) {
|
|
413
416
|
if (!handler)
|
414
417
|
return;
|
415
418
|
RubyCaller.call(handler, on_close_func_id);
|
419
|
+
set_ws(handler, Qnil);
|
416
420
|
Registry.remove(handler);
|
417
421
|
}
|
418
422
|
void ws_on_shutdown(ws_s *ws) {
|