iodine 0.4.19 → 0.5.0

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.

Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -2
  3. data/CHANGELOG.md +22 -0
  4. data/LIMITS.md +19 -9
  5. data/README.md +92 -77
  6. data/SPEC-PubSub-Draft.md +113 -0
  7. data/SPEC-Websocket-Draft.md +127 -143
  8. data/bin/http-hello +0 -1
  9. data/bin/raw-rbhttp +1 -1
  10. data/bin/raw_broadcast +8 -10
  11. data/bin/updated api +2 -2
  12. data/bin/ws-broadcast +2 -4
  13. data/bin/ws-echo +2 -2
  14. data/examples/config.ru +13 -13
  15. data/examples/echo.ru +5 -6
  16. data/examples/hello.ru +2 -3
  17. data/examples/info.md +316 -0
  18. data/examples/pubsub_engine.ru +81 -0
  19. data/examples/redis.ru +9 -9
  20. data/examples/shootout.ru +45 -11
  21. data/ext/iodine/defer.c +194 -297
  22. data/ext/iodine/defer.h +61 -53
  23. data/ext/iodine/evio.c +0 -260
  24. data/ext/iodine/evio.h +50 -22
  25. data/ext/iodine/evio_callbacks.c +26 -0
  26. data/ext/iodine/evio_epoll.c +251 -0
  27. data/ext/iodine/evio_kqueue.c +193 -0
  28. data/ext/iodine/extconf.rb +1 -1
  29. data/ext/iodine/facil.c +1420 -542
  30. data/ext/iodine/facil.h +151 -64
  31. data/ext/iodine/fio_ary.h +418 -0
  32. data/ext/iodine/{base64.c → fio_base64.c} +33 -24
  33. data/ext/iodine/{base64.h → fio_base64.h} +6 -7
  34. data/ext/iodine/{fio_cli_helper.c → fio_cli.c} +77 -58
  35. data/ext/iodine/{fio_cli_helper.h → fio_cli.h} +9 -4
  36. data/ext/iodine/fio_hashmap.h +759 -0
  37. data/ext/iodine/fio_json_parser.h +651 -0
  38. data/ext/iodine/fio_llist.h +257 -0
  39. data/ext/iodine/fio_mem.c +672 -0
  40. data/ext/iodine/fio_mem.h +140 -0
  41. data/ext/iodine/fio_random.c +248 -0
  42. data/ext/iodine/{random.h → fio_random.h} +11 -14
  43. data/ext/iodine/{sha1.c → fio_sha1.c} +28 -24
  44. data/ext/iodine/{sha1.h → fio_sha1.h} +38 -16
  45. data/ext/iodine/{sha2.c → fio_sha2.c} +66 -49
  46. data/ext/iodine/{sha2.h → fio_sha2.h} +57 -26
  47. data/ext/iodine/{fiobj_internal.c → fio_siphash.c} +9 -90
  48. data/ext/iodine/fio_siphash.h +18 -0
  49. data/ext/iodine/fio_tmpfile.h +38 -0
  50. data/ext/iodine/fiobj.h +24 -7
  51. data/ext/iodine/fiobj4sock.h +23 -0
  52. data/ext/iodine/fiobj_ary.c +143 -226
  53. data/ext/iodine/fiobj_ary.h +17 -16
  54. data/ext/iodine/fiobj_data.c +1160 -0
  55. data/ext/iodine/fiobj_data.h +164 -0
  56. data/ext/iodine/fiobj_hash.c +298 -406
  57. data/ext/iodine/fiobj_hash.h +101 -54
  58. data/ext/iodine/fiobj_json.c +478 -601
  59. data/ext/iodine/fiobj_json.h +34 -9
  60. data/ext/iodine/fiobj_numbers.c +383 -51
  61. data/ext/iodine/fiobj_numbers.h +87 -11
  62. data/ext/iodine/fiobj_str.c +423 -184
  63. data/ext/iodine/fiobj_str.h +81 -32
  64. data/ext/iodine/fiobject.c +273 -522
  65. data/ext/iodine/fiobject.h +477 -112
  66. data/ext/iodine/http.c +2243 -83
  67. data/ext/iodine/http.h +842 -121
  68. data/ext/iodine/http1.c +810 -385
  69. data/ext/iodine/http1.h +16 -39
  70. data/ext/iodine/http1_parser.c +146 -74
  71. data/ext/iodine/http1_parser.h +15 -4
  72. data/ext/iodine/http_internal.c +1258 -0
  73. data/ext/iodine/http_internal.h +226 -0
  74. data/ext/iodine/http_mime_parser.h +341 -0
  75. data/ext/iodine/iodine.c +86 -68
  76. data/ext/iodine/iodine.h +26 -11
  77. data/ext/iodine/iodine_helpers.c +8 -7
  78. data/ext/iodine/iodine_http.c +487 -324
  79. data/ext/iodine/iodine_json.c +304 -0
  80. data/ext/iodine/iodine_json.h +6 -0
  81. data/ext/iodine/iodine_protocol.c +107 -45
  82. data/ext/iodine/iodine_pubsub.c +526 -225
  83. data/ext/iodine/iodine_pubsub.h +10 -0
  84. data/ext/iodine/iodine_websockets.c +268 -510
  85. data/ext/iodine/iodine_websockets.h +2 -4
  86. data/ext/iodine/pubsub.c +726 -432
  87. data/ext/iodine/pubsub.h +85 -103
  88. data/ext/iodine/rb-call.c +4 -4
  89. data/ext/iodine/rb-defer.c +46 -22
  90. data/ext/iodine/rb-fiobj2rb.h +117 -0
  91. data/ext/iodine/rb-rack-io.c +73 -238
  92. data/ext/iodine/rb-rack-io.h +2 -2
  93. data/ext/iodine/rb-registry.c +35 -93
  94. data/ext/iodine/rb-registry.h +1 -0
  95. data/ext/iodine/redis_engine.c +742 -304
  96. data/ext/iodine/redis_engine.h +42 -39
  97. data/ext/iodine/resp_parser.h +311 -0
  98. data/ext/iodine/sock.c +627 -490
  99. data/ext/iodine/sock.h +345 -297
  100. data/ext/iodine/spnlock.inc +15 -4
  101. data/ext/iodine/websocket_parser.h +16 -20
  102. data/ext/iodine/websockets.c +188 -257
  103. data/ext/iodine/websockets.h +24 -133
  104. data/lib/iodine.rb +52 -7
  105. data/lib/iodine/cli.rb +6 -24
  106. data/lib/iodine/json.rb +40 -0
  107. data/lib/iodine/version.rb +1 -1
  108. data/lib/iodine/websocket.rb +5 -3
  109. data/lib/rack/handler/iodine.rb +58 -13
  110. metadata +38 -48
  111. data/bin/ws-shootout +0 -107
  112. data/examples/broadcast.ru +0 -56
  113. data/ext/iodine/bscrypt-common.h +0 -116
  114. data/ext/iodine/bscrypt.h +0 -49
  115. data/ext/iodine/fio2resp.c +0 -60
  116. data/ext/iodine/fio2resp.h +0 -51
  117. data/ext/iodine/fio_dict.c +0 -446
  118. data/ext/iodine/fio_dict.h +0 -99
  119. data/ext/iodine/fio_hash_table.h +0 -370
  120. data/ext/iodine/fio_list.h +0 -111
  121. data/ext/iodine/fiobj_internal.h +0 -280
  122. data/ext/iodine/fiobj_primitives.c +0 -131
  123. data/ext/iodine/fiobj_primitives.h +0 -55
  124. data/ext/iodine/fiobj_sym.c +0 -135
  125. data/ext/iodine/fiobj_sym.h +0 -60
  126. data/ext/iodine/hex.c +0 -124
  127. data/ext/iodine/hex.h +0 -70
  128. data/ext/iodine/http1_request.c +0 -81
  129. data/ext/iodine/http1_request.h +0 -58
  130. data/ext/iodine/http1_response.c +0 -417
  131. data/ext/iodine/http1_response.h +0 -95
  132. data/ext/iodine/http_request.c +0 -111
  133. data/ext/iodine/http_request.h +0 -102
  134. data/ext/iodine/http_response.c +0 -1703
  135. data/ext/iodine/http_response.h +0 -250
  136. data/ext/iodine/misc.c +0 -182
  137. data/ext/iodine/misc.h +0 -74
  138. data/ext/iodine/random.c +0 -208
  139. data/ext/iodine/redis_connection.c +0 -278
  140. data/ext/iodine/redis_connection.h +0 -86
  141. data/ext/iodine/resp.c +0 -842
  142. data/ext/iodine/resp.h +0 -261
  143. data/ext/iodine/siphash.c +0 -154
  144. data/ext/iodine/siphash.h +0 -22
  145. data/ext/iodine/xor-crypt.c +0 -193
  146. data/ext/iodine/xor-crypt.h +0 -107
