iodine 0.2.3 → 0.2.4
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/CHANGELOG.md +13 -1
- data/README.md +3 -3
- data/SPEC-Websocket-Draft.md +7 -7
- data/ext/iodine/iodine_core.c +1 -1
- data/ext/iodine/iodine_http.c +26 -3
- data/ext/iodine/libsock.c +20 -14
- data/lib/iodine/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5dd781b994de37f715d28a0bb3d2116d0130ec7
|
4
|
+
data.tar.gz: ef6e1fb31118a909c479c5b3a5eca55984794cfa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dcc16cec26d57a181e7883fef1772abff857f07c5d20ef7900f3ea1c63e953061567185d0456be14b6dfa8e827f7637720555455e38b5146ddcba26ca2d41eee
|
7
|
+
data.tar.gz: 1ca3bb3ccd3d45ad069e9093af6cecdd73c08ccb9b6018394f4ca1467cc7ae157cdcee248da32c5f5e82e91f5042a98d6173f10eeecf073225415c67bf9c7d97
|
data/CHANGELOG.md
CHANGED
@@ -8,9 +8,21 @@ Please notice that this change log contains changes for upcoming releases as wel
|
|
8
8
|
|
9
9
|
***
|
10
10
|
|
11
|
+
Change log v.0.2.4
|
12
|
+
|
13
|
+
**Minor Fix**: Patched Iodine against Apple's broken `getrlimit` on macOS. This allows correct auto-setting of open file limits for the socket layer.
|
14
|
+
|
15
|
+
**Minor Fix**: Fixed the processor under-utilization warning, where "0" might be shown for the number processes instead of "1".
|
16
|
+
|
17
|
+
**Update**: Added support for the `env` keys `HTTP_VERSION` and `SERVER_PROTOCOL` to indicate the HTTP protocol version. Iodine implements an HTTP/1.1 server, so versions aren't expected to be higher than 1.x.
|
18
|
+
|
19
|
+
**Update**: Iodine::Rack startup messages now include details regarding open file limits imposed by the OS (open file limits control the maximum allowed concurrent connections and other resource limits).
|
20
|
+
|
21
|
+
***
|
22
|
+
|
11
23
|
Change log v.0.2.3
|
12
24
|
|
13
|
-
**Update
|
25
|
+
**Update**: The `write` system call is now deferred when resources allow, meaning that (as long as the `write` buffer isn't full) `write` is not only non-blocking, but it's performed as a separate event, outside of the Ruby GIL.
|
14
26
|
|
15
27
|
**Update**: The global socket `write` buffer was increased to ~16Mb (from ~4Mb), allowing for more concurrent `write` operations. However, the `write` buffer is still limited and `write` might block while the buffer is full. Blocking and "hanging" the server until there's enough room in the buffer for the requested `write` will slow the server down while keeping it healthy and more secure. IMHO, it is the lesser of two evils.
|
16
28
|
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
|
9
9
|
Iodine makes writing Object Oriented **Network Services** easy to write.
|
10
10
|
|
11
|
-
Iodine is an **evented** framework with a simple API that builds off
|
11
|
+
Iodine is an **evented** framework with a simple API that builds off the low level [C code library facil.io](https://github.com/boazsegev/facil.io) with support for **epoll** and **kqueue** - this means that:
|
12
12
|
|
13
13
|
* Iodine can handle **thousands of concurrent connections** (tested with 20K connections).
|
14
14
|
|
@@ -352,7 +352,7 @@ Yes, please, here are some thoughts:
|
|
352
352
|
|
353
353
|
* I'm really not good at writing automated tests and benchmarks, any help would be appreciated. I keep testing manually and that's less then ideal (and it's mistake prone).
|
354
354
|
|
355
|
-
* If we can write a Java wrapper for [the C libraries](https://github.com/boazsegev/
|
355
|
+
* If we can write a Java wrapper for [the C libraries](https://github.com/boazsegev/facil.io), it would be nice... but it could be as big a project as the whole gem, as a lot of minor details are implemented within the bridge between these two languages.
|
356
356
|
|
357
357
|
* Bug reports and pull requests are welcome on GitHub at https://github.com/boazsegev/iodine.
|
358
358
|
|
@@ -380,7 +380,7 @@ Here's a few things you can use from this project and they seem to be handy to h
|
|
380
380
|
|
381
381
|
I'm attaching it to one of Iodine's library classes, just in-case someone adopts my code and decides the registry should be owned by the global Object class.
|
382
382
|
|
383
|
-
* I was using a POSIX thread pool library ([`libasync.h`](https://github.com/boazsegev/
|
383
|
+
* I was using a POSIX thread pool library ([`libasync.h`](https://github.com/boazsegev/facil.io/blob/master/lib/libasync.c)) until I realized how many issues Ruby has with non-Ruby threads... So now there's a Ruby-thread port for this library at ([`rb-libasync.h`](https://github.com/boazsegev/iodine/blob/master/ext/iodine/rb-libasync.h)).
|
384
384
|
|
385
385
|
Notice that all the new threads are free from the GVL - this allows true concurrency... but, you can't make Ruby API calls in that state.
|
386
386
|
|
data/SPEC-Websocket-Draft.md
CHANGED
@@ -16,9 +16,9 @@ The Websocket Callback Object should be a class (or an instance of such class) w
|
|
16
16
|
|
17
17
|
* `on_message(data)` WILL be called when incoming Websocket data is received. `data` will be a String with an encoding of UTF-8 for text messages and `binary` encoding for non-text messages (as specified by the Websocket Protocol).
|
18
18
|
|
19
|
-
The *client* **
|
19
|
+
The *client* **MUST** assume that the `data` String will be a **recyclable buffer** and that it's content will be corrupted the moment the `on_message` callback returns.
|
20
20
|
|
21
|
-
* `on_ready()` MAY be called when the state of the out-going socket buffer changes from full to not full (data can be sent to the socket). **If** `has_pending?` returns `true`, the `on_ready` callback **
|
21
|
+
* `on_ready()` **MAY** be called when the state of the out-going socket buffer changes from full to not full (data can be sent to the socket). **If** `has_pending?` returns `true`, the `on_ready` callback **MUST** be called once the buffer state changes.
|
22
22
|
|
23
23
|
* `on_shutdown()` MAY be called during the server's graceful shutdown process, _before_ the connection is closed and in addition to the `on_close` function (which is called _after_ the connection is closed.
|
24
24
|
|
@@ -28,15 +28,15 @@ The Websocket Callback Object should be a class (or an instance of such class) w
|
|
28
28
|
|
29
29
|
The following method names are reserved for the network implementation: `write`, `close` and `has_pending?`.
|
30
30
|
|
31
|
-
The server **
|
31
|
+
The server **MUST** extend the Websocket Callback Object's *class* using `extend`, so that the Websocket Callback Object inherits the following methods:
|
32
32
|
|
33
|
-
* `write(data)` will attempt to send the data through the websocket connection. `data` **
|
33
|
+
* `write(data)` will attempt to send the data through the websocket connection. `data` **MUST** be a String. If `data` is UTF-8 encoded, the data will be sent as text. If `data` is binary encoded it will be sent as non-text (as specified by the Websocket Protocol).
|
34
34
|
|
35
35
|
`write` has the same delivery promise as `Socket#write` (a successful `write` does **not** mean any of the data will reach the other side).
|
36
36
|
|
37
37
|
`write` shall return `true` on success and `false` if the websocket is closed.
|
38
38
|
|
39
|
-
A server **
|
39
|
+
A server **SHOULD** document whether `write` will block or return immediately. It is **RECOMMENDED** that servers implement buffered IO, allowing `write` to return immediately when resources allow and block (or, possibly, disconnect) when the IO buffer is full.
|
40
40
|
|
41
41
|
* `close` closes the connection once all the data in the outgoing queue was sent. If `close` is called while there is still data to be sent, `close` will only take effect once the data was sent.
|
42
42
|
|
@@ -54,9 +54,9 @@ The following keywords (both as method names and instance variable names) are re
|
|
54
54
|
|
55
55
|
* The `conn_id` object may be used as a connection ID for any functionality not specified herein.
|
56
56
|
|
57
|
-
Connection `ping` / `pong`, timeouts and network considerations should be implemented by the server. It is **
|
57
|
+
Connection `ping` / `pong`, timeouts and network considerations should be implemented by the server. It is **RECOMMENDED** (but not required) that the server send `ping`s to prevent connection timeouts and detect network failure.
|
58
58
|
|
59
|
-
Server settings **
|
59
|
+
Server settings **MAY** (not required) be provided to allow for customization and adaptation for different network environments or websocket extensions. It is **RECOMMENDED** that any settings be available as command line arguments and **not** incorporated into the application's logic.
|
60
60
|
|
61
61
|
## Upgrading
|
62
62
|
|
data/ext/iodine/iodine_core.c
CHANGED
@@ -566,7 +566,7 @@ static void *srv_start_no_gvl(void *_) {
|
|
566
566
|
"utilizing %lu processes.\n - %s\n"
|
567
567
|
" - Use the command line option: `-w %lu`\n"
|
568
568
|
" - Or, within Ruby: `Iodine.processes = %lu`\n",
|
569
|
-
cpu_count, processes,
|
569
|
+
cpu_count, (processes ? processes : 1),
|
570
570
|
(processes < cpu_count
|
571
571
|
? "Some CPUs won't be utilized, inhibiting performance."
|
572
572
|
: "This causes excessive context switches, wasting resources."),
|
data/ext/iodine/iodine_http.c
CHANGED
@@ -43,6 +43,9 @@ rack_declare(QUERY_STRING);
|
|
43
43
|
rack_declare(QUERY_ESTRING);
|
44
44
|
rack_declare(SERVER_NAME);
|
45
45
|
rack_declare(SERVER_PORT);
|
46
|
+
rack_declare(SERVER_PROTOCOL);
|
47
|
+
rack_declare(HTTP_VERSION);
|
48
|
+
rack_declare(REMOTE_ADDR);
|
46
49
|
rack_declare(CONTENT_LENGTH);
|
47
50
|
rack_declare(CONTENT_TYPE);
|
48
51
|
rack_declare(R_URL_SCHEME); // rack.url_scheme
|
@@ -78,6 +81,18 @@ static inline VALUE copy2env(http_request_s *request) {
|
|
78
81
|
(request->query
|
79
82
|
? rb_enc_str_new(request->query, request->query_len, BinaryEncoding)
|
80
83
|
: QUERY_ESTRING));
|
84
|
+
rb_hash_aset(
|
85
|
+
env, QUERY_STRING,
|
86
|
+
(request->query
|
87
|
+
? rb_enc_str_new(request->query, request->query_len, BinaryEncoding)
|
88
|
+
: QUERY_ESTRING));
|
89
|
+
|
90
|
+
hname =
|
91
|
+
rb_enc_str_new(request->version, request->version_len, BinaryEncoding);
|
92
|
+
rb_hash_aset(env, SERVER_PROTOCOL, hname);
|
93
|
+
rb_hash_aset(env, HTTP_VERSION, hname);
|
94
|
+
|
95
|
+
// rack_declare(REMOTE_ADDR);
|
81
96
|
|
82
97
|
/* setup input IO + hijack support */
|
83
98
|
rb_hash_aset(env, R_INPUT, (hname = RackIO.new(request, env)));
|
@@ -539,16 +554,21 @@ int iodine_http_review(void) {
|
|
539
554
|
fprintf(stderr, "Starting up Iodine Http Server:\n"
|
540
555
|
" * Ruby v.%s\n * Iodine v.%s \n"
|
541
556
|
" * %d processes X %d thread%s\n"
|
557
|
+
" * %d max concurrent connections / open files\n"
|
542
558
|
" * Serving static files from:\n"
|
543
559
|
" %s\n\n",
|
544
560
|
StringValueCStr(ruby_version), StringValueCStr(iodine_version),
|
545
|
-
processes, threads, (threads > 1 ? "s" : ""),
|
561
|
+
processes, threads, (threads > 1 ? "s" : ""), sock_max_capacity(),
|
562
|
+
public_folder);
|
546
563
|
else
|
547
564
|
fprintf(stderr, "Starting up Iodine Http Server:\n"
|
548
565
|
" * Ruby v.%s\n * Iodine v.%s \n"
|
549
|
-
" * %d processes X %d thread%s\n
|
566
|
+
" * %d processes X %d thread%s\n"
|
567
|
+
" * %d max concurrent connections / open files\n"
|
568
|
+
"\n",
|
550
569
|
StringValueCStr(ruby_version), StringValueCStr(iodine_version),
|
551
|
-
processes, threads, (threads > 1 ? "s" : "")
|
570
|
+
processes, threads, (threads > 1 ? "s" : ""),
|
571
|
+
sock_max_capacity());
|
552
572
|
|
553
573
|
// listen
|
554
574
|
return http1_listen(port, address, .on_request = on_rack_request,
|
@@ -571,6 +591,9 @@ void Init_iodine_http(void) {
|
|
571
591
|
rack_autoset(SERVER_PORT);
|
572
592
|
rack_autoset(CONTENT_LENGTH);
|
573
593
|
rack_autoset(CONTENT_TYPE);
|
594
|
+
rack_autoset(SERVER_PROTOCOL);
|
595
|
+
rack_autoset(HTTP_VERSION);
|
596
|
+
rack_autoset(REMOTE_ADDR);
|
574
597
|
rack_set(HTTP_SCHEME, "http");
|
575
598
|
rack_set(HTTPS_SCHEME, "https");
|
576
599
|
rack_set(QUERY_ESTRING, "");
|
data/ext/iodine/libsock.c
CHANGED
@@ -10,17 +10,18 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
10
10
|
|
11
11
|
#include "libsock.h"
|
12
12
|
|
13
|
-
#include <string.h>
|
14
|
-
#include <stdio.h>
|
15
|
-
#include <time.h>
|
16
|
-
#include <fcntl.h>
|
17
13
|
#include <errno.h>
|
14
|
+
#include <fcntl.h>
|
15
|
+
#include <limits.h>
|
18
16
|
#include <netdb.h>
|
19
|
-
#include <
|
20
|
-
#include <
|
17
|
+
#include <stdio.h>
|
18
|
+
#include <string.h>
|
21
19
|
#include <sys/mman.h>
|
22
|
-
#include <sys/time.h>
|
23
20
|
#include <sys/resource.h>
|
21
|
+
#include <sys/socket.h>
|
22
|
+
#include <sys/time.h>
|
23
|
+
#include <sys/types.h>
|
24
|
+
#include <time.h>
|
24
25
|
|
25
26
|
/* *****************************************************************************
|
26
27
|
Use spinlocks "spnlock.h".
|
@@ -62,7 +63,7 @@ OS Sendfile settings.
|
|
62
63
|
#elif defined(__unix__) /* BSD sendfile should work, but isn't tested */
|
63
64
|
#include <sys/uio.h>
|
64
65
|
#define USE_SENDFILE 0
|
65
|
-
#elif defined(__APPLE__) /*
|
66
|
+
#elif defined(__APPLE__) /* Is the apple sendfile still broken? */
|
66
67
|
#include <sys/uio.h>
|
67
68
|
#define USE_SENDFILE 1
|
68
69
|
#else /* sendfile might not be available - always set to 0 */
|
@@ -130,11 +131,16 @@ ssize_t sock_max_capacity(void) {
|
|
130
131
|
flim = OPEN_MAX;
|
131
132
|
#endif
|
132
133
|
// try to maximize limits - collect max and set to max
|
133
|
-
struct rlimit rlim;
|
134
|
+
struct rlimit rlim = {0};
|
134
135
|
getrlimit(RLIMIT_NOFILE, &rlim);
|
135
|
-
|
136
|
-
|
136
|
+
// printf("Meximum open files are %llu out of %llu\n", rlim.rlim_cur,
|
137
|
+
// rlim.rlim_max);
|
138
|
+
#if defined(__APPLE__) /* Apple's getrlimit is broken. */
|
139
|
+
rlim.rlim_cur = rlim.rlim_max >= OPEN_MAX ? OPEN_MAX : rlim.rlim_max;
|
140
|
+
#else
|
137
141
|
rlim.rlim_cur = rlim.rlim_max;
|
142
|
+
#endif
|
143
|
+
|
138
144
|
setrlimit(RLIMIT_NOFILE, &rlim);
|
139
145
|
getrlimit(RLIMIT_NOFILE, &rlim);
|
140
146
|
// printf("Meximum open files are %llu out of %llu\n", rlim.rlim_cur,
|
@@ -233,9 +239,9 @@ Call this function before calling any `libsock` functions.
|
|
233
239
|
static void destroy_lib_data(void) {
|
234
240
|
if (fd_info) {
|
235
241
|
while (fd_capacity--) { // include 0 in countdown
|
236
|
-
if (fd_info[fd_capacity].open) {
|
237
|
-
|
238
|
-
}
|
242
|
+
// if (fd_info[fd_capacity].open) {
|
243
|
+
// fprintf(stderr, "Socket %lu is marked as open\n", fd_capacity);
|
244
|
+
// }
|
239
245
|
set_fd(fd_capacity, LIB_SOCK_STATE_CLOSED);
|
240
246
|
}
|
241
247
|
#if USE_MALLOC == 1
|
data/lib/iodine/version.rb
CHANGED
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.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boaz Segev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -200,7 +200,7 @@ requirements:
|
|
200
200
|
- Ruby >= 2.2.2
|
201
201
|
- Ruby >= 2.0.0 is recommended.
|
202
202
|
rubyforge_project:
|
203
|
-
rubygems_version: 2.5.
|
203
|
+
rubygems_version: 2.5.2
|
204
204
|
signing_key:
|
205
205
|
specification_version: 4
|
206
206
|
summary: Iodine - leveraging C for Ruby servers.
|