iodine 0.4.11 → 0.4.12
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/ext/iodine/fiobj_hash.c +1 -1
- data/ext/iodine/iodine.c +6 -4
- data/ext/iodine/websocket_parser.h +90 -22
- data/ext/iodine/websockets.c +3 -4
- data/lib/iodine.rb +5 -3
- data/lib/iodine/cli.rb +2 -1
- data/lib/iodine/monkeypatch.rb +1 -0
- data/lib/iodine/pubsub.rb +1 -3
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aca722c23efafe6e1253f5ab4f9cea5157ded7eb
|
4
|
+
data.tar.gz: 3cd0891b931b59d0474a8dc0f4acdb67a1775923
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe7c754d170ec52fe96b77bcd2b18a79586e5d3cd6db4bff5f3ba834e32060b470fb3c5fce9799a9868af7cb832143d396ccc1216691f0a3a17887b06124b72a
|
7
|
+
data.tar.gz: '09be0eccb8cf2a065be75bb2ae96c4e4cc9ea79fc29a7864d122d59aa743ec709551fd345dbb6a79f0910685fc061edc8dee1e1c33649cd2992e931e0654eef4'
|
data/ext/iodine/fiobj_hash.c
CHANGED
@@ -13,7 +13,7 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
13
13
|
#include <errno.h>
|
14
14
|
/* *****************************************************************************
|
15
15
|
Internal Map Array
|
16
|
-
We avoid the fiobj_ary_s to prevent entanglement
|
16
|
+
We avoid the fiobj_ary_s to prevent code entanglement
|
17
17
|
***************************************************************************** */
|
18
18
|
|
19
19
|
static inline void fio_map_reset(fio_map_s *map, uintptr_t capa) {
|
data/ext/iodine/iodine.c
CHANGED
@@ -321,12 +321,18 @@ static VALUE iodine_start(VALUE self) {
|
|
321
321
|
Debug
|
322
322
|
***************************************************************************** */
|
323
323
|
|
324
|
+
/** Used for debugging purpuses. Lists GC protected objects */
|
324
325
|
VALUE iodine_print_registry(VALUE self) {
|
325
326
|
Registry.print();
|
326
327
|
return Qnil;
|
327
328
|
(void)self;
|
328
329
|
}
|
329
330
|
|
331
|
+
/* *****************************************************************************
|
332
|
+
Library Initialization
|
333
|
+
***************************************************************************** */
|
334
|
+
|
335
|
+
/** Any patches required by the running environment for consistent behavior */
|
330
336
|
static void patch_env(void) {
|
331
337
|
#ifdef __APPLE__
|
332
338
|
/* patch for dealing with the High Sierra `fork` limitations */
|
@@ -334,10 +340,6 @@ static void patch_env(void) {
|
|
334
340
|
#endif
|
335
341
|
}
|
336
342
|
|
337
|
-
/* *****************************************************************************
|
338
|
-
Library Initialization
|
339
|
-
***************************************************************************** */
|
340
|
-
|
341
343
|
////////////////////////////////////////////////////////////////////////
|
342
344
|
// Ruby loads the library and invokes the Init_<lib_name> function...
|
343
345
|
//
|
@@ -194,9 +194,29 @@ Message wrapping
|
|
194
194
|
// clang-format on
|
195
195
|
|
196
196
|
#ifdef __BIG_ENDIAN__
|
197
|
-
/** stub byte swap 64 bit integer */
|
197
|
+
/** stub byte swap 64 bit integer from pointer */
|
198
|
+
static inline uint64_t netpiswap64(uint8_t *i) {
|
199
|
+
uint64_t ret = 0;
|
200
|
+
uint8_t *const pret = &ret;
|
201
|
+
pret[7] = i[7];
|
202
|
+
pret[6] = i[6];
|
203
|
+
pret[5] = i[5];
|
204
|
+
pret[4] = i[4];
|
205
|
+
pret[3] = i[3];
|
206
|
+
pret[2] = i[2];
|
207
|
+
pret[1] = i[1];
|
208
|
+
pret[0] = i[0];
|
209
|
+
return ret;
|
210
|
+
}
|
211
|
+
/** stub byte swap 16 bit integer from pointer */
|
212
|
+
static inline uint16_t netpiswap16(uint8_t *i) {
|
213
|
+
uint16_t ret = 0;
|
214
|
+
uint8_t *const pret = (uint8_t *)&ret;
|
215
|
+
pret[1] = i[1];
|
216
|
+
pret[0] = i[0];
|
217
|
+
return ret;
|
218
|
+
}
|
198
219
|
#define netiswap64(i) (i)
|
199
|
-
/** stub byte swap 16 bit integer */
|
200
220
|
#define netiswap16(i) (i)
|
201
221
|
|
202
222
|
#else
|
@@ -209,6 +229,28 @@ Message wrapping
|
|
209
229
|
(((i)&0xFF000000000000ULL) >> 40) | (((i)&0xFF00000000000000ULL) >> 56))
|
210
230
|
/** byte swap 16 bit integer */
|
211
231
|
#define netiswap16(i) ((((i)&0x00ff) << 8) | (((i)&0xff00) >> 8))
|
232
|
+
/** byte swap 64 bit integer from pointer */
|
233
|
+
static inline uint64_t netpiswap64(uint8_t *i) {
|
234
|
+
uint64_t ret = 0;
|
235
|
+
uint8_t *const pret = (uint8_t *)&ret;
|
236
|
+
pret[0] = i[7];
|
237
|
+
pret[1] = i[6];
|
238
|
+
pret[2] = i[5];
|
239
|
+
pret[3] = i[4];
|
240
|
+
pret[4] = i[3];
|
241
|
+
pret[5] = i[2];
|
242
|
+
pret[6] = i[1];
|
243
|
+
pret[7] = i[0];
|
244
|
+
return ret;
|
245
|
+
}
|
246
|
+
/** byte swap 16 bit integer from pointer */
|
247
|
+
static inline uint16_t netpiswap16(uint8_t *i) {
|
248
|
+
uint16_t ret = 0;
|
249
|
+
uint8_t *const pret = (uint8_t *)&ret;
|
250
|
+
pret[0] = i[1];
|
251
|
+
pret[1] = i[0];
|
252
|
+
return ret;
|
253
|
+
}
|
212
254
|
|
213
255
|
#endif
|
214
256
|
|
@@ -260,13 +302,23 @@ static uint64_t websocket_server_wrap(void *target, void *msg, uint64_t len,
|
|
260
302
|
} else if (len < (1UL << 16)) {
|
261
303
|
/* head is 4 bytes */
|
262
304
|
((uint8_t *)target)[1] = 126;
|
263
|
-
|
305
|
+
const uint16_t net_len = netiswap16(len);
|
306
|
+
((uint8_t *)target)[2] = ((uint8_t *)(&net_len))[0];
|
307
|
+
((uint8_t *)target)[3] = ((uint8_t *)(&net_len))[1];
|
264
308
|
memcpy((uint8_t *)target + 4, msg, len);
|
265
309
|
return len + 4;
|
266
310
|
}
|
267
311
|
/* Really Long Message */
|
268
312
|
((uint8_t *)target)[1] = 127;
|
269
|
-
|
313
|
+
const uint64_t net_len = netiswap16(len);
|
314
|
+
((uint8_t *)target)[2] = ((uint8_t *)(&net_len))[0];
|
315
|
+
((uint8_t *)target)[3] = ((uint8_t *)(&net_len))[1];
|
316
|
+
((uint8_t *)target)[4] = ((uint8_t *)(&net_len))[2];
|
317
|
+
((uint8_t *)target)[5] = ((uint8_t *)(&net_len))[3];
|
318
|
+
((uint8_t *)target)[6] = ((uint8_t *)(&net_len))[4];
|
319
|
+
((uint8_t *)target)[7] = ((uint8_t *)(&net_len))[5];
|
320
|
+
((uint8_t *)target)[8] = ((uint8_t *)(&net_len))[6];
|
321
|
+
((uint8_t *)target)[9] = ((uint8_t *)(&net_len))[7];
|
270
322
|
memcpy((uint8_t *)target + 10, msg, len);
|
271
323
|
return len + 10;
|
272
324
|
}
|
@@ -295,23 +347,42 @@ static uint64_t websocket_client_wrap(void *target, void *msg, uint64_t len,
|
|
295
347
|
/*fin*/ ((last & 1) << 7);
|
296
348
|
if (len < 126) {
|
297
349
|
((uint8_t *)target)[1] = len | 128;
|
298
|
-
((
|
350
|
+
((uint8_t *)target)[2] = ((uint8_t *)(&mask))[0];
|
351
|
+
((uint8_t *)target)[3] = ((uint8_t *)(&mask))[1];
|
352
|
+
((uint8_t *)target)[4] = ((uint8_t *)(&mask))[2];
|
353
|
+
((uint8_t *)target)[5] = ((uint8_t *)(&mask))[3];
|
299
354
|
memcpy(((uint8_t *)target) + 6, msg, len);
|
300
355
|
websocket_xmask((uint8_t *)target + 6, len, mask);
|
301
356
|
return len + 6;
|
302
357
|
} else if (len < (1UL << 16)) {
|
303
358
|
/* head is 4 bytes */
|
304
359
|
((uint8_t *)target)[1] = 126 | 128;
|
305
|
-
|
306
|
-
((
|
360
|
+
const uint16_t net_len = netiswap16(len);
|
361
|
+
((uint8_t *)target)[2] = ((uint8_t *)(&net_len))[0];
|
362
|
+
((uint8_t *)target)[3] = ((uint8_t *)(&net_len))[1];
|
363
|
+
((uint8_t *)target)[4] = ((uint8_t *)(&mask))[0];
|
364
|
+
((uint8_t *)target)[5] = ((uint8_t *)(&mask))[1];
|
365
|
+
((uint8_t *)target)[6] = ((uint8_t *)(&mask))[2];
|
366
|
+
((uint8_t *)target)[7] = ((uint8_t *)(&mask))[3];
|
307
367
|
memcpy((uint8_t *)target + 8, msg, len);
|
308
368
|
websocket_xmask((uint8_t *)target + 8, len, mask);
|
309
369
|
return len + 8;
|
310
370
|
}
|
311
371
|
/* Really Long Message */
|
312
372
|
((uint8_t *)target)[1] = 255;
|
313
|
-
|
314
|
-
((
|
373
|
+
const uint64_t net_len = netiswap16(len);
|
374
|
+
((uint8_t *)target)[2] = ((uint8_t *)(&net_len))[0];
|
375
|
+
((uint8_t *)target)[3] = ((uint8_t *)(&net_len))[1];
|
376
|
+
((uint8_t *)target)[4] = ((uint8_t *)(&net_len))[2];
|
377
|
+
((uint8_t *)target)[5] = ((uint8_t *)(&net_len))[3];
|
378
|
+
((uint8_t *)target)[6] = ((uint8_t *)(&net_len))[4];
|
379
|
+
((uint8_t *)target)[7] = ((uint8_t *)(&net_len))[5];
|
380
|
+
((uint8_t *)target)[8] = ((uint8_t *)(&net_len))[6];
|
381
|
+
((uint8_t *)target)[9] = ((uint8_t *)(&net_len))[7];
|
382
|
+
((uint8_t *)target)[10] = ((uint8_t *)(&mask))[0];
|
383
|
+
((uint8_t *)target)[11] = ((uint8_t *)(&mask))[1];
|
384
|
+
((uint8_t *)target)[12] = ((uint8_t *)(&mask))[2];
|
385
|
+
((uint8_t *)target)[13] = ((uint8_t *)(&mask))[3];
|
315
386
|
memcpy((uint8_t *)target + 14, msg, len);
|
316
387
|
websocket_xmask((uint8_t *)target + 14, len, mask);
|
317
388
|
return len + 14;
|
@@ -331,31 +402,28 @@ Message unwrapping
|
|
331
402
|
inline static struct websocket_packet_info_s
|
332
403
|
websocket_buffer_peek(void *buffer, uint64_t len) {
|
333
404
|
if (len < 2) {
|
334
|
-
return (struct websocket_packet_info_s){0
|
405
|
+
return (struct websocket_packet_info_s){0 /* packet */, 2 /* head */,
|
406
|
+
0 /* masked? */};
|
335
407
|
}
|
336
408
|
const uint8_t mask_f = (((uint8_t *)buffer)[1] >> 7) & 1;
|
337
409
|
const uint8_t mask_l = (mask_f << 2);
|
338
|
-
uint8_t len_indicator = (((uint8_t *)buffer)[1] & 127);
|
339
|
-
if (len < 126) {
|
340
|
-
return (struct websocket_packet_info_s){len_indicator,
|
341
|
-
(uint8_t)(2 + mask_l), mask_f};
|
342
|
-
}
|
410
|
+
uint8_t len_indicator = ((((uint8_t *)buffer)[1]) & 127);
|
343
411
|
switch (len_indicator) {
|
344
412
|
case 126:
|
345
413
|
if (len < 4)
|
346
414
|
return (struct websocket_packet_info_s){0, (uint8_t)(4 + mask_l), mask_f};
|
347
415
|
return (struct websocket_packet_info_s){
|
348
|
-
(uint64_t)
|
416
|
+
(uint64_t)netpiswap16(((uint8_t *)buffer) + 2), (uint8_t)(4 + mask_l),
|
349
417
|
mask_f};
|
350
418
|
case 127:
|
351
419
|
if (len < 10)
|
352
420
|
return (struct websocket_packet_info_s){0, (uint8_t)(10 + mask_l),
|
353
421
|
mask_f};
|
354
422
|
return (struct websocket_packet_info_s){
|
355
|
-
|
356
|
-
(uint8_t)(10 + mask_l), mask_f};
|
423
|
+
netpiswap64(((uint8_t *)buffer) + 2), (uint8_t)(10 + mask_l), mask_f};
|
357
424
|
default:
|
358
|
-
return (struct websocket_packet_info_s){
|
425
|
+
return (struct websocket_packet_info_s){len_indicator,
|
426
|
+
(uint8_t)(2 + mask_l), mask_f};
|
359
427
|
}
|
360
428
|
}
|
361
429
|
|
@@ -416,13 +484,13 @@ static uint64_t websocket_consume(void *buffer, uint64_t len, void *udata,
|
|
416
484
|
websocket_on_protocol_error(udata);
|
417
485
|
}
|
418
486
|
/* step forward */
|
419
|
-
reminder
|
487
|
+
reminder = reminder - (info.head_length + info.packet_length);
|
488
|
+
if (!reminder)
|
489
|
+
return 0;
|
420
490
|
pos += info.head_length + info.packet_length;
|
421
491
|
info = websocket_buffer_peek(pos, reminder);
|
422
492
|
}
|
423
493
|
/* reset buffer state - support pipelining */
|
424
|
-
if (!reminder)
|
425
|
-
return 0;
|
426
494
|
memmove(buffer, (uint8_t *)buffer + len - reminder, reminder);
|
427
495
|
return reminder;
|
428
496
|
}
|
data/ext/iodine/websockets.c
CHANGED
@@ -267,13 +267,12 @@ static void on_data(intptr_t sockfd, protocol_s *ws_) {
|
|
267
267
|
}
|
268
268
|
}
|
269
269
|
|
270
|
-
ssize_t len = sock_read(sockfd, (uint8_t *)ws->buffer.data + ws->length,
|
271
|
-
|
270
|
+
const ssize_t len = sock_read(sockfd, (uint8_t *)ws->buffer.data + ws->length,
|
271
|
+
ws->buffer.size - ws->length);
|
272
272
|
if (len <= 0) {
|
273
273
|
return;
|
274
274
|
}
|
275
|
-
ws->length
|
276
|
-
ws->length = websocket_consume(ws->buffer.data, ws->length, ws, 1);
|
275
|
+
ws->length = websocket_consume(ws->buffer.data, ws->length + len, ws, 1);
|
277
276
|
|
278
277
|
facil_force_event(sockfd, FIO_EVENT_ON_DATA);
|
279
278
|
}
|
data/lib/iodine.rb
CHANGED
@@ -57,7 +57,7 @@ require 'iodine/iodine'
|
|
57
57
|
# * {Iodine.connect} creates a new TCP/IP connection using the specified Protocol.
|
58
58
|
# * {Iodine.listen} listens to new TCP/IP connections using the specified Protocol.
|
59
59
|
# * {Iodine.listen2http} listens to new TCP/IP connections using the buildin HTTP / Websocket Protocol.
|
60
|
-
# * {Iodine.warmup} warms up
|
60
|
+
# * {Iodine.warmup} warms up any HTTP Rack applications.
|
61
61
|
# * {Iodine.count} counts the number of connections (including HTTP / Websocket connections).
|
62
62
|
# * {Iodine::Protocol.each} runs a code of block for every connection sharing the process (except HTTP / Websocket connections).
|
63
63
|
# * {Iodine::Websocket.each} runs a code of block for every existing websocket sharing the process.
|
@@ -74,7 +74,7 @@ require 'iodine/iodine'
|
|
74
74
|
# * {Iodine.publish} publishes a message to a Pub/Sub channel. The message will be sent to all subscribers - connections, other processes in the cluster and even other machines (when using the {Iodine::PubSub::RedisEngine}).
|
75
75
|
# * {Iodine.default_pubsub=}, {Iodine.default_pubsub} sets or gets the default Pub/Sub {Iodine::PubSub::Engine}. i.e., when set to a new {Iodine::PubSub::RedisEngine} instance, all Pub/Sub method calls will use the Redis engine (unless explicitly requiring a different engine).
|
76
76
|
#
|
77
|
-
# {Iodine::Websocket} objects have a seperate Pub/Sub implementation that manages the subscription's lifetime to match the connection's lifetime and allows direct client Pub/Sub (forwards the message to the client directly).
|
77
|
+
# {Iodine::Websocket} objects have a seperate Pub/Sub implementation that manages the subscription's lifetime to match the connection's lifetime and allows direct client Pub/Sub (forwards the message to the client directly without invoking the Ruby interpreter).
|
78
78
|
#
|
79
79
|
# == Patching Rack
|
80
80
|
#
|
@@ -149,7 +149,9 @@ module Iodine
|
|
149
149
|
# Runs the warmup sequence. {warmup} attempts to get every "autoloaded" (lazy loaded)
|
150
150
|
# file to load now instead of waiting for "first access". This allows multi-threaded safety and better memory utilization during forking.
|
151
151
|
#
|
152
|
-
#
|
152
|
+
# However, `warmup` might cause undefined behavior and should be avoided when using gems that initiate network / database connections or gems that spawn threads (i.e., ActiveRecord / ActiveCable).
|
153
|
+
#
|
154
|
+
# Use {warmup} when either {processes} or {threads} are set to more then 1 and gems don't spawn threads or initialize network connections.
|
153
155
|
def self.warmup app
|
154
156
|
# load anything marked with `autoload`, since autoload isn't thread safe nor fork friendly.
|
155
157
|
Iodine.run do
|
data/lib/iodine/cli.rb
CHANGED
@@ -2,8 +2,9 @@ require 'iodine'
|
|
2
2
|
require 'rack'
|
3
3
|
|
4
4
|
module Iodine
|
5
|
+
# The Iodine::Base namespace is reserved for internal use and is NOT part of the public API.
|
5
6
|
module Base
|
6
|
-
# Command line interface
|
7
|
+
# Command line interface. The Ruby CLI might be changed in future versions.
|
7
8
|
module CLI
|
8
9
|
|
9
10
|
def print_help
|
data/lib/iodine/monkeypatch.rb
CHANGED
data/lib/iodine/pubsub.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
module Iodine
|
2
2
|
# Iodine is equiped with an internal pub/sub service that allows improved resource management from a deployment perspective.
|
3
3
|
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# publish–subscribe is a messaging pattern where senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers, but instead characterize published messages into classes without knowledge of which subscribers, if any, there may be. Similarly, subscribers express interest in one or more classes and only receive messages that are of interest, without knowledge of which publishers, if any, there are.
|
4
|
+
# @note From {https://en.wikipedia.org/wiki/Publish–subscribe_pattern Wikipedia}: publish–subscribe is a messaging pattern where senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers, but instead characterize published messages into classes without knowledge of which subscribers, if any, there may be. Similarly, subscribers express interest in one or more classes and only receive messages that are of interest, without knowledge of which publishers, if any, there are.
|
7
5
|
#
|
8
6
|
# The common paradigm, which is implemented by pub/sub services like Redis,
|
9
7
|
# is for a "client" to "subscribe" to one or more "channels". Messages are streamed
|
data/lib/iodine/version.rb
CHANGED
data/lib/rack/handler/iodine.rb
CHANGED
@@ -135,7 +135,7 @@ module Iodine
|
|
135
135
|
@app = app
|
136
136
|
end
|
137
137
|
@port = options[:Port].to_s if options[:Port]
|
138
|
-
@
|
138
|
+
@address = options[:Address].to_s if options[:Address]
|
139
139
|
|
140
140
|
# # provide Websocket features using Rack::Websocket
|
141
141
|
# Rack.send :remove_const, :Websocket if defined?(Rack::Websocket)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iodine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boaz Segev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-10-
|
11
|
+
date: 2017-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|