BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file BReactor_badvpn.h
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * @section DESCRIPTION
30 *
31 * Event loop that supports file desciptor (Linux) or HANDLE (Windows) events
32 * and timers.
33 */
34  
35 #ifndef BADVPN_SYSTEM_BREACTOR_H
36 #define BADVPN_SYSTEM_BREACTOR_H
37  
38 #if (defined(BADVPN_USE_WINAPI) + defined(BADVPN_USE_EPOLL) + defined(BADVPN_USE_KEVENT) + defined(BADVPN_USE_POLL)) != 1
39 #error Unknown event backend or too many event backends
40 #endif
41  
42 #ifdef BADVPN_USE_WINAPI
43 #include <windows.h>
44 #endif
45  
46 #ifdef BADVPN_USE_EPOLL
47 #include <sys/epoll.h>
48 #endif
49  
50 #ifdef BADVPN_USE_KEVENT
51 #include <sys/types.h>
52 #include <sys/event.h>
53 #include <sys/time.h>
54 #endif
55  
56 #ifdef BADVPN_USE_POLL
57 #include <poll.h>
58 #endif
59  
60 #include <stdint.h>
61  
62 #include <misc/debug.h>
63 #include <misc/debugcounter.h>
64 #include <base/DebugObject.h>
65 #include <structure/LinkedList1.h>
66 #include <structure/CAvl.h>
67 #include <system/BTime.h>
68 #include <base/BPending.h>
69  
70 struct BSmallTimer_t;
71 typedef struct BSmallTimer_t *BReactor_timerstree_link;
72  
73 #include "BReactor_badvpn_timerstree.h"
74 #include <structure/CAvl_decl.h>
75  
76 #define BTIMER_SET_ABSOLUTE 1
77 #define BTIMER_SET_RELATIVE 2
78  
79 /**
80 * Handler function invoked when the timer expires.
81 * The timer was in running state.
82 * The timer enters not running state before this function is invoked.
83 * This function is being called from within the timer's previosly
84 * associated reactor.
85 *
86 * @param timer pointer to the timer. Use the {@link UPPER_OBJECT} macro
87 * to obtain the pointer to the containing structure.
88 */
89 typedef void (*BSmallTimer_handler) (struct BSmallTimer_t *timer);
90  
91 /**
92 * Handler function invoked when the timer expires.
93 * The timer was in running state.
94 * The timer enters not running state before this function is invoked.
95 * This function is being called from within the timer's previosly
96 * associated reactor.
97 *
98 * @param user value passed to {@link BTimer_Init}
99 */
100 typedef void (*BTimer_handler) (void *user);
101  
102 /**
103 * Timer object used with {@link BReactor}.
104 */
105 typedef struct BSmallTimer_t {
106 union {
107 BSmallTimer_handler smalll; // MSVC doesn't like "small"
108 BTimer_handler heavy;
109 } handler;
110 union {
111 LinkedList1Node list_node;
112 struct BSmallTimer_t *tree_child[2];
113 } u;
114 struct BSmallTimer_t *tree_parent;
115 btime_t absTime;
116 int8_t tree_balance;
117 uint8_t state;
118 uint8_t is_small;
119 } BSmallTimer;
120  
121 /**
122 * Initializes the timer object.
123 * The timer object is initialized in not running state.
124 *
125 * @param bt the object
126 * @param handler handler function invoked when the timer expires
127 */
128 void BSmallTimer_Init (BSmallTimer *bt, BSmallTimer_handler handler);
129  
130 /**
131 * Checks if the timer is running.
132 *
133 * @param bt the object
134 * @return 1 if running, 0 if not running
135 */
136 int BSmallTimer_IsRunning (BSmallTimer *bt);
137  
138 /**
139 * Timer object used with {@link BReactor}. This is a legacy wrapper
140 * around {@link BSmallTimer} with an extra field for the default time.
141 */
142 typedef struct {
143 BSmallTimer base;
144 void *user;
145 btime_t msTime;
146 } BTimer;
147  
148 /**
149 * Initializes the timer object.
150 * The timer object is initialized in not running state.
151 *
152 * @param bt the object
153 * @param msTime default timeout in milliseconds
154 * @param handler handler function invoked when the timer expires
155 * @param user value to pass to the handler function
156 */
157 void BTimer_Init (BTimer *bt, btime_t msTime, BTimer_handler handler, void *user);
158  
159 /**
160 * Checks if the timer is running.
161 *
162 * @param bt the object
163 * @return 1 if running, 0 if not running
164 */
165 int BTimer_IsRunning (BTimer *bt);
166  
167 #ifndef BADVPN_USE_WINAPI
168  
169 struct BFileDescriptor_t;
170  
171 #define BREACTOR_READ (1 << 0)
172 #define BREACTOR_WRITE (1 << 1)
173 #define BREACTOR_ERROR (1 << 2)
174 #define BREACTOR_HUP (1 << 3)
175  
176 /**
177 * Handler function invoked by the reactor when one or more events are detected.
178 * The events argument will contain a subset of the monitored events (BREACTOR_READ, BREACTOR_WRITE),
179 * plus possibly the error event (BREACTOR_ERROR).
180 * The file descriptor object is in active state, being called from within
181 * the associated reactor.
182 *
183 * @param user value passed to {@link BFileDescriptor_Init}
184 * @param events bitmask composed of a subset of monitored events (BREACTOR_READ, BREACTOR_WRITE),
185 * and possibly the error event BREACTOR_ERROR and the hang-up event BREACTOR_HUP.
186 * Will be nonzero.
187 */
188 typedef void (*BFileDescriptor_handler) (void *user, int events);
189  
190 /**
191 * File descriptor object used with {@link BReactor}.
192 */
193 typedef struct BFileDescriptor_t {
194 int fd;
195 BFileDescriptor_handler handler;
196 void *user;
197 int active;
198 int waitEvents;
199  
200 #ifdef BADVPN_USE_EPOLL
201 struct BFileDescriptor_t **epoll_returned_ptr;
202 #endif
203  
204 #ifdef BADVPN_USE_KEVENT
205 int kevent_tag;
206 int kevent_last_event;
207 #endif
208  
209 #ifdef BADVPN_USE_POLL
210 LinkedList1Node poll_enabled_fds_list_node;
211 int poll_returned_index;
212 #endif
213 } BFileDescriptor;
214  
215 /**
216 * Intializes the file descriptor object.
217 * The object is initialized in not active state.
218 *
219 * @param bs file descriptor object to initialize
220 * @param fb file descriptor to represent
221 * @param handler handler function invoked by the reactor when a monitored event is detected
222 * @param user value passed to the handler functuon
223 */
224 void BFileDescriptor_Init (BFileDescriptor *bs, int fd, BFileDescriptor_handler handler, void *user);
225  
226 #endif
227  
228 // BReactor
229  
230 #define BSYSTEM_MAX_RESULTS 64
231 #define BSYSTEM_MAX_HANDLES 64
232 #define BSYSTEM_MAX_POLL_FDS 4096
233  
234 /**
235 * Event loop that supports file desciptor (Linux) or HANDLE (Windows) events
236 * and timers.
237 */
238 typedef struct {
239 int exiting;
240 int exit_code;
241  
242 // jobs
243 BPendingGroup pending_jobs;
244  
245 // timers
246 BReactor__TimersTree timers_tree;
247 LinkedList1 timers_expired_list;
248  
249 // limits
250 LinkedList1 active_limits_list;
251  
252 #ifdef BADVPN_USE_WINAPI
253 LinkedList1 iocp_list;
254 HANDLE iocp_handle;
255 LinkedList1 iocp_ready_list;
256 #endif
257  
258 #ifdef BADVPN_USE_EPOLL
259 int efd; // epoll fd
260 struct epoll_event epoll_results[BSYSTEM_MAX_RESULTS]; // epoll returned events buffer
261 int epoll_results_num; // number of events in the array
262 int epoll_results_pos; // number of events processed so far
263 #endif
264  
265 #ifdef BADVPN_USE_KEVENT
266 int kqueue_fd;
267 struct kevent kevent_results[BSYSTEM_MAX_RESULTS];
268 int kevent_prev_event[BSYSTEM_MAX_RESULTS];
269 int kevent_results_num;
270 int kevent_results_pos;
271 #endif
272  
273 #ifdef BADVPN_USE_POLL
274 LinkedList1 poll_enabled_fds_list;
275 int poll_num_enabled_fds;
276 int poll_results_num;
277 int poll_results_pos;
278 struct pollfd *poll_results_pollfds;
279 BFileDescriptor **poll_results_bfds;
280 #endif
281  
282 DebugObject d_obj;
283 #ifndef BADVPN_USE_WINAPI
284 DebugCounter d_fds_counter;
285 #endif
286 #ifdef BADVPN_USE_KEVENT
287 DebugCounter d_kevent_ctr;
288 #endif
289 DebugCounter d_limits_ctr;
290 } BReactor;
291  
292 /**
293 * Initializes the reactor.
294 * {@link BLog_Init} must have been done.
295 * {@link BTime_Init} must have been done.
296 *
297 * @param bsys the object
298 * @return 1 on success, 0 on failure
299 */
300 int BReactor_Init (BReactor *bsys) WARN_UNUSED;
301  
302 /**
303 * Frees the reactor.
304 * Must not be called from within the event loop ({@link BReactor_Exec}).
305 * There must be no {@link BPending} or {@link BSmallPending} objects using the
306 * pending group returned by {@link BReactor_PendingGroup}.
307 * There must be no running timers in this reactor.
308 * There must be no limit objects in this reactor.
309 * There must be no file descriptors or handles registered
310 * with this reactor.
311 * There must be no {@link BReactorKEvent} objects in this reactor.
312 *
313 * @param bsys the object
314 */
315 void BReactor_Free (BReactor *bsys);
316  
317 /**
318 * Runs the event loop.
319 *
320 * @param bsys the object
321 * @return value passed to {@link BReactor_Quit}
322 */
323 int BReactor_Exec (BReactor *bsys);
324  
325 /**
326 * Causes the event loop ({@link BReactor_Exec}) to cease
327 * dispatching events and return.
328 * Any further calls of {@link BReactor_Exec} will return immediately.
329 *
330 * @param bsys the object
331 * @param code value {@link BReactor_Exec} should return. If this is
332 * called more than once, it will return the last code.
333 */
334 void BReactor_Quit (BReactor *bsys, int code);
335  
336 /**
337 * Starts a timer to expire at the specified time.
338 * The timer must have been initialized with {@link BSmallTimer_Init}.
339 * If the timer is in running state, it must be associated with this reactor.
340 * The timer enters running state, associated with this reactor.
341 *
342 * @param bsys the object
343 * @param bt timer to start
344 * @param mode interpretation of time (BTIMER_SET_ABSOLUTE or BTIMER_SET_RELATIVE)
345 * @param time absolute or relative expiration time
346 */
347 void BReactor_SetSmallTimer (BReactor *bsys, BSmallTimer *bt, int mode, btime_t time);
348  
349 /**
350 * Stops a timer.
351 * If the timer is in running state, it must be associated with this reactor.
352 * The timer enters not running state.
353 *
354 * @param bsys the object
355 * @param bt timer to stop
356 */
357 void BReactor_RemoveSmallTimer (BReactor *bsys, BSmallTimer *bt);
358  
359 /**
360 * Starts a timer to expire after its default time.
361 * The timer must have been initialized with {@link BTimer_Init}.
362 * If the timer is in running state, it must be associated with this reactor.
363 * The timer enters running state, associated with this reactor.
364 *
365 * @param bsys the object
366 * @param bt timer to start
367 */
368 void BReactor_SetTimer (BReactor *bsys, BTimer *bt);
369  
370 /**
371 * Starts a timer to expire after a given time.
372 * The timer must have been initialized with {@link BTimer_Init}.
373 * If the timer is in running state, it must be associated with this reactor.
374 * The timer enters running state, associated with this reactor.
375 *
376 * @param bsys the object
377 * @param bt timer to start
378 * @param after relative expiration time
379 */
380 void BReactor_SetTimerAfter (BReactor *bsys, BTimer *bt, btime_t after);
381  
382 /**
383 * Starts a timer to expire at the specified time.
384 * The timer must have been initialized with {@link BTimer_Init}.
385 * If the timer is in running state, it must be associated with this reactor.
386 * The timer enters running state, associated with this reactor.
387 * The timer's expiration time is set to the time argument.
388 *
389 * @param bsys the object
390 * @param bt timer to start
391 * @param time absolute expiration time (according to {@link btime_gettime})
392 */
393 void BReactor_SetTimerAbsolute (BReactor *bsys, BTimer *bt, btime_t time);
394  
395 /**
396 * Stops a timer.
397 * If the timer is in running state, it must be associated with this reactor.
398 * The timer enters not running state.
399 *
400 * @param bsys the object
401 * @param bt timer to stop
402 */
403 void BReactor_RemoveTimer (BReactor *bsys, BTimer *bt);
404  
405 /**
406 * Returns a {@link BPendingGroup} object that can be used to schedule jobs for
407 * the reactor to execute. These jobs have complete priority over other events
408 * (timers, file descriptors and Windows handles).
409 * The returned pending group may only be used as an argument to {@link BPending_Init},
410 * and must not be accessed by other means.
411 * All {@link BPending} and {@link BSmallPending} objects using this group must be
412 * freed before freeing the reactor.
413 *
414 * @param bsys the object
415 * @return pending group for scheduling jobs for the reactor to execute
416 */
417 BPendingGroup * BReactor_PendingGroup (BReactor *bsys);
418  
419 /**
420 * Executes pending jobs until either:
421 * - the reference job is reached, or
422 * - {@link BReactor_Quit} is called.
423 * The reference job must be reached before the job list empties.
424 * The reference job will not be executed.
425 *
426 * WARNING: Use with care. This should only be used to to work around third-party software
427 * that does not integrade into the jobs system. In particular, you should think about:
428 * - the effects the jobs to be executed may have, and
429 * - the environment those jobs expect to be executed in.
430 *
431 * @param bsys the object
432 * @param ref reference job. It is not accessed in any way, only its address is compared to
433 * pending jobs before they are executed.
434 * @return 1 if the reference job was reached,
435 * 0 if {@link BReactor_Quit} was called (either while executing a job, or before)
436 */
437 int BReactor_Synchronize (BReactor *bsys, BSmallPending *ref);
438  
439 #ifndef BADVPN_USE_WINAPI
440  
441 /**
442 * Starts monitoring a file descriptor.
443 *
444 * @param bsys the object
445 * @param bs file descriptor object. Must have been initialized with
446 * {@link BFileDescriptor_Init} Must be in not active state.
447 * On success, the file descriptor object enters active state,
448 * associated with this reactor.
449 * @return 1 on success, 0 on failure
450 */
451 int BReactor_AddFileDescriptor (BReactor *bsys, BFileDescriptor *bs) WARN_UNUSED;
452  
453 /**
454 * Stops monitoring a file descriptor.
455 *
456 * @param bsys the object
457 * @param bs {@link BFileDescriptor} object. Must be in active state,
458 * associated with this reactor. The file descriptor object
459 * enters not active state.
460 */
461 void BReactor_RemoveFileDescriptor (BReactor *bsys, BFileDescriptor *bs);
462  
463 /**
464 * Sets monitored file descriptor events.
465 *
466 * @param bsys the object
467 * @param bs {@link BFileDescriptor} object. Must be in active state,
468 * associated with this reactor.
469 * @param events events to watch for. Must not have any bits other than
470 * BREACTOR_READ and BREACTOR_WRITE.
471 * This overrides previosly monitored events.
472 */
473 void BReactor_SetFileDescriptorEvents (BReactor *bsys, BFileDescriptor *bs, int events);
474  
475 #endif
476  
477 typedef struct {
478 BReactor *reactor;
479 int limit;
480 int count;
481 LinkedList1Node active_limits_list_node;
482 DebugObject d_obj;
483 } BReactorLimit;
484  
485 /**
486 * Initializes a limit object.
487 * A limit object consists of a counter integer, which is initialized to
488 * zero, is incremented by {@link BReactorLimit_Increment} up to \a limit,
489 * and is reset to zero every time the event loop performs a wait.
490 * If the event loop has processed all detected events, and before performing
491 * a wait, it determines that timers have expired, the counter will not be reset.
492 *
493 * @param o the object
494 * @param reactor reactor the object is tied to
495 * @param limit maximum counter value. Must be >0.
496 */
497 void BReactorLimit_Init (BReactorLimit *o, BReactor *reactor, int limit);
498  
499 /**
500 * Frees a limit object.
501 *
502 * @param o the object
503 */
504 void BReactorLimit_Free (BReactorLimit *o);
505  
506 /**
507 * Attempts to increment the counter of a limit object.
508 *
509 * @param o the object
510 * @return 1 if the counter was lesser than the limit and was incremented,
511 * 0 if the counter was greater or equal to the limit and could not be
512 * incremented
513 */
514 int BReactorLimit_Increment (BReactorLimit *o);
515  
516 /**
517 * Sets the limit of a limit object.
518 *
519 * @param o the object
520 * @param limit new limit. Must be >0.
521 */
522 void BReactorLimit_SetLimit (BReactorLimit *o, int limit);
523  
524 #ifdef BADVPN_USE_KEVENT
525  
526 typedef void (*BReactorKEvent_handler) (void *user, u_int fflags, intptr_t data);
527  
528 typedef struct {
529 BReactor *reactor;
530 BReactorKEvent_handler handler;
531 void *user;
532 uintptr_t ident;
533 short filter;
534 int kevent_tag;
535 int kevent_last_event;
536 DebugObject d_obj;
537 } BReactorKEvent;
538  
539 int BReactorKEvent_Init (BReactorKEvent *o, BReactor *reactor, BReactorKEvent_handler handler, void *user, uintptr_t ident, short filter, u_int fflags, intptr_t data);
540 void BReactorKEvent_Free (BReactorKEvent *o);
541  
542 #endif
543  
544 #ifdef BADVPN_USE_WINAPI
545  
546 #define BREACTOR_IOCP_EVENT_SUCCEEDED 1
547 #define BREACTOR_IOCP_EVENT_FAILED 2
548 #define BREACTOR_IOCP_EVENT_EXITING 3
549  
550 typedef void (*BReactorIOCPOverlapped_handler) (void *user, int event, DWORD bytes);
551  
552 typedef struct {
553 OVERLAPPED olap;
554 BReactor *reactor;
555 void *user;
556 BReactorIOCPOverlapped_handler handler;
557 LinkedList1Node iocp_list_node;
558 int is_ready;
559 LinkedList1Node ready_list_node;
560 int ready_succeeded;
561 DWORD ready_bytes;
562 DebugObject d_obj;
563 } BReactorIOCPOverlapped;
564  
565 HANDLE BReactor_GetIOCPHandle (BReactor *reactor);
566  
567 void BReactorIOCPOverlapped_Init (BReactorIOCPOverlapped *o, BReactor *reactor, void *user, BReactorIOCPOverlapped_handler handler);
568 void BReactorIOCPOverlapped_Free (BReactorIOCPOverlapped *o);
569 void BReactorIOCPOverlapped_Wait (BReactorIOCPOverlapped *o, int *out_succeeded, DWORD *out_bytes);
570  
571 #endif
572  
573 #endif