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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/CHANGELOG.md +22 -0
- data/LIMITS.md +19 -9
- data/README.md +92 -77
- data/SPEC-PubSub-Draft.md +113 -0
- data/SPEC-Websocket-Draft.md +127 -143
- data/bin/http-hello +0 -1
- data/bin/raw-rbhttp +1 -1
- data/bin/raw_broadcast +8 -10
- data/bin/updated api +2 -2
- data/bin/ws-broadcast +2 -4
- data/bin/ws-echo +2 -2
- data/examples/config.ru +13 -13
- data/examples/echo.ru +5 -6
- data/examples/hello.ru +2 -3
- data/examples/info.md +316 -0
- data/examples/pubsub_engine.ru +81 -0
- data/examples/redis.ru +9 -9
- data/examples/shootout.ru +45 -11
- data/ext/iodine/defer.c +194 -297
- data/ext/iodine/defer.h +61 -53
- data/ext/iodine/evio.c +0 -260
- data/ext/iodine/evio.h +50 -22
- data/ext/iodine/evio_callbacks.c +26 -0
- data/ext/iodine/evio_epoll.c +251 -0
- data/ext/iodine/evio_kqueue.c +193 -0
- data/ext/iodine/extconf.rb +1 -1
- data/ext/iodine/facil.c +1420 -542
- data/ext/iodine/facil.h +151 -64
- data/ext/iodine/fio_ary.h +418 -0
- data/ext/iodine/{base64.c → fio_base64.c} +33 -24
- data/ext/iodine/{base64.h → fio_base64.h} +6 -7
- data/ext/iodine/{fio_cli_helper.c → fio_cli.c} +77 -58
- data/ext/iodine/{fio_cli_helper.h → fio_cli.h} +9 -4
- data/ext/iodine/fio_hashmap.h +759 -0
- data/ext/iodine/fio_json_parser.h +651 -0
- data/ext/iodine/fio_llist.h +257 -0
- data/ext/iodine/fio_mem.c +672 -0
- data/ext/iodine/fio_mem.h +140 -0
- data/ext/iodine/fio_random.c +248 -0
- data/ext/iodine/{random.h → fio_random.h} +11 -14
- data/ext/iodine/{sha1.c → fio_sha1.c} +28 -24
- data/ext/iodine/{sha1.h → fio_sha1.h} +38 -16
- data/ext/iodine/{sha2.c → fio_sha2.c} +66 -49
- data/ext/iodine/{sha2.h → fio_sha2.h} +57 -26
- data/ext/iodine/{fiobj_internal.c → fio_siphash.c} +9 -90
- data/ext/iodine/fio_siphash.h +18 -0
- data/ext/iodine/fio_tmpfile.h +38 -0
- data/ext/iodine/fiobj.h +24 -7
- data/ext/iodine/fiobj4sock.h +23 -0
- data/ext/iodine/fiobj_ary.c +143 -226
- data/ext/iodine/fiobj_ary.h +17 -16
- data/ext/iodine/fiobj_data.c +1160 -0
- data/ext/iodine/fiobj_data.h +164 -0
- data/ext/iodine/fiobj_hash.c +298 -406
- data/ext/iodine/fiobj_hash.h +101 -54
- data/ext/iodine/fiobj_json.c +478 -601
- data/ext/iodine/fiobj_json.h +34 -9
- data/ext/iodine/fiobj_numbers.c +383 -51
- data/ext/iodine/fiobj_numbers.h +87 -11
- data/ext/iodine/fiobj_str.c +423 -184
- data/ext/iodine/fiobj_str.h +81 -32
- data/ext/iodine/fiobject.c +273 -522
- data/ext/iodine/fiobject.h +477 -112
- data/ext/iodine/http.c +2243 -83
- data/ext/iodine/http.h +842 -121
- data/ext/iodine/http1.c +810 -385
- data/ext/iodine/http1.h +16 -39
- data/ext/iodine/http1_parser.c +146 -74
- data/ext/iodine/http1_parser.h +15 -4
- data/ext/iodine/http_internal.c +1258 -0
- data/ext/iodine/http_internal.h +226 -0
- data/ext/iodine/http_mime_parser.h +341 -0
- data/ext/iodine/iodine.c +86 -68
- data/ext/iodine/iodine.h +26 -11
- data/ext/iodine/iodine_helpers.c +8 -7
- data/ext/iodine/iodine_http.c +487 -324
- data/ext/iodine/iodine_json.c +304 -0
- data/ext/iodine/iodine_json.h +6 -0
- data/ext/iodine/iodine_protocol.c +107 -45
- data/ext/iodine/iodine_pubsub.c +526 -225
- data/ext/iodine/iodine_pubsub.h +10 -0
- data/ext/iodine/iodine_websockets.c +268 -510
- data/ext/iodine/iodine_websockets.h +2 -4
- data/ext/iodine/pubsub.c +726 -432
- data/ext/iodine/pubsub.h +85 -103
- data/ext/iodine/rb-call.c +4 -4
- data/ext/iodine/rb-defer.c +46 -22
- data/ext/iodine/rb-fiobj2rb.h +117 -0
- data/ext/iodine/rb-rack-io.c +73 -238
- data/ext/iodine/rb-rack-io.h +2 -2
- data/ext/iodine/rb-registry.c +35 -93
- data/ext/iodine/rb-registry.h +1 -0
- data/ext/iodine/redis_engine.c +742 -304
- data/ext/iodine/redis_engine.h +42 -39
- data/ext/iodine/resp_parser.h +311 -0
- data/ext/iodine/sock.c +627 -490
- data/ext/iodine/sock.h +345 -297
- data/ext/iodine/spnlock.inc +15 -4
- data/ext/iodine/websocket_parser.h +16 -20
- data/ext/iodine/websockets.c +188 -257
- data/ext/iodine/websockets.h +24 -133
- data/lib/iodine.rb +52 -7
- data/lib/iodine/cli.rb +6 -24
- data/lib/iodine/json.rb +40 -0
- data/lib/iodine/version.rb +1 -1
- data/lib/iodine/websocket.rb +5 -3
- data/lib/rack/handler/iodine.rb +58 -13
- metadata +38 -48
- data/bin/ws-shootout +0 -107
- data/examples/broadcast.ru +0 -56
- data/ext/iodine/bscrypt-common.h +0 -116
- data/ext/iodine/bscrypt.h +0 -49
- data/ext/iodine/fio2resp.c +0 -60
- data/ext/iodine/fio2resp.h +0 -51
- data/ext/iodine/fio_dict.c +0 -446
- data/ext/iodine/fio_dict.h +0 -99
- data/ext/iodine/fio_hash_table.h +0 -370
- data/ext/iodine/fio_list.h +0 -111
- data/ext/iodine/fiobj_internal.h +0 -280
- data/ext/iodine/fiobj_primitives.c +0 -131
- data/ext/iodine/fiobj_primitives.h +0 -55
- data/ext/iodine/fiobj_sym.c +0 -135
- data/ext/iodine/fiobj_sym.h +0 -60
- data/ext/iodine/hex.c +0 -124
- data/ext/iodine/hex.h +0 -70
- data/ext/iodine/http1_request.c +0 -81
- data/ext/iodine/http1_request.h +0 -58
- data/ext/iodine/http1_response.c +0 -417
- data/ext/iodine/http1_response.h +0 -95
- data/ext/iodine/http_request.c +0 -111
- data/ext/iodine/http_request.h +0 -102
- data/ext/iodine/http_response.c +0 -1703
- data/ext/iodine/http_response.h +0 -250
- data/ext/iodine/misc.c +0 -182
- data/ext/iodine/misc.h +0 -74
- data/ext/iodine/random.c +0 -208
- data/ext/iodine/redis_connection.c +0 -278
- data/ext/iodine/redis_connection.h +0 -86
- data/ext/iodine/resp.c +0 -842
- data/ext/iodine/resp.h +0 -261
- data/ext/iodine/siphash.c +0 -154
- data/ext/iodine/siphash.h +0 -22
- data/ext/iodine/xor-crypt.c +0 -193
- 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 */
|