@@ -0,0 +1,26 @@
1
+ /*
2
+ Copyright: Boaz Segev, 2016-2017
3
+ License: MIT
4
+
5
+ Feel free to copy, use and enjoy according to the license provided.
6
+ */
7
+ #ifndef _GNU_SOURCE
8
+ #define _GNU_SOURCE
9
+ #endif
10
+
11
+ #include "evio.h"
12
+
13
+ #include <stdio.h>
14
+ #include <stdlib.h>
15
+
16
+ /* *****************************************************************************
17
+ Callbacks - weak versions to be overridden.
18
+ ***************************************************************************** */
19
+ #pragma weak evio_on_data
20
+ void __attribute__((weak)) evio_on_data(void *arg) { (void)arg; }
21
+ #pragma weak evio_on_ready
22
+ void __attribute__((weak)) evio_on_ready(void *arg) { (void)arg; }
23
+ #pragma weak evio_on_error
24
+ void __attribute__((weak)) evio_on_error(void *arg) { (void)arg; }
25
+ #pragma weak evio_on_close
26
+ void __attribute__((weak)) evio_on_close(void *arg) { (void)arg; }
@@ -0,0 +1,251 @@
1
+ /*
2
+ Copyright: Boaz Segev, 2016-2017
3
+ License: MIT
4
+
5
+ Feel free to copy, use and enjoy according to the license provided.
6
+ */
7
+ #ifndef _GNU_SOURCE
8
+ #define _GNU_SOURCE
9
+ #endif
10
+
11
+ #include "evio.h"
12
+
13
+ #ifdef EVIO_ENGINE_EPOLL
14
+
15
+ #include <assert.h>
16
+ #include <errno.h>
17
+ #include <fcntl.h>
18
+ #include <netdb.h>
19
+ #include <stdint.h>
20
+ #include <stdio.h>
21
+ #include <stdlib.h>
22
+ #include <string.h>
23
+ #include <sys/socket.h>
24
+ #include <sys/time.h>
25
+ #include <sys/types.h>
26
+ #include <time.h>
27
+ #include <unistd.h>
28
+
29
+ /* *****************************************************************************
30
+ Global data and system independant code
31
+ ***************************************************************************** */
32
+
33
+ /* epoll tester, in and out */
34
+ static int evio_fd[3] = {-1, -1, -1};
35
+
36
+ /** Closes the `epoll` / `kqueue` object, releasing it's resources. */
37
+ void evio_close() {
38
+ for (int i = 0; i < 3; ++i) {
39
+ if (evio_fd[i] != -1) {
40
+ close(evio_fd[i]);
41
+ evio_fd[i] = -1;
42
+ }
43
+ }
44
+ }
45
+
46
+ /**
47
+ returns true if the evio is available for adding or removing file descriptors.
48
+ */
49
+ int evio_isactive(void) { return evio_fd[0] >= 0; }
50
+
51
+ /* *****************************************************************************
52
+ Linux `epoll` implementation
53
+ ***************************************************************************** */
54
+ #include <sys/epoll.h>
55
+ #include <sys/timerfd.h>
56
+
57
+ /**
58
+ Creates the `epoll` or `kqueue` object.
59
+ */
60
+ intptr_t evio_create() {
61
+ evio_close();
62
+ for (int i = 0; i < 3; ++i) {
63
+ evio_fd[i] = epoll_create1(EPOLL_CLOEXEC);
64
+ if (evio_fd[i] == -1)
65
+ goto error;
66
+ }
67
+ for (int i = 1; i < 3; ++i) {
68
+ struct epoll_event chevent = {
69
+ .events = (EPOLLOUT | EPOLLIN), .data.fd = evio_fd[i],
70
+ };
71
+ if (epoll_ctl(evio_fd[0], EPOLL_CTL_ADD, evio_fd[i], &chevent) == -1)
72
+ goto error;
73
+ }
74
+ return 0;
75
+ error:
76
+ #if DEBUB
77
+ perror("ERROR: (evoid) failed to initialize");
78
+ #endif
79
+ evio_close();
80
+ return -1;
81
+ }
82
+
83
+ /**
84
+ Removes a file descriptor from the polling object.
85
+ */
86
+ void evio_remove(int fd) {
87
+ if (evio_fd[0] < 0)
88
+ return;
89
+ struct epoll_event chevent = {.events = (EPOLLOUT | EPOLLIN), .data.fd = fd};
90
+ epoll_ctl(evio_fd[1], EPOLL_CTL_DEL, fd, &chevent);
91
+ epoll_ctl(evio_fd[2], EPOLL_CTL_DEL, fd, &chevent);
92
+ }
93
+
94
+ static inline int evio_add2(int fd, void *callback_arg, uint32_t events,
95
+ int ep_fd) {
96
+ struct epoll_event chevent;
97
+ errno = 0;
98
+ chevent = (struct epoll_event){
99
+ .events = events, .data.ptr = (void *)callback_arg,
100
+ };
101
+ int ret = epoll_ctl(ep_fd, EPOLL_CTL_MOD, fd, &chevent);
102
+ if (ret == -1 && errno == ENOENT) {
103
+ errno = 0;
104
+ chevent = (struct epoll_event){
105
+ .events = events, .data.ptr = (void *)callback_arg,
106
+ };
107
+ ret = epoll_ctl(ep_fd, EPOLL_CTL_ADD, fd, &chevent);
108
+ }
109
+ return ret;
110
+ }
111
+
112
+ /**
113
+ Adds a file descriptor to the polling object.
114
+ */
115
+ int evio_add(int fd, void *callback_arg) {
116
+ if (evio_add2(fd, callback_arg,
117
+ (EPOLLIN | EPOLLRDHUP | EPOLLHUP | EPOLLONESHOT),
118
+ evio_fd[1]) == -1)
119
+ return -1;
120
+ if (evio_add2(fd, callback_arg,
121
+ (EPOLLOUT | EPOLLRDHUP | EPOLLHUP | EPOLLONESHOT),
122
+ evio_fd[2]) == -1)
123
+ return -1;
124
+ return 0;
125
+ }
126
+
127
+ /**
128
+ Adds a file descriptor to the polling object (ONE SHOT), to be polled for
129
+ incoming data (`evio_on_data` wil be called).
130
+ */
131
+ int evio_add_read(int fd, void *callback_arg) {
132
+ return evio_add2(fd, callback_arg,
133
+ (EPOLLIN | EPOLLRDHUP | EPOLLHUP | EPOLLONESHOT),
134
+ evio_fd[1]);
135
+ }
136
+
137
+ /**
138
+ Adds a file descriptor to the polling object (ONE SHOT), to be polled for
139
+ outgoing buffer readiness data (`evio_on_ready` wil be called).
140
+ */
141
+ int evio_add_write(int fd, void *callback_arg) {
142
+ return evio_add2(fd, callback_arg,
143
+ (EPOLLOUT | EPOLLRDHUP | EPOLLHUP | EPOLLONESHOT),
144
+ evio_fd[2]);
145
+ }
146
+
147
+ /**
148
+ Creates a timer file descriptor, system dependent.
149
+ */
150
+ int evio_open_timer(void) {
151
+ #ifndef TFD_NONBLOCK
152
+ int fd = timerfd_create(CLOCK_MONOTONIC, O_NONBLOCK);
153
+ if (fd != -1) { /* make sure it's a non-blocking timer. */
154
+ #if defined(O_NONBLOCK)
155
+ /* Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
156
+ int flags;
157
+ if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
158
+ flags = 0;
159
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
160
+ goto error;
161
+ #else
162
+ /* no O_NONBLOCK, use the old way of doing it */
163
+ static int flags = 1;
164
+ if (ioctl(fd, FIOBIO, &flags) == -1)
165
+ goto error;
166
+ #endif
167
+ }
168
+ return fd;
169
+ error:
170
+ close(fd);
171
+ return -1;
172
+ #else
173
+ return timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
174
+ #endif
175
+ }
176
+
177
+ /**
178
+ Adds a timer file descriptor, so that callbacks will be called for it's events.
179
+ */
180
+ int evio_set_timer(int fd, void *callback_arg, unsigned long milliseconds) {
181
+
182
+ if (evio_fd[0] < 0)
183
+ return -1;
184
+ /* clear out existing timer marker, if exists. */
185
+ char data[8]; // void * is 8 byte long
186
+ if (read(fd, &data, 8) < 0)
187
+ data[0] = 0;
188
+ /* set file's time value */
189
+ struct itimerspec new_t_data;
190
+ new_t_data.it_value.tv_sec = new_t_data.it_interval.tv_sec =
191
+ milliseconds / 1000;
192
+ new_t_data.it_value.tv_nsec = new_t_data.it_interval.tv_nsec =
193
+ (milliseconds % 1000) * 1000000;
194
+ if (timerfd_settime(fd, 0, &new_t_data, NULL) == -1)
195
+ return -1;
196
+ /* add to epoll */
197
+ return evio_add2(fd, callback_arg, (EPOLLIN | EPOLLONESHOT), evio_fd[1]);
198
+ }
199
+
200
+ /**
201
+ Reviews any pending events (up to EVIO_MAX_EVENTS) and calls any callbacks.
202
+ */
203
+ int evio_review(const int timeout_millisec) {
204
+ if (evio_fd[0] < 0)
205
+ return -1;
206
+ struct epoll_event internal[2];
207
+ struct epoll_event events[EVIO_MAX_EVENTS];
208
+ int total = 0;
209
+ /* wait for events and handle them */
210
+ int internal_count = epoll_wait(evio_fd[0], internal, 2, timeout_millisec);
211
+ if (internal_count == -1)
212
+ return -1;
213
+ if (internal_count == 0)
214
+ return 0;
215
+ for (int j = 0; j < internal_count; ++j) {
216
+ int active_count =
217
+ epoll_wait(internal[j].data.fd, events, EVIO_MAX_EVENTS, 0);
218
+ if (active_count > 0) {
219
+ for (int i = 0; i < active_count; i++) {
220
+ if (events[i].events & (~(EPOLLIN | EPOLLOUT))) {
221
+ // errors are hendled as disconnections (on_close)
222
+ evio_on_error(events[i].data.ptr);
223
+ } else {
224
+ // no error, then it's an active event(s)
225
+ if (events[i].events & EPOLLOUT) {
226
+ evio_on_ready(events[i].data.ptr);
227
+ }
228
+ if (events[i].events & EPOLLIN)
229
+ evio_on_data(events[i].data.ptr);
230
+ }
231
+ } // end for loop
232
+ total += active_count;
233
+ }
234
+ }
235
+
236
+ return total;
237
+ }
238
+
239
+ #include <poll.h>
240
+
241
+ /** Waits up to `timeout_millisec` for events. No events are signaled. */
242
+ int evio_wait(const int timeout_millisec) {
243
+ if (evio_fd[0] < 0)
244
+ return -1;
245
+ struct pollfd pollfd = {
246
+ .fd = evio_fd[0], .events = POLLIN,
247
+ };
248
+ return poll(&pollfd, 1, timeout_millisec);
249
+ }
250
+
251
+ #endif /* system dependent code */
@@ -0,0 +1,193 @@
1
+ /*
2
+ Copyright: Boaz Segev, 2016-2017
3
+ License: MIT
4
+
5
+ Feel free to copy, use and enjoy according to the license provided.
6
+ */
7
+ #ifndef _GNU_SOURCE
8
+ #define _GNU_SOURCE
9
+ #endif
10
+
11
+ #include "evio.h"
12
+
13
+ #ifdef EVIO_ENGINE_KQUEUE
14
+
15
+ #include <assert.h>
16
+ #include <errno.h>
17
+ #include <fcntl.h>
18
+ #include <netdb.h>
19
+ #include <stdint.h>
20
+ #include <stdio.h>
21
+ #include <stdlib.h>
22
+ #include <string.h>
23
+ #include <sys/event.h>
24
+ #include <sys/socket.h>
25
+ #include <sys/time.h>
26
+ #include <sys/types.h>
27
+ #include <time.h>
28
+ #include <unistd.h>
29
+
30
+ /* *****************************************************************************
31
+ Global data and system independant code
32
+ ***************************************************************************** */
33
+
34
+ static int evio_fd = -1;
35
+ static pid_t owner_pid = 0;
36
+
37
+ /** Closes the `epoll` / `kqueue` object, releasing it's resources. */
38
+ void evio_close() {
39
+ /* the file descriptor is never inherited by fork */
40
+ if (evio_fd != -1 && owner_pid == getpid()) {
41
+ close(evio_fd);
42
+ evio_fd = -1;
43
+ }
44
+ }
45
+
46
+ /**
47
+ returns true if the evio is available for adding or removing file descriptors.
48
+ */
49
+ int evio_isactive(void) { return evio_fd >= 0; }
50
+
51
+ /* *****************************************************************************
52
+ BSD `kqueue` implementation
53
+ ***************************************************************************** */
54
+
55
+ /**
56
+ Creates the `epoll` or `kqueue` object.
57
+ */
58
+ intptr_t evio_create() {
59
+ evio_close();
60
+ owner_pid = getpid();
61
+ return evio_fd = kqueue();
62
+ }
63
+
64
+ /**
65
+ Removes a file descriptor from the polling object.
66
+ */
67
+ void evio_remove(int fd) {
68
+ if (evio_fd < 0)
69
+ return;
70
+ struct kevent chevent[3];
71
+ EV_SET(chevent, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
72
+ EV_SET(chevent + 1, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
73
+ EV_SET(chevent + 2, fd, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
74
+ kevent(evio_fd, chevent, 3, NULL, 0, NULL);
75
+ }
76
+
77
+ /**
78
+ Adds a file descriptor to the polling object.
79
+ */
80
+ int evio_add(int fd, void *callback_arg) {
81
+ struct kevent chevent[2];
82
+ EV_SET(chevent, fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR | EV_ONESHOT,
83
+ 0, 0, callback_arg);
84
+ EV_SET(chevent + 1, fd, EVFILT_WRITE,
85
+ EV_ADD | EV_ENABLE | EV_CLEAR | EV_ONESHOT, 0, 0, callback_arg);
86
+ return kevent(evio_fd, chevent, 2, NULL, 0, NULL);
87
+ }
88
+
89
+ /**
90
+ Adds a file descriptor to the polling object (ONE SHOT), to be polled for
91
+ incoming data (`evio_on_data` wil be called).
92
+ */
93
+ int evio_add_read(int fd, void *callback_arg) {
94
+ struct kevent chevent[1];
95
+ EV_SET(chevent, fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR | EV_ONESHOT,
96
+ 0, 0, callback_arg);
97
+ return kevent(evio_fd, chevent, 1, NULL, 0, NULL);
98
+ }
99
+
100
+ /**
101
+ Adds a file descriptor to the polling object (ONE SHOT), to be polled for
102
+ outgoing buffer readiness data (`evio_on_ready` wil be called).
103
+ */
104
+ int evio_add_write(int fd, void *callback_arg) {
105
+ struct kevent chevent[1];
106
+ EV_SET(chevent, fd, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_CLEAR | EV_ONESHOT,
107
+ 0, 0, callback_arg);
108
+ return kevent(evio_fd, chevent, 1, NULL, 0, NULL);
109
+ }
110
+
111
+ /**
112
+ Creates a timer file descriptor, system dependent.
113
+ */
114
+ int evio_open_timer() {
115
+ #ifdef P_tmpdir
116
+ if (P_tmpdir[sizeof(P_tmpdir) - 1] == '/') {
117
+ char name_template[] = P_tmpdir "evio_facil_timer_XXXXXX";
118
+ return mkstemp(name_template);
119
+ }
120
+ char name_template[] = P_tmpdir "/evio_facil_timer_XXXXXX";
121
+ return mkstemp(name_template);
122
+ #else
123
+ char name_template[] = "/tmp/evio_facil_timer_XXXXXX";
124
+ return mkstemp(name_template);
125
+ #endif
126
+ }
127
+
128
+ /**
129
+ Adds a timer file descriptor, so that callbacks will be called for it's events.
130
+ */
131
+ int evio_set_timer(int fd, void *callback_arg, unsigned long milliseconds) {
132
+ struct kevent chevent;
133
+ EV_SET(&chevent, fd, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_ONESHOT, 0,
134
+ milliseconds, callback_arg);
135
+ return kevent(evio_fd, &chevent, 1, NULL, 0, NULL);
136
+ }
137
+
138
+ /**
139
+ Reviews any pending events (up to EVIO_MAX_EVENTS) and calls any callbacks.
140
+ */
141
+ int evio_review(const int timeout_millisec) {
142
+ if (evio_fd < 0)
143
+ return -1;
144
+ struct kevent events[EVIO_MAX_EVENTS];
145
+
146
+ const struct timespec timeout = {.tv_sec = (timeout_millisec / 1024),
147
+ .tv_nsec =
148
+ ((timeout_millisec % 1024) * 1000000)};
149
+ /* wait for events and handle them */
150
+ int active_count =
151
+ kevent(evio_fd, NULL, 0, events, EVIO_MAX_EVENTS, &timeout);
152
+
153
+ if (active_count > 0) {
154
+ for (int i = 0; i < active_count; i++) {
155
+ // test for event(s) type
156
+ if (events[i].filter == EVFILT_READ || events[i].filter == EVFILT_TIMER) {
157
+ evio_on_data(events[i].udata);
158
+ }
159
+ // connection errors should be reported after `read` in case there's data
160
+ // left in the buffer.
161
+ if (events[i].flags & (EV_EOF | EV_ERROR)) {
162
+ // errors are hendled as disconnections (on_close)
163
+ // fprintf(stderr, "%p: %s\n", events[i].udata,
164
+ // (events[i].flags & EV_EOF)
165
+ // ? "EV_EOF"
166
+ // : (events[i].flags & EV_ERROR) ? "EV_ERROR" : "WTF?");
167
+ evio_on_error(events[i].udata);
168
+ } else if (events[i].filter == EVFILT_WRITE) {
169
+ // we can only write if there's no error in the socket
170
+ evio_on_ready(events[i].udata);
171
+ }
172
+ }
173
+ } else if (active_count < 0) {
174
+ if (errno == EINTR)
175
+ return 0;
176
+ return -1;
177
+ }
178
+ return active_count;
179
+ }
180
+
181
+ #include <poll.h>
182
+
183
+ /** Waits up to `timeout_millisec` for events. No events are signaled. */
184
+ int evio_wait(const int timeout_millisec) {
185
+ if (evio_fd < 0)
186
+ return -1;
187
+ struct pollfd pollfd = {
188
+ .fd = evio_fd, .events = POLLIN,
189
+ };
190
+ return poll(&pollfd, 1, timeout_millisec);
191
+ }
192
+
193
+ #endif /* system dependent code */