rage-iodine 5.2.0 → 5.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7be7852385079072038ac11985d101e7b05b4a179d9cca4d9714b5259b2e7976
4
- data.tar.gz: 89cfe5691372d27ea1cc2093fa9f47e11b86011013b453a23c90371e7849e4c5
3
+ metadata.gz: 51d87d746e9c30552afbb177d23f52600d6b39668596921d396573cafb2296fc
4
+ data.tar.gz: 8f30fe5b42df456d0322712155ebada9c71c6c71f82748bd49d424ba2ad34707
5
5
  SHA512:
6
- metadata.gz: ffadced84f5141ee01debbb951cf7313d9c1f8fda94db7cec4512c717dd6f71c43d0f5e6375c3a736cc1f5c36820db530397c01196aac9e727c0ee47c95ed832
7
- data.tar.gz: 7cdf3c7c92c855dcb6f07b8063134f6c537f63e4f28bdab4a7b6e58911969c4f069a3d52f3d74ded830bd49a57033bc2fa6e33c77b5ffa1cbdda9d90c7b7307c
6
+ metadata.gz: 71cd1ec57ac2ea2680e4953207a7cbb2541b76e3eab7ce148ec06ab782079d056abb18a15fcbee8c62f6d1c6300ccce4a6951632e7c5b61f4ecac51deb8a8f05
7
+ data.tar.gz: 9c9091274cdecc5feff09ba84957162cfc466b4261eea2f74bf57bcd17ffeae05215b4f791d0250736828b04144e204367e64c6527bf189dabe23b39125fe6ab
@@ -0,0 +1,28 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ paths:
8
+ - lib/iodine/version.rb
9
+
10
+ permissions:
11
+ contents: write
12
+ id-token: write
13
+
14
+ jobs:
15
+ release:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v6
19
+ with:
20
+ persist-credentials: false
21
+
22
+ - name: Set up Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ bundler-cache: true
26
+ ruby-version: 3.4
27
+
28
+ - uses: rubygems/release-gem@v1
data/CHANGELOG.md CHANGED
@@ -6,6 +6,20 @@ Please notice that this change log contains changes for upcoming releases as wel
6
6
 
7
7
  ## Changes:
8
8
 
9
+ #### Change log v.5.3.0 (2026-06-03)
10
+
11
+ **Update**: Add Iodine::WorkerPool
12
+
13
+ **Update**: Allow to wake up the reactor from non-reactor threads
14
+
15
+ **Fix**: Correctly process async requests that return empty body
16
+
17
+ #### Change log v.5.2.1 (2026-03-18)
18
+
19
+ **Fix**: Fix memory leak when setting `x-accel-buffering` header
20
+
21
+ **Fix**: Fix memory leak with async SSE flows
22
+
9
23
  #### Change log v.5.2.0 (2026-03-10)
10
24
 
11
25
  **Update**: Skip connection validity check when closing SSE connections
@@ -138,6 +152,12 @@ Please notice that this change log contains changes for upcoming releases as wel
138
152
 
139
153
  **Update**: Allow to pause and resume fiber requests.
140
154
 
155
+ #### Change log v.0.7.58 (2024-04-28)
156
+
157
+ **Fix**: possible fix for compilation issues on Fedora. Credit to @garytaylor for opening issue #155.
158
+
159
+ **Fix**: possible fix for an OpenSSL certificate chain import issue that would cause certificate chains to be imported incorrectly. Credit to @dwolrdcojp for opening the facil.io repo PR #151.
160
+
141
161
  #### Change log v.0.7.57 (2023-09-04)
142
162
 
143
163
  **Fix**: Fixes possible name collision when loading gem (`.rb` vs. `.so` loading). Credit to @noraj (Alexandre ZANNI) for opening issue #148. Credit to @janbiedermann (Jan Biedermann) for discovering the root cause and offering a solution.
data/Gemfile CHANGED
@@ -5,6 +5,8 @@ group :test do
5
5
  gem 'rspec'
6
6
  gem 'rack'
7
7
  gem 'http'
8
+ gem 'base64'
9
+ gem 'benchmark'
8
10
  end
9
11
 
10
12
  # Specify your gem's dependencies in iodine.gemspec
data/README.md CHANGED
@@ -10,42 +10,42 @@
10
10
 
