iodine 0.2.9 → 0.2.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ba4e058f674e3984cdee2cff5cb107c1b2563ecf
4
- data.tar.gz: 6d733dd6ab5daea3464b2a2f2e1567e9781361a8
3
+ metadata.gz: 30444cc800decb8b3339bdbc34e499e8fa8d7d75
4
+ data.tar.gz: 6657c29ca28a5aa8ef3dd3f50e848020f256b674
5
5
  SHA512:
6
- metadata.gz: 2acca1d13ceb9bfa682fe1f7aa1175349d3d092c15747b700785f9ad5117f7714ee851ac5e61cebf93c31bee793f4af38ecff504d780fdd65c575c42ab3c04a7
7
- data.tar.gz: 8f182b7d745804676f2f7837f36f92419fdd7c1c740cd1a3f9fbfc66c25dbf16eb0c2f11b8454d6ecc30e4be5992c7a0c77f707e3c6f2a52962dbf4979f16fe2
6
+ metadata.gz: be709de0f327815d3c8366f388395f8dc26c4a1789a25d5c80e04445efd9508c746a95df6538d34fcee405c0f7458d6fa9575b256483124e72db042e5c8ad907
7
+ data.tar.gz: f7d0fb12ed10468ffc2a1b3297d2a214da07753570873dc79224a1ae8279034a1abe72f2a78801850606921ae851874b91854380a4b0003d914c199dfbe08589
@@ -6,6 +6,33 @@ Please notice that this change log contains changes for upcoming releases as wel
6
6
 
7
7
  ## Changes:
8
8
 
