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.
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 -21
  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 -148
  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,506 +0,0 @@
1
- /*
2
- copyright: Boaz Segev, 2017-2019
3
- license: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license specified.
6
- */
7
- #ifndef H_WEBSOCKET_PARSER_H
8
- /**\file
9
-
10
- A single file WebSocket message parser and WebSocket message wrapper, decoupled
11
- from any IO layer.
12
-
13
- Notice that this header file library includes static funnction declerations that
14
- must be implemented by the including file (the callbacks).
15
-
16
- */
17
- #define H_WEBSOCKET_PARSER_H
18
- #include <stdint.h>
19
- #include <stdlib.h>
20
- #include <string.h>
21
- #if DEBUG
22
- #include <stdio.h>
23
- #endif
24
- /* *****************************************************************************
25
- API - Message Wrapping
26
- ***************************************************************************** */
27
-
28
- /** returns the length of the buffer required to wrap a message `len` long */
29
- static inline __attribute__((unused)) uint64_t
30
- websocket_wrapped_len(uint64_t len);
31
-
32
- /**
33
- * Wraps a WebSocket server message and writes it to the target buffer.
34
- *
35
- * The `first` and `last` flags can be used to support message fragmentation.
36
- *
37
- * * target: the target buffer to write to.
38
- * * msg: the message to be wrapped.
39
- * * len: the message length.
40
- * * opcode: set to 1 for UTF-8 message, 2 for binary, etc'.
41
- * * first: set to 1 if `msg` points the beginning of the message.
42
- * * last: set to 1 if `msg + len` ends the message.
43
- * * client: set to 1 to use client mode (data masking).
44
- *
45
- * Further opcode values:
46
- * * %x0 denotes a continuation frame
47
- * * %x1 denotes a text frame
48
- * * %x2 denotes a binary frame
49
- * * %x3-7 are reserved for further non-control frames
50
- * * %x8 denotes a connection close
51
- * * %x9 denotes a ping
52
- * * %xA denotes a pong
53
- * * %xB-F are reserved for further control frames
54
- *
55
- * Returns the number of bytes written. Always `websocket_wrapped_len(len)`
56
- */
57
- inline static uint64_t __attribute__((unused))
58
- websocket_server_wrap(void *target, void *msg, uint64_t len,
59
- unsigned char opcode, unsigned char first,
60
- unsigned char last, unsigned char rsv);
61
-
62
- /**
63
- * Wraps a WebSocket client message and writes it to the target buffer.
64
- *
65
- * The `first` and `last` flags can be used to support message fragmentation.
66
- *
67
- * * target: the target buffer to write to.
68
- * * msg: the message to be wrapped.
69
- * * len: the message length.
70
- * * opcode: set to 1 for UTF-8 message, 2 for binary, etc'.
71
- * * first: set to 1 if `msg` points the beginning of the message.
72
- * * last: set to 1 if `msg + len` ends the message.
73
- * * client: set to 1 to use client mode (data masking).
74
- *
75
- * Returns the number of bytes written. Always `websocket_wrapped_len(len) + 4`
76
- */
77
- inline static __attribute__((unused)) uint64_t
78
- websocket_client_wrap(void *target, void *msg, uint64_t len,
79
- unsigned char opcode, unsigned char first,
80
- unsigned char last, unsigned char rsv);
81
-
82
- /* *****************************************************************************
83
- Callbacks - Required functions that must be inplemented to use this header
84
- ***************************************************************************** */
85
-
86
- static void websocket_on_unwrapped(void *udata, void *msg, uint64_t len,
87
- char first, char last, char text,
88
- unsigned char rsv);
89
- static void websocket_on_protocol_ping(void *udata, void *msg, uint64_t len);
90
- static void websocket_on_protocol_pong(void *udata, void *msg, uint64_t len);
91
- static void websocket_on_protocol_close(void *udata);
92
- static void websocket_on_protocol_error(void *udata);
93
-
94
- /* *****************************************************************************
95
- API - Parsing (unwrapping)
96
- ***************************************************************************** */
97
-
98
- /** the returned value for `websocket_buffer_required` */
99
- struct websocket_packet_info_s {
100
- /** the expected packet length */
101
- uint64_t packet_length;
102
- /** the packet's "head" size (before the data) */
103
- uint8_t head_length;
104
- /** a flag indicating if the packet is masked */
105
- uint8_t masked;
106
- };
107
-
108
- /**
109
- * Returns all known information regarding the upcoming message.
110
- *
111
- * @returns a struct websocket_packet_info_s.
112
- *
113
- * On protocol error, the `head_length` value is 0 (no valid head detected).
114
- */
115
- inline static struct websocket_packet_info_s
116
- websocket_buffer_peek(void *buffer, uint64_t len);
117
-
118
- /**
119
- * Consumes the data in the buffer, calling any callbacks required.
120
- *
121
- * Returns the remaining data in the existing buffer (can be 0).
122
- *
123
- * Notice: if there's any data in the buffer that can't be parsed
124
- * just yet, `memmove` is used to place the data at the beginning of the buffer.
125
- */
126
- inline static __attribute__((unused)) uint64_t
127
- websocket_consume(void *buffer, uint64_t len, void *udata,
128
- uint8_t require_masking);
129
-
130
- /* *****************************************************************************
131
- API - Internal Helpers
132
- ***************************************************************************** */
133
-
134
- /** used internally to mask and unmask client messages. */
135
- inline static void websocket_xmask(void *msg, uint64_t len, uint32_t mask);
136
-
137
- /* *****************************************************************************
138
-
139
- Implementation
140
-
141
- ***************************************************************************** */
142
-
143
- /* *****************************************************************************
144
- Message masking
145
- ***************************************************************************** */
146
- /** used internally to mask and unmask client messages. */
147
- void websocket_xmask(void *msg, uint64_t len, uint32_t mask) {
148
- if (len > 7) {
149
- { /* XOR any unaligned memory (4 byte alignment) */
150
- const uintptr_t offset = 4 - ((uintptr_t)msg & 3);
151
- switch (offset) {
152
- case 3:
153
- ((uint8_t *)msg)[2] ^= ((uint8_t *)(&mask))[2];
154
- /* fallthrough */
155
- case 2:
156
- ((uint8_t *)msg)[1] ^= ((uint8_t *)(&mask))[1];
157
- /* fallthrough */
158
- case 1:
159
- ((uint8_t *)msg)[0] ^= ((uint8_t *)(&mask))[0];
160
- /* rotate mask and move pointer to first 4 byte alignment */
161
- uint64_t comb = mask | ((uint64_t)mask << 32);
162
- ((uint8_t *)(&mask))[0] = ((uint8_t *)(&comb))[0 + offset];
163
- ((uint8_t *)(&mask))[1] = ((uint8_t *)(&comb))[1 + offset];
164
- ((uint8_t *)(&mask))[2] = ((uint8_t *)(&comb))[2 + offset];
165
- ((uint8_t *)(&mask))[3] = ((uint8_t *)(&comb))[3 + offset];
166
- msg = (void *)((uintptr_t)msg + offset);
167
- len -= offset;
168
- }
169
- }
170
- #if UINTPTR_MAX <= 0xFFFFFFFF
171
- /* handle 4 byte XOR alignment in 32 bit mnachine*/
172
- while (len >= 4) {
173
- *((uint32_t *)msg) ^= mask;
174
- len -= 4;
175
- msg = (void *)((uintptr_t)msg + 4);
176
- }
177
- #else
178
- /* handle first 4 byte XOR alignment and move on to 64 bits */
179
- if ((uintptr_t)msg & 7) {
180
- *((uint32_t *)msg) ^= mask;
181
- len -= 4;
182
- msg = (void *)((uintptr_t)msg + 4);
183
- }
184
- /* intrinsic / XOR by 8 byte block, memory aligned */
185
- const uint64_t xmask = (((uint64_t)mask) << 32) | mask;
186
- while (len >= 8) {
187
- *((uint64_t *)msg) ^= xmask;
188
- len -= 8;
189
- msg = (void *)((uintptr_t)msg + 8);
190
- }
191
- #endif
192
- }
193
-
194
- /* XOR any leftover bytes (might be non aligned) */
195
- switch (len) {
196
- case 7:
197
- ((uint8_t *)msg)[6] ^= ((uint8_t *)(&mask))[2];
198
- /* fallthrough */
199
- case 6:
200
- ((uint8_t *)msg)[5] ^= ((uint8_t *)(&mask))[1];
201
- /* fallthrough */
202
- case 5:
203
- ((uint8_t *)msg)[4] ^= ((uint8_t *)(&mask))[0];
204
- /* fallthrough */
205
- case 4:
206
- ((uint8_t *)msg)[3] ^= ((uint8_t *)(&mask))[3];
207
- /* fallthrough */
208
- case 3:
209
- ((uint8_t *)msg)[2] ^= ((uint8_t *)(&mask))[2];
210
- /* fallthrough */
211
- case 2:
212
- ((uint8_t *)msg)[1] ^= ((uint8_t *)(&mask))[1];
213
- /* fallthrough */
214
- case 1:
215
- ((uint8_t *)msg)[0] ^= ((uint8_t *)(&mask))[0];
216
- /* fallthrough */
217
- }
218
- }
219
-
220
- /* *****************************************************************************
221
- Message wrapping
222
- ***************************************************************************** */
223
-
224
- /** Converts an unaligned network ordered byte stream to a 16 bit number. */
225
- #define websocket_str2u16(c) \
226
- ((uint16_t)(((uint16_t)(((uint8_t *)(c))[0]) << 8) | \
227
- (uint16_t)(((uint8_t *)(c))[1])))
228
-
229
- /** Converts an unaligned network ordered byte stream to a 64 bit number. */
230
- #define websocket_str2u64(c) \
231
- ((uint64_t)((((uint64_t)((uint8_t *)(c))[0]) << 56) | \
232
- (((uint64_t)((uint8_t *)(c))[1]) << 48) | \
233
- (((uint64_t)((uint8_t *)(c))[2]) << 40) | \
234
- (((uint64_t)((uint8_t *)(c))[3]) << 32) | \
235
- (((uint64_t)((uint8_t *)(c))[4]) << 24) | \
236
- (((uint64_t)((uint8_t *)(c))[5]) << 16) | \
237
- (((uint64_t)((uint8_t *)(c))[6]) << 8) | (((uint8_t *)(c))[7])))
238
-
239
- /** Writes a local 16 bit number to an unaligned buffer in network order. */
240
- #define websocket_u2str16(buffer, i) \
241
- do { \
242
- ((uint8_t *)(buffer))[0] = ((uint16_t)(i) >> 8) & 0xFF; \
243
- ((uint8_t *)(buffer))[1] = ((uint16_t)(i)) & 0xFF; \
244
- } while (0);
245
-
246
- /** Writes a local 64 bit number to an unaligned buffer in network order. */
247
- #define websocket_u2str64(buffer, i) \
248
- do { \
249
- ((uint8_t *)(buffer))[0] = ((uint64_t)(i) >> 56) & 0xFF; \
250
- ((uint8_t *)(buffer))[1] = ((uint64_t)(i) >> 48) & 0xFF; \
251
- ((uint8_t *)(buffer))[2] = ((uint64_t)(i) >> 40) & 0xFF; \
252
- ((uint8_t *)(buffer))[3] = ((uint64_t)(i) >> 32) & 0xFF; \
253
- ((uint8_t *)(buffer))[4] = ((uint64_t)(i) >> 24) & 0xFF; \
254
- ((uint8_t *)(buffer))[5] = ((uint64_t)(i) >> 16) & 0xFF; \
255
- ((uint8_t *)(buffer))[6] = ((uint64_t)(i) >> 8) & 0xFF; \
256
- ((uint8_t *)(buffer))[7] = ((uint64_t)(i)) & 0xFF; \
257
- } while (0);
258
-
259
- /** returns the length of the buffer required to wrap a message `len` long */
260
- static inline uint64_t websocket_wrapped_len(uint64_t len) {
261
- if (len < 126)
262
- return len + 2;
263
- if (len < (1UL << 16))
264
- return len + 4;
265
- return len + 10;
266
- }
267
-
268
- /**
269
- * Wraps a WebSocket server message and writes it to the target buffer.
270
- *
271
- * The `first` and `last` flags can be used to support message fragmentation.
272
- *
273
- * * target: the target buffer to write to.
274
- * * msg: the message to be wrapped.
275
- * * len: the message length.
276
- * * opcode: set to 1 for UTF-8 message, 2 for binary, etc'.
277
- * * first: set to 1 if `msg` points the beginning of the message.
278
- * * last: set to 1 if `msg + len` ends the message.
279
- * * client: set to 1 to use client mode (data masking).
280
- *
281
- * Further opcode values:
282
- * * %x0 denotes a continuation frame
283
- * * %x1 denotes a text frame
284
- * * %x2 denotes a binary frame
285
- * * %x3-7 are reserved for further non-control frames
286
- * * %x8 denotes a connection close
287
- * * %x9 denotes a ping
288
- * * %xA denotes a pong
289
- * * %xB-F are reserved for further control frames
290
- *
291
- * Returns the number of bytes written. Always `websocket_wrapped_len(len)`
292
- */
293
- static uint64_t websocket_server_wrap(void *target, void *msg, uint64_t len,
294
- unsigned char opcode, unsigned char first,
295
- unsigned char last, unsigned char rsv) {
296
- ((uint8_t *)target)[0] = 0 |
297
- /* opcode */ (((first ? opcode : 0) & 15)) |
298
- /* rsv */ ((rsv & 7) << 4) |
299
- /*fin*/ ((last & 1) << 7);
300
- if (len < 126) {
301
- ((uint8_t *)target)[1] = len;
302
- memcpy(((uint8_t *)target) + 2, msg, len);
303
- return len + 2;
304
- } else if (len < (1UL << 16)) {
305
- /* head is 4 bytes */
306
- ((uint8_t *)target)[1] = 126;
307
- websocket_u2str16(((uint8_t *)target + 2), len);
308
- memcpy((uint8_t *)target + 4, msg, len);
309
- return len + 4;
310
- }
311
- /* Really Long Message */
312
- ((uint8_t *)target)[1] = 127;
313
- websocket_u2str64(((uint8_t *)target + 2), len);
314
- memcpy((uint8_t *)target + 10, msg, len);
315
- return len + 10;
316
- }
317
-
318
- /**
319
- * Wraps a WebSocket client message and writes it to the target buffer.
320
- *
321
- * The `first` and `last` flags can be used to support message fragmentation.
322
- *
323
- * * target: the target buffer to write to.
324
- * * msg: the message to be wrapped.
325
- * * len: the message length.
326
- * * opcode: set to 1 for UTF-8 message, 2 for binary, etc'.
327
- * * first: set to 1 if `msg` points the beginning of the message.
328
- * * last: set to 1 if `msg + len` ends the message.
329
- *
330
- * Returns the number of bytes written. Always `websocket_wrapped_len(len) +
331
- * 4`
332
- */
333
- static uint64_t websocket_client_wrap(void *target, void *msg, uint64_t len,
334
- unsigned char opcode, unsigned char first,
335
- unsigned char last, unsigned char rsv) {
336
- uint32_t mask = rand() | 0x01020408;
337
- ((uint8_t *)target)[0] = 0 |
338
- /* opcode */ (((first ? opcode : 0) & 15)) |
339
- /* rsv */ ((rsv & 7) << 4) |
340
- /*fin*/ ((last & 1) << 7);
341
- if (len < 126) {
342
- ((uint8_t *)target)[1] = len | 128;
343
- ((uint8_t *)target)[2] = ((uint8_t *)(&mask))[0];
344
- ((uint8_t *)target)[3] = ((uint8_t *)(&mask))[1];
345
- ((uint8_t *)target)[4] = ((uint8_t *)(&mask))[2];
346
- ((uint8_t *)target)[5] = ((uint8_t *)(&mask))[3];
347
- memcpy(((uint8_t *)target) + 6, msg, len);
348
- websocket_xmask((uint8_t *)target + 6, len, mask);
349
- return len + 6;
350
- } else if (len < (1UL << 16)) {
351
- /* head is 4 bytes */
352
- ((uint8_t *)target)[1] = 126 | 128;
353
- websocket_u2str16(((uint8_t *)target + 2), len);
354
- ((uint8_t *)target)[4] = ((uint8_t *)(&mask))[0];
355
- ((uint8_t *)target)[5] = ((uint8_t *)(&mask))[1];
356
- ((uint8_t *)target)[6] = ((uint8_t *)(&mask))[2];
357
- ((uint8_t *)target)[7] = ((uint8_t *)(&mask))[3];
358
- memcpy((uint8_t *)target + 8, msg, len);
359
- websocket_xmask((uint8_t *)target + 8, len, mask);
360
- return len + 8;
361
- }
362
- /* Really Long Message */
363
- ((uint8_t *)target)[1] = 255;
364
- websocket_u2str64(((uint8_t *)target + 2), len);
365
- ((uint8_t *)target)[10] = ((uint8_t *)(&mask))[0];
366
- ((uint8_t *)target)[11] = ((uint8_t *)(&mask))[1];
367
- ((uint8_t *)target)[12] = ((uint8_t *)(&mask))[2];
368
- ((uint8_t *)target)[13] = ((uint8_t *)(&mask))[3];
369
- memcpy((uint8_t *)target + 14, msg, len);
370
- websocket_xmask((uint8_t *)target + 14, len, mask);
371
- return len + 14;
372
- }
373
-
374
- /* *****************************************************************************
375
- Message unwrapping
376
- ***************************************************************************** */
377
-
378
- /**
379
- * Returns all known information regarding the upcoming message.
380
- *
381
- * @returns a struct websocket_packet_info_s.
382
- *
383
- * On protocol error, the `head_length` value is 0 (no valid head detected).
384
- */
385
- inline static struct websocket_packet_info_s
386
- websocket_buffer_peek(void *buffer, uint64_t len) {
387
- if (len < 2) {
388
- const struct websocket_packet_info_s info = {0 /* packet */, 2 /* head */,
389
- 0 /* masked? */};
390
- return info;
391
- }
392
- const uint8_t mask_f = (((uint8_t *)buffer)[1] >> 7) & 1;
393
- const uint8_t mask_l = (mask_f << 2);
394
- uint8_t len_indicator = ((((uint8_t *)buffer)[1]) & 127);
395
- switch (len_indicator) {
396
- case 126:
397
- if (len < 4)
398
- return (struct websocket_packet_info_s){0, (uint8_t)(4 + mask_l), mask_f};
399
- return (struct websocket_packet_info_s){
400
- (uint64_t)websocket_str2u16(((uint8_t *)buffer + 2)),
401
- (uint8_t)(4 + mask_l), mask_f};
402
- case 127:
403
- if (len < 10)
404
- return (struct websocket_packet_info_s){0, (uint8_t)(10 + mask_l),
405
- mask_f};
406
- {
407
- uint64_t msg_len = websocket_str2u64(((uint8_t *)buffer + 2));
408
- if (msg_len >> 62)
409
- return (struct websocket_packet_info_s){0, 0, 0};
410
- return (struct websocket_packet_info_s){msg_len, (uint8_t)(10 + mask_l),
411
- mask_f};
412
- }
413
- default:
414
- return (struct websocket_packet_info_s){len_indicator,
415
- (uint8_t)(2 + mask_l), mask_f};
416
- }
417
- }
418
-
419
- /**
420
- * Consumes the data in the buffer, calling any callbacks required.
421
- *
422
- * Returns the remaining data in the existing buffer (can be 0).
423
- */
424
- static uint64_t websocket_consume(void *buffer, uint64_t len, void *udata,
425
- uint8_t require_masking) {
426
- volatile struct websocket_packet_info_s info =
427
- websocket_buffer_peek(buffer, len);
428
- if (!info.head_length) {
429
- #if DEBUG
430
- fprintf(stderr, "ERROR: WebSocket protocol error - malicious header.\n");
431
- #endif
432
- websocket_on_protocol_error(udata);
433
- return 0;
434
- }
435
- if (info.head_length + info.packet_length > len)
436
- return len;
437
- uint64_t reminder = len;
438
- uint8_t *pos = (uint8_t *)buffer;
439
- while (info.head_length + info.packet_length <= reminder) {
440
- /* parse head */
441
- void *payload = (void *)(pos + info.head_length);
442
- /* unmask? */
443
- if (info.masked) {
444
- /* masked */
445
- uint32_t mask; // = ((uint32_t *)payload)[-1];
446
- ((uint8_t *)(&mask))[0] = ((uint8_t *)(payload))[-4];
447
- ((uint8_t *)(&mask))[1] = ((uint8_t *)(payload))[-3];
448
- ((uint8_t *)(&mask))[2] = ((uint8_t *)(payload))[-2];
449
- ((uint8_t *)(&mask))[3] = ((uint8_t *)(payload))[-1];
450
- websocket_xmask(payload, info.packet_length, mask);
451
- } else if (require_masking && info.packet_length) {
452
- #if DEBUG
453
- fprintf(stderr, "ERROR: WebSocket protocol error - unmasked data.\n");
454
- #endif
455
- websocket_on_protocol_error(udata);
456
- return 0;
457
- }
458
- /* call callback */
459
- switch (pos[0] & 15) {
460
- case 0:
461
- /* continuation frame */
462
- websocket_on_unwrapped(udata, payload, info.packet_length, 0,
463
- ((pos[0] >> 7) & 1), 0, ((pos[0] >> 4) & 7));
464
- break;
465
- case 1:
466
- /* text frame */
467
- websocket_on_unwrapped(udata, payload, info.packet_length, 1,
468
- ((pos[0] >> 7) & 1), 1, ((pos[0] >> 4) & 7));
469
- break;
470
- case 2:
471
- /* data frame */
472
- websocket_on_unwrapped(udata, payload, info.packet_length, 1,
473
- ((pos[0] >> 7) & 1), 0, ((pos[0] >> 4) & 7));
474
- break;
475
- case 8:
476
- /* close frame */
477
- websocket_on_protocol_close(udata);
478
- break;
479
- case 9:
480
- /* ping frame */
481
- websocket_on_protocol_ping(udata, payload, info.packet_length);
482
- break;
483
- case 10:
484
- /* pong frame */
485
- websocket_on_protocol_pong(udata, payload, info.packet_length);
486
- break;
487
- default:
488
- #if DEBUG
489
- fprintf(stderr, "ERROR: WebSocket protocol error - unknown opcode %u\n",
490
- (unsigned int)(pos[0] & 15));
491
- #endif
492
- websocket_on_protocol_error(udata);
493
- }
494
- /* step forward */
495
- reminder = reminder - (info.head_length + info.packet_length);
496
- if (!reminder)
497
- return 0;
498
- pos += info.head_length + info.packet_length;
499
- info = websocket_buffer_peek(pos, reminder);
500
- }
501
- /* reset buffer state - support pipelining */
502
- memmove(buffer, (uint8_t *)buffer + len - reminder, reminder);
503
- return reminder;
504
- }
505
-
506
- #endif