iodine 0.7.60 → 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 -21
- 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 -148
- 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.h
CHANGED
|
@@ -1,63 +1,258 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @file iodine.h
|
|
3
|
+
* @brief Main header file for the Iodine Ruby C extension.
|
|
4
|
+
*
|
|
5
|
+
* This file serves as the central include point for the Iodine HTTP/WebSocket
|
|
6
|
+
* server extension. It includes Ruby headers, defines global constants and
|
|
7
|
+
* symbols, configures the facil.io C STL library, and includes all Iodine
|
|
8
|
+
* sub-modules in the correct dependency order.
|
|
9
|
+
*
|
|
10
|
+
* Iodine is built on top of the facil.io C STL library (fio-stl.h) which
|
|
11
|
+
* provides the underlying IO reactor, HTTP server, WebSocket support, and
|
|
12
|
+
* various utilities.
|
|
13
|
+
*/
|
|
14
|
+
#ifndef H___IODINE___H
|
|
15
|
+
#define H___IODINE___H
|
|
16
|
+
/* *****************************************************************************
|
|
17
|
+
facil.io
|
|
18
|
+
***************************************************************************** */
|
|
19
|
+
|
|
20
|
+
/* Fix: __attribute__((weak)) doesn't work correctly on Windows PE/COFF
|
|
21
|
+
(MinGW DLLs) — weak symbols may not be properly allocated in the DLL's data
|
|
22
|
+
segment, causing segfaults when accessed (e.g., writing to FIO_LOG_LEVEL).
|
|
23
|
+
Since iodine compiles as a single translation unit, weak symbols are
|
|
24
|
+
unnecessary — override FIO_WEAK to empty before fio-stl.h is included. */
|
|
25
|
+
#if defined(_WIN32) || defined(__MINGW32__) || defined(__CYGWIN__)
|
|
26
|
+
#ifndef FIO_WEAK
|
|
27
|
+
#define FIO_WEAK /* empty — no weak attribute on Windows */
|
|
28
|
+
#endif
|
|
20
29
|
#endif
|
|
21
|
-
VALUE handler;
|
|
22
|
-
FIOBJ headers;
|
|
23
|
-
FIOBJ cookies;
|
|
24
|
-
size_t max_headers;
|
|
25
|
-
size_t max_body;
|
|
26
|
-
intptr_t max_clients;
|
|
27
|
-
size_t max_msg;
|
|
28
|
-
uint8_t timeout;
|
|
29
|
-
uint8_t ping;
|
|
30
|
-
uint8_t log;
|
|
31
|
-
enum {
|
|
32
|
-
IODINE_SERVICE_RAW,
|
|
33
|
-
IODINE_SERVICE_HTTP,
|
|
34
|
-
IODINE_SERVICE_WS,
|
|
35
|
-
} service;
|
|
36
|
-
} iodine_connection_args_s;
|
|
37
30
|
|
|
38
|
-
#
|
|
39
|
-
#include "
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
#
|
|
45
|
-
#include
|
|
46
|
-
|
|
47
|
-
#
|
|
48
|
-
#include
|
|
49
|
-
|
|
31
|
+
#define FIO_LEAK_COUNTER 1
|
|
32
|
+
#include "fio-stl.h"
|
|
33
|
+
|
|
34
|
+
typedef unsigned long long fio_thread_t;
|
|
35
|
+
typedef int fio_thread_pid_t;
|
|
36
|
+
|
|
37
|
+
#if defined(_WIN32) || defined(__MINGW32__) || defined(__CYGWIN__)
|
|
38
|
+
#include <synchapi.h>
|
|
39
|
+
typedef CONDITION_VARIABLE fio_thread_cond_t;
|
|
40
|
+
#else
|
|
41
|
+
#include <pthread.h>
|
|
42
|
+
typedef pthread_cond_t fio_thread_cond_t;
|
|
43
|
+
#endif
|
|
44
|
+
|
|
45
|
+
#define FIO_MUSTACHE_LAMBDA_SUPPORT 1
|
|
46
|
+
#define FIO_THREADS_BYO 1
|
|
47
|
+
#define FIO_THREADS_FORK_BYO 1
|
|
48
|
+
#define FIO_MEMORY_ARENA_COUNT_MAX 4
|
|
49
|
+
#define FIO_EVERYTHING
|
|
50
|
+
|
|
51
|
+
#ifndef DEBUG
|
|
52
|
+
// #undef FIO_LEAK_COUNTER_SKIP_EXIT
|
|
53
|
+
// #define FIO_LEAK_COUNTER_SKIP_EXIT 1
|
|
54
|
+
/* Ruby doesn't always free everything pre-cleanup, so no point in counting */
|
|
55
|
+
// #undef FIO_LEAK_COUNTER
|
|
56
|
+
// #define FIO_LEAK_COUNTER 0
|
|
57
|
+
#endif
|
|
58
|
+
|
|
59
|
+
#include FIO_INCLUDE_FILE
|
|
60
|
+
|
|
61
|
+
#ifndef DEBUG
|
|
62
|
+
#endif
|
|
50
63
|
|
|
51
64
|
/* *****************************************************************************
|
|
52
|
-
|
|
65
|
+
Ruby
|
|
53
66
|
***************************************************************************** */
|
|
54
|
-
extern VALUE IodineModule;
|
|
55
|
-
extern VALUE IodineBaseModule;
|
|
56
|
-
extern VALUE iodine_default_args;
|
|
57
|
-
extern ID iodine_call_id;
|
|
58
|
-
extern ID iodine_to_s_id;
|
|
59
67
|
|
|
60
|
-
#
|
|
61
|
-
|
|
68
|
+
#include <ruby.h>
|
|
69
|
+
#include <ruby/encoding.h>
|
|
70
|
+
#include <ruby/intern.h>
|
|
71
|
+
#include <ruby/io.h>
|
|
72
|
+
#include <ruby/thread.h>
|
|
62
73
|
|
|
74
|
+
/* ruby_thread_has_gvl_p() exists since Ruby 2.x but was only publicly declared
|
|
75
|
+
in ruby/thread.h starting with Ruby 4.0. On older Rubies, provide our own
|
|
76
|
+
declaration to avoid implicit-function-declaration errors on Windows/macOS.
|
|
77
|
+
On Ruby 4.0+, rb_thread_call_with_gvl() is GVL-lenient (safe to call whether
|
|
78
|
+
or not the GVL is held), so the check is unnecessary — but we still declare
|
|
79
|
+
it to keep the code unconditionally compilable. */
|
|
80
|
+
#if RUBY_API_VERSION_MAJOR < 4
|
|
81
|
+
int ruby_thread_has_gvl_p(void);
|
|
63
82
|
#endif
|
|
83
|
+
|
|
84
|
+
/* *****************************************************************************
|
|
85
|
+
Ruby Method ID Constants
|
|
86
|
+
|
|
87
|
+
These IDs are cached for efficient Ruby method calls from C code.
|
|
88
|
+
They are initialized in Init_iodine() using IODINE_CONST_ID_STORE().
|
|
89
|
+
***************************************************************************** */
|
|
90
|
+
|
|
91
|
+
/** @brief Cached Ruby method ID for `call` */
|
|
92
|
+
static ID IODINE_CALL_ID;
|
|
93
|
+
static ID IODINE_CLOSE_ID;
|
|
94
|
+
static ID IODINE_EACH_ID;
|
|
95
|
+
static ID IODINE_FILENO_ID;
|
|
96
|
+
static ID IODINE_NEW_ID;
|
|
97
|
+
static ID IODINE_CURRENT_ID;
|
|
98
|
+
static ID IODINE_JOIN_ID;
|
|
99
|
+
static ID IODINE_TO_PATH_ID;
|
|
100
|
+
static ID IODINE_TO_S_ID;
|
|
101
|
+
static ID IODINE_TO_JSON_ID;
|
|
102
|
+
static ID IODINE_RACK_HIJACK_ID;
|
|
103
|
+
static ID IODINE_ON_AUTHENTICATE_ID;
|
|
104
|
+
static ID IODINE_ON_AUTHENTICATE_SSE_ID;
|
|
105
|
+
static ID IODINE_ON_AUTHENTICATE_WEBSOCKET_ID;
|
|
106
|
+
static ID IODINE_ON_CLOSE_ID;
|
|
107
|
+
static ID IODINE_ON_DATA_ID;
|
|
108
|
+
static ID IODINE_ON_DRAINED_ID;
|
|
109
|
+
static ID IODINE_ON_EVENTSOURCE_ID;
|
|
110
|
+
static ID IODINE_ON_EVENTSOURCE_RECONNECT_ID;
|
|
111
|
+
static ID IODINE_ON_FINISH_ID;
|
|
112
|
+
static ID IODINE_ON_HTTP_ID;
|
|
113
|
+
static ID IODINE_ON_MESSAGE_ID;
|
|
114
|
+
static ID IODINE_ON_OPEN_ID;
|
|
115
|
+
static ID IODINE_ON_SHUTDOWN_ID;
|
|
116
|
+
static ID IODINE_ON_TIMEOUT_ID;
|
|
117
|
+
static ID IODINE_QUERY_ID;
|
|
118
|
+
|
|
119
|
+
static ID IODINE_INDEX_ID;
|
|
120
|
+
static ID IODINE_SHOW_ID;
|
|
121
|
+
// static ID IODINE_NEW_ID;
|
|
122
|
+
static ID IODINE_EDIT_ID;
|
|
123
|
+
static ID IODINE_CREATE_ID;
|
|
124
|
+
static ID IODINE_UPDATE_ID;
|
|
125
|
+
static ID IODINE_DELETE_ID;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Stores a Ruby method ID constant and protects its Symbol from GC.
|
|
129
|
+
*
|
|
130
|
+
* @param name The C variable name to store the ID in.
|
|
131
|
+
* @param value The Ruby method name as a C string.
|
|
132
|
+
*/
|
|
133
|
+
#define IODINE_CONST_ID_STORE(name, value) \
|
|
134
|
+
name = rb_intern(value); \
|
|
135
|
+
STORE.hold(RB_ID2SYM(name));
|
|
136
|
+
|
|
137
|
+
static VALUE iodine_rb_IODINE;
|
|
138
|
+
static VALUE iodine_rb_IODINE_BASE;
|
|
139
|
+
static VALUE iodine_rb_IODINE_BASE_APP404;
|
|
140
|
+
static VALUE iodine_rb_IODINE_CONNECTION;
|
|
141
|
+
static VALUE iodine_rb_IODINE_PUBSUB;
|
|
142
|
+
static VALUE iodine_rb_IODINE_PUBSUB_ENG;
|
|
143
|
+
static VALUE iodine_rb_IODINE_PUBSUB_MSG;
|
|
144
|
+
static VALUE iodine_rb_IODINE_PUBSUB_SUB;
|
|
145
|
+
static VALUE iodine_rb_IODINE_TLS;
|
|
146
|
+
static rb_encoding *IodineUTF8Encoding;
|
|
147
|
+
static rb_encoding *IodineBinaryEncoding;
|
|
148
|
+
|
|
149
|
+
static VALUE IODINE_CONNECTION_ENV_TEMPLATE = Qnil;
|
|
150
|
+
static VALUE IODINE_CONNECTION_ENV_TEMPLATE_HTTPS = Qnil;
|
|
151
|
+
static VALUE IODINE_RACK_PROTOCOL_STR;
|
|
152
|
+
static VALUE IODINE_RACK_HIJACK_ID_SYM;
|
|
153
|
+
static VALUE IODINE_RACK_HIJACK_STR;
|
|
154
|
+
static VALUE IODINE_RACK_HIJACK_SYM;
|
|
155
|
+
static VALUE IODINE_RACK_UPGRADE_STR;
|
|
156
|
+
static VALUE IODINE_RACK_UPGRADE_Q_STR;
|
|
157
|
+
static VALUE IODINE_RACK_UPGRADE_WS_SYM;
|
|
158
|
+
static VALUE IODINE_RACK_UPGRADE_SSE_SYM;
|
|
159
|
+
static VALUE IODINE_RACK_AFTER_RPLY_STR;
|
|
160
|
+
|
|
161
|
+
/** Buffer size for raw TCP/IP connection data reads (16KB default). */
|
|
162
|
+
#ifndef IODINE_RAW_ON_DATA_READ_BUFFER
|
|
163
|
+
#define IODINE_RAW_ON_DATA_READ_BUFFER (1ULL << 14)
|
|
164
|
+
#endif
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Returns true if the Ruby VALUE should be skipped for GC store operations.
|
|
168
|
+
* Immediate values (nil, true, false, fixnums) don't need GC protection.
|
|
169
|
+
*/
|
|
170
|
+
#define IODINE_STORE_IS_SKIP(o) \
|
|
171
|
+
(!o || o == Qnil || o == Qtrue || o == Qfalse || TYPE(o) == RUBY_T_FIXNUM)
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Converts a Ruby String to a fio_str_info_s struct.
|
|
175
|
+
* @note The Ruby String must remain valid while the struct is in use.
|
|
176
|
+
*/
|
|
177
|
+
#define IODINE_RSTR_INFO(o) \
|
|
178
|
+
{ .buf = RSTRING_PTR(o), .len = (size_t)RSTRING_LEN(o) }
|
|
179
|
+
|
|
180
|
+
/* *****************************************************************************
|
|
181
|
+
Deferring Ruby Blocks
|
|
182
|
+
|
|
183
|
+
Provides macros for scheduling Ruby blocks to run asynchronously in the
|
|
184
|
+
IO reactor's thread pool.
|
|
185
|
+
***************************************************************************** */
|
|
186
|
+
|
|
187
|
+
/** Forward declaration for async block execution callback. */
|
|
188
|
+
static void iodine_defer_performe_once(void *block, void *ignr);
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Schedules a Ruby block (Proc) to run asynchronously in the thread pool.
|
|
192
|
+
*
|
|
193
|
+
* The block is protected from GC until execution completes.
|
|
194
|
+
*
|
|
195
|
+
* @param blk A Ruby VALUE representing a Proc object.
|
|
196
|
+
*/
|
|
197
|
+
#define IODINE_DEFER_BLOCK(blk) \
|
|
198
|
+
do { \
|
|
199
|
+
STORE.hold((blk)); \
|
|
200
|
+
fio_io_async(&IODINE_THREAD_POOL, \
|
|
201
|
+
iodine_defer_performe_once, \
|
|
202
|
+
(void *)(blk)); \
|
|
203
|
+
} while (0)
|
|
204
|
+
|
|
205
|
+
/* *****************************************************************************
|
|
206
|
+
Leak Counters
|
|
207
|
+
***************************************************************************** */
|
|
208
|
+
FIO_LEAK_COUNTER_DEF(iodine_connection)
|
|
209
|
+
FIO_LEAK_COUNTER_DEF(iodine_minimap)
|
|
210
|
+
FIO_LEAK_COUNTER_DEF(iodine_mustache)
|
|
211
|
+
FIO_LEAK_COUNTER_DEF(iodine_pubsub_msg)
|
|
212
|
+
FIO_LEAK_COUNTER_DEF(iodine_pubsub_sub)
|
|
213
|
+
// FIO_LEAK_COUNTER_DEF(iodine_pubsub_eng) /* Ruby doesn't free */
|
|
214
|
+
FIO_LEAK_COUNTER_DEF(iodine_hmap)
|
|
215
|
+
|
|
216
|
+
/* *****************************************************************************
|
|
217
|
+
Common Iodine Helpers
|
|
218
|
+
|
|
219
|
+
Core infrastructure shared across all Iodine modules.
|
|
220
|
+
***************************************************************************** */
|
|
221
|
+
|
|
222
|
+
/** The global IO reactor thread pool for async task execution. */
|
|
223
|
+
static fio_io_async_s IODINE_THREAD_POOL;
|
|
224
|
+
|
|
225
|
+
static VALUE iodine_handler_method_injection__inner(VALUE self,
|
|
226
|
+
VALUE handler,
|
|
227
|
+
bool is_middleware);
|
|
228
|
+
/* Core GC protection */
|
|
229
|
+
#include "iodine_store.h"
|
|
230
|
+
/* layer 1 helpers */
|
|
231
|
+
#include "iodine_arg_helper.h"
|
|
232
|
+
/* layer 2 helpers */
|
|
233
|
+
#include "iodine_caller.h"
|
|
234
|
+
#include "iodine_json.h"
|
|
235
|
+
#include "iodine_listener.h"
|
|
236
|
+
#include "iodine_pubsub_msg.h"
|
|
237
|
+
#include "iodine_utils.h"
|
|
238
|
+
/* layer 1 modules */
|
|
239
|
+
#include "iodine_cli.h"
|
|
240
|
+
#include "iodine_defer.h"
|
|
241
|
+
#include "iodine_log.h"
|
|
242
|
+
#include "iodine_minimap.h"
|
|
243
|
+
/* layer 2 modules */
|
|
244
|
+
#include "iodine_compression.h"
|
|
245
|
+
#include "iodine_crypto.h"
|
|
246
|
+
#include "iodine_mustache.h"
|
|
247
|
+
#include "iodine_pubsub_eng.h"
|
|
248
|
+
#include "iodine_pubsub_history.h"
|
|
249
|
+
#include "iodine_redis.h"
|
|
250
|
+
#include "iodine_threads.h"
|
|
251
|
+
#include "iodine_tls.h"
|
|
252
|
+
/* layer 3 modules */
|
|
253
|
+
#include "iodine_connection.h"
|
|
254
|
+
|
|
255
|
+
/* layer 4 modules */
|
|
256
|
+
#include "iodine_core.h"
|
|
257
|
+
|
|
258
|
+
#endif /* H___IODINE___H */
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
#ifndef H___IODINE_ARG_HELPER___H
|
|
2
|
+
#define H___IODINE_ARG_HELPER___H
|
|
3
|
+
#include "iodine.h"
|
|
4
|
+
|
|
5
|
+
/* *****************************************************************************
|
|
6
|
+
Ruby Multi-Argument Helper
|
|
7
|
+
|
|
8
|
+
Reads and validates method arguments (either "splat" or Hash Map).
|
|
9
|
+
|
|
10
|
+
iodine_rb2c_arg(argc, argv,
|
|
11
|
+
IODINE_ARG_RB(var_name, id_or_0, "name1", 1),
|
|
12
|
+
IODINE_ARG_STR(var_name, id_or_0, "name2", 0),
|
|
13
|
+
IODINE_ARG_NUM(var_name, id_or_0, "name3", 0),
|
|
14
|
+
IODINE_ARG_PROC(var_name, id_or_0, "name4", 0));
|
|
15
|
+
|
|
16
|
+
The `IODINE_ARG_XXX` macro arguments are as follows:
|
|
17
|
+
|
|
18
|
+
IODINE_ARG_XXX(target_varriable, id_or_0, named_argument, required)
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
|
|
22
|
+
fio_buf_info_s file_name = {0};
|
|
23
|
+
fio_buf_info_s file_content = {0};
|
|
24
|
+
VALUE on_yaml_block = Qnil;
|
|
25
|
+
iodine_rb2c_arg(argc, argv,
|
|
26
|
+
IODINE_ARG_STR(file_name, 0, "file", 0),
|
|
27
|
+
IODINE_ARG_STR(file_content, 0, "data", 0),
|
|
28
|
+
IODINE_ARG_PROC(on_yaml_block, 0, "on_yaml", 1));
|
|
29
|
+
|
|
30
|
+
For Ruby methods declared as:
|
|
31
|
+
|
|
32
|
+
static VALUE my_method(int argc, VALUE *argv, VALUE klass);
|
|
33
|
+
rb_define_singleton_method(klass, "method", my_method, -1);
|
|
34
|
+
|
|
35
|
+
***************************************************************************** */
|
|
36
|
+
|
|
37
|
+
/* *****************************************************************************
|
|
38
|
+
Ruby arguments to C arguments
|
|
39
|
+
***************************************************************************** */
|
|
40
|
+
|
|
41
|
+
typedef struct {
|
|
42
|
+
int expected_type;
|
|
43
|
+
union {
|
|
44
|
+
VALUE *rb;
|
|
45
|
+
fio_buf_info_s *buf;
|
|
46
|
+
fio_str_info_s *str;
|
|
47
|
+
int64_t *num;
|
|
48
|
+
size_t *zu;
|
|
49
|
+
int32_t *i32;
|
|
50
|
+
int16_t *i16;
|
|
51
|
+
int8_t *i8;
|
|
52
|
+
uint64_t *u64;
|
|
53
|
+
uint32_t *u32;
|
|
54
|
+
uint16_t *u16;
|
|
55
|
+
uint8_t *u8;
|
|
56
|
+
};
|
|
57
|
+
ID id;
|
|
58
|
+
fio_buf_info_s name;
|
|
59
|
+
int required;
|
|
60
|
+
} iodine_rb2c_arg_s;
|
|
61
|
+
|
|
62
|
+
#define IODINE_ARG_RB(t_var, id_, name_, required_) \
|
|
63
|
+
{ \
|
|
64
|
+
.expected_type = 0, .rb = &(t_var), .id = (id_), \
|
|
65
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
66
|
+
}
|
|
67
|
+
#define IODINE_ARG_BUF(t_var, id_, name_, required_) \
|
|
68
|
+
{ \
|
|
69
|
+
.expected_type = 1, .buf = &(t_var), .id = (id_), \
|
|
70
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
71
|
+
}
|
|
72
|
+
#define IODINE_ARG_STR(t_var, id_, name_, required_) \
|
|
73
|
+
{ \
|
|
74
|
+
.expected_type = 2, .str = &(t_var), .id = (id_), \
|
|
75
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
76
|
+
}
|
|
77
|
+
#define IODINE_ARG_NUM(t_var, id_, name_, required_) \
|
|
78
|
+
{ \
|
|
79
|
+
.expected_type = 3, .num = &(t_var), .id = (id_), \
|
|
80
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
81
|
+
}
|
|
82
|
+
#define IODINE_ARG_PROC(t_var, id_, name_, required_) \
|
|
83
|
+
{ \
|
|
84
|
+
.expected_type = 4, .rb = &(t_var), .id = (id_), \
|
|
85
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
86
|
+
}
|
|
87
|
+
#define IODINE_ARG_SIZE_T(t_var, id_, name_, required_) \
|
|
88
|
+
{ \
|
|
89
|
+
.expected_type = 5, .zu = &(t_var), .id = (id_), \
|
|
90
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
91
|
+
}
|
|
92
|
+
#define IODINE_ARG_I32(t_var, id_, name_, required_) \
|
|
93
|
+
{ \
|
|
94
|
+
.expected_type = 6, .i32 = &(t_var), .id = (id_), \
|
|
95
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
96
|
+
}
|
|
97
|
+
#define IODINE_ARG_I16(t_var, id_, name_, required_) \
|
|
98
|
+
{ \
|
|
99
|
+
.expected_type = 7, .i16 = &(t_var), .id = (id_), \
|
|
100
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
101
|
+
}
|
|
102
|
+
#define IODINE_ARG_I8(t_var, id_, name_, required_) \
|
|
103
|
+
{ \
|
|
104
|
+
.expected_type = 8, .i8 = &(t_var), .id = (id_), \
|
|
105
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
106
|
+
}
|
|
107
|
+
#define IODINE_ARG_BOOL(t_var, id_, name_, required_) \
|
|
108
|
+
{ \
|
|
109
|
+
.expected_type = 9, .u8 = &(t_var), .id = (id_), \
|
|
110
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
111
|
+
}
|
|
112
|
+
#define IODINE_ARG_U64(t_var, id_, name_, required_) \
|
|
113
|
+
{ \
|
|
114
|
+
.expected_type = 10, .u64 = &(t_var), .id = (id_), \
|
|
115
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
116
|
+
}
|
|
117
|
+
#define IODINE_ARG_U32(t_var, id_, name_, required_) \
|
|
118
|
+
{ \
|
|
119
|
+
.expected_type = 11, .u32 = &(t_var), .id = (id_), \
|
|
120
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
121
|
+
}
|
|
122
|
+
#define IODINE_ARG_U16(t_var, id_, name_, required_) \
|
|
123
|
+
{ \
|
|
124
|
+
.expected_type = 12, .u16 = &(t_var), .id = (id_), \
|
|
125
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
126
|
+
}
|
|
127
|
+
#define IODINE_ARG_U8(t_var, id_, name_, required_) \
|
|
128
|
+
{ \
|
|
129
|
+
.expected_type = 13, .u8 = &(t_var), .id = (id_), \
|
|
130
|
+
.name = FIO_BUF_INFO1(((char *)name_)), .required = (required_) \
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Converts a Ruby Integer to a signed value in [min, max] or raises. */
|
|
134
|
+
static int64_t iodine___rb2c_arg2i(VALUE o,
|
|
135
|
+
int64_t min,
|
|
136
|
+
int64_t max,
|
|
137
|
+
const char *name) {
|
|
138
|
+
if (!RB_INTEGER_TYPE_P(o))
|
|
139
|
+
rb_raise(rb_eTypeError, "%s should be a Number", name);
|
|
140
|
+
long long v = NUM2LL(o); /* raises RangeError beyond int64 */
|
|
141
|
+
if (v < min || v > max)
|
|
142
|
+
rb_raise(rb_eRangeError, "%s out of range", name);
|
|
143
|
+
return (int64_t)v;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Converts a Ruby Integer to an unsigned value in [0, max] or raises. */
|
|
147
|
+
static uint64_t iodine___rb2c_arg2u(VALUE o, uint64_t max, const char *name) {
|
|
148
|
+
if (!RB_INTEGER_TYPE_P(o))
|
|
149
|
+
rb_raise(rb_eTypeError, "%s should be a Number", name);
|
|
150
|
+
uint64_t u = 0;
|
|
151
|
+
/* returns sign: -1/-2 when negative, +2 on uint64 overflow */
|
|
152
|
+
int s = rb_integer_pack(o,
|
|
153
|
+
&u,
|
|
154
|
+
1,
|
|
155
|
+
sizeof(u),
|
|
156
|
+
0,
|
|
157
|
+
INTEGER_PACK_LSWORD_FIRST |
|
|
158
|
+
INTEGER_PACK_NATIVE_BYTE_ORDER);
|
|
159
|
+
if (s < 0 || s > 1 || u > max)
|
|
160
|
+
rb_raise(rb_eRangeError, "%s out of range", name);
|
|
161
|
+
return u;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Reads and validates method arguments (either "splat" or Hash Map). */
|
|
165
|
+
static int iodine_rb2c_arg(int argc, const VALUE *argv, iodine_rb2c_arg_s *a) {
|
|
166
|
+
int i = 0;
|
|
167
|
+
VALUE tmp = Qnil;
|
|
168
|
+
|
|
169
|
+
#define IODINE_RB2C_STORE_ARG() \
|
|
170
|
+
if (!a[i].rb) \
|
|
171
|
+
goto too_many_arguments; \
|
|
172
|
+
if (tmp == Qnil && a[i].expected_type != 4) { \
|
|
173
|
+
if (a[i].required) \
|
|
174
|
+
goto missing_required; \
|
|
175
|
+
continue; \
|
|
176
|
+
} \
|
|
177
|
+
switch (a[i].expected_type) { \
|
|
178
|
+
case 0: \
|
|
179
|
+
a[i].rb[0] = tmp; \
|
|
180
|
+
STORE.cache(tmp); \
|
|
181
|
+
continue; \
|
|
182
|
+
case 1: \
|
|
183
|
+
if (RB_TYPE_P(tmp, RUBY_T_SYMBOL)) \
|
|
184
|
+
tmp = rb_sym2str(tmp); \
|
|
185
|
+
if (!RB_TYPE_P(tmp, RUBY_T_STRING)) \
|
|
186
|
+
rb_raise(rb_eTypeError, \
|
|
187
|
+
"%s should be a String (or Symbol)", \
|
|
188
|
+
a[i].name.buf); \
|
|
189
|
+
STORE.cache(tmp); \
|
|
190
|
+
a[i].buf[0] = FIO_BUF_INFO2(RSTRING_PTR(tmp), (size_t)RSTRING_LEN(tmp)); \
|
|
191
|
+
continue; \
|
|
192
|
+
case 2: \
|
|
193
|
+
if (RB_TYPE_P(tmp, RUBY_T_SYMBOL)) \
|
|
194
|
+
tmp = rb_sym2str(tmp); \
|
|
195
|
+
if (!RB_TYPE_P(tmp, RUBY_T_STRING)) \
|
|
196
|
+
rb_raise(rb_eTypeError, \
|
|
197
|
+
"%s should be a String (or Symbol)", \
|
|
198
|
+
a[i].name.buf); \
|
|
199
|
+
STORE.cache(tmp); \
|
|
200
|
+
a[i].str[0] = FIO_STR_INFO2(RSTRING_PTR(tmp), (size_t)RSTRING_LEN(tmp)); \
|
|
201
|
+
continue; \
|
|
202
|
+
case 3: \
|
|
203
|
+
a[i].num[0] = (int64_t) \
|
|
204
|
+
iodine___rb2c_arg2i(tmp, INT64_MIN, INT64_MAX, a[i].name.buf); \
|
|
205
|
+
continue; \
|
|
206
|
+
case 4: \
|
|
207
|
+
if (tmp == Qnil) { \
|
|
208
|
+
if (rb_block_given_p()) { \
|
|
209
|
+
tmp = rb_block_proc(); \
|
|
210
|
+
STORE.cache(tmp); \
|
|
211
|
+
} else if (a[i].required) \
|
|
212
|
+
goto missing_required; \
|
|
213
|
+
else \
|
|
214
|
+
continue; \
|
|
215
|
+
} else if (tmp != Qnil && !rb_respond_to(tmp, rb_intern2("call", 4))) \
|
|
216
|
+
rb_raise(rb_eArgError, "a callback object MUST respond to `call`"); \
|
|
217
|
+
a[i].rb[0] = tmp; \
|
|
218
|
+
STORE.cache(tmp); \
|
|
219
|
+
continue; \
|
|
220
|
+
case 5: \
|
|
221
|
+
a[i].zu[0] = (size_t) \
|
|
222
|
+
iodine___rb2c_arg2u(tmp, SIZE_MAX, a[i].name.buf); \
|
|
223
|
+
continue; \
|
|
224
|
+
case 6: \
|
|
225
|
+
a[i].i32[0] = (int32_t) \
|
|
226
|
+
iodine___rb2c_arg2i(tmp, INT32_MIN, INT32_MAX, a[i].name.buf); \
|
|
227
|
+
continue; \
|
|
228
|
+
case 7: \
|
|
229
|
+
a[i].i16[0] = (int16_t) \
|
|
230
|
+
iodine___rb2c_arg2i(tmp, INT16_MIN, INT16_MAX, a[i].name.buf); \
|
|
231
|
+
continue; \
|
|
232
|
+
case 8: \
|
|
233
|
+
a[i].i8[0] = (int8_t) \
|
|
234
|
+
iodine___rb2c_arg2i(tmp, INT8_MIN, INT8_MAX, a[i].name.buf); \
|
|
235
|
+
continue; \
|
|
236
|
+
case 9: /* nil keeps the default (handled above) */ \
|
|
237
|
+
if (tmp != Qtrue && tmp != Qfalse) \
|
|
238
|
+
rb_raise(rb_eTypeError, "%s should be a Boolean", a[i].name.buf); \
|
|
239
|
+
a[i].u8[0] = (tmp == Qtrue); \
|
|
240
|
+
continue; \
|
|
241
|
+
case 10: \
|
|
242
|
+
a[i].u64[0] = (uint64_t) \
|
|
243
|
+
iodine___rb2c_arg2u(tmp, UINT64_MAX, a[i].name.buf); \
|
|
244
|
+
continue; \
|
|
245
|
+
case 11: \
|
|
246
|
+
a[i].u32[0] = (uint32_t) \
|
|
247
|
+
iodine___rb2c_arg2u(tmp, UINT32_MAX, a[i].name.buf); \
|
|
248
|
+
continue; \
|
|
249
|
+
case 12: \
|
|
250
|
+
a[i].u16[0] = (uint16_t) \
|
|
251
|
+
iodine___rb2c_arg2u(tmp, UINT16_MAX, a[i].name.buf); \
|
|
252
|
+
continue; \
|
|
253
|
+
case 13: \
|
|
254
|
+
a[i].u8[0] = (uint8_t) \
|
|
255
|
+
iodine___rb2c_arg2u(tmp, UINT8_MAX, a[i].name.buf); \
|
|
256
|
+
continue; \
|
|
257
|
+
default: \
|
|
258
|
+
rb_raise(rb_eException, \
|
|
259
|
+
"C code failure - missing valid expected_type @ %s", \
|
|
260
|
+
a[i].name.buf); \
|
|
261
|
+
}
|
|
262
|
+
/* FIXME: allow partially named arguments. */
|
|
263
|
+
if (argc) {
|
|
264
|
+
--argc;
|
|
265
|
+
for (; i < argc; ++i) {
|
|
266
|
+
/* unnamed parameters (list of parameters), excluding last parameter */
|
|
267
|
+
tmp = argv[i];
|
|
268
|
+
IODINE_RB2C_STORE_ARG();
|
|
269
|
+
}
|
|
270
|
+
/* last parameter is special, as it may be a named parameter Hash */
|
|
271
|
+
tmp = argv[argc];
|
|
272
|
+
i = argc; /* does `for` add even after condition breaks loop? no, so why? */
|
|
273
|
+
|
|
274
|
+
if (RB_TYPE_P(tmp, RUBY_T_HASH)) { /* named parameters (hash table) */
|
|
275
|
+
VALUE tbl = tmp;
|
|
276
|
+
if (a[i].expected_type == 0)
|
|
277
|
+
a[i].rb[0] = tmp;
|
|
278
|
+
for (; a[i].rb; ++i) {
|
|
279
|
+
tmp = rb_hash_aref(
|
|
280
|
+
tbl,
|
|
281
|
+
rb_id2sym(a[i].id ? a[i].id
|
|
282
|
+
: rb_intern2(a[i].name.buf, a[i].name.len)));
|
|
283
|
+
IODINE_RB2C_STORE_ARG();
|
|
284
|
+
}
|
|
285
|
+
return 0;
|
|
286
|
+
}
|
|
287
|
+
if (a[i].rb) {
|
|
288
|
+
do {
|
|
289
|
+
IODINE_RB2C_STORE_ARG();
|
|
290
|
+
} while (0);
|
|
291
|
+
++i;
|
|
292
|
+
}
|
|
293
|
+
tmp = Qnil;
|
|
294
|
+
}
|
|
295
|
+
for (; a[i].rb; ++i) {
|
|
296
|
+
/* possible leftover last parameter */
|
|
297
|
+
if (a[i].expected_type == 4) {
|
|
298
|
+
IODINE_RB2C_STORE_ARG();
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
if (a[i].required)
|
|
302
|
+
goto missing_required;
|
|
303
|
+
}
|
|
304
|
+
return 0;
|
|
305
|
+
|
|
306
|
+
#undef IODINE_RB2C_STORE_ARG
|
|
307
|
+
too_many_arguments:
|
|
308
|
+
rb_raise(rb_eArgError, "too many arguments in method call.");
|
|
309
|
+
return -1;
|
|
310
|
+
missing_required:
|
|
311
|
+
rb_raise(rb_eArgError, "missing required argument %s.", a[i].name.buf);
|
|
312
|
+
return -1;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Reads and validates method arguments (either "splat" or Hash Map).
|
|
317
|
+
*
|
|
318
|
+
* Use:
|
|
319
|
+
*
|
|
320
|
+
* iodine_rb2c_arg(argc, argv,
|
|
321
|
+
* IODINE_ARG_RB(var_name, id_or_0, "name1", 1),
|
|
322
|
+
* IODINE_ARG_STR(var_name, id_or_0, "name2", 0),
|
|
323
|
+
* IODINE_ARG_NUM(var_name, id_or_0, "name3", 0),
|
|
324
|
+
* IODINE_ARG_PROC(var_name, id_or_0, "name4", 0));
|
|
325
|
+
*/
|
|
326
|
+
#define iodine_rb2c_arg(argc, argv, ...) \
|
|
327
|
+
iodine_rb2c_arg(argc, argv, (iodine_rb2c_arg_s[]){__VA_ARGS__, {0}})
|
|
328
|
+
|
|
329
|
+
#endif /* H___IODINE_ARG_HELPER___H */
|