9
+ ***
10
+
11
+ Change log v.0.2.10 (next release)
12
+
13
+ **Update**: added documentation and an extra helper method to set a connection's timeout when using custom protocols (Iodine as an EventMachine alternative).
14
+
15
+ **C Layer Update** updated the [`facil.io`](http://facil.io) library used, to incorporate the following fixes / update:
16
+
17
+ * Better cross platform compilation by avoiding some name-space clashes. i.e, fixes a name clash with the `__used` directive / macro, where some OSs (i.e. CentOS) used a similar directive with different semantics.
18
+
19
+ * Reviewed and fixed some signed vs. unsigned integer comparisons.
20
+
21
+ * Smoother event scheduling by increasing the event-node's pool size.
22
+
23
+ * Smoother thread concurrency growth by managing thread `nanosleep` times as thread count dependent.
24
+
25
+ * Cleared out "unused variable" warnings.
26
+
27
+ * Streamlined the `accept` process to remove a double socket's data clean-up.
28
+
29
+ * `SERVER_DELAY_IO` is now implemented as an event instead of a stack frame.
30
+
31
+ * Fixed a possible Linux `sendfile` implementation issue where sometimes errors wouldn't be caught or `sendfile` would be called past a file's limit (edge case handling).
32
+
33
+ * `bscrypt` random generator (where `dev/random` is unavailable) should now provide more entropy.
34
+
35
+
9
36
  ***
10
37
 
11
38
  Change log v.0.2.9
data/README.md CHANGED
@@ -6,7 +6,9 @@
6
6
  [![Inline docs](http://inch-ci.org/github/boazsegev/iodine.svg?branch=master)](http://www.rubydoc.info/github/boazsegev/iodine/master/frames)
7
7
  [![GitHub](https://img.shields.io/badge/GitHub-Open%20Source-blue.svg)](https://github.com/boazsegev/iodine)
8
8
 
9
- Iodine makes writing Object Oriented **Network Services** easy to write.
9
+ Iodine is a fast concurrent web server for real-time Ruby applications, with native support for Websockets, static file service and HTTP/1.1.
10
+
11
+ Iodine also supports custom protocol authoring, making Object Oriented **Network Services** easy to write.
10
12
 
11
13
  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
14
 
@@ -63,7 +65,7 @@ This means that even a Gigabyte long response will use ~32Kb of memory, as long
63
65
 
64
66
  Iodine supports static file serving that allows the server to serve static files directly, with no Ruby layer (all from C-land).
65
67
 
66
- This means that Iodine won't lock Ruby's GVL when sending static files (nor log these requests). The files will be sent directly, allowing for true native concurrency.
68
+ This means that Iodine won't lock Ruby's GVL when sending static files. The files will be sent directly, allowing for true native concurrency. Since the Ruby layer is unaware of these requests, logging can be performed by turning iodine's logger on.
67
69
 
68
70
  To setup native static file service, setup the public folder's address **before** starting the server.
69
71
 
@@ -83,9 +85,17 @@ app = Proc.new { out }
83
85
  run app
84
86
  ```
85
87
 
88
+ To enable logging from the command line, use the `-v` (verbose) option:
89
+
90
+ ```bash
91
+ bundler exec iodine -p $PORT -t 16 -w 4 -www /my/public/folder -v
92
+ ```
93
+
86
94
  #### X-Sendfile
87
95
 
88
- Sending can be performed by using the `X-Sendfile` header in the Ruby application response.
96
+ Ruby can leverage static file support (if enabled) by using the `X-Sendfile` header in the Ruby application response.
97
+
98
+ This allows Ruby to send very large files using a very small memory footprint, as well as (when possible) leveraging the `sendfile` system call.
89
99
 
90
100
  i.e. (example `config.ru` for Iodine):
91
101
 
@@ -95,7 +105,7 @@ app = proc do |env|
95
105
  if request.path_info == '/source'.freeze
96
106
  [200, { 'X-Sendfile' => File.expand_path(__FILE__) }, []]
97
107
  elsif request.path_info == '/file'.freeze
98
- [200, { 'X-Header' => 'This was a Rack::Sendfile response sent as text' }, File.open(__FILE__)]
108
+ [200, { 'X-Header' => 'This was a Rack::Sendfile response sent as text.' }, File.open(__FILE__)]
99
109
  else
100
110
  [200, { 'Content-Type'.freeze => 'text/html'.freeze,
101
111
  'Content-Length'.freeze => request.path_info.length.to_s },
@@ -15,21 +15,19 @@ require 'bundler/setup'
15
15
  require 'iodine'
16
16
 
17
17
  class HttpProtocol
18
- @timeout = 5
18
+ @timeout = 10
19
19
  # `on_message` is an optional alternative to the `on_data` callback.
20
20
  # `on_message` has a 1Kb buffer that recycles itself for memory optimization.
21
21
  def on_data
22
22
  # writing will never block and will use a buffer written in C when needed.
23
- data = nil
24
- while (data = read)
25
- write "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nKeep-Alive: timeout=1\r\nContent-Length: 12\r\n\r\nHello World!"
26
- end
23
+ write "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nKeep-Alive: timeout=1\r\nContent-Length: 12\r\n\r\nHello World!"
27
24
  end
28
25
  end
29
26
 
30
27
  puts "thread #{Iodine.threads}"
31
28
  # Listen
32
29
  Iodine.listen '3000', HttpProtocol
33
- Iodine.threads = 7
30
+ Iodine.threads = 8
31
+ Iodine.processes = 1
34
32
  puts "now, thread #{Iodine.threads}"
35
33
  Iodine.start
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # this will compile Iodine and run a raw sockets server that emulates HTTP (without parsing any incoming requests).
4
+
5
+ # # test using:
6
+ # ab -n 100000 -c 200 -k http://127.0.0.1:3000/
7
+ # wrk -c200 -d4 -t12 http://localhost:3000/
8
+
9
+ Dir.chdir(File.expand_path(File.join('..', '..'), __FILE__))
10
+ # puts `rake clean`
11
+ # puts `rake compile`
12
+
13
+ require 'benchmark'
14
+ # $LOAD_PATH.unshift File.expand_path(File.join('..', '..', 'lib'), __FILE__)
15
+ # require 'bundler/setup'
16
+
17
+ require 'eventmachine'
18
+
19
+ module HttpProtocol
20
+ def receive_data data
21
+ send_data "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nKeep-Alive: timeout=1\r\nContent-Length: 12\r\n\r\nHello World!"
22
+ end
23
+ end
24
+
25
+ puts "Running EM emulating HTTP."
26
+
27
+ if EventMachine.kqueue?
28
+ EventMachine.kqueue = true
29
+ puts "using Kqueue."
30
+ end
31
+ if EventMachine.epoll?
32
+ EventMachine.epoll = true
33
+ puts "using epoll."
34
+ end
35
+
36
+ # Note that this will block current thread.
37
+ EventMachine.run {
38
+ EventMachine.start_server "127.0.0.1", 3030, HttpProtocol
39
+ }
40
+
41
+ #
42
+ # require 'iodine'
43
+ #
44
+ # class HttpProtocol
45
+ # @timeout = 5
46
+ # # `on_message` is an optional alternative to the `on_data` callback.
47
+ # # `on_message` has a 1Kb buffer that recycles itself for memory optimization.
48
+ # def on_data
49
+ # # writing will never block and will use a buffer written in C when needed.
50
+ # data = nil
51
+ # while (data = read)
52
+ # write "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nKeep-Alive: timeout=1\r\nContent-Length: 12\r\n\r\nHello World!"
53
+ # end
54
+ # end
55
+ # end
56
+ #
57
+ # puts "thread #{Iodine.threads}"
58
+ # # Listen
59
+ # Iodine.listen '3000', HttpProtocol
60
+ # Iodine.threads = 7
61
+ # Iodine.processes = 1
62
+ # puts "now, thread #{Iodine.threads}"
63
+ # Iodine.start
@@ -57,8 +57,8 @@ and: https://software.intel.com/sites/landingpage/IntrinsicsGuide/
57
57
  # endif
58
58
  #endif
59
59
 
60
- #ifndef __unused
61
- # define __unused __attribute__((unused))
60
+ #ifndef UNUSED_FUNC
61
+ # define UNUSED_FUNC __attribute__((unused))
62
62
  #endif
63
63
  // clang-format on
64
64
 
@@ -47,7 +47,7 @@ struct {
47
47
  void *memory;
48
48
  http1_protocol_s *pool;
49
49
  spn_lock_i lock;
50
- } http1_pool = {0};
50
+ } http1_pool = {.memory = NULL};
51
51
 
52
52
  inline static http1_protocol_s *pool_pop() {
53
53
  http1_protocol_s *prot;
@@ -184,7 +184,7 @@ is_busy:
184
184
  p_len = 94 + http_ul2a(packet->buffer + 94, file_data.st_size);
185
185
  memcpy(packet->buffer + p_len, "\r\n\r\n", 4);
186
186
  p_len += 4;
187
- if (BUFFER_PACKET_SIZE - p_len > file_data.st_size) {
187
+ if ((off_t)(BUFFER_PACKET_SIZE - p_len) > file_data.st_size) {
188
188
  if (read(file, packet->buffer + p_len, file_data.st_size) < 0) {
189
189
  close(file);
190
190
  sock_free_packet(packet);
@@ -297,7 +297,8 @@ ssize_t http1_parse_request_headers(void *buffer, size_t len,
297
297
  }
298
298
  // check if the body is contained within the buffer
299
299
  EAT_EOL();
300
- if (request->content_length && (end - pos) >= request->content_length) {
300
+ if (request->content_length &&
301
+ (end - pos) >= (ssize_t)request->content_length) {
301
302
  request->body_str = (void *)pos;
302
303
  // fprintf(stderr,
303
304
  // "assigning body to string. content-length %lu, buffer left: "
@@ -18,8 +18,8 @@ Feel free to copy, use and enjoy according to the license provided.
18
18
  #include <strings.h>
19
19
  #include <unistd.h>
20
20
 
21
- #ifndef __unused
22
- #define __unused __attribute__((unused))
21
+ #ifndef UNUSED_FUNC
22
+ #define UNUSED_FUNC __attribute__((unused))
23
23
  #endif
24
24
 
25
25
  typedef struct {
@@ -97,7 +97,7 @@ typedef struct {
97
97
  http_headers_s headers[];
98
98
  } http_request_s;
99
99
 
100
- __unused static inline void http_request_clear(http_request_s *request) {
100
+ UNUSED_FUNC static inline void http_request_clear(http_request_s *request) {
101
101
  if (request->body_file > 0) /* assumes no tempfile with fd 0 */
102
102
  close(request->body_file);
103
103
  *request = (http_request_s){
@@ -109,7 +109,7 @@ __unused static inline void http_request_clear(http_request_s *request) {
109
109
 
110
110
  /** searches for a header in the header array, both reaturnning it's value and
111
111
  * setting it's position in the `request->metadata.header_pos` variable.*/
112
- __unused static inline const char *
112
+ UNUSED_FUNC static inline const char *
113
113
  http_request_find_header(http_request_s *request, const char *header,
114
114
  size_t header_len) {
115
115
  if (header == NULL || request == NULL)
@@ -24,6 +24,7 @@ Feel free to copy, use and enjoy according to the license provided.
24
24
  #include <sys/stat.h>
25
25
  #include <sys/types.h>
26
26
  #include <time.h>
27
+ #include <unistd.h>
27
28
 
28
29
  /* *****************************************************************************
29
30
  Helpers
@@ -340,7 +341,7 @@ int http_response_sendfile2(http_response_s *response, http_request_s *request,
340
341
  ext++;
341
342
  }
342
343
  // fprintf(stderr, "Start: %lu / %lld\n", start, file_data.st_size);
343
- if (start >= file_data.st_size - 1)
344
+ if ((off_t)start >= file_data.st_size - 1)
344
345
  goto invalid_range;
345
346
  ext++;
346
347
  while (is_num(*ext)) {
@@ -349,7 +350,7 @@ int http_response_sendfile2(http_response_s *response, http_request_s *request,
349
350
  ext++;
350
351
  }
351
352
  // going to the EOF (big chunk or EOL requested) - send as file
352
- if (finish >= file_data.st_size)
353
+ if ((off_t)finish >= file_data.st_size)
353
354
  finish = file_data.st_size;
354
355
  char *pos = buffer + 6;
355
356
  memcpy(buffer, "bytes ", 6);
@@ -405,7 +406,7 @@ no_file:
405
406
  }
406
407
 
407
408
  #ifdef RUSAGE_SELF
408
- const static size_t CLOCK_RESOLUTION = 1000; /* in miliseconds */
409
+ static const size_t CLOCK_RESOLUTION = 1000; /* in miliseconds */
409
410
  static size_t get_clock_mili(void) {
410
411
  struct rusage rusage;
411
412
  getrusage(RUSAGE_SELF, &rusage);
@@ -12,8 +12,8 @@ Feel free to copy, use and enjoy according to the license provided.
12
12
  #include "http_response.h"
13
13
  // clang-format on
14
14
 
15
- #ifndef __unused
16
- #define __unused __attribute__((unused))
15
+ #ifndef UNUSED_FUNC
16
+ #define UNUSED_FUNC __attribute__((unused))
17
17
  #endif
18
18
 
19
19
  /* *****************************************************************************
@@ -63,7 +63,7 @@ static inline int h1p_protected_copy(http_response_s *response,
63
63
 
64
64
  /* this function assume the padding in `h1p_protected_copy` saved enough room
65
65
  * for the data to be safely written.*/
66
- __unused static inline sock_packet_s *
66
+ UNUSED_FUNC static inline sock_packet_s *
67
67
  h1p_finalize_headers(http_response_s *response) {
68
68
  if (HEADERS_FINISHED(response))
69
69
  return NULL;
@@ -157,7 +157,7 @@ static int h1p_send_headers(http_response_s *response, sock_packet_s *packet) {
157
157
  Implementation
158
158
  ***************************************************************************** */
159
159
 
160
- __unused static inline int h1p_response_write_header(http_response_s *response,
160
+ UNUSED_FUNC static inline int h1p_response_write_header(http_response_s *response,
161
161
  http_headers_s header) {
162
162
  if (HEADERS_FINISHED(response) || header.name == NULL)
163
163
  return -1;
@@ -179,7 +179,7 @@ __unused static inline int h1p_response_write_header(http_response_s *response,
179
179
  /**
180
180
  Set / Delete a cookie using this helper function.
181
181
  */
182
- __unused static int h1p_response_set_cookie(http_response_s *response,
182
+ UNUSED_FUNC static int h1p_response_set_cookie(http_response_s *response,
183
183
  http_cookie_s cookie) {
184
184
  if (HEADERS_FINISHED(response) || cookie.name == NULL ||
185
185
  overflowing(response))
@@ -287,7 +287,7 @@ __unused static int h1p_response_set_cookie(http_response_s *response,
287
287
  /**
288
288
  Sends the headers (if unsent) and sends the body.
289
289
  */
290
- __unused static inline int h1p_response_write_body(http_response_s *response,
290
+ UNUSED_FUNC static inline int h1p_response_write_body(http_response_s *response,
291
291
  const char *body,
292
292
  size_t length) {
293
293
  if (!response->content_length)
@@ -298,7 +298,7 @@ __unused static inline int h1p_response_write_body(http_response_s *response,
298
298
  ((BUFFER_PACKET_SIZE - H1P_HEADER_START) - headers->length);
299
299
  if (i_read > 1024) {
300
300
  /* we can fit at least some of the data inside the response buffer. */
301
- if (i_read > length) {
301
+ if ((size_t)i_read > length) {
302
302
  i_read = length;
303
303
  /* we can fit the data inside the response buffer. */
304
304
  memcpy(response->metadata.headers_pos, body, i_read);
@@ -322,7 +322,7 @@ __unused static inline int h1p_response_write_body(http_response_s *response,
322
322
  /**
323
323
  Sends the headers (if unsent) and schedules the file to be sent.
324
324
  */
325
- __unused static inline int h1p_response_sendfile(http_response_s *response,
325
+ UNUSED_FUNC static inline int h1p_response_sendfile(http_response_s *response,
326
326
  int source_fd, off_t offset,
327
327
  size_t length) {
328
328
  if (!response->content_length)
@@ -337,7 +337,7 @@ __unused static inline int h1p_response_sendfile(http_response_s *response,
337
337
  source_fd, response->metadata.headers_pos,
338
338
  ((BUFFER_PACKET_SIZE - H1P_HEADER_START) - headers->length), offset);
339
339
  if (i_read > 0) {
340
- if (i_read >= length) {
340
+ if ((size_t)i_read >= length) {
341
341
  headers->length += length;
342
342
  close(source_fd);
343
343
  return h1p_send_headers(response, headers);
@@ -358,7 +358,7 @@ __unused static inline int h1p_response_sendfile(http_response_s *response,
358
358
  return sock_sendfile(response->metadata.fd, source_fd, offset, length);
359
359
  }
360
360
 
361
- __unused static inline int h1p_response_finish(http_response_s *response) {
361
+ UNUSED_FUNC static inline int h1p_response_finish(http_response_s *response) {
362
362
  sock_packet_s *headers = h1p_finalize_headers(response);
363
363
  if (headers) {
364
364
  return h1p_send_headers(response, headers);
@@ -96,7 +96,7 @@ static VALUE dyn_read(int argc, VALUE *argv, VALUE self) {
96
96
  len = rb_str_capacity(buffer);
97
97
  // make sure the string is modifiable
98
98
  rb_str_modify(buffer);
99
- // resize te string if needed.
99
+ // resize the string if needed.
100
100
  if (len < 1024)
101
101
  rb_str_resize(buffer, (len = 1024));
102
102
  str = buffer;
@@ -139,6 +139,30 @@ static VALUE dyn_write_urgent(VALUE self, VALUE data) {
139
139
  return self;
140
140
  }
141
141
 
142
+ /**
143
+ Update's a connection's timeout.
144
+
145
+ Returns self.
146
+ */
147
+ static VALUE dyn_set_timeout(VALUE self, VALUE timeout) {
148
+ intptr_t fd = iodine_get_fd(self);
149
+ unsigned int tout = FIX2UINT(timeout);
150
+ if (tout > 255)
151
+ tout = 255;
152
+ server_set_timeout(fd, tout);
153
+ return self;
154
+ }
155
+
156
+ /**
157
+ Returns the connection's timeout.
158
+ */
159
+ static VALUE dyn_get_timeout(VALUE self) {
160
+ intptr_t fd = iodine_get_fd(self);
161
+ uint8_t tout = server_get_timeout(fd);
162
+ unsigned int tout_int = tout;
163
+ return UINT2NUM(tout_int);
164
+ }
165
+
142
166
  /**
143
167
  Closes a connection.
144
168
 
@@ -157,10 +181,13 @@ The Core dynamic Iodine protocol task implementation
157
181
  */
158
182
 
159
183
  static void dyn_perform_defer(intptr_t uuid, protocol_s *protocol, void *arg) {
184
+ (void)(uuid);
185
+ (void)(protocol);
160
186
  RubyCaller.call((VALUE)arg, call_proc_id);
161
187
  Registry.remove((VALUE)arg);
162
188
  }
163
189
  static void dyn_defer_fallback(intptr_t uuid, void *arg) {
190
+ (void)(uuid);
164
191
  Registry.remove((VALUE)arg);
165
192
  };
166
193
 
@@ -190,11 +217,14 @@ static VALUE dyn_defer(VALUE self) {
190
217
 
191
218
  static void dyn_perform_each_task(intptr_t fd, protocol_s *protocol,
192
219
  void *data) {
220
+ (void)(fd);
193
221
  RubyCaller.call2((VALUE)data, call_proc_id, 1,
194
222
  &(dyn_prot(protocol)->handler));
195
223
  }
196
224
  static void dyn_finish_each_task(intptr_t fd, protocol_s *protocol,
197
225
  void *data) {
226
+ (void)(protocol);
227
+ (void)(fd);
198
228
  Registry.remove((VALUE)data);
199
229
  }
200
230
 
@@ -268,9 +298,16 @@ static VALUE not_implemented_ping(VALUE self) {
268
298
  return Qnil;
269
299
  }
270
300
  /** implement this callback to handle the event. */
271
- static VALUE not_implemented(VALUE self) { return Qnil; }
301
+ static VALUE not_implemented(VALUE self) {
302
+ (void)(self);
303
+ return Qnil;
304
+ }
272
305
  /** implement this callback to handle the event. */
273
- static VALUE not_implemented2(VALUE self, VALUE data) { return Qnil; }
306
+ static VALUE not_implemented2(VALUE self, VALUE data) {
307
+ (void)(self);
308
+ (void)(data);
309
+ return Qnil;
310
+ }
274
311
 
275
312
  /**
276
313
  A default on_data implementation will read up to 1Kb into a reusable buffer from
@@ -295,15 +332,18 @@ static VALUE default_on_data(VALUE self) {
295
332
 
296
333
  /** called when a data is available, but will not run concurrently */
297
334
  static void dyn_protocol_on_data(intptr_t fduuid, protocol_s *protocol) {
335
+ (void)(fduuid);
298
336
  RubyCaller.call(dyn_prot(protocol)->handler, on_data_func_id);
299
337
  }
300
338
  /** called when the socket is ready to be written to. */
301
339
  static void dyn_protocol_on_ready(intptr_t fduuid, protocol_s *protocol) {
340
+ (void)(fduuid);
302
341
  RubyCaller.call(dyn_prot(protocol)->handler, on_ready_func_id);
303
342
  }
304
343
  /** called when the server is shutting down,
305
344
  * but before closing the connection. */
306
345
  static void dyn_protocol_on_shutdown(intptr_t fduuid, protocol_s *protocol) {
346
+ (void)(fduuid);
307
347
  RubyCaller.call(dyn_prot(protocol)->handler, on_shutdown_func_id);
308
348
  }
309
349
  /** called when the connection was closed, but will not run concurrently */
@@ -314,9 +354,10 @@ static void dyn_protocol_on_close(protocol_s *protocol) {
314
354
  }
315
355
  /** called when a connection's timeout was reached */
316
356
  static void dyn_protocol_ping(intptr_t fduuid, protocol_s *protocol) {
357
+ (void)(fduuid);
317
358
  RubyCaller.call(dyn_prot(protocol)->handler, ping_func_id);
318
359
  }
319
-
360
+ /** Update's a connection's handler and timeout. */
320
361
  static inline protocol_s *dyn_set_protocol(intptr_t fduuid, VALUE handler,
321
362
  uint8_t timeout) {
322
363
  Registry.add(handler);
@@ -339,6 +380,7 @@ static inline protocol_s *dyn_set_protocol(intptr_t fduuid, VALUE handler,
339
380
  RubyCaller.call(handler, on_open_func_id);
340
381
  return (protocol_s *)protocol;
341
382
  }
383
+
342
384
  static protocol_s *on_open_dyn_protocol(intptr_t fduuid, void *udata) {
343
385
  VALUE rb_tout = rb_ivar_get((VALUE)udata, timeout_var_id);
344
386
  uint8_t timeout = (TYPE(rb_tout) == T_FIXNUM) ? FIX2UINT(rb_tout) : 0;
@@ -385,6 +427,8 @@ void Init_DynamicProtocol(void) {
385
427
  rb_define_method(DynamicProtocol, "defer", dyn_defer, 0);
386
428
  rb_define_method(DynamicProtocol, "each", dyn_each, 0);
387
429
  rb_define_method(DynamicProtocol, "upgrade", dyn_upgrade, 1);
430
+ rb_define_method(DynamicProtocol, "timeout=", dyn_set_timeout, 1);
431
+ rb_define_method(DynamicProtocol, "timeout", dyn_get_timeout, 0);
388
432
  }
389
433
 
390
434
  /* *****************************************************************************
@@ -474,6 +518,7 @@ will be delayed until Iodine.start is called, unless Iodine's event loop is
474
518
  active).
475
519
  */
476
520
  static VALUE iodine_run_async(VALUE self) {
521
+ (void)(self);
477
522
  // requires a block to be passed
478
523
  rb_need_block();
479
524
  VALUE block = rb_block_proc();
@@ -494,6 +539,7 @@ Time is counted only once Iodine started running (using {Iodine.start}).
494
539
  Always returns a copy of the block object.
495
540
  */
496
541
  static VALUE iodine_run_after(VALUE self, VALUE milliseconds) {
542
+ (void)(self);
497
543
  if (TYPE(milliseconds) != T_FIXNUM) {
498
544
  rb_raise(rb_eTypeError, "milliseconds must be a number");
499
545
  return Qnil;
@@ -526,6 +572,7 @@ The event will repeat itself until the number of repetitions had been delpeted.
526
572
  Always returns a copy of the block object.
527
573
  */
528
574
  static VALUE iodine_run_every(int argc, VALUE *argv, VALUE self) {
575
+ (void)(self);
529
576
  VALUE milliseconds, repetitions, block;
530
577
 
531
578
  rb_scan_args(argc, argv, "11&", &milliseconds, &repetitions, &block);
@@ -549,12 +596,16 @@ static VALUE iodine_run_every(int argc, VALUE *argv, VALUE self) {
549
596
  return block;
550
597
  }
551
598
 
552
- static VALUE iodine_count(VALUE self) { return ULONG2NUM(server_count(NULL)); }
599
+ static VALUE iodine_count(VALUE self) {
600
+ (void)(self);
601
+ return ULONG2NUM(server_count(NULL));
602
+ }
553
603
  /* *****************************************************************************
554
604
  Running the server
555
605
  */
556
606
 
557
607
  static void *srv_start_no_gvl(void *_) {
608
+ (void)(_);
558
609
  // collect requested settings
559
610
  VALUE rb_th_i = rb_iv_get(Iodine, "@threads");
560
611
  VALUE rb_pr_i = rb_iv_get(Iodine, "@processes");
@@ -591,7 +642,10 @@ static void *srv_start_no_gvl(void *_) {
591
642
  return NULL;
592
643
  }
593
644
 
594
- static void unblck(void *_) { server_stop(); }
645
+ static void unblck(void *_) {
646
+ (void)(_);
647
+ server_stop();
648
+ }
595
649
  /**
596
650
  Starts the Iodine event loop. This will hang the thread until an interrupt
597
651
  (`^C`) signal is received.