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.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +15 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -3
  5. data/CHANGELOG.md +132 -12
  6. data/Gemfile +5 -7
  7. data/LICENSE.txt +1 -1
  8. data/README.md +147 -671
  9. data/Rakefile +9 -16
  10. data/examples/chatroom.nru +9 -0
  11. data/examples/client +74 -0
  12. data/examples/config-hello.nru +9 -0
  13. data/examples/config-hello.ru +11 -0
  14. data/examples/config-hijack.ru +13 -0
  15. data/examples/config-shootout.ru +43 -0
  16. data/examples/config.nru +120 -0
  17. data/examples/config.rb +37 -0
  18. data/examples/config.ru +42 -53
  19. data/examples/fake +24 -0
  20. data/examples/hello_neorack +137 -0
  21. data/examples/routes.nru +29 -0
  22. data/examples/routes.ru +42 -0
  23. data/exe/iodine +218 -258
  24. data/ext/iodine/extconf.rb +27 -100
  25. data/ext/iodine/fio-stl.h +128336 -0
  26. data/ext/iodine/fio-stl.md +26396 -0
  27. data/ext/iodine/iodine.c +213 -1393
  28. data/ext/iodine/iodine.h +250 -55
  29. data/ext/iodine/iodine_arg_helper.h +329 -0
  30. data/ext/iodine/iodine_caller.h +234 -25
  31. data/ext/iodine/iodine_cli.h +434 -0
  32. data/ext/iodine/iodine_compression.h +312 -0
  33. data/ext/iodine/iodine_connection.h +3484 -34
  34. data/ext/iodine/iodine_core.h +363 -0
  35. data/ext/iodine/iodine_crypto.h +1441 -0
  36. data/ext/iodine/iodine_defer.h +225 -4
  37. data/ext/iodine/iodine_json.h +738 -4
  38. data/ext/iodine/iodine_listener.h +263 -0
  39. data/ext/iodine/iodine_log.h +297 -0
  40. data/ext/iodine/iodine_minimap.h +543 -0
  41. data/ext/iodine/iodine_mustache.h +461 -4
  42. data/ext/iodine/iodine_pubsub_eng.h +729 -0
  43. data/ext/iodine/iodine_pubsub_history.h +547 -0
  44. data/ext/iodine/iodine_pubsub_msg.h +228 -0
  45. data/ext/iodine/iodine_redis.h +322 -0
  46. data/ext/iodine/iodine_store.h +418 -16
  47. data/ext/iodine/iodine_threads.h +279 -0
  48. data/ext/iodine/iodine_tls.h +515 -6
  49. data/ext/iodine/iodine_utils.h +923 -0
  50. data/iodine.gemspec +37 -42
  51. data/lib/iodine/benchmark.rb +1690 -0
  52. data/lib/iodine/documentation.rb +3085 -0
  53. data/lib/iodine/version.rb +17 -1
  54. data/lib/iodine.rb +54 -255
  55. data/logo.svg +36 -0
  56. data/mustache.md +55 -0
  57. data/sig/iodine.rbs +4 -0
  58. metadata +58 -184
  59. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  60. data/.github/workflows/ruby.yml +0 -42
  61. data/.gitignore +0 -20
  62. data/LIMITS.md +0 -41
  63. data/SPEC-PubSub-Draft.md +0 -159
  64. data/SPEC-WebSocket-Draft.md +0 -239
  65. data/bin/console +0 -22
  66. data/bin/info.md +0 -353
  67. data/bin/mustache_bench.rb +0 -100
  68. data/bin/poc/Gemfile.lock +0 -23
  69. data/bin/poc/README.md +0 -37
  70. data/bin/poc/config.ru +0 -66
  71. data/bin/poc/gemfile +0 -1
  72. data/bin/poc/www/index.html +0 -57
  73. data/examples/async_task.ru +0 -92
  74. data/examples/bates/README.md +0 -3
  75. data/examples/bates/config.ru +0 -342
  76. data/examples/bates/david+bold.pdf +0 -0
  77. data/examples/bates/public/drop-pdf.png +0 -0
  78. data/examples/bates/public/index.html +0 -600
  79. data/examples/echo.ru +0 -59
  80. data/examples/etag.ru +0 -16
  81. data/examples/hello.ru +0 -29
  82. data/examples/pubsub_engine.ru +0 -81
  83. data/examples/rack3.ru +0 -12
  84. data/examples/redis.ru +0 -70
  85. data/examples/shootout.ru +0 -73
  86. data/examples/sub-protocols.ru +0 -90
  87. data/examples/tcp_client.rb +0 -66
  88. data/examples/x-sendfile.ru +0 -14
  89. data/ext/iodine/fio.c +0 -11995
  90. data/ext/iodine/fio.h +0 -6371
  91. data/ext/iodine/fio_cli.c +0 -431
  92. data/ext/iodine/fio_cli.h +0 -189
  93. data/ext/iodine/fio_json_parser.h +0 -688
  94. data/ext/iodine/fio_siphash.c +0 -157
  95. data/ext/iodine/fio_siphash.h +0 -37
  96. data/ext/iodine/fio_tls.h +0 -129
  97. data/ext/iodine/fio_tls_missing.c +0 -649
  98. data/ext/iodine/fio_tls_openssl.c +0 -1106
  99. data/ext/iodine/fio_tmpfile.h +0 -50
  100. data/ext/iodine/fiobj.h +0 -44
  101. data/ext/iodine/fiobj4fio.h +0 -21
  102. data/ext/iodine/fiobj_ary.c +0 -333
  103. data/ext/iodine/fiobj_ary.h +0 -139
  104. data/ext/iodine/fiobj_data.c +0 -1187
  105. data/ext/iodine/fiobj_data.h +0 -167
  106. data/ext/iodine/fiobj_hash.c +0 -409
  107. data/ext/iodine/fiobj_hash.h +0 -176
  108. data/ext/iodine/fiobj_json.c +0 -622
  109. data/ext/iodine/fiobj_json.h +0 -68
  110. data/ext/iodine/fiobj_mem.h +0 -71
  111. data/ext/iodine/fiobj_mustache.c +0 -317
  112. data/ext/iodine/fiobj_mustache.h +0 -62
  113. data/ext/iodine/fiobj_numbers.c +0 -344
  114. data/ext/iodine/fiobj_numbers.h +0 -127
  115. data/ext/iodine/fiobj_str.c +0 -433
  116. data/ext/iodine/fiobj_str.h +0 -172
  117. data/ext/iodine/fiobject.c +0 -620
  118. data/ext/iodine/fiobject.h +0 -655
  119. data/ext/iodine/hpack.h +0 -1923
  120. data/ext/iodine/http.c +0 -2743
  121. data/ext/iodine/http.h +0 -1002
  122. data/ext/iodine/http1.c +0 -910
  123. data/ext/iodine/http1.h +0 -29
  124. data/ext/iodine/http1_parser.h +0 -878
  125. data/ext/iodine/http_internal.c +0 -1279
  126. data/ext/iodine/http_internal.h +0 -237
  127. data/ext/iodine/http_mime_parser.h +0 -350
  128. data/ext/iodine/iodine_caller.c +0 -230
  129. data/ext/iodine/iodine_connection.c +0 -941
  130. data/ext/iodine/iodine_defer.c +0 -420
  131. data/ext/iodine/iodine_fiobj2rb.h +0 -120
  132. data/ext/iodine/iodine_helpers.c +0 -282
  133. data/ext/iodine/iodine_helpers.h +0 -12
  134. data/ext/iodine/iodine_http.c +0 -1181
  135. data/ext/iodine/iodine_http.h +0 -23
  136. data/ext/iodine/iodine_json.c +0 -302
  137. data/ext/iodine/iodine_mustache.c +0 -567
  138. data/ext/iodine/iodine_pubsub.c +0 -580
  139. data/ext/iodine/iodine_pubsub.h +0 -26
  140. data/ext/iodine/iodine_rack_io.c +0 -273
  141. data/ext/iodine/iodine_rack_io.h +0 -20
  142. data/ext/iodine/iodine_store.c +0 -146
  143. data/ext/iodine/iodine_tcp.c +0 -346
  144. data/ext/iodine/iodine_tcp.h +0 -13
  145. data/ext/iodine/iodine_tls.c +0 -261
  146. data/ext/iodine/mustache_parser.h +0 -1546
  147. data/ext/iodine/redis_engine.c +0 -957
  148. data/ext/iodine/redis_engine.h +0 -79
  149. data/ext/iodine/resp_parser.h +0 -317
  150. data/ext/iodine/websocket_parser.h +0 -506
  151. data/ext/iodine/websockets.c +0 -743
  152. data/ext/iodine/websockets.h +0 -185
  153. data/lib/iodine/connection.rb +0 -61
  154. data/lib/iodine/json.rb +0 -42
  155. data/lib/iodine/mustache.rb +0 -113
  156. data/lib/iodine/pubsub.rb +0 -55
  157. data/lib/iodine/rack_utils.rb +0 -43
  158. data/lib/iodine/tls.rb +0 -16
  159. data/lib/rack/handler/iodine.rb +0 -33
  160. data/logo.png +0 -0
