1 /*
2 * Event loop based on select() loop
3 * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15 #include "includes.h"
16
17 #include "common.h"
18 #include "eloop.h"
19
20
21 struct eloop_sock {
22 int sock;
23 void *eloop_data;
24 void *user_data;
25 eloop_sock_handler handler;
26 };
27
28 struct eloop_timeout {
29 struct os_time time;
30 void *eloop_data;
31 void *user_data;
32 eloop_timeout_handler handler;
33 struct eloop_timeout *next;
34 };
35
36 struct eloop_signal {
37 int sig;
38 void *user_data;
39 eloop_signal_handler handler;
40 int signaled;
41 };
42
43 struct eloop_sock_table {
44 int count;
45 struct eloop_sock *table;
46 int changed;
47 };
48
49 struct eloop_data {
50 void *user_data;
51
52 int max_sock;
53
54 struct eloop_sock_table readers;
55 struct eloop_sock_table writers;
56 struct eloop_sock_table exceptions;
57
58 struct eloop_timeout *timeout;
59
60 int signal_count;
61 struct eloop_signal *signals;
62 int signaled;
63 int pending_terminate;
64
65 int terminate;
66 int reader_table_changed;
67 };
68
69 static struct eloop_data eloop;
70
71
eloop_init(void * user_data)72 int eloop_init(void *user_data)
73 {
74 os_memset(&eloop, 0, sizeof(eloop));
75 eloop.user_data = user_data;
76 return 0;
77 }
78
79
eloop_sock_table_add_sock(struct eloop_sock_table * table,int sock,eloop_sock_handler handler,void * eloop_data,void * user_data)80 static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
81 int sock, eloop_sock_handler handler,
82 void *eloop_data, void *user_data)
83 {
84 struct eloop_sock *tmp;
85
86 if (table == NULL)
87 return -1;
88
89 tmp = (struct eloop_sock *)
90 os_realloc(table->table,
91 (table->count + 1) * sizeof(struct eloop_sock));
92 if (tmp == NULL)
93 return -1;
94
95 tmp[table->count].sock = sock;
96 tmp[table->count].eloop_data = eloop_data;
97 tmp[table->count].user_data = user_data;
98 tmp[table->count].handler = handler;
99 table->count++;
100 table->table = tmp;
101 if (sock > eloop.max_sock)
102 eloop.max_sock = sock;
103 table->changed = 1;
104
105 return 0;
106 }
107
108
eloop_sock_table_remove_sock(struct eloop_sock_table * table,int sock)109 static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
110 int sock)
111 {
112 int i;
113
114 if (table == NULL || table->table == NULL || table->count == 0)
115 return;
116
117 for (i = 0; i < table->count; i++) {
118 if (table->table[i].sock == sock)
119 break;
120 }
121 if (i == table->count)
122 return;
123 if (i != table->count - 1) {
124 os_memmove(&table->table[i], &table->table[i + 1],
125 (table->count - i - 1) *
126 sizeof(struct eloop_sock));
127 }
128 table->count--;
129 table->changed = 1;
130 }
131
132
eloop_sock_table_set_fds(struct eloop_sock_table * table,fd_set * fds)133 static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
134 fd_set *fds)
135 {
136 int i;
137
138 FD_ZERO(fds);
139
140 if (table->table == NULL)
141 return;
142
143 for (i = 0; i < table->count; i++)
144 FD_SET(table->table[i].sock, fds);
145 }
146
147
eloop_sock_table_dispatch(struct eloop_sock_table * table,fd_set * fds)148 static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
149 fd_set *fds)
150 {
151 int i;
152
153 if (table == NULL || table->table == NULL)
154 return;
155
156 table->changed = 0;
157 for (i = 0; i < table->count; i++) {
158 if (FD_ISSET(table->table[i].sock, fds)) {
159 table->table[i].handler(table->table[i].sock,
160 table->table[i].eloop_data,
161 table->table[i].user_data);
162 if (table->changed)
163 break;
164 }
165 }
166 }
167
168
eloop_sock_table_destroy(struct eloop_sock_table * table)169 static void eloop_sock_table_destroy(struct eloop_sock_table *table)
170 {
171 if (table)
172 os_free(table->table);
173 }
174
175
eloop_register_read_sock(int sock,eloop_sock_handler handler,void * eloop_data,void * user_data)176 int eloop_register_read_sock(int sock, eloop_sock_handler handler,
177 void *eloop_data, void *user_data)
178 {
179 return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
180 eloop_data, user_data);
181 }
182
183
eloop_unregister_read_sock(int sock)184 void eloop_unregister_read_sock(int sock)
185 {
186 eloop_unregister_sock(sock, EVENT_TYPE_READ);
187 }
188
189
eloop_get_sock_table(eloop_event_type type)190 static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
191 {
192 switch (type) {
193 case EVENT_TYPE_READ:
194 return &eloop.readers;
195 case EVENT_TYPE_WRITE:
196 return &eloop.writers;
197 case EVENT_TYPE_EXCEPTION:
198 return &eloop.exceptions;
199 }
200
201 return NULL;
202 }
203
204
eloop_register_sock(int sock,eloop_event_type type,eloop_sock_handler handler,void * eloop_data,void * user_data)205 int eloop_register_sock(int sock, eloop_event_type type,
206 eloop_sock_handler handler,
207 void *eloop_data, void *user_data)
208 {
209 struct eloop_sock_table *table;
210
211 table = eloop_get_sock_table(type);
212 return eloop_sock_table_add_sock(table, sock, handler,
213 eloop_data, user_data);
214 }
215
216
eloop_unregister_sock(int sock,eloop_event_type type)217 void eloop_unregister_sock(int sock, eloop_event_type type)
218 {
219 struct eloop_sock_table *table;
220
221 table = eloop_get_sock_table(type);
222 eloop_sock_table_remove_sock(table, sock);
223 }
224
225
eloop_register_timeout(unsigned int secs,unsigned int usecs,eloop_timeout_handler handler,void * eloop_data,void * user_data)226 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
227 eloop_timeout_handler handler,
228 void *eloop_data, void *user_data)
229 {
230 struct eloop_timeout *timeout, *tmp, *prev;
231
232 timeout = os_malloc(sizeof(*timeout));
233 if (timeout == NULL)
234 return -1;
235 if (os_get_time(&timeout->time) < 0) {
236 os_free(timeout);
237 return -1;
238 }
239 timeout->time.sec += secs;
240 timeout->time.usec += usecs;
241 while (timeout->time.usec >= 1000000) {
242 timeout->time.sec++;
243 timeout->time.usec -= 1000000;
244 }
245 timeout->eloop_data = eloop_data;
246 timeout->user_data = user_data;
247 timeout->handler = handler;
248 timeout->next = NULL;
249
250 if (eloop.timeout == NULL) {
251 eloop.timeout = timeout;
252 return 0;
253 }
254
255 prev = NULL;
256 tmp = eloop.timeout;
257 while (tmp != NULL) {
258 if (os_time_before(&timeout->time, &tmp->time))
259 break;
260 prev = tmp;
261 tmp = tmp->next;
262 }
263
264 if (prev == NULL) {
265 timeout->next = eloop.timeout;
266 eloop.timeout = timeout;
267 } else {
268 timeout->next = prev->next;
269 prev->next = timeout;
270 }
271
272 return 0;
273 }
274
275
eloop_cancel_timeout(eloop_timeout_handler handler,void * eloop_data,void * user_data)276 int eloop_cancel_timeout(eloop_timeout_handler handler,
277 void *eloop_data, void *user_data)
278 {
279 struct eloop_timeout *timeout, *prev, *next;
280 int removed = 0;
281
282 prev = NULL;
283 timeout = eloop.timeout;
284 while (timeout != NULL) {
285 next = timeout->next;
286
287 if (timeout->handler == handler &&
288 (timeout->eloop_data == eloop_data ||
289 eloop_data == ELOOP_ALL_CTX) &&
290 (timeout->user_data == user_data ||
291 user_data == ELOOP_ALL_CTX)) {
292 if (prev == NULL)
293 eloop.timeout = next;
294 else
295 prev->next = next;
296 os_free(timeout);
297 removed++;
298 } else
299 prev = timeout;
300
301 timeout = next;
302 }
303
304 return removed;
305 }
306
307
eloop_is_timeout_registered(eloop_timeout_handler handler,void * eloop_data,void * user_data)308 int eloop_is_timeout_registered(eloop_timeout_handler handler,
309 void *eloop_data, void *user_data)
310 {
311 struct eloop_timeout *tmp;
312
313 tmp = eloop.timeout;
314 while (tmp != NULL) {
315 if (tmp->handler == handler &&
316 tmp->eloop_data == eloop_data &&
317 tmp->user_data == user_data)
318 return 1;
319
320 tmp = tmp->next;
321 }
322
323 return 0;
324 }
325
326
327 #ifndef CONFIG_NATIVE_WINDOWS
eloop_handle_alarm(int sig)328 static void eloop_handle_alarm(int sig)
329 {
330 fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
331 "seconds. Looks like there\n"
332 "is a bug that ends up in a busy loop that "
333 "prevents clean shutdown.\n"
334 "Killing program forcefully.\n");
335 exit(1);
336 }
337 #endif /* CONFIG_NATIVE_WINDOWS */
338
339
eloop_handle_signal(int sig)340 static void eloop_handle_signal(int sig)
341 {
342 int i;
343
344 #ifndef CONFIG_NATIVE_WINDOWS
345 if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
346 /* Use SIGALRM to break out from potential busy loops that
347 * would not allow the program to be killed. */
348 eloop.pending_terminate = 1;
349 signal(SIGALRM, eloop_handle_alarm);
350 alarm(2);
351 }
352 #endif /* CONFIG_NATIVE_WINDOWS */
353
354 eloop.signaled++;
355 for (i = 0; i < eloop.signal_count; i++) {
356 if (eloop.signals[i].sig == sig) {
357 eloop.signals[i].signaled++;
358 break;
359 }
360 }
361 }
362
363
eloop_process_pending_signals(void)364 static void eloop_process_pending_signals(void)
365 {
366 int i;
367
368 if (eloop.signaled == 0)
369 return;
370 eloop.signaled = 0;
371
372 if (eloop.pending_terminate) {
373 #ifndef CONFIG_NATIVE_WINDOWS
374 alarm(0);
375 #endif /* CONFIG_NATIVE_WINDOWS */
376 eloop.pending_terminate = 0;
377 }
378
379 for (i = 0; i < eloop.signal_count; i++) {
380 if (eloop.signals[i].signaled) {
381 eloop.signals[i].signaled = 0;
382 eloop.signals[i].handler(eloop.signals[i].sig,
383 eloop.user_data,
384 eloop.signals[i].user_data);
385 }
386 }
387 }
388
389
eloop_register_signal(int sig,eloop_signal_handler handler,void * user_data)390 int eloop_register_signal(int sig, eloop_signal_handler handler,
391 void *user_data)
392 {
393 struct eloop_signal *tmp;
394
395 tmp = (struct eloop_signal *)
396 os_realloc(eloop.signals,
397 (eloop.signal_count + 1) *
398 sizeof(struct eloop_signal));
399 if (tmp == NULL)
400 return -1;
401
402 tmp[eloop.signal_count].sig = sig;
403 tmp[eloop.signal_count].user_data = user_data;
404 tmp[eloop.signal_count].handler = handler;
405 tmp[eloop.signal_count].signaled = 0;
406 eloop.signal_count++;
407 eloop.signals = tmp;
408 signal(sig, eloop_handle_signal);
409
410 return 0;
411 }
412
413
eloop_register_signal_terminate(eloop_signal_handler handler,void * user_data)414 int eloop_register_signal_terminate(eloop_signal_handler handler,
415 void *user_data)
416 {
417 int ret = eloop_register_signal(SIGINT, handler, user_data);
418 if (ret == 0)
419 ret = eloop_register_signal(SIGTERM, handler, user_data);
420 if (ret == 0)
421 ret = eloop_register_signal(SIGSEGV, handler, user_data);
422 return ret;
423 }
424
425
eloop_register_signal_reconfig(eloop_signal_handler handler,void * user_data)426 int eloop_register_signal_reconfig(eloop_signal_handler handler,
427 void *user_data)
428 {
429 #ifdef CONFIG_NATIVE_WINDOWS
430 return 0;
431 #else /* CONFIG_NATIVE_WINDOWS */
432 return eloop_register_signal(SIGHUP, handler, user_data);
433 #endif /* CONFIG_NATIVE_WINDOWS */
434 }
435
436
eloop_run(void)437 void eloop_run(void)
438 {
439 fd_set *rfds, *wfds, *efds;
440 int res;
441 struct timeval _tv;
442 struct os_time tv, now;
443
444 rfds = os_malloc(sizeof(*rfds));
445 wfds = os_malloc(sizeof(*wfds));
446 efds = os_malloc(sizeof(*efds));
447 if (rfds == NULL || wfds == NULL || efds == NULL) {
448 printf("eloop_run - malloc failed\n");
449 goto out;
450 }
451
452 while (!eloop.terminate &&
453 (eloop.timeout || eloop.readers.count > 0 ||
454 eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
455 if (eloop.timeout) {
456 os_get_time(&now);
457 if (os_time_before(&now, &eloop.timeout->time))
458 os_time_sub(&eloop.timeout->time, &now, &tv);
459 else
460 tv.sec = tv.usec = 0;
461 #if 0
462 printf("next timeout in %lu.%06lu sec\n",
463 tv.sec, tv.usec);
464 #endif
465 _tv.tv_sec = tv.sec;
466 _tv.tv_usec = tv.usec;
467 }
468
469 eloop_sock_table_set_fds(&eloop.readers, rfds);
470 eloop_sock_table_set_fds(&eloop.writers, wfds);
471 eloop_sock_table_set_fds(&eloop.exceptions, efds);
472 res = select(eloop.max_sock + 1, rfds, wfds, efds,
473 eloop.timeout ? &_tv : NULL);
474 if (res < 0 && errno != EINTR && errno != 0) {
475 perror("select");
476 goto out;
477 }
478 eloop_process_pending_signals();
479
480 /* check if some registered timeouts have occurred */
481 if (eloop.timeout) {
482 struct eloop_timeout *tmp;
483
484 os_get_time(&now);
485 if (!os_time_before(&now, &eloop.timeout->time)) {
486 tmp = eloop.timeout;
487 eloop.timeout = eloop.timeout->next;
488 tmp->handler(tmp->eloop_data,
489 tmp->user_data);
490 os_free(tmp);
491 }
492
493 }
494
495 if (res <= 0)
496 continue;
497
498 eloop_sock_table_dispatch(&eloop.readers, rfds);
499 eloop_sock_table_dispatch(&eloop.writers, wfds);
500 eloop_sock_table_dispatch(&eloop.exceptions, efds);
501 }
502
503 out:
504 os_free(rfds);
505 os_free(wfds);
506 os_free(efds);
507 }
508
509
eloop_terminate(void)510 void eloop_terminate(void)
511 {
512 eloop.terminate = 1;
513 }
514
515
eloop_destroy(void)516 void eloop_destroy(void)
517 {
518 struct eloop_timeout *timeout, *prev;
519
520 timeout = eloop.timeout;
521 while (timeout != NULL) {
522 prev = timeout;
523 timeout = timeout->next;
524 os_free(prev);
525 }
526 eloop_sock_table_destroy(&eloop.readers);
527 eloop_sock_table_destroy(&eloop.writers);
528 eloop_sock_table_destroy(&eloop.exceptions);
529 os_free(eloop.signals);
530 }
531
532
eloop_terminated(void)533 int eloop_terminated(void)
534 {
535 return eloop.terminate;
536 }
537
538
eloop_wait_for_read_sock(int sock)539 void eloop_wait_for_read_sock(int sock)
540 {
541 fd_set rfds;
542
543 if (sock < 0)
544 return;
545
546 FD_ZERO(&rfds);
547 FD_SET(sock, &rfds);
548 select(sock + 1, &rfds, NULL, NULL, NULL);
549 }
550
551
eloop_get_user_data(void)552 void * eloop_get_user_data(void)
553 {
554 return eloop.user_data;
555 }
556