11
11
  Iodine is a fast concurrent web application server for real-time Ruby applications, with native support for WebSockets and Pub/Sub services - but it's also so much more.
12
12
 
13
- Iodine is a Ruby wrapper for many of the [facil.io](https://facil.io) C framework, leveraging the speed of C for many common web application tasks. In addition, iodine abstracts away all network concerns, so you never need to worry about the transport layer, free to concentrate on your application logic.
13
+ Iodine is a Ruby wrapper for much of the [facil.io](https://facil.io) C framework, leveraging the speed of C for many common web application tasks. In addition, iodine abstracts away all network concerns, so you never need to worry about the transport layer, leaving you free to concentrate on your application logic.
14
14
 
15
15
  Iodine includes native support for:
16
16
 
17
17
  * HTTP, WebSockets and EventSource (SSE) Services (server);
18
18
  * WebSocket connections (server / client);
19
19
  * Pub/Sub (with optional Redis Pub/Sub scaling);
20
- * Fast(!) builtin Mustache template engine.
20
+ * Fast(!) builtin Mustache templating;
21
21
  * Static file service (with automatic `gzip` support for pre-compressed assets);
22
- * Optimized Logging to `stderr`.
22
+ * Optimized Logging to `stderr`;
23
23
  * Asynchronous event scheduling and timers;
24
24
  * HTTP/1.1 keep-alive and pipelining;
25
- * Heap Fragmentation Protection.
26
- * TLS 1.2 and above (Requires OpenSSL >= 1.1.0);
25
+ * Heap Fragmentation Protection;
26
+ * TLS 1.2 and above (Requiring OpenSSL >= 1.1.0);
27
27
  * TCP/IP server and client connectivity;
28
28
  * Unix Socket server and client connectivity;
29
- * Hot Restart (using the USR1 signal and without hot deployment);
29
+ * Hot Restarts (using the USR1 signal and without hot deployment);
30
30
  * Custom protocol authoring;
31
- * [Sequel](https://github.com/jeremyevans/sequel) and ActiveRecord forking protection.
31
+ * [Sequel](https://github.com/jeremyevans/sequel) and ActiveRecord forking protection;
32
32
  * and more!
33
33
 
34
- Since iodine wraps much of the [C facil.io framework](https://github.com/boazsegev/facil.io) to Ruby:
34
+ Since iodine wraps much of the [C facil.io framework](https://github.com/boazsegev/facil.io) for Ruby:
35
35
 
36
- * Iodine can handle **thousands of concurrent connections** (tested with more then 20K connections on Linux)!
36
+ * Iodine can handle **thousands of concurrent connections** (tested with more than 20K connections on Linux)!
37
37
 
38
38
  * Iodine is ideal for **Linux/Unix** based systems (i.e. macOS, Ubuntu, FreeBSD etc'), which are ideal for evented IO (while Windows and Solaris are better at IO *completion* events, which are very different).
39
39
 
40
40
  Iodine is a C extension for Ruby, developed and optimized for Ruby MRI 2.3 and up... it should support the whole Ruby 2.x and 3.x MRI family, but CI tests start at Ruby 2.3.
41
41
 
42
- **Note**: iodine does **not** support streaming when using Rack. It's recommended to avoid blocking the server when using `body.each` since the `each` loop will block the iodine's thread until it's finished and iodine won't send any data before the loop is done.
42
+ **Note**: iodine does **not** support streaming when using Rack. It's recommended to avoid blocking the server when using `body.each` since the `each` loop will block iodine's thread until it's finished and iodine won't send any data before the loop is done.
43
43
 
44
44
  ## Iodine - a fast & powerful HTTP + WebSockets server with native Pub/Sub
45
45
 
46
46
  Iodine includes a light and fast HTTP and Websocket server written in C that was written according to the [Rack interface specifications](http://www.rubydoc.info/github/rack/rack/master/file/SPEC) and the [Websocket draft extension](./SPEC-Websocket-Draft.md).
47
47
 
48
- With `Iodine.listen service: :http` it's possible to run multiple HTTP applications (please remember not to set more than a single application on a single TCP/IP port).
48
+ With `Iodine.listen service: :http` it's possible to run multiple HTTP applications (but please remember not to set more than a single application on a single TCP/IP port).
49
49
 
50
50
  Iodine also supports native process cluster Pub/Sub and a native RedisEngine to easily scale iodine's Pub/Sub horizontally.
51
51
 
@@ -278,11 +278,11 @@ module WebsocketChat
278
278
  extend self
279
279
  end
280
280
  APP = Proc.new do |env|
281
- if env['rack.upgrade?'.freeze] == :websocket
282
- env['rack.upgrade'.freeze] = WebsocketChat
281
+ if env['rack.upgrade?'.freeze] == :websocket
282
+ env['rack.upgrade'.freeze] = WebsocketChat
283
283
  [0,{}, []] # It's possible to set cookies for the response.
284
284
  elsif env['rack.upgrade?'.freeze] == :sse
285
- puts "SSE connections can only receive data from the server, the can't write."
285
+ puts "SSE connections can only receive data from the server, the can't write."
286
286
  env['rack.upgrade'.freeze] = WebsocketChat
287
287
  [0,{}, []] # It's possible to set cookies for the response.
288
288
  else
@@ -556,7 +556,7 @@ Iodine is written in C and allows some compile-time customizations, such as:
556
556
  * `FIO_MAX_SOCK_CAPACITY` - limits iodine's maximum client capacity. Defaults to 131,072 clients.
557
557
 
558
558
  * `FIO_USE_RISKY_HASH` - replaces SipHash with RiskyHash for iodine's internal hash maps.
559
-
559
+
560
560
  Since iodine hash maps have internal protection against collisions and hash flooding attacks, it's possible for iodine to leverage RiskyHash, which is faster than SipHash.
561
561
 
562
562
  By default, SipHash will be used. This is a community related choice, since the community seems to believe a hash function should protect the hash map rather than it being enough for a hash map implementation to be attack resistance.
@@ -611,7 +611,7 @@ end
611
611
 
612
612
  In pure Ruby (without using C extensions or Java), it's possible to do the same by using `select`... and although `select` has some issues, it could work well for lighter loads.
613
613
 
614
- The server events are fairly fast and fragmented (longer code is fragmented across multiple events), so one thread is enough to run the server including it's static file service and everything...
614
+ The server events are fairly fast and fragmented (longer code is fragmented across multiple events), so one thread is enough to run the server including it's static file service and everything...
615
615
 
616
616
  ...but single threaded mode should probably be avoided.
617
617
 
@@ -642,7 +642,7 @@ If you have the development headers but still can't compile the iodine extension
642
642
 
643
643
  ## Mr. Sandman, write me a server
644
644
 
645
- Iodine allows custom TCP/IP server authoring, for those cases where we need raw TCP/IP (UDP isn't supported just yet).
645
+ Iodine allows custom TCP/IP server authoring, for those cases where we need raw TCP/IP (UDP isn't supported just yet).
646
646
 
647
647
  Here's a short and sweet echo server - No HTTP, just use `telnet`:
648
648
 
data/SECURITY.md ADDED
@@ -0,0 +1,32 @@
1
+ # Security Policy
2
+
3
+ Please report any security issues you discover on GitHub using the [`Security and quality`](https://github.com/boazsegev/iodine/security) reporting form.
4
+
5
+ Please remember that this is an open source project that I work on in my free time. Take it as is, I don't promise anything.
6
+
7
+ ## Supported Versions
8
+
9
+ I support what I have time to support, with my main focus being:
10
+
11
+ | Version | Support |
12
+ | ------- | ------------------ |
13
+ | 0.8.x | :green_circle: |
14
+ | 0.7.x | :orange_circle: |
15
+ | < 0.7.0 | :red_circle: |
16
+
17
+
18
+
19
+ ### [facil.io](https://facil.io) Security Issues
20
+
21
+
22
+ | Version | facil.io link |
23
+ | ------- | ------------------ |
24
+ | 0.8.x | https://github.com/facil-io/cstl/security |
25
+ | 0.7.x | https://github.com/boazsegev/facil.io/security |
26
+ | < 0.7.0 | :red_circle: |
27
+
28
+ ## Reporting a Vulnerability
29
+
30
+ Please report any security issues you discover on GitHub using the [`Security and quality`](https://github.com/boazsegev/iodine/security) reporting form or privately using email.
31
+
32
+ Usually I implement a security patch for the version reported before porting to the current developer version. Please note that it's usually possible to port the patch manually if you don't want to upgrade an older version.
@@ -107,4 +107,14 @@ EOS
107
107
  end
108
108
  end
109
109
 
110
+ # Feature detection for blocking operation support (Ruby 4.0+)
111
+ has_blocking_op_extract = have_func("rb_fiber_scheduler_blocking_operation_extract")
112
+
113
+ if has_blocking_op_extract
114
+ puts "detected blocking_operation APIs - enabling WorkerPool"
115
+ $defs << "-DHAVE_IODINE_WORKER_POOL"
116
+ else
117
+ puts "blocking_operation APIs not available (requires Ruby 4.0+) - WorkerPool disabled"
118
+ end
119
+
110
120
  create_makefile 'iodine/iodine_ext'
data/ext/iodine/fio.c CHANGED
@@ -1018,6 +1018,15 @@ static void init_static_throttle_key(void) {
1018
1018
  }
1019
1019
 
1020
1020
  static size_t fio_poll(void);
1021
+
1022
+ /*
1023
+ * Wake reactor when pushing tasks from non-reactor threads.
1024
+ * fio_is_reactor_thread() assumes single-threaded reactor (threads=1).
1025
+ * With multiple threads, fio_cycle can run on any worker, making this check
1026
+ * unreliable. Safe for Rage which enforces single-thread mode.
1027
+ */
1028
+ FIO_FUNC void fio_reactor_wakeup(void);
1029
+ FIO_FUNC int fio_is_reactor_thread(void);
1021
1030
  /**
1022
1031
  * A thread entering this function should wait for new events.
1023
1032
  */
@@ -1200,13 +1209,19 @@ critical_error:
1200
1209
  (fio_defer_task_s){.func = func_, .arg1 = arg1_, .arg2 = arg2_}, \
1201
1210
  &task_queue_normal); \
1202
1211
  fio_defer_thread_signal(); \
1212
+ if (!fio_is_reactor_thread()) \
1213
+ fio_reactor_wakeup(); \
1203
1214
  } while (0)
1204
1215
 
1205
1216
  #if FIO_USE_URGENT_QUEUE
1206
1217
  #define fio_defer_push_urgent(func_, arg1_, arg2_) \
1207
- fio_defer_push_task_fn( \
1208
- (fio_defer_task_s){.func = func_, .arg1 = arg1_, .arg2 = arg2_}, \
1209
- &task_queue_urgent)
1218
+ do { \
1219
+ fio_defer_push_task_fn( \
1220
+ (fio_defer_task_s){.func = func_, .arg1 = arg1_, .arg2 = arg2_}, \
1221
+ &task_queue_urgent); \
1222
+ if (!fio_is_reactor_thread()) \
1223
+ fio_reactor_wakeup(); \
1224
+ } while (0)
1210
1225
  #else
1211
1226
  #define fio_defer_push_urgent(func_, arg1_, arg2_) \
1212
1227
  fio_defer_push_task(func_, arg1_, arg2_)
@@ -1974,6 +1989,7 @@ Section Start Marker
1974
1989
  ***************************************************************************** */
1975
1990
  #if FIO_ENGINE_EPOLL
1976
1991
  #include <sys/epoll.h>
1992
+ #include <sys/eventfd.h>
1977
1993
 
1978
1994
  /**
1979
1995
  * Returns a C string detailing the IO engine selected during compilation.
@@ -1984,6 +2000,10 @@ char const *fio_engine(void) { return "epoll"; }
1984
2000
 
1985
2001
  /* epoll tester, in and out */
1986
2002
  static int evio_fd[3] = {-1, -1, -1};
2003
+ /* eventfd for cross-thread reactor wakeup */
2004
+ static int fio_wakeup_fd = -1;
2005
+ /* reactor thread ID */
2006
+ static pthread_t fio_reactor_thread;
1987
2007
 
1988
2008
  static void fio_poll_close(void) {
1989
2009
  for (int i = 0; i < 3; ++i) {
@@ -1992,6 +2012,10 @@ static void fio_poll_close(void) {
1992
2012
  evio_fd[i] = -1;
1993
2013
  }
1994
2014
  }
2015
+ if (fio_wakeup_fd != -1) {
2016
+ close(fio_wakeup_fd);
2017
+ fio_wakeup_fd = -1;
2018
+ }
1995
2019
  }
1996
2020
 
1997
2021
  static void fio_poll_init(void) {
@@ -2009,6 +2033,20 @@ static void fio_poll_init(void) {
2009
2033
  if (epoll_ctl(evio_fd[0], EPOLL_CTL_ADD, evio_fd[i], &chevent) == -1)
2010
2034
  goto error;
2011
2035
  }
2036
+ /* initialize eventfd for cross-thread wakeup */
2037
+ fio_wakeup_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
2038
+ if (fio_wakeup_fd == -1) {
2039
+ FIO_LOG_FATAL("couldn't create eventfd.");
2040
+ goto error;
2041
+ }
2042
+ {
2043
+ struct epoll_event ev = {.events = EPOLLIN, .data.fd = fio_wakeup_fd};
2044
+ if (epoll_ctl(evio_fd[1], EPOLL_CTL_ADD, fio_wakeup_fd, &ev) == -1) {
2045
+ FIO_LOG_FATAL("couldn't register eventfd with epoll.");
2046
+ goto error;
2047
+ }
2048
+ }
2049
+ fio_reactor_thread = pthread_self();
2012
2050
  return;
2013
2051
  error:
2014
2052
  FIO_LOG_FATAL("couldn't initialize epoll.");
@@ -2081,6 +2119,11 @@ static size_t fio_poll(void) {
2081
2119
  epoll_wait(internal[j].data.fd, events, FIO_POLL_MAX_EVENTS, 0);
2082
2120
  if (active_count > 0) {
2083
2121
  for (int i = 0; i < active_count; i++) {
2122
+ if (events[i].data.fd == fio_wakeup_fd) {
2123
+ uint64_t val;
2124
+ read(fio_wakeup_fd, &val, sizeof(val));
2125
+ continue;
2126
+ }
2084
2127
  if (events[i].events & (~(EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLRDHUP | EPOLLERR))) {
2085
2128
  // errors are hendled as disconnections (on_close)
2086
2129
  fio_force_close_in_poll(fd2uuid(events[i].data.fd));
@@ -2109,6 +2152,17 @@ static size_t fio_poll(void) {
2109
2152
  return total;
2110
2153
  }
2111
2154
 
2155
+ FIO_FUNC int fio_is_reactor_thread(void) {
2156
+ return pthread_equal(pthread_self(), fio_reactor_thread);
2157
+ }
2158
+
2159
+ FIO_FUNC void fio_reactor_wakeup(void) {
2160
+ if (fio_wakeup_fd == -1)
2161
+ return;
2162
+ uint64_t val = 1;
2163
+ write(fio_wakeup_fd, &val, sizeof(val));
2164
+ }
2165
+
2112
2166
  #endif
2113
2167
  /* *****************************************************************************
2114
2168
  Section Start Marker
@@ -2152,8 +2206,24 @@ Section Start Marker
2152
2206
  char const *fio_engine(void) { return "kqueue"; }
2153
2207
 
2154
2208
  static int evio_fd = -1;
2209
+ /* EVFILT_USER identifier for cross-thread reactor wakeup */
2210
+ #define FIO_WAKEUP_IDENT 0xF10A11EUL
2211
+ static volatile int fio_wakeup_registered = 0;
2212
+ /* reactor thread ID */
2213
+ static pthread_t fio_reactor_thread;
2155
2214
 
2156
- static void fio_poll_close(void) { close(evio_fd); }
2215
+ static void fio_poll_close(void) {
2216
+ if (fio_wakeup_registered && evio_fd >= 0) {
2217
+ struct kevent kev;
2218
+ EV_SET(&kev, FIO_WAKEUP_IDENT, EVFILT_USER, EV_DELETE, 0, 0, NULL);
2219
+ kevent(evio_fd, &kev, 1, NULL, 0, NULL);
2220
+ fio_wakeup_registered = 0;
2221
+ }
2222
+ if (evio_fd >= 0) {
2223
+ close(evio_fd);
2224
+ evio_fd = -1;
2225
+ }
2226
+ }
2157
2227
 
2158
2228
  static void fio_poll_init(void) {
2159
2229
  fio_poll_close();
@@ -2162,6 +2232,17 @@ static void fio_poll_init(void) {
2162
2232
  FIO_LOG_FATAL("couldn't open kqueue.\n");
2163
2233
  exit(errno);
2164
2234
  }
2235
+ /* register EVFILT_USER for cross-thread wakeup */
2236
+ {
2237
+ struct kevent kev;
2238
+ EV_SET(&kev, FIO_WAKEUP_IDENT, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL);
2239
+ if (kevent(evio_fd, &kev, 1, NULL, 0, NULL) == -1) {
2240
+ FIO_LOG_FATAL("couldn't register EVFILT_USER.\n");
2241
+ exit(errno);
2242
+ }
2243
+ fio_wakeup_registered = 1;
2244
+ }
2245
+ fio_reactor_thread = pthread_self();
2165
2246
  }
2166
2247
 
2167
2248
  static inline void fio_poll_add_read(intptr_t fd) {
@@ -2226,6 +2307,11 @@ static size_t fio_poll(void) {
2226
2307
 
2227
2308
  if (active_count > 0) {
2228
2309
  for (int i = 0; i < active_count; i++) {
2310
+ if (events[i].filter == EVFILT_USER &&
2311
+ events[i].ident == FIO_WAKEUP_IDENT) {
2312
+ /* EV_CLEAR auto-resets, nothing to drain */
2313
+ continue;
2314
+ }
2229
2315
  // test for event(s) type
2230
2316
  if (events[i].filter == EVFILT_WRITE) {
2231
2317
  fio_defer_push_urgent(deferred_on_ready,
@@ -2250,6 +2336,18 @@ static size_t fio_poll(void) {
2250
2336
  return active_count;
2251
2337
  }
2252
2338
 
2339
+ FIO_FUNC int fio_is_reactor_thread(void) {
2340
+ return pthread_equal(pthread_self(), fio_reactor_thread);
2341
+ }
2342
+
2343
+ FIO_FUNC void fio_reactor_wakeup(void) {
2344
+ if (!fio_wakeup_registered)
2345
+ return;
2346
+ struct kevent kev;
2347
+ EV_SET(&kev, FIO_WAKEUP_IDENT, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
2348
+ kevent(evio_fd, &kev, 1, NULL, 0, NULL);
2349
+ }
2350
+
2253
2351
  #endif
2254
2352
  /* *****************************************************************************
2255
2353
  Section Start Marker
@@ -2399,6 +2497,13 @@ finish:
2399
2497
  return count;
2400
2498
  }
2401
2499
 
2500
+ FIO_FUNC int fio_is_reactor_thread(void) {
2501
+ return 1;
2502
+ }
2503
+
2504
+ FIO_FUNC void fio_reactor_wakeup(void) {
2505
+ }
2506
+
2402
2507
  #endif /* FIO_ENGINE_POLL */
2403
2508
 
2404
2509
  /* *****************************************************************************
@@ -2581,6 +2686,13 @@ finish:
2581
2686
  return count;
2582
2687
  }
2583
2688
 
2689
+ FIO_FUNC int fio_is_reactor_thread(void) {
2690
+ return 1;
2691
+ }
2692
+
2693
+ FIO_FUNC void fio_reactor_wakeup(void) {
2694
+ }
2695
+
2584
2696
  #endif /* FIO_ENGINE_WSAPOLL */
2585
2697
 
2586
2698
  /* *****************************************************************************
@@ -3437,7 +3549,7 @@ read_error:
3437
3549
  static int fio_sock_sendfile_from_fd(int fd, fio_packet_s *packet) {
3438
3550
  ssize_t sent;
3439
3551
  sent =
3440
- sendfile64(fd, packet->data.fd, (off_t *)&packet->offset, packet->length);
3552
+ sendfile(fd, packet->data.fd, (off_t *)&packet->offset, packet->length);
3441
3553
  if (sent < 0)
3442
3554
  return -1;
3443
3555
  packet->length -= sent;
data/ext/iodine/fio.h CHANGED
@@ -109,7 +109,7 @@ Version and helper macros
109
109
 
110
110
  #define FIO_VERSION_MAJOR 0
111
111
  #define FIO_VERSION_MINOR 7
112
- #define FIO_VERSION_PATCH 4
112
+ #define FIO_VERSION_PATCH 7
113
113
  #define FIO_VERSION_BETA 0
114
114
 
115
115
  /* Automatically convert version data to a string constant - ignore these two */
@@ -221,6 +221,7 @@ Version and helper macros
221
221
  #include <unistd.h>
222
222
  #ifdef __MINGW32__
223
223
  #include <winsock2.h>
224
+
224
225
  #include <winsock.h>
225
226
  #include <ws2tcpip.h>
226
227
  #endif
@@ -251,10 +252,10 @@ Version and helper macros
251
252
  #endif
252
253
 
253
254
  #ifdef __MINGW32__
254
- #define __S_IFMT 0170000
255
- #define __S_IFLNK 0120000
256
- #define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask))
257
- #define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
255
+ #define __S_IFMT 0170000
256
+ #define __S_IFLNK 0120000
257
+ #define __S_ISTYPE(mode, mask) (((mode)&__S_IFMT) == (mask))
258
+ #define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
258
259
 
259
260
  #define SIGKILL 9
260
261
  #define SIGTERM 15
@@ -4781,14 +4782,11 @@ static FIO_ARY_TYPE const FIO_NAME(s___const_invalid_object);
4781
4782
  /* minimizes allocation "dead space" by alligning allocated length to 16bytes */
4782
4783
  #undef FIO_ARY_SIZE2WORDS
4783
4784
  #define FIO_ARY_SIZE2WORDS(size) \
4784
- ((sizeof(FIO_ARY_TYPE) & 1) \
4785
- ? (((size) & (~15)) + 16) \
4786
- : (sizeof(FIO_ARY_TYPE) & 2) \
4787
- ? (((size) & (~7)) + 8) \
4788
- : (sizeof(FIO_ARY_TYPE) & 4) \
4789
- ? (((size) & (~3)) + 4) \
4790
- : (sizeof(FIO_ARY_TYPE) & 8) ? (((size) & (~1)) + 2) \
4791
- : (size))
4785
+ ((sizeof(FIO_ARY_TYPE) & 1) ? (((size) & (~15)) + 16) \
4786
+ : (sizeof(FIO_ARY_TYPE) & 2) ? (((size) & (~7)) + 8) \
4787
+ : (sizeof(FIO_ARY_TYPE) & 4) ? (((size) & (~3)) + 4) \
4788
+ : (sizeof(FIO_ARY_TYPE) & 8) ? (((size) & (~1)) + 2) \
4789
+ : (size))
4792
4790
 
4793
4791
  /* *****************************************************************************
4794
4792
  Array API
@@ -6086,7 +6084,7 @@ FIO_NAME(_insert_or_overwrite_)(FIO_NAME(s) * set, FIO_SET_HASH_TYPE hash_value,
6086
6084
  pos->hash = hash_value;
6087
6085
  pos->pos->hash = hash_value;
6088
6086
  FIO_SET_COPY(pos->pos->obj, obj);
6089
-
6087
+
6090
6088
  return pos->pos->obj;
6091
6089
  }
6092
6090
 
@@ -393,7 +393,7 @@ fio_json_parse(json_parser_s *parser, const char *buffer, size_t length) {
393
393
  goto error;
394
394
  break;
395
395
  case ']':
396
- if ((parser->dict & 1))
396
+ if ((parser->dict & 1) || !parser->depth)
397
397
  goto error;
398
398
  --parser->depth;
399
399
  ++pos;
@@ -453,12 +453,12 @@ fio_json_parse(json_parser_s *parser, const char *buffer, size_t length) {
453
453
  long long i = fio_atol((char **)&tmp);
454
454
  if (tmp > limit)
455
455
  goto stop;
456
- if (!tmp || JSON_NUMERAL[*tmp]) {
456
+ if (!tmp || tmp == pos || JSON_NUMERAL[*tmp]) {
457
457
  tmp = pos;
458
458
  double f = fio_atof((char **)&tmp);
459
459
  if (tmp > limit)
460
460
  goto stop;
461
- if (!tmp || JSON_NUMERAL[*tmp])
461
+ if (!tmp || tmp == pos || JSON_NUMERAL[*tmp])
462
462
  goto error;
463
463
  fio_json_on_float(parser, f);
464
464
  pos = tmp;
@@ -481,8 +481,9 @@ fio_json_parse(json_parser_s *parser, const char *buffer, size_t length) {
481
481
  if (pos[1] == '*') {
482
482
  if (pos + 4 > limit)
483
483
  goto stop;
484
- uint8_t *tmp = pos + 3; /* avoid this: /*/
484
+ uint8_t *tmp = pos + 2; /* avoid this: /*/
485
485
  do {
486
+ ++tmp;
486
487
  tmp = memchr(tmp, '/', (uintptr_t)(limit - tmp));
487
488
  } while (tmp && tmp[-1] != '*');
488
489
  if (!tmp)