@@ -1,649 +0,0 @@
1
- /*
2
- Copyright: Boaz Segev, 2018-2019
3
- License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
- */
7
- #ifdef __MINGW32__
8
- // make pedantic compiler happy
9
- typedef struct {
10
- int bogus;
11
- } bogus_s;
12
-
13
- #else
14
- #include <fio.h>
15
-
16
- /**
17
- * This implementation of the facil.io SSL/TLS wrapper API is the default
18
- * implementation that will be used when no SSL/TLS library is available...
19
- *
20
- * ... without modification, this implementation crashes the program.
21
- *
22
- * The implementation can be USED AS A TEMPLATE for future implementations.
23
- *
24
- * This implementation is optimized for ease of development rather than memory
25
- * consumption.
26
- */
27
- #include "fio_tls.h"
28
-
29
- #if !defined(FIO_TLS_FOUND) /* Library compiler flags */
30
-
31
- #define REQUIRE_LIBRARY()
32
- #define FIO_TLS_WEAK
33
-
34
- /* TODO: delete me! */
35
- #undef FIO_TLS_WEAK
36
- #define FIO_TLS_WEAK __attribute__((weak))
37
- #if !FIO_IGNORE_TLS_IF_MISSING
38
- #undef REQUIRE_LIBRARY
39
- #define REQUIRE_LIBRARY() \
40
- FIO_LOG_FATAL("No supported SSL/TLS library available."); \
41
- exit(-1);
42
- #endif
43
-
44
- #ifndef FIO_TLS_TIMEOUT
45
- #define FIO_TLS_TIMEOUT 4
46
- #endif
47
-
48
- /* STOP deleting after this line */
49
-
50
- /* *****************************************************************************
51
- The SSL/TLS helper data types (can be left as is)
52
- ***************************************************************************** */
53
- #define FIO_INCLUDE_STR 1
54
- #define FIO_FORCE_MALLOC_TMP 1
55
- #include <fio.h>
56
-
57
- typedef struct {
58
- fio_str_s private_key;
59
- fio_str_s public_key;
60
- fio_str_s password;
61
- } cert_s;
62
-
63
- static inline int fio_tls_cert_cmp(const cert_s *dest, const cert_s *src) {
64
- return fio_str_iseq(&dest->private_key, &src->private_key);
65
- }
66
- static inline void fio_tls_cert_copy(cert_s *dest, cert_s *src) {
67
- *dest = (cert_s){
68
- .private_key = FIO_STR_INIT,
69
- .public_key = FIO_STR_INIT,
70
- .password = FIO_STR_INIT,
71
- };
72
- fio_str_concat(&dest->private_key, &src->private_key);
73
- fio_str_concat(&dest->public_key, &src->public_key);
74
- fio_str_concat(&dest->password, &src->password);
75
- }
76
- static inline void fio_tls_cert_destroy(cert_s *obj) {
77
- fio_str_free(&obj->private_key);
78
- fio_str_free(&obj->public_key);
79
- fio_str_free(&obj->password);
80
- }
81
-
82
- #define FIO_ARY_NAME cert_ary
83
- #define FIO_ARY_TYPE cert_s
84
- #define FIO_ARY_COMPARE(k1, k2) (fio_tls_cert_cmp(&(k1), &(k2)))
85
- #define FIO_ARY_COPY(dest, obj) fio_tls_cert_copy(&(dest), &(obj))
86
- #define FIO_ARY_DESTROY(key) fio_tls_cert_destroy(&(key))
87
- #define FIO_FORCE_MALLOC_TMP 1
88
- #include <fio.h>
89
-
90
- typedef struct {
91
- fio_str_s pem;
92
- } trust_s;
93
-
94
- static inline int fio_tls_trust_cmp(const trust_s *dest, const trust_s *src) {
95
- return fio_str_iseq(&dest->pem, &src->pem);
96
- }
97
- static inline void fio_tls_trust_copy(trust_s *dest, trust_s *src) {
98
- *dest = (trust_s){
99
- .pem = FIO_STR_INIT,
100
- };
101
- fio_str_concat(&dest->pem, &src->pem);
102
- }
103
- static inline void fio_tls_trust_destroy(trust_s *obj) {
104
- fio_str_free(&obj->pem);
105
- }
106
-
107
- #define FIO_ARY_NAME trust_ary
108
- #define FIO_ARY_TYPE trust_s
109
- #define FIO_ARY_COMPARE(k1, k2) (fio_tls_trust_cmp(&(k1), &(k2)))
110
- #define FIO_ARY_COPY(dest, obj) fio_tls_trust_copy(&(dest), &(obj))
111
- #define FIO_ARY_DESTROY(key) fio_tls_trust_destroy(&(key))
112
- #define FIO_FORCE_MALLOC_TMP 1
113
- #include <fio.h>
114
-
115
- typedef struct {
116
- fio_str_s name; /* fio_str_s provides cache locality for small strings */
117
- void (*on_selected)(intptr_t uuid, void *udata_connection, void *udata_tls);
118
- void *udata_tls;
119
- void (*on_cleanup)(void *udata_tls);
120
- } alpn_s;
121
-
122
- static inline int fio_alpn_cmp(const alpn_s *dest, const alpn_s *src) {
123
- return fio_str_iseq(&dest->name, &src->name);
124
- }
125
- static inline void fio_alpn_copy(alpn_s *dest, alpn_s *src) {
126
- *dest = (alpn_s){
127
- .name = FIO_STR_INIT,
128
- .on_selected = src->on_selected,
129
- .udata_tls = src->udata_tls,
130
- .on_cleanup = src->on_cleanup,
131
- };
132
- fio_str_concat(&dest->name, &src->name);
133
- }
134
- static inline void fio_alpn_destroy(alpn_s *obj) {
135
- if (obj->on_cleanup)
136
- obj->on_cleanup(obj->udata_tls);
137
- fio_str_free(&obj->name);
138
- }
139
-
140
- #define FIO_SET_NAME alpn_list
141
- #define FIO_SET_OBJ_TYPE alpn_s
142
- #define FIO_SET_OBJ_COMPARE(k1, k2) fio_alpn_cmp(&(k1), &(k2))
143
- #define FIO_SET_OBJ_COPY(dest, obj) fio_alpn_copy(&(dest), &(obj))
144
- #define FIO_SET_OBJ_DESTROY(key) fio_alpn_destroy(&(key))
145
- #define FIO_FORCE_MALLOC_TMP 1
146
- #include <fio.h>
147
-
148
- /* *****************************************************************************
149
- The SSL/TLS Context type
150
- ***************************************************************************** */
151
-
152
- /** An opaque type used for the SSL/TLS functions. */
153
- struct fio_tls_s {
154
- size_t ref; /* Reference counter, to guards the ALPN registry */
155
- alpn_list_s alpn; /* ALPN is the name for the protocol selection extension */
156
-
157
- /*** the next two components could be optimized away with tweaking stuff ***/
158
-
159
- cert_ary_s sni; /* SNI (server name extension) stores ID certificates */
160
- trust_ary_s trust; /* Trusted certificate registry (peer verification) */
161
-
162
- /************ TODO: implementation data fields go here ******************/
163
- };
164
-
165
- /* *****************************************************************************
166
- ALPN Helpers
167
- ***************************************************************************** */
168
-
169
- /** Returns a pointer to the ALPN data (callback, etc') IF exists in the TLS. */
170
- FIO_FUNC inline alpn_s *alpn_find(fio_tls_s *tls, char *name, size_t len) {
171
- alpn_s tmp = {.name = FIO_STR_INIT_STATIC2(name, len)};
172
- alpn_list__map_s_ *pos =
173
- alpn_list__find_map_pos_(&tls->alpn, fio_str_hash(&tmp.name), tmp);
174
- if (!pos || !pos->pos)
175
- return NULL;
176
- return &pos->pos->obj;
177
- }
178
-
179
- /** Adds an ALPN data object to the ALPN "list" (set) */
180
- FIO_FUNC inline void alpn_add(
181
- fio_tls_s *tls, const char *protocol_name,
182
- void (*on_selected)(intptr_t uuid, void *udata_connection, void *udata_tls),
183
- void *udata_tls, void (*on_cleanup)(void *udata_tls)) {
184
- alpn_s tmp = {
185
- .name = FIO_STR_INIT_STATIC(protocol_name),
186
- .on_selected = on_selected,
187
- .udata_tls = udata_tls,
188
- .on_cleanup = on_cleanup,
189
- };
190
- if (fio_str_len(&tmp.name) > 255) {
191
- FIO_LOG_ERROR("ALPN protocol names are limited to 255 bytes.");
192
- return;
193
- }
194
- alpn_list_overwrite(&tls->alpn, fio_str_hash(&tmp.name), tmp, NULL);
195
- tmp.on_cleanup = NULL;
196
- fio_alpn_destroy(&tmp);
197
- }
198
-
199
- /** Returns a pointer to the default (first) ALPN object in the TLS (if any). */
200
- FIO_FUNC inline alpn_s *alpn_default(fio_tls_s *tls) {
201
- if (!tls || !alpn_list_count(&tls->alpn) || !tls->alpn.ordered)
202
- return NULL;
203
- return &tls->alpn.ordered[0].obj;
204
- }
205
-
206
- typedef struct {
207
- alpn_s alpn;
208
- intptr_t uuid;
209
- void *udata_connection;
210
- } alpn_task_s;
211
-
212
- FIO_FUNC inline void alpn_select___task(void *t_, void *ignr_) {
213
- alpn_task_s *t = t_;
214
- if (fio_is_valid(t->uuid))
215
- t->alpn.on_selected(t->uuid, t->udata_connection, t->alpn.udata_tls);
216
- fio_free(t);
217
- (void)ignr_;
218
- }
219
-
220
- /** Schedules the ALPN protocol callback. */
221
- FIO_FUNC inline void alpn_select(alpn_s *alpn, intptr_t uuid,
222
- void *udata_connection) {
223
- if (!alpn || !alpn->on_selected)
224
- return;
225
- alpn_task_s *t = fio_malloc(sizeof(*t));
226
- *t = (alpn_task_s){
227
- .alpn = *alpn,
228
- .uuid = uuid,
229
- .udata_connection = udata_connection,
230
- };
231
- /* move task out of the socket's lock */
232
- fio_defer(alpn_select___task, t, NULL);
233
- }
234
-
235
- /* *****************************************************************************
236
- SSL/TLS Context (re)-building - TODO: add implementation details
237
- ***************************************************************************** */
238
-
239
- /** Called when the library specific data for the context should be destroyed */
240
- static void fio_tls_destroy_context(fio_tls_s *tls) {
241
- /* TODO: Library specific implementation */
242
- FIO_LOG_DEBUG("destroyed TLS context %p", (void *)tls);
243
- }
244
-
245
- /** Called when the library specific data for the context should be built */
246
- static void fio_tls_build_context(fio_tls_s *tls) {
247
- fio_tls_destroy_context(tls);
248
- /* TODO: Library specific implementation */
249
-
250
- /* Certificates */
251
- FIO_ARY_FOR(&tls->sni, pos) {
252
- fio_str_info_s k = fio_str_info(&pos->private_key);
253
- fio_str_info_s p = fio_str_info(&pos->public_key);
254
- fio_str_info_s pw = fio_str_info(&pos->password);
255
- if (p.len && k.len) {
256
- /* TODO: attache certificate */
257
- (void)pw;
258
- } else {
259
- /* TODO: self signed certificate */
260
- }
261
- }
262
-
263
- /* ALPN Protocols */
264
- FIO_SET_FOR_LOOP(&tls->alpn, pos) {
265
- fio_str_info_s name = fio_str_info(&pos->obj.name);
266
- (void)name;
267
- // map to pos->callback;
268
- }
269
-
270
- /* Peer Verification / Trust */
271
- if (trust_ary_count(&tls->trust)) {
272
- /* TODO: enable peer verification */
273
-
274
- /* TODO: Add each ceriticate in the PEM to the trust "store" */
275
- FIO_ARY_FOR(&tls->trust, pos) {
276
- fio_str_info_s pem = fio_str_info(&pos->pem);
277
- (void)pem;
278
- }
279
- }
280
-
281
- FIO_LOG_DEBUG("(re)built TLS context %p", (void *)tls);
282
- }
283
-
284
- /* *****************************************************************************
285
- SSL/TLS RW Hooks - TODO: add implementation details
286
- ***************************************************************************** */
287
-
288
- /* TODO: this is an example implementation - fix for specific library. */
289
-
290
- #define TLS_BUFFER_LENGTH (1 << 15)
291
- typedef struct {
292
- fio_tls_s *tls;
293
- size_t len;
294
- uint8_t alpn_ok;
295
- char buffer[TLS_BUFFER_LENGTH];
296
- } buffer_s;
297
-
298
- /**
299
- * Implement reading from a file descriptor. Should behave like the file
300
- * system `read` call, including the setup or errno to EAGAIN / EWOULDBLOCK.
301
- *
302
- * Note: facil.io library functions MUST NEVER be called by any r/w hook, or a
303
- * deadlock might occur.
304
- */
305
- static ssize_t fio_tls_read(intptr_t uuid, void *udata, void *buf,
306
- size_t count) {
307
- ssize_t ret = read(fio_uuid2fd(uuid), buf, count);
308
- if (ret > 0) {
309
- FIO_LOG_DEBUG("Read %zd bytes from %p", ret, (void *)uuid);
310
- }
311
- return ret;
312
- (void)udata;
313
- }
314
-
315
- /**
316
- * When implemented, this function will be called to flush any data remaining
317
- * in the internal buffer.
318
- *
319
- * The function should return the number of bytes remaining in the internal
320
- * buffer (0 is a valid response) or -1 (on error).
321
- *
322
- * Note: facil.io library functions MUST NEVER be called by any r/w hook, or a
323
- * deadlock might occur.
324
- */
325
- static ssize_t fio_tls_flush(intptr_t uuid, void *udata) {
326
- buffer_s *buffer = udata;
327
- if (!buffer->len) {
328
- FIO_LOG_DEBUG("Flush empty for %p", (void *)uuid);
329
- return 0;
330
- }
331
- ssize_t r = write(fio_uuid2fd(uuid), buffer->buffer, buffer->len);
332
- if (r < 0)
333
- return -1;
334
- if (r == 0) {
335
- errno = ECONNRESET;
336
- return -1;
337
- }
338
- size_t len = buffer->len - r;
339
- if (len)
340
- memmove(buffer->buffer, buffer->buffer + r, len);
341
- buffer->len = len;
342
- FIO_LOG_DEBUG("Sent %zd bytes to %p", r, (void *)uuid);
343
- return r;
344
- }
345
-
346
- /**
347
- * Implement writing to a file descriptor. Should behave like the file system
348
- * `write` call.
349
- *
350
- * If an internal buffer is implemented and it is full, errno should be set to
351
- * EWOULDBLOCK and the function should return -1.
352
- *
353
- * Note: facil.io library functions MUST NEVER be called by any r/w hook, or a
354
- * deadlock might occur.
355
- */
356
- static ssize_t fio_tls_write(intptr_t uuid, void *udata, const void *buf,
357
- size_t count) {
358
- buffer_s *buffer = udata;
359
- size_t can_copy = TLS_BUFFER_LENGTH - buffer->len;
360
- if (can_copy > count)
361
- can_copy = count;
362
- if (!can_copy)
363
- goto would_block;
364
- memcpy(buffer->buffer + buffer->len, buf, can_copy);
365
- buffer->len += can_copy;
366
- FIO_LOG_DEBUG("Copied %zu bytes to %p", can_copy, (void *)uuid);
367
- fio_tls_flush(uuid, udata);
368
- return can_copy;
369
- would_block:
370
- errno = EWOULDBLOCK;
371
- return -1;
372
- }
373
-
374
- /**
375
- * The `close` callback should close the underlying socket / file descriptor.
376
- *
377
- * If the function returns a non-zero value, it will be called again after an
378
- * attempt to flush the socket and any pending outgoing buffer.
379
- *
380
- * Note: facil.io library functions MUST NEVER be called by any r/w hook, or a
381
- * deadlock might occur.
382
- * */
383
- static ssize_t fio_tls_before_close(intptr_t uuid, void *udata) {
384
- FIO_LOG_DEBUG("The `before_close` callback was called for %p", (void *)uuid);
385
- return 1;
386
- (void)udata;
387
- }
388
- /**
389
- * Called to perform cleanup after the socket was closed.
390
- * */
391
- static void fio_tls_cleanup(void *udata) {
392
- buffer_s *buffer = udata;
393
- /* make sure the ALPN callback was called, just in case cleanup is required */
394
- if (!buffer->alpn_ok) {
395
- alpn_select(alpn_default(buffer->tls), -1, NULL /* ALPN udata */);
396
- }
397
- fio_tls_destroy(buffer->tls); /* manage reference count */
398
- fio_free(udata);
399
- }
400
-
401
- static fio_rw_hook_s FIO_TLS_HOOKS = {
402
- .read = fio_tls_read,
403
- .write = fio_tls_write,
404
- .before_close = fio_tls_before_close,
405
- .flush = fio_tls_flush,
406
- .cleanup = fio_tls_cleanup,
407
- };
408
-
409
- static size_t fio_tls_handshake(intptr_t uuid, void *udata) {
410
- /*TODO: test for handshake completion */
411
- if (0 /*handshake didn't complete */)
412
- return 0;
413
- if (fio_rw_hook_replace_unsafe(uuid, &FIO_TLS_HOOKS, udata) == 0) {
414
- FIO_LOG_DEBUG("Completed TLS handshake for %p", (void *)uuid);
415
- /*
416
- * make sure the connection is re-added to the reactor...
417
- * in case, while waiting for ALPN, it was suspended for missing a protocol.
418
- */
419
- fio_force_event(uuid, FIO_EVENT_ON_DATA);
420
- } else {
421
- FIO_LOG_DEBUG("Something went wrong during TLS handshake for %p",
422
- (void *)uuid);
423
- }
424
- return 1;
425
- }
426
-
427
- static ssize_t fio_tls_read4handshake(intptr_t uuid, void *udata, void *buf,
428
- size_t count) {
429
- FIO_LOG_DEBUG("TLS handshake from read %p", (void *)uuid);
430
- if (fio_tls_handshake(uuid, udata))
431
- return fio_tls_read(uuid, udata, buf, count);
432
- errno = EWOULDBLOCK;
433
- return -1;
434
- }
435
-
436
- static ssize_t fio_tls_write4handshake(intptr_t uuid, void *udata,
437
- const void *buf, size_t count) {
438
- FIO_LOG_DEBUG("TLS handshake from write %p", (void *)uuid);
439
- if (fio_tls_handshake(uuid, udata))
440
- return fio_tls_write(uuid, udata, buf, count);
441
- errno = EWOULDBLOCK;
442
- return -1;
443
- }
444
-
445
- static ssize_t fio_tls_flush4handshake(intptr_t uuid, void *udata) {
446
- FIO_LOG_DEBUG("TLS handshake from flush %p", (void *)uuid);
447
- if (fio_tls_handshake(uuid, udata))
448
- return fio_tls_flush(uuid, udata);
449
- /* TODO: return a positive value only if handshake requires a write */
450
- return 1;
451
- }
452
- static fio_rw_hook_s FIO_TLS_HANDSHAKE_HOOKS = {
453
- .read = fio_tls_read4handshake,
454
- .write = fio_tls_write4handshake,
455
- .before_close = fio_tls_before_close,
456
- .flush = fio_tls_flush4handshake,
457
- .cleanup = fio_tls_cleanup,
458
- };
459
-
460
- static inline void fio_tls_attach2uuid(intptr_t uuid, fio_tls_s *tls,
461
- void *udata, uint8_t is_server) {
462
- fio_atomic_add(&tls->ref, 1); /* manage reference count */
463
- /* TODO: this is only an example implementation - fix for specific library */
464
- if (is_server) {
465
- /* Server mode (accept) */
466
- FIO_LOG_DEBUG("Attaching TLS read/write hook for %p (server mode).",
467
- (void *)uuid);
468
- } else {
469
- /* Client mode (connect) */
470
- FIO_LOG_DEBUG("Attaching TLS read/write hook for %p (client mode).",
471
- (void *)uuid);
472
- }
473
- /* common implementation (TODO) */
474
- buffer_s *connection_data = fio_malloc(sizeof(*connection_data));
475
- FIO_ASSERT_ALLOC(connection_data);
476
- fio_rw_hook_set(uuid, &FIO_TLS_HANDSHAKE_HOOKS,
477
- connection_data); /* 32Kb buffer */
478
- alpn_select(alpn_default(tls), uuid, udata);
479
- connection_data->alpn_ok = 1;
480
- }
481
-
482
- /* *****************************************************************************
483
- SSL/TLS API implementation - this can be pretty much used as is...
484
- ***************************************************************************** */
485
-
486
- /**
487
- * Creates a new SSL/TLS context / settings object with a default certificate
488
- * (if any).
489
- */
490
- fio_tls_s *FIO_TLS_WEAK fio_tls_new(const char *server_name, const char *cert,
491
- const char *key, const char *pk_password) {
492
- REQUIRE_LIBRARY();
493
- fio_tls_s *tls = calloc(sizeof(*tls), 1);
494
- tls->ref = 1;
495
- fio_tls_cert_add(tls, server_name, key, cert, pk_password);
496
- return tls;
497
- }
498
-
499
- /**
500
- * Adds a certificate a new SSL/TLS context / settings object.
501
- */
502
- void FIO_TLS_WEAK fio_tls_cert_add(fio_tls_s *tls, const char *server_name,
503
- const char *cert, const char *key,
504
- const char *pk_password) {
505
- REQUIRE_LIBRARY();
506
- cert_s c = {
507
- .private_key = FIO_STR_INIT,
508
- .public_key = FIO_STR_INIT,
509
- .password = FIO_STR_INIT_STATIC2(pk_password,
510
- (pk_password ? strlen(pk_password) : 0)),
511
- };
512
- if (key && cert) {
513
- if (fio_str_readfile(&c.private_key, key, 0, 0).data == NULL)
514
- goto file_missing;
515
- if (fio_str_readfile(&c.public_key, cert, 0, 0).data == NULL)
516
- goto file_missing;
517
- cert_ary_push(&tls->sni, c);
518
- } else if (server_name) {
519
- /* Self-Signed TLS Certificates */
520
- c.private_key = FIO_STR_INIT_STATIC(server_name);
521
- cert_ary_push(&tls->sni, c);
522
- }
523
- fio_tls_cert_destroy(&c);
524
- fio_tls_build_context(tls);
525
- return;
526
- file_missing:
527
- FIO_LOG_FATAL("TLS certificate file missing for either %s or %s or both.",
528
- key, cert);
529
- exit(-1);
530
- }
531
-
532
- /**
533
- * Adds an ALPN protocol callback to the SSL/TLS context.
534
- *
535
- * The first protocol added will act as the default protocol to be selected.
536
- *
537
- * The callback should accept the `uuid`, the user data pointer passed to either
538
- * `fio_tls_accept` or `fio_tls_connect` (here: `udata_connetcion`) and the user
539
- * data pointer passed to the `fio_tls_alpn_add` function (`udata_tls`).
540
- *
541
- * The `on_cleanup` callback will be called when the TLS object is destroyed (or
542
- * `fio_tls_alpn_add` is called again with the same protocol name). The
543
- * `udata_tls` argumrnt will be passed along, as is, to the callback (if set).
544
- *
545
- * Except for the `tls` and `protocol_name` arguments, all arguments can be
546
- * NULL.
547
- */
548
- void FIO_TLS_WEAK fio_tls_alpn_add(
549
- fio_tls_s *tls, const char *protocol_name,
550
- void (*on_selected)(intptr_t uuid, void *udata_connection, void *udata_tls),
551
- void *udata_tls, void (*on_cleanup)(void *udata_tls)) {
552
- REQUIRE_LIBRARY();
553
- alpn_add(tls, protocol_name, on_selected, udata_tls, on_cleanup);
554
- fio_tls_build_context(tls);
555
- }
556
-
557
- /**
558
- * Returns the number of registered ALPN protocol names.
559
- *
560
- * This could be used when deciding if protocol selection should be delegated to
561
- * the ALPN mechanism, or whether a protocol should be immediately assigned.
562
- *
563
- * If no ALPN protocols are registered, zero (0) is returned.
564
- */
565
- uintptr_t FIO_TLS_WEAK fio_tls_alpn_count(fio_tls_s *tls) {
566
- return tls ? alpn_list_count(&tls->alpn) : 0;
567
- }
568
-
569
- /**
570
- * Adds a certificate to the "trust" list, which automatically adds a peer
571
- * verification requirement.
572
- *
573
- * fio_tls_trust(tls, "google-ca.pem" );
574
- */
575
- void FIO_TLS_WEAK fio_tls_trust(fio_tls_s *tls, const char *public_cert_file) {
576
- REQUIRE_LIBRARY();
577
- trust_s c = {
578
- .pem = FIO_STR_INIT,
579
- };
580
- if (!public_cert_file)
581
- return;
582
- if (fio_str_readfile(&c.pem, public_cert_file, 0, 0).data == NULL)
583
- goto file_missing;
584
- trust_ary_push(&tls->trust, c);
585
- fio_tls_trust_destroy(&c);
586
- fio_tls_build_context(tls);
587
- return;
588
- file_missing:
589
- FIO_LOG_FATAL("TLS certificate file missing for %s ", public_cert_file);
590
- exit(-1);
591
- }
592
-
593
- /**
594
- * Establishes an SSL/TLS connection as an SSL/TLS Server, using the specified
595
- * context / settings object.
596
- *
597
- * The `uuid` should be a socket UUID that is already connected to a peer (i.e.,
598
- * the result of `fio_accept`).
599
- *
600
- * The `udata` is an opaque user data pointer that is passed along to the
601
- * protocol selected (if any protocols were added using `fio_tls_alpn_add`).
602
- */
603
- void FIO_TLS_WEAK fio_tls_accept(intptr_t uuid, fio_tls_s *tls, void *udata) {
604
- REQUIRE_LIBRARY();
605
- fio_timeout_set(uuid, FIO_TLS_TIMEOUT);
606
- fio_tls_attach2uuid(uuid, tls, udata, 1);
607
- }
608
-
609
- /**
610
- * Establishes an SSL/TLS connection as an SSL/TLS Client, using the specified
611
- * context / settings object.
612
- *
613
- * The `uuid` should be a socket UUID that is already connected to a peer (i.e.,
614
- * one received by a `fio_connect` specified callback `on_connect`).
615
- *
616
- * The `udata` is an opaque user data pointer that is passed along to the
617
- * protocol selected (if any protocols were added using `fio_tls_alpn_add`).
618
- */
619
- void FIO_TLS_WEAK fio_tls_connect(intptr_t uuid, fio_tls_s *tls, void *udata) {
620
- REQUIRE_LIBRARY();
621
- fio_tls_attach2uuid(uuid, tls, udata, 0);
622
- }
623
-
624
- /**
625
- * Increase the reference count for the TLS object.
626
- *
627
- * Decrease with `fio_tls_destroy`.
628
- */
629
- void FIO_TLS_WEAK fio_tls_dup(fio_tls_s *tls) { fio_atomic_add(&tls->ref, 1); }
630
-
631
- /**
632
- * Destroys the SSL/TLS context / settings object and frees any related
633
- * resources / memory.
634
- */
635
- void FIO_TLS_WEAK fio_tls_destroy(fio_tls_s *tls) {
636
- if (!tls)
637
- return;
638
- REQUIRE_LIBRARY();
639
- if (fio_atomic_sub(&tls->ref, 1))
640
- return;
641
- fio_tls_destroy_context(tls);
642
- alpn_list_free(&tls->alpn);
643
- cert_ary_free(&tls->sni);
644
- trust_ary_free(&tls->trust);
645
- free(tls);
646
- }
647
-
648
- #endif /* Library compiler flags */
649
- #endif