iodine 0.7.59 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.clang-format +15 -0
- data/.rspec +1 -0
- data/.yardopts +1 -3
- data/CHANGELOG.md +132 -12
- data/Gemfile +5 -7
- data/LICENSE.txt +1 -1
- data/README.md +147 -671
- data/Rakefile +9 -16
- data/examples/chatroom.nru +9 -0
- data/examples/client +74 -0
- data/examples/config-hello.nru +9 -0
- data/examples/config-hello.ru +11 -0
- data/examples/config-hijack.ru +13 -0
- data/examples/config-shootout.ru +43 -0
- data/examples/config.nru +120 -0
- data/examples/config.rb +37 -0
- data/examples/config.ru +42 -53
- data/examples/fake +24 -0
- data/examples/hello_neorack +137 -0
- data/examples/routes.nru +29 -0
- data/examples/routes.ru +42 -0
- data/exe/iodine +218 -258
- data/ext/iodine/extconf.rb +27 -100
- data/ext/iodine/fio-stl.h +128336 -0
- data/ext/iodine/fio-stl.md +26396 -0
- data/ext/iodine/iodine.c +213 -1393
- data/ext/iodine/iodine.h +250 -55
- data/ext/iodine/iodine_arg_helper.h +329 -0
- data/ext/iodine/iodine_caller.h +234 -25
- data/ext/iodine/iodine_cli.h +434 -0
- data/ext/iodine/iodine_compression.h +312 -0
- data/ext/iodine/iodine_connection.h +3484 -34
- data/ext/iodine/iodine_core.h +363 -0
- data/ext/iodine/iodine_crypto.h +1441 -0
- data/ext/iodine/iodine_defer.h +225 -4
- data/ext/iodine/iodine_json.h +738 -4
- data/ext/iodine/iodine_listener.h +263 -0
- data/ext/iodine/iodine_log.h +297 -0
- data/ext/iodine/iodine_minimap.h +543 -0
- data/ext/iodine/iodine_mustache.h +461 -4
- data/ext/iodine/iodine_pubsub_eng.h +729 -0
- data/ext/iodine/iodine_pubsub_history.h +547 -0
- data/ext/iodine/iodine_pubsub_msg.h +228 -0
- data/ext/iodine/iodine_redis.h +322 -0
- data/ext/iodine/iodine_store.h +418 -16
- data/ext/iodine/iodine_threads.h +279 -0
- data/ext/iodine/iodine_tls.h +515 -6
- data/ext/iodine/iodine_utils.h +923 -0
- data/iodine.gemspec +37 -42
- data/lib/iodine/benchmark.rb +1690 -0
- data/lib/iodine/documentation.rb +3085 -0
- data/lib/iodine/version.rb +17 -1
- data/lib/iodine.rb +54 -255
- data/logo.svg +36 -0
- data/mustache.md +55 -0
- data/sig/iodine.rbs +4 -0
- metadata +58 -184
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- data/.github/workflows/ruby.yml +0 -42
- data/.gitignore +0 -20
- data/LIMITS.md +0 -41
- data/SPEC-PubSub-Draft.md +0 -159
- data/SPEC-WebSocket-Draft.md +0 -239
- data/bin/console +0 -22
- data/bin/info.md +0 -353
- data/bin/mustache_bench.rb +0 -100
- data/bin/poc/Gemfile.lock +0 -23
- data/bin/poc/README.md +0 -37
- data/bin/poc/config.ru +0 -66
- data/bin/poc/gemfile +0 -1
- data/bin/poc/www/index.html +0 -57
- data/examples/async_task.ru +0 -92
- data/examples/bates/README.md +0 -3
- data/examples/bates/config.ru +0 -342
- data/examples/bates/david+bold.pdf +0 -0
- data/examples/bates/public/drop-pdf.png +0 -0
- data/examples/bates/public/index.html +0 -600
- data/examples/echo.ru +0 -59
- data/examples/etag.ru +0 -16
- data/examples/hello.ru +0 -29
- data/examples/pubsub_engine.ru +0 -81
- data/examples/rack3.ru +0 -12
- data/examples/redis.ru +0 -70
- data/examples/shootout.ru +0 -73
- data/examples/sub-protocols.ru +0 -90
- data/examples/tcp_client.rb +0 -66
- data/examples/x-sendfile.ru +0 -14
- data/ext/iodine/fio.c +0 -11995
- data/ext/iodine/fio.h +0 -6371
- data/ext/iodine/fio_cli.c +0 -431
- data/ext/iodine/fio_cli.h +0 -189
- data/ext/iodine/fio_json_parser.h +0 -688
- data/ext/iodine/fio_siphash.c +0 -157
- data/ext/iodine/fio_siphash.h +0 -37
- data/ext/iodine/fio_tls.h +0 -129
- data/ext/iodine/fio_tls_missing.c +0 -649
- data/ext/iodine/fio_tls_openssl.c +0 -1106
- data/ext/iodine/fio_tmpfile.h +0 -50
- data/ext/iodine/fiobj.h +0 -44
- data/ext/iodine/fiobj4fio.h +0 -21
- data/ext/iodine/fiobj_ary.c +0 -333
- data/ext/iodine/fiobj_ary.h +0 -139
- data/ext/iodine/fiobj_data.c +0 -1187
- data/ext/iodine/fiobj_data.h +0 -167
- data/ext/iodine/fiobj_hash.c +0 -409
- data/ext/iodine/fiobj_hash.h +0 -176
- data/ext/iodine/fiobj_json.c +0 -622
- data/ext/iodine/fiobj_json.h +0 -68
- data/ext/iodine/fiobj_mem.h +0 -71
- data/ext/iodine/fiobj_mustache.c +0 -317
- data/ext/iodine/fiobj_mustache.h +0 -62
- data/ext/iodine/fiobj_numbers.c +0 -344
- data/ext/iodine/fiobj_numbers.h +0 -127
- data/ext/iodine/fiobj_str.c +0 -433
- data/ext/iodine/fiobj_str.h +0 -172
- data/ext/iodine/fiobject.c +0 -620
- data/ext/iodine/fiobject.h +0 -655
- data/ext/iodine/hpack.h +0 -1923
- data/ext/iodine/http.c +0 -2743
- data/ext/iodine/http.h +0 -1002
- data/ext/iodine/http1.c +0 -910
- data/ext/iodine/http1.h +0 -29
- data/ext/iodine/http1_parser.h +0 -878
- data/ext/iodine/http_internal.c +0 -1279
- data/ext/iodine/http_internal.h +0 -237
- data/ext/iodine/http_mime_parser.h +0 -350
- data/ext/iodine/iodine_caller.c +0 -230
- data/ext/iodine/iodine_connection.c +0 -941
- data/ext/iodine/iodine_defer.c +0 -420
- data/ext/iodine/iodine_fiobj2rb.h +0 -120
- data/ext/iodine/iodine_helpers.c +0 -282
- data/ext/iodine/iodine_helpers.h +0 -12
- data/ext/iodine/iodine_http.c +0 -1181
- data/ext/iodine/iodine_http.h +0 -23
- data/ext/iodine/iodine_json.c +0 -302
- data/ext/iodine/iodine_mustache.c +0 -567
- data/ext/iodine/iodine_pubsub.c +0 -580
- data/ext/iodine/iodine_pubsub.h +0 -26
- data/ext/iodine/iodine_rack_io.c +0 -273
- data/ext/iodine/iodine_rack_io.h +0 -20
- data/ext/iodine/iodine_store.c +0 -146
- data/ext/iodine/iodine_tcp.c +0 -346
- data/ext/iodine/iodine_tcp.h +0 -13
- data/ext/iodine/iodine_tls.c +0 -261
- data/ext/iodine/mustache_parser.h +0 -1546
- data/ext/iodine/redis_engine.c +0 -957
- data/ext/iodine/redis_engine.h +0 -79
- data/ext/iodine/resp_parser.h +0 -317
- data/ext/iodine/websocket_parser.h +0 -506
- data/ext/iodine/websockets.c +0 -743
- data/ext/iodine/websockets.h +0 -185
- data/lib/iodine/connection.rb +0 -61
- data/lib/iodine/json.rb +0 -42
- data/lib/iodine/mustache.rb +0 -113
- data/lib/iodine/pubsub.rb +0 -55
- data/lib/iodine/rack_utils.rb +0 -43
- data/lib/iodine/tls.rb +0 -16
- data/lib/rack/handler/iodine.rb +0 -33
- data/logo.png +0 -0
data/ext/iodine/iodine.c
CHANGED
|
@@ -1,1430 +1,250 @@
|
|
|
1
|
+
/* core include */
|
|
1
2
|
#include "iodine.h"
|
|
2
3
|
|
|
3
|
-
#include <ruby/version.h>
|
|
4
|
-
|
|
5
|
-
#define FIO_INCLUDE_LINKED_LIST
|
|
6
|
-
#include "fio.h"
|
|
7
|
-
#include "fio_cli.h"
|
|
8
4
|
/* *****************************************************************************
|
|
9
|
-
|
|
5
|
+
Deprecation Warnings
|
|
10
6
|
***************************************************************************** */
|
|
11
7
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
#endif
|
|
15
|
-
|
|
16
|
-
/** Any patches required by the running environment for consistent behavior */
|
|
17
|
-
static void patch_env(void) {
|
|
18
|
-
#ifdef __APPLE__
|
|
19
|
-
/* patch for dealing with the High Sierra `fork` limitations */
|
|
20
|
-
void *obj_c_runtime = dlopen("Foundation.framework/Foundation", RTLD_LAZY);
|
|
21
|
-
(void)obj_c_runtime;
|
|
22
|
-
#endif
|
|
23
|
-
}
|
|
8
|
+
/** @deprecated use {Iodine::TLS.add_cert}. */
|
|
9
|
+
static VALUE iodine_tls_cert_add_old_name(int argc, VALUE *argv, VALUE self);
|
|
24
10
|
|
|
25
11
|
/* *****************************************************************************
|
|
26
|
-
|
|
12
|
+
Initialize module
|
|
27
13
|
***************************************************************************** */
|
|
28
14
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
i.e.
|
|
79
|
-
|
|
80
|
-
IDLE_PROC = Proc.new { puts "idle"; Iodine.on_idle &IDLE_PROC }
|
|
81
|
-
Iodine.on_idle &IDLE_PROC
|
|
82
|
-
*/
|
|
83
|
-
static VALUE iodine_sched_on_idle(VALUE self) {
|
|
84
|
-
// clang-format on
|
|
85
|
-
rb_need_block();
|
|
86
|
-
VALUE block = rb_block_proc();
|
|
87
|
-
IodineStore.add(block);
|
|
88
|
-
fio_state_callback_add(FIO_CALL_ON_IDLE, iodine_perform_on_idle_callback,
|
|
89
|
-
(void *)block);
|
|
90
|
-
return block;
|
|
91
|
-
(void)self;
|
|
15
|
+
static void Init_Iodine(void) {
|
|
16
|
+
rb_define_singleton_method(iodine_rb_IODINE, "start", iodine_start, 0);
|
|
17
|
+
rb_define_singleton_method(iodine_rb_IODINE, "stop", iodine_stop, 0);
|
|
18
|
+
|
|
19
|
+
rb_define_singleton_method(iodine_rb_IODINE,
|
|
20
|
+
"running?",
|
|
21
|
+
iodine_is_running,
|
|
22
|
+
0);
|
|
23
|
+
rb_define_singleton_method(iodine_rb_IODINE, "master?", iodine_is_master, 0);
|
|
24
|
+
rb_define_singleton_method(iodine_rb_IODINE, "worker?", iodine_is_worker, 0);
|
|
25
|
+
|
|
26
|
+
rb_define_singleton_method(iodine_rb_IODINE, "workers", iodine_workers, 0);
|
|
27
|
+
rb_define_singleton_method(iodine_rb_IODINE,
|
|
28
|
+
"workers=",
|
|
29
|
+
iodine_workers_set,
|
|
30
|
+
1);
|
|
31
|
+
|
|
32
|
+
rb_define_singleton_method(iodine_rb_IODINE, "threads", iodine_threads, 0);
|
|
33
|
+
rb_define_singleton_method(iodine_rb_IODINE,
|
|
34
|
+
"threads=",
|
|
35
|
+
iodine_threads_set,
|
|
36
|
+
1);
|
|
37
|
+
|
|
38
|
+
rb_define_singleton_method(iodine_rb_IODINE, "secret", iodine_secret, 0);
|
|
39
|
+
rb_define_singleton_method(iodine_rb_IODINE, "secret=", iodine_secret_set, 1);
|
|
40
|
+
|
|
41
|
+
rb_define_singleton_method(iodine_rb_IODINE,
|
|
42
|
+
"shutdown_timeout",
|
|
43
|
+
iodine_shutdown_timeout,
|
|
44
|
+
0);
|
|
45
|
+
rb_define_singleton_method(iodine_rb_IODINE,
|
|
46
|
+
"shutdown_timeout=",
|
|
47
|
+
iodine_shutdown_timeout_set,
|
|
48
|
+
1);
|
|
49
|
+
|
|
50
|
+
rb_define_module_function(iodine_rb_IODINE, "run", iodine_defer_run, 0);
|
|
51
|
+
rb_define_module_function(iodine_rb_IODINE,
|
|
52
|
+
"async",
|
|
53
|
+
iodine_defer_run_async,
|
|
54
|
+
0);
|
|
55
|
+
|
|
56
|
+
rb_define_module_function(iodine_rb_IODINE,
|
|
57
|
+
"run_after",
|
|
58
|
+
iodine_defer_run_after,
|
|
59
|
+
-1);
|
|
60
|
+
rb_define_module_function(iodine_rb_IODINE, "on_state", iodine_on_state, 1);
|
|
61
|
+
|
|
62
|
+
rb_define_singleton_method(iodine_rb_IODINE, "listen", iodine_listen_rb, -1);
|
|
92
63
|
}
|
|
93
64
|
|
|
94
65
|
/* *****************************************************************************
|
|
95
|
-
|
|
66
|
+
Cleanup
|
|
96
67
|
***************************************************************************** */
|
|
97
68
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
fio_start(.threads = params->threads, .workers = params->workers);
|
|
69
|
+
FIO_SFUNC void *iodine___perform_exit_outside_gvl(void *ignr_) {
|
|
70
|
+
(void)ignr_;
|
|
71
|
+
fio_queue_perform_all(fio_io_queue());
|
|
72
|
+
fio_cli_end();
|
|
73
|
+
fio_state_callback_force(FIO_CALL_AT_EXIT);
|
|
74
|
+
fio_state_callback_clear(FIO_CALL_AT_EXIT);
|
|
75
|
+
STORE.destroy();
|
|
106
76
|
return NULL;
|
|
107
77
|
}
|
|
108
78
|
|
|
109
|
-
/*
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
*
|
|
117
|
-
* Negative numbers are translated as fractions of the number of CPU cores.
|
|
118
|
-
* i.e., -2 == half the number of detected CPU cores.
|
|
119
|
-
*
|
|
120
|
-
* Zero values promise nothing (iodine will decide what to do with them).
|
|
121
|
-
*
|
|
122
|
-
* @return [FixNum] Thread Count
|
|
123
|
-
*/
|
|
124
|
-
static VALUE iodine_threads_get(VALUE self) {
|
|
125
|
-
VALUE i = rb_ivar_get(self, rb_intern2("@threads", 8));
|
|
126
|
-
if (i == Qnil)
|
|
127
|
-
i = INT2NUM(0);
|
|
128
|
-
return i;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Sets the number of worker threads that will be used when {Iodine.start}
|
|
133
|
-
* is called.
|
|
134
|
-
*
|
|
135
|
-
* Negative numbers are translated as fractions of the number of CPU cores.
|
|
136
|
-
* i.e., -2 == half the number of detected CPU cores.
|
|
137
|
-
*
|
|
138
|
-
* Zero values promise nothing (iodine will decide what to do with them).
|
|
139
|
-
*
|
|
140
|
-
* @param thread_count [FixNum] The number of worker threads to use
|
|
141
|
-
*/
|
|
142
|
-
static VALUE iodine_threads_set(VALUE self, VALUE val) {
|
|
143
|
-
Check_Type(val, T_FIXNUM);
|
|
144
|
-
if (NUM2SSIZET(val) >= (1 << 12)) {
|
|
145
|
-
rb_raise(rb_eRangeError, "requsted thread count is out of range.");
|
|
146
|
-
}
|
|
147
|
-
rb_ivar_set(self, rb_intern2("@threads", 8), val);
|
|
148
|
-
return val;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Gets the logging level used for Iodine messages.
|
|
153
|
-
*
|
|
154
|
-
* Levels range from 0-5, where:
|
|
155
|
-
*
|
|
156
|
-
* 0 == Quite (no messages)
|
|
157
|
-
* 1 == Fatal Errors only.
|
|
158
|
-
* 2 == Errors only (including fatal errors).
|
|
159
|
-
* 3 == Warnings and errors only.
|
|
160
|
-
* 4 == Informational messages, warnings and errors (default).
|
|
161
|
-
* 5 == Everything, including debug information.
|
|
162
|
-
*
|
|
163
|
-
* Logging is always performed to the process's STDERR and can be piped away.
|
|
164
|
-
*
|
|
165
|
-
* @return [FixNum] Logging Level
|
|
166
|
-
*
|
|
167
|
-
* NOTE: this does NOT effect HTTP logging.
|
|
168
|
-
*/
|
|
169
|
-
static VALUE iodine_logging_get(VALUE self) {
|
|
170
|
-
return INT2FIX(FIO_LOG_LEVEL);
|
|
171
|
-
(void)self;
|
|
79
|
+
/* Workers end with the C STL's `exit(0)`, which skips Ruby's VM cleanup (the
|
|
80
|
+
* step that frees every remaining TypedData object). Without it, objects that
|
|
81
|
+
* are already unreferenced but not yet collected look like leaks. ON_STOP runs
|
|
82
|
+
* after all IO is closed and the thread pool stopped, so collect them here. */
|
|
83
|
+
FIO_SFUNC void *iodine___worker_gc_in_gvl(void *ignr_) {
|
|
84
|
+
rb_gc();
|
|
85
|
+
return ignr_;
|
|
172
86
|
}
|
|
173
87
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
*
|
|
179
|
-
* 0 == Quite (no messages)
|
|
180
|
-
* 1 == Fatal Errors only.
|
|
181
|
-
* 2 == Errors only (including fatal errors).
|
|
182
|
-
* 3 == Warnings and errors only.
|
|
183
|
-
* 4 == Informational messages, warnings and errors (default).
|
|
184
|
-
* 5 == Everything, including debug information.
|
|
185
|
-
*
|
|
186
|
-
* Logging is always performed to the process's STDERR and can be piped away.
|
|
187
|
-
*
|
|
188
|
-
* @param log_level [FixNum] Sets the logging level
|
|
189
|
-
*
|
|
190
|
-
* NOTE: this does NOT effect HTTP logging.
|
|
191
|
-
*/
|
|
192
|
-
static VALUE iodine_logging_set(VALUE self, VALUE val) {
|
|
193
|
-
Check_Type(val, T_FIXNUM);
|
|
194
|
-
FIO_LOG_LEVEL = FIX2INT(val);
|
|
195
|
-
return self;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Returns the number of worker processes that will be used when {Iodine.start}
|
|
200
|
-
* is called.
|
|
201
|
-
*
|
|
202
|
-
* Negative numbers are translated as fractions of the number of CPU cores.
|
|
203
|
-
* i.e., -2 == half the number of detected CPU cores.
|
|
204
|
-
*
|
|
205
|
-
* Zero values promise nothing (iodine will decide what to do with them).
|
|
206
|
-
*
|
|
207
|
-
* 1 == single process mode, the msater process acts as a worker process.
|
|
208
|
-
*
|
|
209
|
-
* @return [FixNum] Worker Count
|
|
210
|
-
*/
|
|
211
|
-
static VALUE iodine_workers_get(VALUE self) {
|
|
212
|
-
VALUE i = rb_ivar_get(self, rb_intern2("@workers", 8));
|
|
213
|
-
if (i == Qnil)
|
|
214
|
-
i = INT2NUM(0);
|
|
215
|
-
return i;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Sets the number of worker processes that will be used when {Iodine.start}
|
|
220
|
-
* is called.
|
|
221
|
-
*
|
|
222
|
-
* Negative numbers are translated as fractions of the number of CPU cores.
|
|
223
|
-
* i.e., -2 == half the number of detected CPU cores.
|
|
224
|
-
*
|
|
225
|
-
* Zero values promise nothing (iodine will decide what to do with them).
|
|
226
|
-
*
|
|
227
|
-
* 1 == single process mode, the msater process acts as a worker process.
|
|
228
|
-
*
|
|
229
|
-
* @param worker_count [FixNum] Number of worker processes
|
|
230
|
-
*/
|
|
231
|
-
static VALUE iodine_workers_set(VALUE self, VALUE val) {
|
|
232
|
-
Check_Type(val, T_FIXNUM);
|
|
233
|
-
if (NUM2SSIZET(val) >= (1 << 9)) {
|
|
234
|
-
rb_raise(rb_eRangeError, "requsted worker process count is out of range.");
|
|
235
|
-
}
|
|
236
|
-
rb_ivar_set(self, rb_intern2("@workers", 8), val);
|
|
237
|
-
return val;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/** Logs the Iodine startup message */
|
|
241
|
-
static void iodine_print_startup_message(iodine_start_params_s params) {
|
|
242
|
-
VALUE iodine_version = rb_const_get(IodineModule, rb_intern("VERSION"));
|
|
243
|
-
VALUE ruby_version = rb_const_get(IodineModule, rb_intern("RUBY_VERSION"));
|
|
244
|
-
fio_expected_concurrency(¶ms.threads, ¶ms.workers);
|
|
245
|
-
FIO_LOG_INFO("Starting up Iodine:\n"
|
|
246
|
-
" * Iodine %s\n * Ruby %s\n"
|
|
247
|
-
" * facil.io " FIO_VERSION_STRING " (%s)\n"
|
|
248
|
-
" * %d Workers X %d Threads per worker.\n"
|
|
249
|
-
" * Maximum %zu open files / sockets per worker.\n"
|
|
250
|
-
" * Master (root) process: %d.\n",
|
|
251
|
-
StringValueCStr(iodine_version), StringValueCStr(ruby_version),
|
|
252
|
-
fio_engine(), params.workers, params.threads, fio_capa(),
|
|
253
|
-
fio_parent_pid());
|
|
254
|
-
(void)params;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* This will block the calling (main) thread and start the Iodine reactor.
|
|
259
|
-
*
|
|
260
|
-
* When using cluster mode (2 or more worker processes), it is important that no
|
|
261
|
-
* other threads are active.
|
|
262
|
-
*
|
|
263
|
-
* For many reasons, `fork` should NOT be called while multi-threading, so
|
|
264
|
-
* cluster mode must always be initiated from the main thread in a single thread
|
|
265
|
-
* environment.
|
|
266
|
-
*
|
|
267
|
-
* For information about why forking in multi-threaded environments should be
|
|
268
|
-
* avoided, see (for example):
|
|
269
|
-
* http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them
|
|
270
|
-
*
|
|
271
|
-
*/
|
|
272
|
-
static VALUE iodine_start(VALUE self) {
|
|
273
|
-
if (fio_is_running()) {
|
|
274
|
-
rb_raise(rb_eRuntimeError, "Iodine already running!");
|
|
275
|
-
}
|
|
276
|
-
IodineCaller.set_GVL(1);
|
|
277
|
-
VALUE threads_rb = iodine_threads_get(self);
|
|
278
|
-
VALUE workers_rb = iodine_workers_get(self);
|
|
279
|
-
iodine_start_params_s params = {
|
|
280
|
-
.threads = NUM2SHORT(threads_rb),
|
|
281
|
-
.workers = NUM2SHORT(workers_rb),
|
|
282
|
-
};
|
|
283
|
-
iodine_print_startup_message(params);
|
|
284
|
-
IodineCaller.leaveGVL(iodine_run_outside_GVL, ¶ms);
|
|
285
|
-
return self;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* This will stop the iodine server, shutting it down.
|
|
290
|
-
*
|
|
291
|
-
* If called within a worker process (rather than the root/master process), this
|
|
292
|
-
* will cause a hot-restart for the worker.
|
|
293
|
-
*/
|
|
294
|
-
static VALUE iodine_stop(VALUE self) {
|
|
295
|
-
fio_stop();
|
|
296
|
-
return self;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Returns `true` if this process is the master / root process, `false`
|
|
301
|
-
* otherwise.
|
|
302
|
-
*
|
|
303
|
-
* Note that the master process might be a worker process as well, when running
|
|
304
|
-
* in single process mode (see {Iodine.workers}).
|
|
305
|
-
*/
|
|
306
|
-
static VALUE iodine_master_is(VALUE self) {
|
|
307
|
-
return fio_is_master() ? Qtrue : Qfalse;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Returns `true` if this process is a worker process or if iodine is running in
|
|
312
|
-
* a single process mode (the master is also a worker), `false` otherwise.
|
|
313
|
-
*/
|
|
314
|
-
static VALUE iodine_worker_is(VALUE self) {
|
|
315
|
-
return fio_is_worker() ? Qtrue : Qfalse;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Returns `true` if Iodine is currently running a server
|
|
320
|
-
*/
|
|
321
|
-
static VALUE iodine_running(VALUE self) {
|
|
322
|
-
if (fio_is_running()) {
|
|
323
|
-
return Qtrue;
|
|
324
|
-
} else {
|
|
325
|
-
return Qfalse;
|
|
326
|
-
}
|
|
88
|
+
FIO_SFUNC void iodine___worker_gc_on_stop(void *ignr_) {
|
|
89
|
+
if (fio_io_is_master()) /* the master process exits through Ruby */
|
|
90
|
+
return;
|
|
91
|
+
iodine_c_call_with(iodine___worker_gc_in_gvl, ignr_);
|
|
327
92
|
}
|
|
328
93
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
*
|
|
338
|
-
* @params [String] desc a String containg the iodine server's description.
|
|
339
|
-
*/
|
|
340
|
-
static VALUE iodine_cli_parse(VALUE self) {
|
|
341
|
-
(void)self;
|
|
342
|
-
VALUE ARGV = rb_get_argv();
|
|
343
|
-
VALUE ret = Qtrue;
|
|
344
|
-
VALUE defaults = iodine_default_args;
|
|
345
|
-
VALUE iodine_version = rb_const_get(IodineModule, rb_intern("VERSION"));
|
|
346
|
-
char desc[1024];
|
|
347
|
-
if (!defaults || !ARGV || TYPE(ARGV) != T_ARRAY || TYPE(defaults) != T_HASH ||
|
|
348
|
-
TYPE(iodine_version) != T_STRING || RSTRING_LEN(iodine_version) > 512) {
|
|
349
|
-
FIO_LOG_ERROR("CLI parsing initialization error "
|
|
350
|
-
"ARGV=%p, Array?(%d), defaults == %p (%d)",
|
|
351
|
-
(void *)ARGV, (int)(TYPE(ARGV) == T_ARRAY), (void *)defaults,
|
|
352
|
-
(int)(TYPE(defaults) == T_HASH));
|
|
353
|
-
return Qnil;
|
|
354
|
-
}
|
|
355
|
-
/* Copy the Ruby ARGV to a C valid ARGV */
|
|
356
|
-
int argc = (int)RARRAY_LEN(ARGV) + 1;
|
|
357
|
-
if (argc <= 1) {
|
|
358
|
-
FIO_LOG_DEBUG("CLI: No arguments to parse...\n");
|
|
359
|
-
return Qnil;
|
|
360
|
-
} else {
|
|
361
|
-
FIO_LOG_DEBUG("Iodine CLI parsing %d arguments", argc);
|
|
362
|
-
}
|
|
363
|
-
char **argv = calloc(argc, sizeof(*argv));
|
|
364
|
-
FIO_ASSERT_ALLOC(argv);
|
|
365
|
-
argv[0] = (char *)"iodine";
|
|
366
|
-
for (int i = 1; i < argc; ++i) {
|
|
367
|
-
VALUE tmp = rb_ary_entry(ARGV, (long)(i - 1));
|
|
368
|
-
if (TYPE(tmp) != T_STRING) {
|
|
369
|
-
FIO_LOG_ERROR("ARGV Array contains a non-String object.");
|
|
370
|
-
ret = Qnil;
|
|
371
|
-
goto finish;
|
|
372
|
-
}
|
|
373
|
-
fio_str_info_s s = IODINE_RSTRINFO(tmp);
|
|
374
|
-
argv[i] = malloc(s.len + 1);
|
|
375
|
-
FIO_ASSERT_ALLOC(argv[i]);
|
|
376
|
-
memcpy(argv[i], s.data, s.len);
|
|
377
|
-
argv[i][s.len] = 0;
|
|
378
|
-
}
|
|
379
|
-
/* Levarage the facil.io CLI library */
|
|
380
|
-
memcpy(desc, "Iodine's HTTP/WebSocket server version ", 39);
|
|
381
|
-
memcpy(desc + 39, StringValueCStr(iodine_version),
|
|
382
|
-
RSTRING_LEN(iodine_version));
|
|
383
|
-
memcpy(desc + 39 + RSTRING_LEN(iodine_version),
|
|
384
|
-
"\r\n\r\nUse:\r\n iodine <options> <filename>\r\n\r\n"
|
|
385
|
-
"Both <options> and <filename> are optional. i.e.,:\r\n"
|
|
386
|
-
" iodine -p 0 -b /tmp/my_unix_sock\r\n"
|
|
387
|
-
" iodine -p 8080 path/to/app/conf.ru\r\n"
|
|
388
|
-
" iodine -p 8080 -w 4 -t 16\r\n"
|
|
389
|
-
" iodine -w -1 -t 4 -r redis://usr:pass@localhost:6379/",
|
|
390
|
-
263);
|
|
391
|
-
desc[39 + 263 + RSTRING_LEN(iodine_version)] = 0;
|
|
392
|
-
fio_cli_start(
|
|
393
|
-
argc, (const char **)argv, 0, -1, desc,
|
|
394
|
-
FIO_CLI_PRINT_HEADER("Address Binding:"),
|
|
395
|
-
"-bind -b -address address to listen to. defaults to any available.",
|
|
396
|
-
FIO_CLI_INT("-port -p port number to listen to. defaults port 3000"),
|
|
397
|
-
FIO_CLI_PRINT("\t\t\x1B[4mNote\x1B[0m: to bind to a Unix socket, set "
|
|
398
|
-
"\x1B[1mport\x1B[0m to 0."),
|
|
399
|
-
FIO_CLI_PRINT_HEADER("Concurrency:"),
|
|
400
|
-
FIO_CLI_INT("-threads -t number of threads per process."),
|
|
401
|
-
FIO_CLI_INT("-workers -w number of processes to use."),
|
|
402
|
-
FIO_CLI_PRINT("Negative concurrency values "
|
|
403
|
-
"map to fractions of available CPU cores."),
|
|
404
|
-
FIO_CLI_PRINT_HEADER("HTTP Settings:"),
|
|
405
|
-
FIO_CLI_STRING("-public -www public folder, for static file service."),
|
|
406
|
-
FIO_CLI_INT("-keep-alive -k -tout HTTP keep-alive timeout in seconds "
|
|
407
|
-
"(0..255). Default: 40s"),
|
|
408
|
-
FIO_CLI_BOOL("-log -v HTTP request logging."),
|
|
409
|
-
FIO_CLI_INT(
|
|
410
|
-
"-max-body -maxbd HTTP upload limit in Mega-Bytes. Default: 50Mb"),
|
|
411
|
-
FIO_CLI_INT("-max-header -maxhd header limit per HTTP request in Kb. "
|
|
412
|
-
"Default: 32Kb."),
|
|
413
|
-
FIO_CLI_PRINT_HEADER("WebSocket Settings:"),
|
|
414
|
-
FIO_CLI_INT("-max-msg -maxms incoming WebSocket message limit in Kb. "
|
|
415
|
-
"Default: 250Kb"),
|
|
416
|
-
FIO_CLI_INT("-ping websocket ping interval (1..255). Default: 40s"),
|
|
417
|
-
FIO_CLI_PRINT_HEADER("SSL/TLS:"),
|
|
418
|
-
FIO_CLI_BOOL("-tls enable SSL/TLS using a self-signed certificate."),
|
|
419
|
-
FIO_CLI_STRING(
|
|
420
|
-
"-tls-cert -cert the SSL/TLS public certificate file name."),
|
|
421
|
-
FIO_CLI_STRING("-tls-key -key the SSL/TLS private key file name."),
|
|
422
|
-
FIO_CLI_STRING(
|
|
423
|
-
"-tls-pass -tls-password the password (if any) protecting the "
|
|
424
|
-
"private key file."),
|
|
425
|
-
FIO_CLI_PRINT("\t\t\x1B[1m-tls-password\x1B[0m is deprecated, use "
|
|
426
|
-
"\x1B[1m-tls-pass\x1B[0m"),
|
|
427
|
-
FIO_CLI_PRINT_HEADER("Connecting Iodine to Redis:"),
|
|
428
|
-
FIO_CLI_STRING(
|
|
429
|
-
"-redis -r an optional Redis URL server address. Default: none."),
|
|
430
|
-
FIO_CLI_INT(
|
|
431
|
-
"-redis-ping -rp websocket ping interval (0..255). Default: 300s"),
|
|
432
|
-
FIO_CLI_PRINT_HEADER("Misc:"),
|
|
433
|
-
FIO_CLI_STRING("-config -C configuration file to be loaded."),
|
|
434
|
-
FIO_CLI_STRING("-pid -pidfile name for the pid file to be created."),
|
|
435
|
-
FIO_CLI_INT("-verbosity -V 0..5 server verbosity level. Default: 4"),
|
|
436
|
-
FIO_CLI_BOOL(
|
|
437
|
-
"-warmup --preload warm up the application. CAREFUL! with workers."));
|
|
438
|
-
|
|
439
|
-
/* copy values from CLI library to iodine */
|
|
440
|
-
if (fio_cli_get("-V")) {
|
|
441
|
-
int level = fio_cli_get_i("-V");
|
|
442
|
-
if (level >= 0 && level < 100)
|
|
443
|
-
FIO_LOG_LEVEL = level;
|
|
444
|
-
}
|
|
445
|
-
if (!fio_cli_get("-w") && getenv("WEB_CONCURRENCY")) {
|
|
446
|
-
fio_cli_set("-w", getenv("WEB_CONCURRENCY"));
|
|
447
|
-
}
|
|
448
|
-
if (!fio_cli_get("-w") && getenv("WORKERS")) {
|
|
449
|
-
fio_cli_set("-w", getenv("WORKERS"));
|
|
450
|
-
}
|
|
451
|
-
if (fio_cli_get("-w")) {
|
|
452
|
-
iodine_workers_set(IodineModule, INT2NUM(fio_cli_get_i("-w")));
|
|
453
|
-
}
|
|
454
|
-
if (!fio_cli_get("-t") && getenv("THREADS")) {
|
|
455
|
-
fio_cli_set("-t", getenv("THREADS"));
|
|
456
|
-
}
|
|
457
|
-
if (fio_cli_get("-t")) {
|
|
458
|
-
iodine_threads_set(IodineModule, INT2NUM(fio_cli_get_i("-t")));
|
|
459
|
-
}
|
|
460
|
-
if (fio_cli_get_bool("-v")) {
|
|
461
|
-
rb_hash_aset(defaults, log_sym, Qtrue);
|
|
462
|
-
}
|
|
463
|
-
if (fio_cli_get_bool("-warmup")) {
|
|
464
|
-
rb_hash_aset(defaults, ID2SYM(rb_intern("warmup_")), Qtrue);
|
|
465
|
-
}
|
|
466
|
-
// if (!fio_cli_get("-b") && getenv("ADDRESS")) {
|
|
467
|
-
// fio_cli_set("-b", getenv("ADDRESS"));
|
|
468
|
-
// }
|
|
469
|
-
if (fio_cli_get("-b")) {
|
|
470
|
-
if (fio_cli_get("-b")[0] == '/' ||
|
|
471
|
-
(fio_cli_get("-b")[0] == '.' && fio_cli_get("-b")[1] == '/')) {
|
|
472
|
-
if (fio_cli_get("-p") &&
|
|
473
|
-
(fio_cli_get("-p")[0] != '0' || fio_cli_get("-p")[1])) {
|
|
474
|
-
FIO_LOG_WARNING(
|
|
475
|
-
"Detected a Unix socket binding (-b) conflicting with port.\n"
|
|
476
|
-
" Port settings (-p %s) are ignored",
|
|
477
|
-
fio_cli_get("-p"));
|
|
478
|
-
}
|
|
479
|
-
fio_cli_set("-p", "0");
|
|
480
|
-
} else {
|
|
481
|
-
// if (!fio_cli_get("-p") && getenv("PORT")) {
|
|
482
|
-
// fio_cli_set("-p", getenv("PORT"));
|
|
483
|
-
// }
|
|
484
|
-
}
|
|
485
|
-
rb_hash_aset(defaults, address_sym, rb_str_new_cstr(fio_cli_get("-b")));
|
|
486
|
-
}
|
|
487
|
-
if (fio_cli_get("-p")) {
|
|
488
|
-
rb_hash_aset(defaults, port_sym, rb_str_new_cstr(fio_cli_get("-p")));
|
|
489
|
-
}
|
|
490
|
-
if (fio_cli_get("-www")) {
|
|
491
|
-
rb_hash_aset(defaults, public_sym, rb_str_new_cstr(fio_cli_get("-www")));
|
|
492
|
-
}
|
|
493
|
-
if (!fio_cli_get("-redis") && getenv("IODINE_REDIS_URL")) {
|
|
494
|
-
fio_cli_set("-redis", getenv("IODINE_REDIS_URL"));
|
|
495
|
-
}
|
|
496
|
-
if (fio_cli_get("-redis")) {
|
|
497
|
-
rb_hash_aset(defaults, ID2SYM(rb_intern("redis_")),
|
|
498
|
-
rb_str_new_cstr(fio_cli_get("-redis")));
|
|
499
|
-
}
|
|
500
|
-
if (fio_cli_get("-k")) {
|
|
501
|
-
rb_hash_aset(defaults, timeout_sym, INT2NUM(fio_cli_get_i("-k")));
|
|
502
|
-
}
|
|
503
|
-
if (fio_cli_get("-ping")) {
|
|
504
|
-
rb_hash_aset(defaults, ping_sym, INT2NUM(fio_cli_get_i("-ping")));
|
|
505
|
-
}
|
|
506
|
-
if (fio_cli_get("-redis-ping")) {
|
|
507
|
-
rb_hash_aset(defaults, ID2SYM(rb_intern("redis_ping_")),
|
|
508
|
-
INT2NUM(fio_cli_get_i("-redis-ping")));
|
|
509
|
-
}
|
|
510
|
-
if (fio_cli_get("-max-body")) {
|
|
511
|
-
rb_hash_aset(defaults, max_body_sym,
|
|
512
|
-
INT2NUM((fio_cli_get_i("-max-body") /* * 1024 * 1024 */)));
|
|
513
|
-
}
|
|
514
|
-
if (fio_cli_get("-maxms")) {
|
|
515
|
-
rb_hash_aset(defaults, max_msg_sym,
|
|
516
|
-
INT2NUM((fio_cli_get_i("-maxms") /* * 1024 */)));
|
|
517
|
-
}
|
|
518
|
-
if (fio_cli_get("-maxhd")) {
|
|
519
|
-
rb_hash_aset(defaults, max_headers_sym,
|
|
520
|
-
INT2NUM((fio_cli_get_i("-maxhd") /* * 1024 */)));
|
|
521
|
-
}
|
|
522
|
-
#ifndef __MINGW32__
|
|
523
|
-
if (fio_cli_get_bool("-tls") || fio_cli_get("-key") || fio_cli_get("-cert")) {
|
|
524
|
-
VALUE rbtls = IodineCaller.call(IodineTLSClass, rb_intern2("new", 3));
|
|
525
|
-
if (rbtls == Qnil) {
|
|
526
|
-
FIO_LOG_FATAL("Iodine internal error, Ruby TLS object is nil.");
|
|
527
|
-
exit(-1);
|
|
528
|
-
}
|
|
529
|
-
fio_tls_s *tls = iodine_tls2c(rbtls);
|
|
530
|
-
if (!tls) {
|
|
531
|
-
FIO_LOG_FATAL("Iodine internal error, TLS object NULL.");
|
|
532
|
-
exit(-1);
|
|
533
|
-
}
|
|
534
|
-
if (fio_cli_get("-tls-key") && fio_cli_get("-tls-cert")) {
|
|
535
|
-
fio_tls_cert_add(tls, NULL, fio_cli_get("-tls-cert"),
|
|
536
|
-
fio_cli_get("-tls-key"), fio_cli_get("-tls-pass"));
|
|
537
|
-
} else {
|
|
538
|
-
if (!fio_cli_get_bool("-tls"))
|
|
539
|
-
FIO_LOG_ERROR("TLS support requires both key and certificate."
|
|
540
|
-
"\r\n\t\tfalling back on a self signed certificate.");
|
|
541
|
-
char name[1024];
|
|
542
|
-
fio_local_addr(name, 1024);
|
|
543
|
-
fio_tls_cert_add(tls, name, NULL, NULL, NULL);
|
|
544
|
-
}
|
|
545
|
-
rb_hash_aset(defaults, tls_sym, rbtls);
|
|
546
|
-
}
|
|
547
|
-
#endif
|
|
548
|
-
if (fio_cli_unnamed_count()) {
|
|
549
|
-
rb_hash_aset(defaults, ID2SYM(rb_intern("filename_")),
|
|
550
|
-
rb_str_new_cstr(fio_cli_unnamed(0)));
|
|
551
|
-
}
|
|
552
|
-
if (fio_cli_get("-pid")) {
|
|
553
|
-
VALUE pid_filename = rb_str_new_cstr(fio_cli_get("-pid"));
|
|
554
|
-
rb_hash_aset(defaults, ID2SYM(rb_intern("pid_")), pid_filename);
|
|
555
|
-
rb_hash_aset(defaults, ID2SYM(rb_intern("pid")), pid_filename);
|
|
556
|
-
}
|
|
557
|
-
if (fio_cli_get("-config")) {
|
|
558
|
-
VALUE conf_filename = rb_str_new_cstr(fio_cli_get("-config"));
|
|
559
|
-
rb_hash_aset(defaults, ID2SYM(rb_intern("conf_")), conf_filename);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
/* create `filename` String, cleanup and return */
|
|
563
|
-
fio_cli_end();
|
|
564
|
-
finish:
|
|
565
|
-
for (int i = 1; i < argc; ++i) {
|
|
566
|
-
free(argv[i]);
|
|
567
|
-
}
|
|
568
|
-
free(argv);
|
|
569
|
-
return ret;
|
|
94
|
+
FIO_SFUNC void iodine___perform_exit(VALUE ignr_) {
|
|
95
|
+
(void)ignr_;
|
|
96
|
+
// rb_gc();
|
|
97
|
+
/* iodine runs outside of GVL, but at_exit runs in GVL.. so... */
|
|
98
|
+
rb_thread_call_without_gvl(iodine___perform_exit_outside_gvl,
|
|
99
|
+
NULL,
|
|
100
|
+
NULL,
|
|
101
|
+
NULL);
|
|
570
102
|
}
|
|
571
103
|
|
|
572
104
|
/* *****************************************************************************
|
|
573
|
-
|
|
105
|
+
OS specific patches
|
|
574
106
|
***************************************************************************** */
|
|
575
107
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
if (RB_TYPE_P(key, T_SYMBOL))
|
|
579
|
-
key = rb_sym2str(key);
|
|
580
|
-
if (!RB_TYPE_P(key, T_STRING)) {
|
|
581
|
-
FIO_LOG_WARNING("invalid key type in header hash, ignored.");
|
|
582
|
-
return ST_CONTINUE;
|
|
583
|
-
}
|
|
584
|
-
if (RB_TYPE_P(val, T_SYMBOL))
|
|
585
|
-
val = rb_sym2str(val);
|
|
586
|
-
if (RB_TYPE_P(val, T_STRING)) {
|
|
587
|
-
FIOBJ k = fiobj_str_new(RSTRING_PTR(key), RSTRING_LEN(key));
|
|
588
|
-
fiobj_hash_set(h, k, fiobj_str_new(RSTRING_PTR(val), RSTRING_LEN(val)));
|
|
589
|
-
fiobj_free(k);
|
|
590
|
-
} else if (RB_TYPE_P(val, T_ARRAY)) {
|
|
591
|
-
FIOBJ k = fiobj_str_new(RSTRING_PTR(key), RSTRING_LEN(key));
|
|
592
|
-
size_t len = rb_array_len(val);
|
|
593
|
-
FIOBJ v = fiobj_ary_new2(len);
|
|
594
|
-
fiobj_hash_set(h, k, v);
|
|
595
|
-
fiobj_free(k);
|
|
596
|
-
for (size_t i = 0; i < len; ++i) {
|
|
597
|
-
VALUE tmp = rb_ary_entry(val, i);
|
|
598
|
-
if (RB_TYPE_P(tmp, T_SYMBOL))
|
|
599
|
-
tmp = rb_sym2str(tmp);
|
|
600
|
-
if (RB_TYPE_P(tmp, T_STRING))
|
|
601
|
-
fiobj_ary_push(v, fiobj_str_new(RSTRING_PTR(tmp), RSTRING_LEN(tmp)));
|
|
602
|
-
}
|
|
603
|
-
} else {
|
|
604
|
-
FIO_LOG_WARNING("invalid header value type, ignored.");
|
|
605
|
-
}
|
|
606
|
-
return ST_CONTINUE;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
static int for_each_cookie(VALUE key, VALUE val, VALUE h_) {
|
|
610
|
-
FIOBJ h = h_;
|
|
611
|
-
if (RB_TYPE_P(key, T_SYMBOL))
|
|
612
|
-
key = rb_sym2str(key);
|
|
613
|
-
if (!RB_TYPE_P(key, T_STRING)) {
|
|
614
|
-
FIO_LOG_WARNING("invalid key type in cookie hash, ignored.");
|
|
615
|
-
return ST_CONTINUE;
|
|
616
|
-
}
|
|
617
|
-
if (RB_TYPE_P(val, T_SYMBOL))
|
|
618
|
-
val = rb_sym2str(val);
|
|
619
|
-
if (RB_TYPE_P(val, T_STRING)) {
|
|
620
|
-
FIOBJ k = fiobj_str_new(RSTRING_PTR(key), RSTRING_LEN(key));
|
|
621
|
-
fiobj_hash_set(h, k, fiobj_str_new(RSTRING_PTR(val), RSTRING_LEN(val)));
|
|
622
|
-
fiobj_free(k);
|
|
623
|
-
} else {
|
|
624
|
-
FIO_LOG_WARNING("invalid cookie value type, ignored.");
|
|
625
|
-
}
|
|
626
|
-
return ST_CONTINUE;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
/* cleans up any resources used by the argument list processing */
|
|
630
|
-
FIO_FUNC void iodine_connect_args_cleanup(iodine_connection_args_s *s) {
|
|
631
|
-
if (!s)
|
|
632
|
-
return;
|
|
633
|
-
fiobj_free(s->cookies);
|
|
634
|
-
fiobj_free(s->headers);
|
|
635
|
-
if (s->port.capa)
|
|
636
|
-
fio_free(s->port.data);
|
|
637
|
-
if (s->address.capa)
|
|
638
|
-
fio_free(s->address.data);
|
|
639
|
-
#ifndef __MINGW32__
|
|
640
|
-
if (s->tls)
|
|
641
|
-
fio_tls_destroy(s->tls);
|
|
642
|
-
#endif
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
/*
|
|
646
|
-
Accepts:
|
|
647
|
-
|
|
648
|
-
func(settings)
|
|
649
|
-
|
|
650
|
-
Supported Settigs:
|
|
651
|
-
- `:url`
|
|
652
|
-
- `:handler` (deprecated: `app`)
|
|
653
|
-
- `:service` (raw / ws / wss / http / https )
|
|
654
|
-
- `:address`
|
|
655
|
-
- `:port`
|
|
656
|
-
- `:path` (HTTP/WebSocket client)
|
|
657
|
-
- `:method` (HTTP client)
|
|
658
|
-
- `:headers` (HTTP/WebSocket client)
|
|
659
|
-
- `:cookies` (HTTP/WebSocket client)
|
|
660
|
-
- `:body` (HTTP client)
|
|
661
|
-
- `:tls`
|
|
662
|
-
- `:log` (HTTP only)
|
|
663
|
-
- `:public` (public folder, HTTP server only)
|
|
664
|
-
- `:timeout` (HTTP only)
|
|
665
|
-
- `:ping` (`:raw` clients and WebSockets only)
|
|
666
|
-
- `:max_headers` (HTTP only)
|
|
667
|
-
- `:max_body` (HTTP only)
|
|
668
|
-
- `:max_msg` (WebSockets only)
|
|
669
|
-
|
|
670
|
-
*/
|
|
671
|
-
FIO_FUNC iodine_connection_args_s iodine_connect_args(VALUE s, uint8_t is_srv) {
|
|
672
|
-
Check_Type(s, T_HASH);
|
|
673
|
-
iodine_connection_args_s r = {.ping = 0}; /* set all to 0 */
|
|
674
|
-
/* Collect argument values */
|
|
675
|
-
VALUE address = rb_hash_aref(s, address_sym);
|
|
676
|
-
VALUE app = rb_hash_aref(s, app_sym);
|
|
677
|
-
VALUE body = rb_hash_aref(s, body_sym);
|
|
678
|
-
VALUE cookies = rb_hash_aref(s, cookies_sym);
|
|
679
|
-
VALUE handler = rb_hash_aref(s, handler_sym);
|
|
680
|
-
VALUE headers = rb_hash_aref(s, headers_sym);
|
|
681
|
-
VALUE log = rb_hash_aref(s, log_sym);
|
|
682
|
-
VALUE max_body = rb_hash_aref(s, max_body_sym);
|
|
683
|
-
VALUE max_clients = rb_hash_aref(s, max_clients_sym);
|
|
684
|
-
VALUE max_headers = rb_hash_aref(s, max_headers_sym);
|
|
685
|
-
VALUE max_msg = rb_hash_aref(s, max_msg_sym);
|
|
686
|
-
VALUE method = rb_hash_aref(s, method_sym);
|
|
687
|
-
VALUE path = rb_hash_aref(s, path_sym);
|
|
688
|
-
VALUE ping = rb_hash_aref(s, ping_sym);
|
|
689
|
-
VALUE port = rb_hash_aref(s, port_sym);
|
|
690
|
-
VALUE r_public = rb_hash_aref(s, public_sym);
|
|
691
|
-
VALUE service = rb_hash_aref(s, service_sym);
|
|
692
|
-
VALUE timeout = rb_hash_aref(s, timeout_sym);
|
|
693
|
-
#ifndef __MINGW32__
|
|
694
|
-
VALUE tls = rb_hash_aref(s, tls_sym);
|
|
695
|
-
#endif
|
|
696
|
-
VALUE r_url = rb_hash_aref(s, url_sym);
|
|
697
|
-
fio_str_info_s service_str = {.data = NULL};
|
|
698
|
-
|
|
699
|
-
/* Complete using default values */
|
|
700
|
-
if (address == Qnil)
|
|
701
|
-
address = rb_hash_aref(iodine_default_args, address_sym);
|
|
702
|
-
if (app == Qnil)
|
|
703
|
-
app = rb_hash_aref(iodine_default_args, app_sym);
|
|
704
|
-
if (cookies == Qnil)
|
|
705
|
-
cookies = rb_hash_aref(iodine_default_args, cookies_sym);
|
|
706
|
-
if (handler == Qnil)
|
|
707
|
-
handler = rb_hash_aref(iodine_default_args, handler_sym);
|
|
708
|
-
if (headers == Qnil)
|
|
709
|
-
headers = rb_hash_aref(iodine_default_args, headers_sym);
|
|
710
|
-
if (log == Qnil)
|
|
711
|
-
log = rb_hash_aref(iodine_default_args, log_sym);
|
|
712
|
-
if (max_body == Qnil)
|
|
713
|
-
max_body = rb_hash_aref(iodine_default_args, max_body_sym);
|
|
714
|
-
if (max_clients == Qnil)
|
|
715
|
-
max_clients = rb_hash_aref(iodine_default_args, max_clients_sym);
|
|
716
|
-
if (max_headers == Qnil)
|
|
717
|
-
max_headers = rb_hash_aref(iodine_default_args, max_headers_sym);
|
|
718
|
-
if (max_msg == Qnil)
|
|
719
|
-
max_msg = rb_hash_aref(iodine_default_args, max_msg_sym);
|
|
720
|
-
if (method == Qnil)
|
|
721
|
-
method = rb_hash_aref(iodine_default_args, method_sym);
|
|
722
|
-
if (path == Qnil)
|
|
723
|
-
path = rb_hash_aref(iodine_default_args, path_sym);
|
|
724
|
-
if (ping == Qnil)
|
|
725
|
-
ping = rb_hash_aref(iodine_default_args, ping_sym);
|
|
726
|
-
if (port == Qnil)
|
|
727
|
-
port = rb_hash_aref(iodine_default_args, port_sym);
|
|
728
|
-
if (r_public == Qnil) {
|
|
729
|
-
r_public = rb_hash_aref(iodine_default_args, public_sym);
|
|
730
|
-
}
|
|
731
|
-
// if (service == Qnil) // not supported by default settings...
|
|
732
|
-
// service = rb_hash_aref(iodine_default_args, service_sym);
|
|
733
|
-
if (timeout == Qnil)
|
|
734
|
-
timeout = rb_hash_aref(iodine_default_args, timeout_sym);
|
|
735
|
-
#ifndef __MINGW32__
|
|
736
|
-
if (tls == Qnil)
|
|
737
|
-
tls = rb_hash_aref(iodine_default_args, tls_sym);
|
|
108
|
+
#ifdef __APPLE__
|
|
109
|
+
#include <dlfcn.h>
|
|
738
110
|
#endif
|
|
739
111
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
/* specific for HTTP */
|
|
749
|
-
if (is_srv && handler == Qnil && rb_block_given_p()) {
|
|
750
|
-
handler = rb_block_proc();
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
/* Raise exceptions on errors (last chance) */
|
|
754
|
-
if (handler == Qnil) {
|
|
755
|
-
rb_raise(rb_eArgError, "a :handler is required.");
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
/* Set existing values */
|
|
759
|
-
if (handler != Qnil) {
|
|
760
|
-
r.handler = handler;
|
|
761
|
-
}
|
|
762
|
-
if (address != Qnil && RB_TYPE_P(address, T_STRING)) {
|
|
763
|
-
r.address = IODINE_RSTRINFO(address);
|
|
764
|
-
}
|
|
765
|
-
if (body != Qnil && RB_TYPE_P(body, T_STRING)) {
|
|
766
|
-
r.body = IODINE_RSTRINFO(body);
|
|
767
|
-
}
|
|
768
|
-
if (cookies != Qnil && RB_TYPE_P(cookies, T_HASH)) {
|
|
769
|
-
r.cookies = fiobj_hash_new2(rb_hash_size(cookies));
|
|
770
|
-
rb_hash_foreach(cookies, for_each_cookie, r.cookies);
|
|
771
|
-
}
|
|
772
|
-
if (headers != Qnil && RB_TYPE_P(headers, T_HASH)) {
|
|
773
|
-
r.headers = fiobj_hash_new2(rb_hash_size(headers));
|
|
774
|
-
rb_hash_foreach(headers, for_each_header_value, r.headers);
|
|
775
|
-
}
|
|
776
|
-
if (log != Qnil && log != Qfalse) {
|
|
777
|
-
r.log = 1;
|
|
778
|
-
}
|
|
779
|
-
if (max_body != Qnil && RB_TYPE_P(max_body, T_FIXNUM)) {
|
|
780
|
-
r.max_body = FIX2ULONG(max_body) * 1024 * 1024;
|
|
781
|
-
}
|
|
782
|
-
if (max_clients != Qnil && RB_TYPE_P(max_clients, T_FIXNUM)) {
|
|
783
|
-
r.max_clients = FIX2ULONG(max_clients);
|
|
784
|
-
}
|
|
785
|
-
if (max_headers != Qnil && RB_TYPE_P(max_headers, T_FIXNUM)) {
|
|
786
|
-
r.max_headers = FIX2ULONG(max_headers) * 1024;
|
|
787
|
-
}
|
|
788
|
-
if (max_msg != Qnil && RB_TYPE_P(max_msg, T_FIXNUM)) {
|
|
789
|
-
r.max_msg = FIX2ULONG(max_msg) * 1024;
|
|
790
|
-
}
|
|
791
|
-
if (method != Qnil && RB_TYPE_P(method, T_STRING)) {
|
|
792
|
-
r.method = IODINE_RSTRINFO(method);
|
|
793
|
-
}
|
|
794
|
-
if (path != Qnil && RB_TYPE_P(path, T_STRING)) {
|
|
795
|
-
r.path = IODINE_RSTRINFO(path);
|
|
796
|
-
}
|
|
797
|
-
if (ping != Qnil && RB_TYPE_P(ping, T_FIXNUM)) {
|
|
798
|
-
if (FIX2ULONG(ping) > 255)
|
|
799
|
-
FIO_LOG_WARNING(":ping value over 255 will be silently ignored.");
|
|
800
|
-
else
|
|
801
|
-
r.ping = FIX2ULONG(ping);
|
|
802
|
-
}
|
|
803
|
-
if (port != Qnil) {
|
|
804
|
-
if (RB_TYPE_P(port, T_STRING)) {
|
|
805
|
-
char *tmp = RSTRING_PTR(port);
|
|
806
|
-
if (fio_atol(&tmp))
|
|
807
|
-
r.port = IODINE_RSTRINFO(port);
|
|
808
|
-
} else if (RB_TYPE_P(port, T_FIXNUM) && FIX2UINT(port)) {
|
|
809
|
-
if (FIX2UINT(port) >= 65536) {
|
|
810
|
-
FIO_LOG_WARNING("Port number %u is too high, quietly ignored.",
|
|
811
|
-
FIX2UINT(port));
|
|
812
|
-
} else {
|
|
813
|
-
r.port = (fio_str_info_s){.data = fio_malloc(16), .len = 0, .capa = 1};
|
|
814
|
-
r.port.len = fio_ltoa(r.port.data, FIX2INT(port), 10);
|
|
815
|
-
r.port.data[r.port.len] = 0;
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
if (r_public != Qnil && RB_TYPE_P(r_public, T_STRING)) {
|
|
821
|
-
r.public = IODINE_RSTRINFO(r_public);
|
|
822
|
-
}
|
|
823
|
-
if (service != Qnil && RB_TYPE_P(service, T_STRING)) {
|
|
824
|
-
service_str = IODINE_RSTRINFO(service);
|
|
825
|
-
} else if (service != Qnil && RB_TYPE_P(service, T_SYMBOL)) {
|
|
826
|
-
service = rb_sym2str(service);
|
|
827
|
-
service_str = IODINE_RSTRINFO(service);
|
|
828
|
-
}
|
|
829
|
-
if (timeout != Qnil && RB_TYPE_P(ping, T_FIXNUM)) {
|
|
830
|
-
if (FIX2ULONG(timeout) > 255)
|
|
831
|
-
FIO_LOG_WARNING(":timeout value over 255 will be silently ignored.");
|
|
832
|
-
else
|
|
833
|
-
r.timeout = FIX2ULONG(timeout);
|
|
834
|
-
}
|
|
835
|
-
#ifndef __MINGW32__
|
|
836
|
-
if (tls != Qnil) {
|
|
837
|
-
r.tls = iodine_tls2c(tls);
|
|
838
|
-
if (r.tls)
|
|
839
|
-
fio_tls_dup(r.tls);
|
|
840
|
-
}
|
|
841
|
-
#endif
|
|
842
|
-
/* URL parsing */
|
|
843
|
-
if (r_url != Qnil && RB_TYPE_P(r_url, T_STRING)) {
|
|
844
|
-
r.url = IODINE_RSTRINFO(r_url);
|
|
845
|
-
fio_url_s u = fio_url_parse(r.url.data, r.url.len);
|
|
846
|
-
/* set service string */
|
|
847
|
-
if (u.scheme.data) {
|
|
848
|
-
service_str = u.scheme;
|
|
849
|
-
}
|
|
850
|
-
/* copy port number */
|
|
851
|
-
if (u.port.data) {
|
|
852
|
-
char *tmp = u.port.data;
|
|
853
|
-
if (fio_atol(&tmp) == 0) {
|
|
854
|
-
if (r.port.capa)
|
|
855
|
-
fio_free(r.port.data);
|
|
856
|
-
r.port = (fio_str_info_s){.data = NULL};
|
|
857
|
-
} else {
|
|
858
|
-
if (u.port.len > 5)
|
|
859
|
-
FIO_LOG_WARNING("Port number error (%.*s too long to be valid).",
|
|
860
|
-
(int)u.port.len, u.port.data);
|
|
861
|
-
if (r.port.capa && u.port.len >= 16) {
|
|
862
|
-
fio_free(r.port.data);
|
|
863
|
-
r.port = (fio_str_info_s){.data = NULL};
|
|
864
|
-
}
|
|
865
|
-
if (!r.port.capa)
|
|
866
|
-
r.port = (fio_str_info_s){
|
|
867
|
-
.data = fio_malloc(u.port.len + 1), .len = u.port.len, .capa = 1};
|
|
868
|
-
memcpy(r.port.data, u.port.data, u.port.len);
|
|
869
|
-
r.port.len = u.port.len;
|
|
870
|
-
r.port.data[r.port.len] = 0;
|
|
871
|
-
}
|
|
872
|
-
} else {
|
|
873
|
-
if (r.port.capa)
|
|
874
|
-
fio_free(r.port.data);
|
|
875
|
-
r.port = (fio_str_info_s){.data = NULL};
|
|
876
|
-
}
|
|
877
|
-
/* copy host / address */
|
|
878
|
-
if (u.host.data) {
|
|
879
|
-
r.address = (fio_str_info_s){
|
|
880
|
-
.data = fio_malloc(u.host.len + 1), .len = u.host.len, .capa = 1};
|
|
881
|
-
memcpy(r.address.data, u.host.data, u.host.len);
|
|
882
|
-
r.address.len = u.host.len;
|
|
883
|
-
r.address.data[r.address.len] = 0;
|
|
884
|
-
} else {
|
|
885
|
-
if (r.address.capa)
|
|
886
|
-
fio_free(r.address.data);
|
|
887
|
-
r.address = (fio_str_info_s){.data = NULL};
|
|
888
|
-
}
|
|
889
|
-
/* set path */
|
|
890
|
-
if (u.path.data) {
|
|
891
|
-
/* support possible Unix address as "raw://:0/my/sock.sock" */
|
|
892
|
-
if (r.address.data || r.port.data)
|
|
893
|
-
r.path = u.path;
|
|
894
|
-
else
|
|
895
|
-
r.address = u.path;
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
/* test/set service type */
|
|
899
|
-
r.service = IODINE_SERVICE_RAW;
|
|
900
|
-
if (service_str.data) {
|
|
901
|
-
#ifdef __MINGW32__
|
|
902
|
-
switch (service_str.data[0]) {
|
|
903
|
-
case 't': /* overflow */
|
|
904
|
-
/* tcp or tls */
|
|
905
|
-
if (service_str.data[1] == 'l') {
|
|
906
|
-
char *local = NULL;
|
|
907
|
-
char buf[1024];
|
|
908
|
-
buf[1023] = 0;
|
|
909
|
-
if (is_srv) {
|
|
910
|
-
local = buf;
|
|
911
|
-
if (fio_local_addr(buf, 1023) >= 1022)
|
|
912
|
-
local = NULL;
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
/* overflow */
|
|
916
|
-
case 'u': /* overflow */
|
|
917
|
-
/* unix */
|
|
918
|
-
case 'r':
|
|
919
|
-
/* raw */
|
|
920
|
-
r.service = IODINE_SERVICE_RAW;
|
|
921
|
-
break;
|
|
922
|
-
case 'h':
|
|
923
|
-
/* http(s) */
|
|
924
|
-
r.service = IODINE_SERVICE_HTTP;
|
|
925
|
-
if (service_str.len == 5) {
|
|
926
|
-
char *local = NULL;
|
|
927
|
-
char buf[1024];
|
|
928
|
-
buf[1023] = 0;
|
|
929
|
-
if (is_srv) {
|
|
930
|
-
local = buf;
|
|
931
|
-
if (fio_local_addr(buf, 1023) >= 1022)
|
|
932
|
-
local = NULL;
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
case 'w':
|
|
936
|
-
/* ws(s) */
|
|
937
|
-
r.service = IODINE_SERVICE_WS;
|
|
938
|
-
if (service_str.len == 3) {
|
|
939
|
-
char *local = NULL;
|
|
940
|
-
char buf[1024];
|
|
941
|
-
buf[1023] = 0;
|
|
942
|
-
if (is_srv) {
|
|
943
|
-
local = buf;
|
|
944
|
-
if (fio_local_addr(buf, 1023) >= 1022)
|
|
945
|
-
local = NULL;
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
break;
|
|
949
|
-
}
|
|
950
|
-
#else
|
|
951
|
-
switch (service_str.data[0]) {
|
|
952
|
-
case 't': /* overflow */
|
|
953
|
-
/* tcp or tls */
|
|
954
|
-
if (service_str.data[1] == 'l' && !r.tls) {
|
|
955
|
-
char *local = NULL;
|
|
956
|
-
char buf[1024];
|
|
957
|
-
buf[1023] = 0;
|
|
958
|
-
if (is_srv) {
|
|
959
|
-
local = buf;
|
|
960
|
-
if (fio_local_addr(buf, 1023) >= 1022)
|
|
961
|
-
local = NULL;
|
|
962
|
-
}
|
|
963
|
-
r.tls = fio_tls_new(local, NULL, NULL, NULL);
|
|
964
|
-
}
|
|
965
|
-
/* overflow */
|
|
966
|
-
case 'u': /* overflow */
|
|
967
|
-
/* unix */
|
|
968
|
-
case 'r':
|
|
969
|
-
/* raw */
|
|
970
|
-
r.service = IODINE_SERVICE_RAW;
|
|
971
|
-
break;
|
|
972
|
-
case 'h':
|
|
973
|
-
/* http(s) */
|
|
974
|
-
r.service = IODINE_SERVICE_HTTP;
|
|
975
|
-
if (service_str.len == 5 && !r.tls) {
|
|
976
|
-
char *local = NULL;
|
|
977
|
-
char buf[1024];
|
|
978
|
-
buf[1023] = 0;
|
|
979
|
-
if (is_srv) {
|
|
980
|
-
local = buf;
|
|
981
|
-
if (fio_local_addr(buf, 1023) >= 1022)
|
|
982
|
-
local = NULL;
|
|
983
|
-
}
|
|
984
|
-
r.tls = fio_tls_new(local, NULL, NULL, NULL);
|
|
985
|
-
}
|
|
986
|
-
case 'w':
|
|
987
|
-
/* ws(s) */
|
|
988
|
-
r.service = IODINE_SERVICE_WS;
|
|
989
|
-
if (service_str.len == 3 && !r.tls) {
|
|
990
|
-
char *local = NULL;
|
|
991
|
-
char buf[1024];
|
|
992
|
-
buf[1023] = 0;
|
|
993
|
-
if (is_srv) {
|
|
994
|
-
local = buf;
|
|
995
|
-
if (fio_local_addr(buf, 1023) >= 1022)
|
|
996
|
-
local = NULL;
|
|
997
|
-
}
|
|
998
|
-
r.tls = fio_tls_new(local, NULL, NULL, NULL);
|
|
999
|
-
}
|
|
1000
|
-
break;
|
|
1001
|
-
}
|
|
112
|
+
/** Any patches required by the running environment for consistent behavior */
|
|
113
|
+
static void patch_env(void) {
|
|
114
|
+
#ifdef __APPLE__
|
|
115
|
+
/* patch for dealing with the High Sierra `fork` limitations */
|
|
116
|
+
void *obj_c_runtime = dlopen("Foundation.framework/Foundation", RTLD_LAZY);
|
|
117
|
+
(void)obj_c_runtime;
|
|
1002
118
|
#endif
|
|
1003
|
-
}
|
|
1004
|
-
return r;
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
/* *****************************************************************************
|
|
1008
|
-
Listen function routing
|
|
1009
|
-
***************************************************************************** */
|
|
1010
|
-
|
|
1011
|
-
// clang-format off
|
|
1012
|
-
/*
|
|
1013
|
-
{Iodine.listen} can be used to listen to any incoming connections, including HTTP and raw (tcp/ip and unix sockets) connections.
|
|
1014
|
-
|
|
1015
|
-
Iodine.listen(settings)
|
|
1016
|
-
|
|
1017
|
-
Supported Settigs:
|
|
1018
|
-
|
|
1019
|
-
| | |
|
|
1020
|
-
|---|---|
|
|
1021
|
-
| `:url` | URL indicating service type, host name and port. Path will be parsed as a Unix socket. |
|
|
1022
|
-
| `:handler` | (deprecated: `:app`) see details below. |
|
|
1023
|
-
| `:address` | an IP address or a unix socket address. Only relevant if `:url` is missing. |
|
|
1024
|
-
| `:log` | (HTTP only) request logging. For global verbosity see {Iodine.verbosity} |
|
|
1025
|
-
| `:max_body` | (HTTP only) maximum upload size allowed per request before disconnection (in Mb). |
|
|
1026
|
-
| `:max_headers` | (HTTP only) maximum total header length allowed per request (in Kb). |
|
|
1027
|
-
| `:max_msg` | (WebSockets only) maximum message size pre message (in Kb). |
|
|
1028
|
-
| `:ping` | (`:raw` clients and WebSockets only) ping interval (in seconds). Up to 255 seconds. |
|
|
1029
|
-
| `:port` | port number to listen to either a String or Number) |
|
|
1030
|
-
| `:public` | (HTTP server only) public folder for static file service. |
|
|
1031
|
-
| `:service` | (`:raw` / `:tls` / `:ws` / `:wss` / `:http` / `:https` ) a supported service this socket will listen to. |
|
|
1032
|
-
| `:timeout` | (HTTP only) keep-alive timeout in seconds. Up to 255 seconds. |
|
|
1033
|
-
| `:tls` | an {Iodine::TLS} context object for encrypted connections. |
|
|
1034
|
-
|
|
1035
|
-
Some connection settings are only valid when listening to HTTP / WebSocket connections.
|
|
1036
|
-
|
|
1037
|
-
If `:url` is provided, it will overwrite the `:address` and `:port` settings (if provided).
|
|
1038
|
-
|
|
1039
|
-
For HTTP connections, the `:handler` **must** be a valid Rack application object (answers `.call(env)`).
|
|
1040
|
-
|
|
1041
|
-
Here's an example for an HTTP hello world application:
|
|
1042
|
-
|
|
1043
|
-
require 'iodine'
|
|
1044
|
-
# a handler can be a block
|
|
1045
|
-
Iodine.listen(service: :http, port: "3000") {|env| [200, {"Content-Length" => "12"}, ["Hello World!"]] }
|
|
1046
|
-
# start the service
|
|
1047
|
-
Iodine.threads = 1
|
|
1048
|
-
Iodine.start
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
Here's another example, using a Unix Socket instead of a TCP/IP socket for an HTTP hello world application.
|
|
1052
|
-
|
|
1053
|
-
This example shows how the `:url` option can be used, but the `:address` settings could have been used for the same effect (with `port: 0`).
|
|
1054
|
-
|
|
1055
|
-
require 'iodine'
|
|
1056
|
-
# note that unix sockets in URL form use an absolute path.
|
|
1057
|
-
Iodine.listen(url: "http://:0/tmp/sock.sock") {|env| [200, {"Content-Length" => "12"}, ["Hello World!"]] }
|
|
1058
|
-
# start the service
|
|
1059
|
-
Iodine.threads = 1
|
|
1060
|
-
Iodine.start
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
For raw connections, the `:handler` object should be an object that answer `.call` and returns a valid callback object that supports the following callbacks (see also {Iodine::Connection}):
|
|
1064
|
-
|
|
1065
|
-
| | |
|
|
1066
|
-
|---|---|
|
|
1067
|
-
| `on_open(client)` | called after a connection was established |
|
|
1068
|
-
| `on_message(client,data)` | called when incoming data is available. Data may be fragmented. |
|
|
1069
|
-
| `on_drained(client)` | called after pending `client.write` events have been processed (see {Iodine::Connection#pending}). |
|
|
1070
|
-
| `ping(client)` | called whenever a timeout has occured (see {Iodine::Connection#timeout=}). |
|
|
1071
|
-
| `on_shutdown(client)` | called if the server is shutting down. This is called before the connection is closed. |
|
|
1072
|
-
| `on_close(client)` | called when the connection with the client was closed. |
|
|
1073
|
-
|
|
1074
|
-
The `client` argument passed to the `:handler` callbacks is an {Iodine::Connection} instance that represents the connection / the client.
|
|
1075
|
-
|
|
1076
|
-
Here's an example for a telnet based chat-room example:
|
|
1077
|
-
|
|
1078
|
-
require 'iodine'
|
|
1079
|
-
# define the protocol for our service
|
|
1080
|
-
module ChatHandler
|
|
1081
|
-
def self.on_open(client)
|
|
1082
|
-
# Set a connection timeout
|
|
1083
|
-
client.timeout = 10
|
|
1084
|
-
# subscribe to the chat channel.
|
|
1085
|
-
client.subscribe :chat
|
|
1086
|
-
# Write a welcome message
|
|
1087
|
-
client.publish :chat, "new member entered the chat\r\n"
|
|
1088
|
-
end
|
|
1089
|
-
# this is called for incoming data - note data might be fragmented.
|
|
1090
|
-
def self.on_message(client, data)
|
|
1091
|
-
# publish the data we received
|
|
1092
|
-
client.publish :chat, data
|
|
1093
|
-
# close the connection when the time comes
|
|
1094
|
-
client.close if data =~ /^bye[\n\r]/
|
|
1095
|
-
end
|
|
1096
|
-
# called whenever timeout occurs.
|
|
1097
|
-
def self.ping(client)
|
|
1098
|
-
client.write "System: quite, isn't it...?\r\n"
|
|
1099
|
-
end
|
|
1100
|
-
# called if the connection is still open and the server is shutting down.
|
|
1101
|
-
def self.on_shutdown(client)
|
|
1102
|
-
# write the data we received
|
|
1103
|
-
client.write "Chat server going away. Try again later.\r\n"
|
|
1104
|
-
end
|
|
1105
|
-
# returns the callback object (self).
|
|
1106
|
-
def self.call
|
|
1107
|
-
self
|
|
1108
|
-
end
|
|
1109
|
-
end
|
|
1110
|
-
# we use can both the `handler` keyword or a block, anything that answers #call.
|
|
1111
|
-
Iodine.listen(service: :raw, port: "3000", handler: ChatHandler)
|
|
1112
|
-
# we can listen to more than a single socket at a time.
|
|
1113
|
-
Iodine.listen(url: "raw://:3030", handler: ChatHandler)
|
|
1114
|
-
# start the service
|
|
1115
|
-
Iodine.threads = 1
|
|
1116
|
-
Iodine.start
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
Returns the handler object used.
|
|
1121
|
-
*/
|
|
1122
|
-
static VALUE iodine_listen(VALUE self, VALUE args) {
|
|
1123
|
-
// clang-format on
|
|
1124
|
-
iodine_connection_args_s s = iodine_connect_args(args, 1);
|
|
1125
|
-
intptr_t uuid = -1;
|
|
1126
|
-
switch (s.service) {
|
|
1127
|
-
case IODINE_SERVICE_RAW:
|
|
1128
|
-
uuid = iodine_tcp_listen(s);
|
|
1129
|
-
break;
|
|
1130
|
-
case IODINE_SERVICE_HTTP: /* overflow */
|
|
1131
|
-
case IODINE_SERVICE_WS:
|
|
1132
|
-
uuid = iodine_http_listen(s);
|
|
1133
|
-
break;
|
|
1134
|
-
}
|
|
1135
|
-
iodine_connect_args_cleanup(&s);
|
|
1136
|
-
if (uuid == -1)
|
|
1137
|
-
rb_raise(rb_eRuntimeError, "Couldn't open listening socket.");
|
|
1138
|
-
return s.handler;
|
|
1139
|
-
(void)self;
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
/* *****************************************************************************
|
|
1143
|
-
Connect function routing
|
|
1144
|
-
***************************************************************************** */
|
|
1145
|
-
|
|
1146
|
-
// clang-format off
|
|
1147
|
-
/*
|
|
1148
|
-
|
|
1149
|
-
The {connect} method instructs iodine to connect to a server using either TCP/IP or Unix sockets.
|
|
1150
|
-
|
|
1151
|
-
Iodine.connect(settings)
|
|
1152
|
-
|
|
1153
|
-
Supported Settigs:
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
| | |
|
|
1157
|
-
|---|---|
|
|
1158
|
-
| `:url` | URL indicating service type, host name, port and optional path. |
|
|
1159
|
-
| `:handler` | see details below. |
|
|
1160
|
-
| `:address` | an IP address or a unix socket address. Only relevant if `:url` is missing. |
|
|
1161
|
-
| `:body` | (HTTP client) the body to be sent. |
|
|
1162
|
-
| `:cookies` | (HTTP/WebSocket client) cookie data. |
|
|
1163
|
-
| `:headers` | (HTTP/WebSocket client) custom headers. |
|
|
1164
|
-
| `:log` | (HTTP only) - logging the requests. |
|
|
1165
|
-
| `:max_body` | (HTTP only) - limits HTTP body in the response, see {listen}. |
|
|
1166
|
-
| `:max_headers` | (HTTP only) - limits the header length in the response, see {listen}. |
|
|
1167
|
-
| `:max_msg` | (WebSockets only) maximum incoming message size pre message (in Kb). |
|
|
1168
|
-
| `:method` | (HTTP client) a String such as "GET" or "POST". |
|
|
1169
|
-
| `:path` |HTTP/WebSocket client) the HTTP path to be used. |
|
|
1170
|
-
| `:ping` | ping interval (in seconds). Up to 255 seconds. |
|
|
1171
|
-
| `:port` | port number to listen to either a String or Number) |
|
|
1172
|
-
| `:public` | (public folder, HTTP server only) |
|
|
1173
|
-
| `:service` | (`:raw` / `:tls` / `:ws` / `:wss` ) |
|
|
1174
|
-
| `:timeout` | (HTTP only) keep-alive timeout in seconds. Up to 255 seconds. |
|
|
1175
|
-
| `:tls` | an {Iodine::TLS} context object for encrypted connections. |
|
|
1176
|
-
|
|
1177
|
-
Some connection settings are only valid for HTTP / WebSocket connections.
|
|
1178
|
-
|
|
1179
|
-
If `:url` is provided, it will overwrite the `:address`, `:port` and `:path` settings (if provided).
|
|
1180
|
-
|
|
1181
|
-
Unlike {Iodine.listen}, a block can't be used and a `:handler` object **must** be provided.
|
|
1182
|
-
|
|
1183
|
-
If the connection fails, only the `on_close` callback will be called (with a `nil` client).
|
|
1184
|
-
|
|
1185
|
-
Here's an example TCP/IP client that sends a simple HTTP GET request:
|
|
1186
|
-
|
|
1187
|
-
# use a secure connection?
|
|
1188
|
-
USE_TLS = false
|
|
1189
|
-
|
|
1190
|
-
# remote server details
|
|
1191
|
-
$port = USE_TLS ? 443 : 80
|
|
1192
|
-
$address = "google.com"
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
# require iodine
|
|
1196
|
-
require 'iodine'
|
|
1197
|
-
|
|
1198
|
-
# Iodine runtime settings
|
|
1199
|
-
Iodine.threads = 1
|
|
1200
|
-
Iodine.workers = 1
|
|
1201
|
-
Iodine.verbosity = 3 # warnings only
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
# a client callback handler
|
|
1205
|
-
module Client
|
|
1206
|
-
|
|
1207
|
-
def self.on_open(connection)
|
|
1208
|
-
# Set a connection timeout
|
|
1209
|
-
connection.timeout = 10
|
|
1210
|
-
# subscribe to the chat channel.
|
|
1211
|
-
puts "* Sending request..."
|
|
1212
|
-
connection.write "GET / HTTP/1.1\r\nHost: #{$address}\r\n\r\n"
|
|
1213
|
-
end
|
|
1214
|
-
|
|
1215
|
-
def self.on_message(connection, data)
|
|
1216
|
-
# publish the data we received
|
|
1217
|
-
STDOUT.write data
|
|
1218
|
-
# close the connection after a second... we're not really parsing anything, so it's a guess.
|
|
1219
|
-
Iodine.run_after(1000) { connection.close }
|
|
1220
|
-
end
|
|
1221
|
-
|
|
1222
|
-
def self.on_close(connection)
|
|
1223
|
-
# stop iodine
|
|
1224
|
-
Iodine.stop
|
|
1225
|
-
puts "Done."
|
|
1226
|
-
end
|
|
1227
|
-
|
|
1228
|
-
# returns the callback object (self).
|
|
1229
|
-
def self.call
|
|
1230
|
-
self
|
|
1231
|
-
end
|
|
1232
|
-
end
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
if(USE_TLS)
|
|
1237
|
-
tls = Iodine::TLS.new
|
|
1238
|
-
# ALPN blocks should return a valid calback object
|
|
1239
|
-
tls.on_protocol("http/1.1") { Client }
|
|
1240
|
-
end
|
|
1241
|
-
|
|
1242
|
-
Iodine.connect(address: $address, port: $port, handler: Client, tls: tls)
|
|
1243
|
-
|
|
1244
|
-
# start the iodine reactor
|
|
1245
|
-
Iodine.start
|
|
1246
|
-
|
|
1247
|
-
Iodine also supports WebSocket client connections, using either the `url` property or the `ws` and `wss` service names.
|
|
1248
|
-
|
|
1249
|
-
The following example establishes a secure (TLS) connects to the WebSocket echo testing server at `wss://echo.websocket.org`:
|
|
1250
|
-
|
|
1251
|
-
# require iodine
|
|
1252
|
-
require 'iodine'
|
|
1253
|
-
|
|
1254
|
-
# The client class
|
|
1255
|
-
class EchoClient
|
|
1256
|
-
|
|
1257
|
-
def on_open(connection)
|
|
1258
|
-
@messages = [ "Hello World!",
|
|
1259
|
-
"I'm alive and sending messages",
|
|
1260
|
-
"I also receive messages",
|
|
1261
|
-
"now that we all know this...",
|
|
1262
|
-
"I can stop.",
|
|
1263
|
-
"Goodbye." ]
|
|
1264
|
-
send_one_message(connection)
|
|
1265
|
-
end
|
|
1266
|
-
|
|
1267
|
-
def on_message(connection, message)
|
|
1268
|
-
puts "Received: #{message}"
|
|
1269
|
-
send_one_message(connection)
|
|
1270
|
-
end
|
|
1271
|
-
|
|
1272
|
-
def on_close(connection)
|
|
1273
|
-
# in this example, we stop iodine once the client is closed
|
|
1274
|
-
puts "* Client closed."
|
|
1275
|
-
Iodine.stop
|
|
1276
|
-
end
|
|
1277
|
-
|
|
1278
|
-
# We use this method to pop messages from the queue and send them
|
|
1279
|
-
#
|
|
1280
|
-
# When the queue is empty, we disconnect the client.
|
|
1281
|
-
def send_one_message(connection)
|
|
1282
|
-
msg = @messages.shift
|
|
1283
|
-
if(msg)
|
|
1284
|
-
connection.write msg
|
|
1285
|
-
else
|
|
1286
|
-
connection.close
|
|
1287
|
-
end
|
|
1288
|
-
end
|
|
1289
|
-
end
|
|
1290
|
-
|
|
1291
|
-
Iodine.threads = 1
|
|
1292
|
-
Iodine.connect url: "wss://echo.websocket.org", handler: EchoClient.new, ping: 40
|
|
1293
|
-
Iodine.start
|
|
1294
|
-
|
|
1295
|
-
**Note**: the `on_close` callback is always called, even if a connection couldn't be established.
|
|
1296
|
-
|
|
1297
|
-
Returns the handler object used.
|
|
1298
|
-
*/
|
|
1299
|
-
static VALUE iodine_connect(VALUE self, VALUE args) {
|
|
1300
|
-
// clang-format on
|
|
1301
|
-
iodine_connection_args_s s = iodine_connect_args(args, 0);
|
|
1302
|
-
intptr_t uuid = -1;
|
|
1303
|
-
switch (s.service) {
|
|
1304
|
-
case IODINE_SERVICE_RAW:
|
|
1305
|
-
uuid = iodine_tcp_connect(s);
|
|
1306
|
-
break;
|
|
1307
|
-
case IODINE_SERVICE_HTTP:
|
|
1308
|
-
iodine_connect_args_cleanup(&s);
|
|
1309
|
-
rb_raise(rb_eRuntimeError, "HTTP client connections aren't supported yet.");
|
|
1310
|
-
return Qnil;
|
|
1311
|
-
break;
|
|
1312
|
-
case IODINE_SERVICE_WS:
|
|
1313
|
-
uuid = iodine_ws_connect(s);
|
|
1314
|
-
break;
|
|
1315
|
-
}
|
|
1316
|
-
iodine_connect_args_cleanup(&s);
|
|
1317
|
-
if (uuid == -1)
|
|
1318
|
-
rb_raise(rb_eRuntimeError, "Couldn't open client socket.");
|
|
1319
|
-
return self;
|
|
1320
119
|
}
|
|
1321
120
|
|
|
1322
121
|
/* *****************************************************************************
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
Here we connect all the C code to the Ruby interface, completing the bridge
|
|
1326
|
-
between Lib-Server and Ruby.
|
|
122
|
+
Initialize Extension
|
|
1327
123
|
***************************************************************************** */
|
|
1328
|
-
void Init_iodine_ext(void) {
|
|
1329
|
-
/* common Symbol objects in use by Iodine */
|
|
1330
|
-
#define IODINE_MAKE_SYM(name) \
|
|
1331
|
-
do { \
|
|
1332
|
-
name##_sym = rb_id2sym(rb_intern(#name)); \
|
|
1333
|
-
rb_global_variable(&name##_sym); \
|
|
1334
|
-
} while (0)
|
|
1335
|
-
IODINE_MAKE_SYM(address);
|
|
1336
|
-
IODINE_MAKE_SYM(app);
|
|
1337
|
-
IODINE_MAKE_SYM(body);
|
|
1338
|
-
IODINE_MAKE_SYM(cookies);
|
|
1339
|
-
IODINE_MAKE_SYM(handler);
|
|
1340
|
-
IODINE_MAKE_SYM(headers);
|
|
1341
|
-
IODINE_MAKE_SYM(log);
|
|
1342
|
-
IODINE_MAKE_SYM(max_body);
|
|
1343
|
-
IODINE_MAKE_SYM(max_clients);
|
|
1344
|
-
IODINE_MAKE_SYM(max_headers);
|
|
1345
|
-
IODINE_MAKE_SYM(max_msg);
|
|
1346
|
-
IODINE_MAKE_SYM(method);
|
|
1347
|
-
IODINE_MAKE_SYM(path);
|
|
1348
|
-
IODINE_MAKE_SYM(ping);
|
|
1349
|
-
IODINE_MAKE_SYM(port);
|
|
1350
|
-
IODINE_MAKE_SYM(public);
|
|
1351
|
-
IODINE_MAKE_SYM(service);
|
|
1352
|
-
IODINE_MAKE_SYM(timeout);
|
|
1353
|
-
IODINE_MAKE_SYM(tls);
|
|
1354
|
-
IODINE_MAKE_SYM(url);
|
|
1355
124
|
|
|
1356
|
-
|
|
125
|
+
void Init_iodine(void) {
|
|
1357
126
|
patch_env();
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
127
|
+
IODINE_THREAD_POOL = (fio_io_async_s)FIO_IO_ASYN_INIT;
|
|
128
|
+
fio_state_callback_force(FIO_CALL_ON_INITIALIZE);
|
|
129
|
+
|
|
130
|
+
IodineUTF8Encoding = rb_enc_find("UTF-8");
|
|
131
|
+
IodineBinaryEncoding = rb_enc_find("binary");
|
|
132
|
+
|
|
133
|
+
/** The Iodine module is where it all happens. */
|
|
134
|
+
iodine_rb_IODINE = rb_define_module("Iodine");
|
|
135
|
+
STORE.hold(iodine_rb_IODINE);
|
|
136
|
+
/** The PubSub module contains Pub/Sub related classes / data. */
|
|
137
|
+
iodine_rb_IODINE_PUBSUB = rb_define_module_under(iodine_rb_IODINE, "PubSub");
|
|
138
|
+
STORE.hold(iodine_rb_IODINE_PUBSUB);
|
|
139
|
+
/** The Iodine::Base module is for internal concerns. */
|
|
140
|
+
iodine_rb_IODINE_BASE =
|
|
141
|
+
rb_define_class_under(iodine_rb_IODINE, "Base", rb_cObject);
|
|
142
|
+
rb_undef_alloc_func(iodine_rb_IODINE_BASE);
|
|
143
|
+
STORE.hold(iodine_rb_IODINE_BASE);
|
|
144
|
+
/** The Iodine::Base::App404 module is for static file only. */
|
|
145
|
+
iodine_rb_IODINE_BASE_APP404 =
|
|
146
|
+
rb_define_module_under(iodine_rb_IODINE_BASE, "App404");
|
|
147
|
+
STORE.hold(iodine_rb_IODINE_BASE_APP404);
|
|
148
|
+
{ /** Initialize `STORE` and object reference counting. */
|
|
149
|
+
iodine_setup_value_reference_counter(iodine_rb_IODINE_BASE);
|
|
150
|
+
rb_define_singleton_method(iodine_rb_IODINE_BASE,
|
|
151
|
+
"print_debug",
|
|
152
|
+
iodine_store___print_debug,
|
|
153
|
+
0);
|
|
154
|
+
rb_define_singleton_method(iodine_rb_IODINE_BASE,
|
|
155
|
+
"store_size",
|
|
156
|
+
iodine_store___held_count,
|
|
157
|
+
0);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
IODINE_CONST_ID_STORE(IODINE_CALL_ID, "call");
|
|
161
|
+
IODINE_CONST_ID_STORE(IODINE_CLOSE_ID, "close");
|
|
162
|
+
IODINE_CONST_ID_STORE(IODINE_EACH_ID, "each");
|
|
163
|
+
IODINE_CONST_ID_STORE(IODINE_FILENO_ID, "fileno");
|
|
164
|
+
IODINE_CONST_ID_STORE(IODINE_NEW_ID, "new");
|
|
165
|
+
IODINE_CONST_ID_STORE(IODINE_CURRENT_ID, "current");
|
|
166
|
+
IODINE_CONST_ID_STORE(IODINE_JOIN_ID, "join");
|
|
167
|
+
IODINE_CONST_ID_STORE(IODINE_TO_PATH_ID, "to_path");
|
|
168
|
+
IODINE_CONST_ID_STORE(IODINE_TO_S_ID, "to_s");
|
|
169
|
+
IODINE_CONST_ID_STORE(IODINE_TO_JSON_ID, "to_json");
|
|
170
|
+
|
|
171
|
+
IODINE_CONST_ID_STORE(IODINE_INDEX_ID, "index");
|
|
172
|
+
IODINE_CONST_ID_STORE(IODINE_SHOW_ID, "show");
|
|
173
|
+
IODINE_CONST_ID_STORE(IODINE_EDIT_ID, "edit");
|
|
174
|
+
IODINE_CONST_ID_STORE(IODINE_CREATE_ID, "create");
|
|
175
|
+
IODINE_CONST_ID_STORE(IODINE_UPDATE_ID, "update");
|
|
176
|
+
IODINE_CONST_ID_STORE(IODINE_DELETE_ID, "delete");
|
|
177
|
+
|
|
178
|
+
IODINE_CONST_ID_STORE(IODINE_RACK_HIJACK_ID, "rack_hijack");
|
|
179
|
+
IODINE_CONST_ID_STORE(IODINE_ON_AUTHENTICATE_ID, "on_authenticate");
|
|
180
|
+
IODINE_CONST_ID_STORE(IODINE_ON_AUTHENTICATE_SSE_ID, "on_authenticate_sse");
|
|
181
|
+
IODINE_CONST_ID_STORE(IODINE_ON_AUTHENTICATE_WEBSOCKET_ID,
|
|
182
|
+
"on_authenticate_websocket");
|
|
183
|
+
IODINE_CONST_ID_STORE(IODINE_ON_CLOSE_ID, "on_close");
|
|
184
|
+
IODINE_CONST_ID_STORE(IODINE_ON_DATA_ID, "on_data");
|
|
185
|
+
IODINE_CONST_ID_STORE(IODINE_ON_DRAINED_ID, "on_drained");
|
|
186
|
+
IODINE_CONST_ID_STORE(IODINE_ON_EVENTSOURCE_ID, "on_eventsource");
|
|
187
|
+
IODINE_CONST_ID_STORE(IODINE_ON_EVENTSOURCE_RECONNECT_ID,
|
|
188
|
+
"on_eventsource_reconnect");
|
|
189
|
+
IODINE_CONST_ID_STORE(IODINE_ON_FINISH_ID, "on_finish");
|
|
190
|
+
IODINE_CONST_ID_STORE(IODINE_ON_HTTP_ID, "on_http");
|
|
191
|
+
IODINE_CONST_ID_STORE(IODINE_ON_MESSAGE_ID, "on_message");
|
|
192
|
+
IODINE_CONST_ID_STORE(IODINE_ON_OPEN_ID, "on_open");
|
|
193
|
+
IODINE_CONST_ID_STORE(IODINE_ON_SHUTDOWN_ID, "on_shutdown");
|
|
194
|
+
IODINE_CONST_ID_STORE(IODINE_ON_TIMEOUT_ID, "on_timeout");
|
|
195
|
+
IODINE_CONST_ID_STORE(IODINE_QUERY_ID, "query");
|
|
196
|
+
|
|
197
|
+
IODINE_CONST_ID_STORE(IODINE_STATE_PRE_START, "pre_start");
|
|
198
|
+
IODINE_CONST_ID_STORE(IODINE_STATE_BEFORE_FORK, "before_fork");
|
|
199
|
+
IODINE_CONST_ID_STORE(IODINE_STATE_AFTER_FORK, "after_fork");
|
|
200
|
+
IODINE_CONST_ID_STORE(IODINE_STATE_ENTER_CHILD, "enter_child");
|
|
201
|
+
IODINE_CONST_ID_STORE(IODINE_STATE_ENTER_MASTER, "enter_master");
|
|
202
|
+
IODINE_CONST_ID_STORE(IODINE_STATE_ON_START, "start");
|
|
203
|
+
IODINE_CONST_ID_STORE(IODINE_STATE_ON_PARENT_CRUSH, "parent_crush");
|
|
204
|
+
IODINE_CONST_ID_STORE(IODINE_STATE_ON_CHILD_CRUSH, "child_crush");
|
|
205
|
+
IODINE_CONST_ID_STORE(IODINE_STATE_ON_SHUTDOWN, "shutdown");
|
|
206
|
+
IODINE_CONST_ID_STORE(IODINE_STATE_ON_STOP, "stop");
|
|
207
|
+
IODINE_CONST_ID_STORE(IODINE_STATE_ON_IDLE, "idle");
|
|
208
|
+
IODINE_CONST_ID_STORE(IODINE_STATE_ON_EXIT, "exit");
|
|
209
|
+
|
|
210
|
+
STORE.hold(IODINE_RACK_HIJACK_ID_SYM = rb_id2sym(IODINE_RACK_HIJACK_ID));
|
|
211
|
+
STORE.hold(IODINE_RACK_HIJACK_SYM = rb_id2sym(rb_intern("rack.hijack")));
|
|
212
|
+
STORE.hold(IODINE_RACK_HIJACK_STR = rb_sym_to_s(IODINE_RACK_HIJACK_SYM));
|
|
213
|
+
|
|
214
|
+
IODINE_RACK_PROTOCOL_STR =
|
|
215
|
+
STORE.frozen_str(FIO_STR_INFO1((char *)"rack.protocol"));
|
|
216
|
+
IODINE_RACK_UPGRADE_STR =
|
|
217
|
+
STORE.frozen_str(FIO_STR_INFO1((char *)"rack.upgrade"));
|
|
218
|
+
IODINE_RACK_UPGRADE_Q_STR =
|
|
219
|
+
STORE.frozen_str(FIO_STR_INFO1((char *)"rack.upgrade?"));
|
|
220
|
+
STORE.hold(IODINE_RACK_UPGRADE_WS_SYM = rb_id2sym(rb_intern("websocket")));
|
|
221
|
+
STORE.hold(IODINE_RACK_UPGRADE_SSE_SYM = rb_id2sym(rb_intern("sse")));
|
|
222
|
+
STORE.hold(IODINE_RACK_AFTER_RPLY_STR =
|
|
223
|
+
rb_str_new_static("rack.after_reply", 16));
|
|
224
|
+
|
|
225
|
+
Init_Iodine();
|
|
226
|
+
Init_Iodine_Base_CLI();
|
|
227
|
+
Init_Iodine_Compression();
|
|
228
|
+
Init_Iodine_Crypto();
|
|
229
|
+
Init_Iodine_Mustache();
|
|
230
|
+
Init_Iodine_Utils();
|
|
231
|
+
Init_Iodine_JSON();
|
|
232
|
+
Init_Iodine_Listener();
|
|
233
|
+
Init_Iodine_Logger();
|
|
234
|
+
Init_Iodine_MiniMap();
|
|
235
|
+
Init_Iodine_PubSub_Engine();
|
|
236
|
+
Init_Iodine_PubSub_Subscription();
|
|
237
|
+
Init_Iodine_PubSub_History();
|
|
238
|
+
Init_Iodine_RESP3();
|
|
239
|
+
Init_Iodine_PubSub_Message();
|
|
240
|
+
Init_Iodine_TLS();
|
|
241
|
+
Init_Iodine_Connection();
|
|
242
|
+
/* make sure the Iodine.run / async methods are available pre-start */
|
|
243
|
+
fio_io_async_attach(&IODINE_THREAD_POOL, (uint32_t)fio_cli_get_i("-t"));
|
|
244
|
+
#ifdef SIGUSR1
|
|
245
|
+
/* support hot restarting of workers */
|
|
246
|
+
fio_io_restart_on_signal(SIGUSR1);
|
|
1416
247
|
#endif
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
iodine_init_json();
|
|
1420
|
-
|
|
1421
|
-
// initialize Mustache engine
|
|
1422
|
-
iodine_init_mustache();
|
|
1423
|
-
|
|
1424
|
-
// initialize Rack helpers and IO
|
|
1425
|
-
iodine_init_helpers();
|
|
1426
|
-
IodineRackIO.init();
|
|
1427
|
-
|
|
1428
|
-
// initialize Pub/Sub extension (for Engines)
|
|
1429
|
-
iodine_pubsub_init();
|
|
248
|
+
fio_state_callback_add(FIO_CALL_ON_STOP, iodine___worker_gc_on_stop, NULL);
|
|
249
|
+
rb_set_end_proc(iodine___perform_exit, (VALUE)Qnil);
|
|
1430
250
|
}
|