iodine 0.1.21 → 0.2.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/.gitignore +3 -2
- data/.travis.yml +23 -2
- data/CHANGELOG.md +9 -2
- data/README.md +232 -179
- data/Rakefile +13 -1
- data/bin/config.ru +63 -0
- data/bin/console +6 -0
- data/bin/echo +42 -32
- data/bin/http-hello +62 -0
- data/bin/http-playground +124 -0
- data/bin/playground +62 -0
- data/bin/poc/Gemfile.lock +23 -0
- data/bin/poc/README.md +37 -0
- data/bin/poc/config.ru +66 -0
- data/bin/poc/gemfile +1 -0
- data/bin/poc/www/index.html +57 -0
- data/bin/raw-rbhttp +35 -0
- data/bin/raw_broadcast +66 -0
- data/bin/test_with_faye +40 -0
- data/bin/ws-broadcast +108 -0
- data/bin/ws-echo +108 -0
- data/exe/iodine +59 -0
- data/ext/iodine/base64.c +264 -0
- data/ext/iodine/base64.h +72 -0
- data/ext/iodine/bscrypt-common.h +109 -0
- data/ext/iodine/bscrypt.h +49 -0
- data/ext/iodine/extconf.rb +41 -0
- data/ext/iodine/hex.c +123 -0
- data/ext/iodine/hex.h +70 -0
- data/ext/iodine/http.c +200 -0
- data/ext/iodine/http.h +128 -0
- data/ext/iodine/http1.c +402 -0
- data/ext/iodine/http1.h +56 -0
- data/ext/iodine/http1_simple_parser.c +473 -0
- data/ext/iodine/http1_simple_parser.h +59 -0
- data/ext/iodine/http_request.h +128 -0
- data/ext/iodine/http_response.c +1606 -0
- data/ext/iodine/http_response.h +393 -0
- data/ext/iodine/http_response_http1.h +374 -0
- data/ext/iodine/iodine_core.c +641 -0
- data/ext/iodine/iodine_core.h +70 -0
- data/ext/iodine/iodine_http.c +615 -0
- data/ext/iodine/iodine_http.h +19 -0
- data/ext/iodine/iodine_websocket.c +430 -0
- data/ext/iodine/iodine_websocket.h +21 -0
- data/ext/iodine/libasync.c +552 -0
- data/ext/iodine/libasync.h +117 -0
- data/ext/iodine/libreact.c +347 -0
- data/ext/iodine/libreact.h +244 -0
- data/ext/iodine/libserver.c +912 -0
- data/ext/iodine/libserver.h +435 -0
- data/ext/iodine/libsock.c +950 -0
- data/ext/iodine/libsock.h +478 -0
- data/ext/iodine/misc.c +181 -0
- data/ext/iodine/misc.h +76 -0
- data/ext/iodine/random.c +193 -0
- data/ext/iodine/random.h +48 -0
- data/ext/iodine/rb-call.c +127 -0
- data/ext/iodine/rb-call.h +60 -0
- data/ext/iodine/rb-libasync.h +79 -0
- data/ext/iodine/rb-rack-io.c +389 -0
- data/ext/iodine/rb-rack-io.h +17 -0
- data/ext/iodine/rb-registry.c +213 -0
- data/ext/iodine/rb-registry.h +33 -0
- data/ext/iodine/sha1.c +359 -0
- data/ext/iodine/sha1.h +85 -0
- data/ext/iodine/sha2.c +825 -0
- data/ext/iodine/sha2.h +138 -0
- data/ext/iodine/siphash.c +136 -0
- data/ext/iodine/siphash.h +15 -0
- data/ext/iodine/spnlock.h +235 -0
- data/ext/iodine/websockets.c +696 -0
- data/ext/iodine/websockets.h +120 -0
- data/ext/iodine/xor-crypt.c +189 -0
- data/ext/iodine/xor-crypt.h +107 -0
- data/iodine.gemspec +25 -18
- data/lib/iodine.rb +57 -58
- data/lib/iodine/http.rb +0 -189
- data/lib/iodine/protocol.rb +36 -245
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +145 -2
- metadata +115 -37
- data/bin/core_http_test +0 -51
- data/bin/em playground +0 -56
- data/bin/hello_world +0 -75
- data/bin/setup +0 -7
- data/lib/iodine/client.rb +0 -5
- data/lib/iodine/core.rb +0 -102
- data/lib/iodine/core_init.rb +0 -143
- data/lib/iodine/http/hpack.rb +0 -553
- data/lib/iodine/http/http1.rb +0 -251
- data/lib/iodine/http/http2.rb +0 -507
- data/lib/iodine/http/rack_support.rb +0 -108
- data/lib/iodine/http/request.rb +0 -462
- data/lib/iodine/http/response.rb +0 -474
- data/lib/iodine/http/session.rb +0 -143
- data/lib/iodine/http/websocket_client.rb +0 -335
- data/lib/iodine/http/websocket_handler.rb +0 -101
- data/lib/iodine/http/websockets.rb +0 -336
- data/lib/iodine/io.rb +0 -56
- data/lib/iodine/logging.rb +0 -46
- data/lib/iodine/settings.rb +0 -158
- data/lib/iodine/ssl_connector.rb +0 -48
- data/lib/iodine/timers.rb +0 -95
@@ -0,0 +1,117 @@
|
|
1
|
+
/*
|
2
|
+
copyright: Boaz segev, 2016
|
3
|
+
license: MIT
|
4
|
+
|
5
|
+
Feel free to copy, use and enjoy according to the license provided.
|
6
|
+
*/
|
7
|
+
#ifndef LIB_ASYNC
|
8
|
+
#define LIB_ASYNC "0.4.0"
|
9
|
+
#define LIB_ASYNC_VERSION_MAJOR 0
|
10
|
+
#define LIB_ASYNC_VERSION_MINOR 4
|
11
|
+
#define LIB_ASYNC_VERSION_PATCH 0
|
12
|
+
|
13
|
+
#include <stdlib.h>
|
14
|
+
#include <stdio.h>
|
15
|
+
|
16
|
+
#ifdef DEBUG
|
17
|
+
// prints out testing and benchmarking data
|
18
|
+
void async_test_library_speed(void);
|
19
|
+
#endif
|
20
|
+
|
21
|
+
/** \file
|
22
|
+
This is an easy to use **global** thread pool library. Once the thread pool was
|
23
|
+
initiated it makes running tasks very simple. i.e.:
|
24
|
+
|
25
|
+
async_start(4); // 4 worker threads
|
26
|
+
async_run(task, arg);
|
27
|
+
async_finish(); // waits for tasks and releases threads.
|
28
|
+
|
29
|
+
Please note, this library isn't fork-friendly - fork **before** you create the
|
30
|
+
thread pool. In general, mixing `fork` with multi-threading isn't safe nor
|
31
|
+
trivial - always fork before multi-threading.
|
32
|
+
*/
|
33
|
+
|
34
|
+
/**
|
35
|
+
Starts running the global thread pool. Use:
|
36
|
+
|
37
|
+
async_start(8, 0);
|
38
|
+
|
39
|
+
The `use_sentinal` variable protects threads from crashing and produces error
|
40
|
+
reports. It isn't effective against all errors, but it should protect against
|
41
|
+
some.
|
42
|
+
|
43
|
+
*/
|
44
|
+
ssize_t async_start(size_t threads);
|
45
|
+
|
46
|
+
/**
|
47
|
+
Use `async_join` instead.
|
48
|
+
|
49
|
+
Performs tasks until the task queue is empty. An empty task queue does NOT mean
|
50
|
+
all the tasks have completed, since some other threads might be running tasks
|
51
|
+
that have yet to complete (and these tasks might schedule new tasks as well).
|
52
|
+
|
53
|
+
Use:
|
54
|
+
|
55
|
+
async_perform();
|
56
|
+
|
57
|
+
*/
|
58
|
+
void async_perform();
|
59
|
+
|
60
|
+
/**
|
61
|
+
Waits for all the present tasks to complete and threads to exist.
|
62
|
+
|
63
|
+
The function won't return unless `async_signal` is called to signal the threads
|
64
|
+
to stop waiting for new tasks.
|
65
|
+
|
66
|
+
After this function returns, the thread pool will remain active, waiting for new
|
67
|
+
tasts.
|
68
|
+
|
69
|
+
Unline finish (that uses `join`) this is an **active** wait where the waiting
|
70
|
+
thread acts as a working thread and performs any pending tasks and then
|
71
|
+
spinlocks until the active thread count drops to 0.
|
72
|
+
|
73
|
+
Use:
|
74
|
+
|
75
|
+
async_join();
|
76
|
+
|
77
|
+
*/
|
78
|
+
void async_join();
|
79
|
+
|
80
|
+
/**
|
81
|
+
Signals all the threads to finish up and stop waiting for new tasks.
|
82
|
+
|
83
|
+
Use:
|
84
|
+
|
85
|
+
async_join();
|
86
|
+
|
87
|
+
*/
|
88
|
+
void async_signal();
|
89
|
+
|
90
|
+
/**
|
91
|
+
Schedules a task to be performed by the thread pool.
|
92
|
+
|
93
|
+
The Task should be a function such as `void task(void *arg)`.
|
94
|
+
|
95
|
+
Use:
|
96
|
+
|
97
|
+
void task(void * arg) { printf("%s", arg); }
|
98
|
+
|
99
|
+
char arg[] = "Demo Task";
|
100
|
+
|
101
|
+
async_run(task, arg);
|
102
|
+
|
103
|
+
*/
|
104
|
+
int async_run(void (*task)(void*), void* arg);
|
105
|
+
|
106
|
+
/**
|
107
|
+
Same as:
|
108
|
+
|
109
|
+
`async_signal(); async_wait();`
|
110
|
+
*/
|
111
|
+
#define async_finish() \
|
112
|
+
{ \
|
113
|
+
async_signal(); \
|
114
|
+
async_join(); \
|
115
|
+
}
|
116
|
+
|
117
|
+
#endif /* LIB_ASYNC */
|
@@ -0,0 +1,347 @@
|
|
1
|
+
/*
|
2
|
+
copyright: Boaz segev, 2016
|
3
|
+
license: MIT
|
4
|
+
|
5
|
+
Feel free to copy, use and enjoy according to the license provided.
|
6
|
+
*/
|
7
|
+
#include "libreact.h"
|
8
|
+
|
9
|
+
#if !defined(__linux__) && !defined(__CYGWIN__)
|
10
|
+
#include <sys/event.h>
|
11
|
+
#else
|
12
|
+
#include <sys/timerfd.h>
|
13
|
+
#include <sys/epoll.h>
|
14
|
+
#endif
|
15
|
+
#include <time.h>
|
16
|
+
#include <assert.h>
|
17
|
+
#include <unistd.h>
|
18
|
+
#include <fcntl.h>
|
19
|
+
#include <errno.h>
|
20
|
+
#include <stdio.h>
|
21
|
+
#include <stdlib.h>
|
22
|
+
#include <string.h>
|
23
|
+
#include <netdb.h>
|
24
|
+
#include <sys/types.h>
|
25
|
+
#include <sys/socket.h>
|
26
|
+
|
27
|
+
/* The (sadly, global) reactor fd */
|
28
|
+
static int reactor_fd = -1;
|
29
|
+
|
30
|
+
/* an inner helper function that removes and adds events */
|
31
|
+
|
32
|
+
/* *****************************************************************************
|
33
|
+
Callbacks
|
34
|
+
*/
|
35
|
+
|
36
|
+
#pragma weak reactor_on_close
|
37
|
+
void reactor_on_close(intptr_t uuid) {}
|
38
|
+
|
39
|
+
#pragma weak reactor_on_data
|
40
|
+
void reactor_on_data(intptr_t uuid) {
|
41
|
+
char data[1024];
|
42
|
+
while (read(sock_uuid2fd(uuid), data, 1024) > 0)
|
43
|
+
;
|
44
|
+
}
|
45
|
+
|
46
|
+
#pragma weak reactor_on_ready
|
47
|
+
void reactor_on_ready(intptr_t uuid) {}
|
48
|
+
|
49
|
+
/* *****************************************************************************
|
50
|
+
Integrate the `libsock` library if exists.
|
51
|
+
*/
|
52
|
+
|
53
|
+
#pragma weak sock_flush
|
54
|
+
ssize_t sock_flush(intptr_t uuid) { return 0; }
|
55
|
+
|
56
|
+
#pragma weak sock_close
|
57
|
+
void sock_close(intptr_t uuid) {
|
58
|
+
shutdown(sock_uuid2fd(uuid), SHUT_RDWR);
|
59
|
+
close(sock_uuid2fd(uuid));
|
60
|
+
/* this is automatic on epoll... what about kqueue? */
|
61
|
+
reactor_remove(uuid);
|
62
|
+
/* call callback */
|
63
|
+
reactor_on_close(uuid);
|
64
|
+
}
|
65
|
+
|
66
|
+
/* *****************************************************************************
|
67
|
+
The main libreact API.
|
68
|
+
*/
|
69
|
+
|
70
|
+
/**
|
71
|
+
Closes a file descriptor, calling it's callback if it was registered with the
|
72
|
+
reactor.
|
73
|
+
*/
|
74
|
+
void reactor_close(intptr_t uuid) {
|
75
|
+
sock_close(uuid);
|
76
|
+
return;
|
77
|
+
}
|
78
|
+
|
79
|
+
/* *****************************************************************************
|
80
|
+
KQueue implementation.
|
81
|
+
*/
|
82
|
+
#ifdef EV_SET
|
83
|
+
|
84
|
+
int reactor_add(intptr_t uuid) {
|
85
|
+
struct kevent chevent[2];
|
86
|
+
EV_SET(chevent, sock_uuid2fd(uuid), EVFILT_READ,
|
87
|
+
EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, (void *)uuid);
|
88
|
+
EV_SET(chevent + 1, sock_uuid2fd(uuid), EVFILT_WRITE,
|
89
|
+
EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, (void *)uuid);
|
90
|
+
return kevent(reactor_fd, chevent, 2, NULL, 0, NULL);
|
91
|
+
}
|
92
|
+
int reactor_add_timer(intptr_t uuid, long milliseconds) {
|
93
|
+
struct kevent chevent;
|
94
|
+
EV_SET(&chevent, sock_uuid2fd(uuid), EVFILT_TIMER, EV_ADD | EV_ENABLE, 0,
|
95
|
+
milliseconds, (void *)uuid);
|
96
|
+
return kevent(reactor_fd, &chevent, 1, NULL, 0, NULL);
|
97
|
+
}
|
98
|
+
|
99
|
+
int reactor_remove(intptr_t uuid) {
|
100
|
+
struct kevent chevent[2];
|
101
|
+
EV_SET(chevent, sock_uuid2fd(uuid), EVFILT_READ, EV_DELETE, 0, 0,
|
102
|
+
(void *)uuid);
|
103
|
+
EV_SET(chevent + 1, sock_uuid2fd(uuid), EVFILT_WRITE, EV_DELETE, 0, 0,
|
104
|
+
(void *)uuid);
|
105
|
+
return kevent(reactor_fd, chevent, 2, NULL, 0, NULL);
|
106
|
+
}
|
107
|
+
int reactor_remove_timer(intptr_t uuid) {
|
108
|
+
struct kevent chevent;
|
109
|
+
EV_SET(&chevent, sock_uuid2fd(uuid), EVFILT_TIMER, EV_DELETE, 0, 0,
|
110
|
+
(void *)uuid);
|
111
|
+
return kevent(reactor_fd, &chevent, 1, NULL, 0, NULL);
|
112
|
+
}
|
113
|
+
|
114
|
+
/**
|
115
|
+
epoll requires the timer to be "reset" before repeating. Kqueue requires no such
|
116
|
+
thing.
|
117
|
+
|
118
|
+
This method promises that the timer will be repeated when running on epoll. This
|
119
|
+
method is redundent on kqueue.
|
120
|
+
*/
|
121
|
+
void reactor_reset_timer(intptr_t uuid) {} /* EPoll only */
|
122
|
+
|
123
|
+
/**
|
124
|
+
Creates a timer file descriptor, system dependent.
|
125
|
+
|
126
|
+
Opens a new file decriptor for creating timer events. On BSD this will revert to
|
127
|
+
an `fileno(tmpfile())` (with error handling) and on Linux it will call
|
128
|
+
`timerfd_create(CLOCK_MONOTONIC, ...)`.
|
129
|
+
|
130
|
+
Returns -1 on error, otherwise returns the file descriptor.
|
131
|
+
*/
|
132
|
+
intptr_t reactor_make_timer() {
|
133
|
+
#ifdef P_tmpdir
|
134
|
+
char template[] = P_tmpdir "libreact_timer_XXXXXX";
|
135
|
+
#else
|
136
|
+
char template[] = "/tmp/libreact_timer_XXXXXX";
|
137
|
+
#endif
|
138
|
+
return mkstemp(template);
|
139
|
+
}
|
140
|
+
|
141
|
+
/* *****************************************************************************
|
142
|
+
EPoll implementation.
|
143
|
+
*/
|
144
|
+
#elif defined(EPOLLIN)
|
145
|
+
|
146
|
+
int reactor_add(intptr_t uuid) {
|
147
|
+
struct epoll_event chevent = {0};
|
148
|
+
chevent.data.ptr = (void *)uuid;
|
149
|
+
chevent.events =
|
150
|
+
EPOLLOUT | EPOLLIN | EPOLLET | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
|
151
|
+
return epoll_ctl(reactor_fd, EPOLL_CTL_ADD, sock_uuid2fd(uuid), &chevent);
|
152
|
+
}
|
153
|
+
int reactor_add_timer(intptr_t uuid, long milliseconds) {
|
154
|
+
struct epoll_event chevent;
|
155
|
+
chevent.data.ptr = (void *)uuid;
|
156
|
+
chevent.events =
|
157
|
+
EPOLLOUT | EPOLLIN | EPOLLET | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
|
158
|
+
struct itimerspec new_t_data;
|
159
|
+
new_t_data.it_value.tv_sec = new_t_data.it_interval.tv_sec =
|
160
|
+
milliseconds / 1000;
|
161
|
+
new_t_data.it_value.tv_nsec = new_t_data.it_interval.tv_nsec =
|
162
|
+
(milliseconds % 1000) * 1000000;
|
163
|
+
timerfd_settime(sock_uuid2fd(uuid), 0, &new_t_data, NULL);
|
164
|
+
return epoll_ctl(reactor_fd, EPOLL_CTL_ADD, sock_uuid2fd(uuid), &chevent);
|
165
|
+
}
|
166
|
+
|
167
|
+
int reactor_remove(intptr_t uuid) {
|
168
|
+
struct epoll_event chevent = {0};
|
169
|
+
// chevent.data.ptr = (void *)uuid;
|
170
|
+
// chevent.events =
|
171
|
+
// EPOLLOUT | EPOLLIN | EPOLLET | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
|
172
|
+
return epoll_ctl(reactor_fd, EPOLL_CTL_DEL, sock_uuid2fd(uuid), &chevent);
|
173
|
+
}
|
174
|
+
int reactor_remove_timer(intptr_t uuid) {
|
175
|
+
struct epoll_event chevent = {0};
|
176
|
+
// chevent.data.ptr = (void *)uuid;
|
177
|
+
// chevent.events =
|
178
|
+
// EPOLLOUT | EPOLLIN | EPOLLET | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
|
179
|
+
return epoll_ctl(reactor_fd, EPOLL_CTL_DEL, sock_uuid2fd(uuid), &chevent);
|
180
|
+
}
|
181
|
+
|
182
|
+
/**
|
183
|
+
epoll requires the timer to be "reset" before repeating. Kqueue requires no such
|
184
|
+
thing.
|
185
|
+
|
186
|
+
This method promises that the timer will be repeated when running on epoll. This
|
187
|
+
method is redundent on kqueue.
|
188
|
+
*/
|
189
|
+
void reactor_reset_timer(intptr_t uuid) {
|
190
|
+
char data[8]; // void * is 8 byte long
|
191
|
+
if (read(sock_uuid2fd(uuid), &data, 8) < 0)
|
192
|
+
data[0] = 0;
|
193
|
+
}
|
194
|
+
/**
|
195
|
+
Creates a timer file descriptor, system dependent.
|
196
|
+
|
197
|
+
Opens a new file decriptor for creating timer events. On BSD this will revert to
|
198
|
+
an `fileno(tmpfile())` (with error handling) and on Linux it will call
|
199
|
+
`timerfd_create(CLOCK_MONOTONIC, ...)`.
|
200
|
+
|
201
|
+
Returns -1 on error, otherwise returns the file descriptor.
|
202
|
+
*/
|
203
|
+
intptr_t reactor_make_timer() {
|
204
|
+
return timerfd_create(CLOCK_MONOTONIC, O_NONBLOCK);
|
205
|
+
;
|
206
|
+
}
|
207
|
+
|
208
|
+
/* *****************************************************************************
|
209
|
+
This library requires either kqueue or epoll to be available.
|
210
|
+
Please help us be implementing support for your OS.
|
211
|
+
*/
|
212
|
+
#else
|
213
|
+
int reactor_add(intptr_t uuid) { return -1; }
|
214
|
+
int reactor_add_timer(intptr_t uuid, long milliseconds) { return -1; }
|
215
|
+
|
216
|
+
int reactor_remove(intptr_t uuid) { return -1; }
|
217
|
+
int reactor_remove_timer(intptr_t uuid) { return -1; }
|
218
|
+
#error(This library requires either kqueue or epoll to be available. Please help us be implementing support for your OS.)
|
219
|
+
#endif
|
220
|
+
|
221
|
+
/* *****************************************************************************
|
222
|
+
The Reactor loop.
|
223
|
+
*/
|
224
|
+
|
225
|
+
/*
|
226
|
+
define some macros to help us write a cleaner main function.
|
227
|
+
*/
|
228
|
+
|
229
|
+
/* KQueue */
|
230
|
+
#ifdef EV_SET
|
231
|
+
/* global timout value for the reactors */
|
232
|
+
static struct timespec _reactor_timeout = {
|
233
|
+
.tv_sec = (REACTOR_TICK / 1000),
|
234
|
+
.tv_nsec = ((REACTOR_TICK % 1000) * 1000000)};
|
235
|
+
#define _CRAETE_QUEUE_ kqueue()
|
236
|
+
#define _EVENT_TYPE_ struct kevent
|
237
|
+
// #define _EVENTS_ ((_EVENT_TYPE_*)(reactor->internal_data.events))
|
238
|
+
#define _WAIT_FOR_EVENTS_(events) \
|
239
|
+
kevent(reactor_fd, NULL, 0, (events), REACTOR_MAX_EVENTS, &_reactor_timeout);
|
240
|
+
#define _GET_FDUUID_(events, _ev_) ((intptr_t)((events)[(_ev_)].udata))
|
241
|
+
#define _EVENTERROR_(events, _ev_) (events)[(_ev_)].flags &(EV_EOF | EV_ERROR)
|
242
|
+
#define _EVENTREADY_(events, _ev_) (events)[(_ev_)].filter == EVFILT_WRITE
|
243
|
+
#define _EVENTDATA_(events, _ev_) \
|
244
|
+
(events)[(_ev_)].filter == EVFILT_READ || \
|
245
|
+
(events)[(_ev_)].filter == EVFILT_TIMER
|
246
|
+
|
247
|
+
/* EPoll */
|
248
|
+
#elif defined(EPOLLIN)
|
249
|
+
static int const _reactor_timeout = REACTOR_TICK;
|
250
|
+
#define _CRAETE_QUEUE_ epoll_create1(0)
|
251
|
+
#define _EVENT_TYPE_ struct epoll_event
|
252
|
+
// #define _EVENTS_ ((_EVENT_TYPE_*)reactor->internal_data.events)
|
253
|
+
#define _QUEUE_READY_FLAG_ EPOLLOUT
|
254
|
+
#define _WAIT_FOR_EVENTS_(events) \
|
255
|
+
epoll_wait(reactor_fd, (events), REACTOR_MAX_EVENTS, _reactor_timeout)
|
256
|
+
#define _GET_FDUUID_(events, _ev_) ((intptr_t)((events)[(_ev_)].data.ptr))
|
257
|
+
#define _EVENTERROR_(events, _ev_) \
|
258
|
+
((events)[(_ev_)].events & (~(EPOLLIN | EPOLLOUT)))
|
259
|
+
#define _EVENTREADY_(_events, _ev_) (_events)[(_ev_)].events &EPOLLOUT
|
260
|
+
#define _EVENTDATA_(_events, _ev_) (_events)[(_ev_)].events &EPOLLIN
|
261
|
+
|
262
|
+
#else /* no epoll, no kqueue - this is where support ends */
|
263
|
+
#error(This library requires either kqueue or epoll to be available. Please help us be implementing support for your OS.)
|
264
|
+
#endif
|
265
|
+
|
266
|
+
/**
|
267
|
+
Initializes the reactor, making the reactor "live".
|
268
|
+
|
269
|
+
Returns -1 on error, otherwise returns 0.
|
270
|
+
*/
|
271
|
+
ssize_t reactor_init() {
|
272
|
+
if (reactor_fd > 0)
|
273
|
+
return -1;
|
274
|
+
reactor_fd = _CRAETE_QUEUE_;
|
275
|
+
return 0;
|
276
|
+
}
|
277
|
+
|
278
|
+
/**
|
279
|
+
Closes the reactor, releasing it's resources (except the actual struct Reactor,
|
280
|
+
which might have been allocated on the stack and should be handled by the
|
281
|
+
caller).
|
282
|
+
*/
|
283
|
+
void reactor_stop() {
|
284
|
+
close(reactor_fd);
|
285
|
+
reactor_fd = -1;
|
286
|
+
}
|
287
|
+
|
288
|
+
/* *****************************************************************************
|
289
|
+
The main Reactor Review function
|
290
|
+
*/
|
291
|
+
|
292
|
+
/**
|
293
|
+
Reviews any pending events (up to REACTOR_MAX_EVENTS)
|
294
|
+
|
295
|
+
Returns -1 on error, otherwise returns 0.
|
296
|
+
*/
|
297
|
+
int reactor_review() {
|
298
|
+
if (reactor_fd < 0)
|
299
|
+
return -1;
|
300
|
+
_EVENT_TYPE_ events[REACTOR_MAX_EVENTS];
|
301
|
+
|
302
|
+
/* wait for events and handle them */
|
303
|
+
int active_count = _WAIT_FOR_EVENTS_(events);
|
304
|
+
if (active_count > 0) {
|
305
|
+
for (int i = 0; i < active_count; i++) {
|
306
|
+
if (_EVENTERROR_(events, i)) {
|
307
|
+
// errors are hendled as disconnections (on_close)
|
308
|
+
// printf("on_close for %lu\n", _GET_FDUUID_(events, i));
|
309
|
+
sock_close(_GET_FDUUID_(events, i));
|
310
|
+
} else {
|
311
|
+
// no error, then it's an active event(s)
|
312
|
+
if (_EVENTREADY_(events, i)) {
|
313
|
+
// printf("on_ready for %lu\n", _GET_FDUUID_(events, i));
|
314
|
+
if (sock_flush(_GET_FDUUID_(events, i)) < 0) {
|
315
|
+
sock_close(_GET_FDUUID_(events, i));
|
316
|
+
} else {
|
317
|
+
// printf("on_ready callback for %lu fd(%d)\n",
|
318
|
+
// _GET_FDUUID_(events, i),
|
319
|
+
// sock_uuid2fd(_GET_FDUUID_(events, i)));
|
320
|
+
reactor_on_ready(_GET_FDUUID_(events, i));
|
321
|
+
}
|
322
|
+
}
|
323
|
+
if (_EVENTDATA_(events, i)) {
|
324
|
+
// printf("on_data callback for %lu fd(%d)\n",
|
325
|
+
// _GET_FDUUID_(events, i),
|
326
|
+
// sock_uuid2fd(_GET_FDUUID_(events, i)));
|
327
|
+
reactor_on_data(_GET_FDUUID_(events, i));
|
328
|
+
}
|
329
|
+
}
|
330
|
+
} // end for loop
|
331
|
+
} else if (active_count < 0) {
|
332
|
+
// perror("Please close the reactor, it's dying...");
|
333
|
+
return -1;
|
334
|
+
}
|
335
|
+
return active_count;
|
336
|
+
}
|
337
|
+
|
338
|
+
// we're done with these
|
339
|
+
#undef _CRAETE_QUEUE_
|
340
|
+
#undef _EVENT_TYPE_
|
341
|
+
#undef _EVENTS
|
342
|
+
#undef _INIT_TIMEOUT_
|
343
|
+
#undef _WAIT_FOR_EVENTS_
|
344
|
+
#undef _GET_FDUUID_
|
345
|
+
#undef _EVENTERROR_
|
346
|
+
#undef _EVENTREADY_
|
347
|
+
#undef _EVENTDATA_
|