udp: Merge udp_send and udp_output
[dragonfly.git] / contrib / wpa_supplicant / src / utils / eloop.c
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
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
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
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
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
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
169 static void eloop_sock_table_destroy(struct eloop_sock_table *table)
170 {
171         if (table) {
172                 int i;
173                 for (i = 0; i < table->count && table->table; i++) {
174                         printf("ELOOP: remaining socket: sock=%d "
175                                "eloop_data=%p user_data=%p handler=%p\n",
176                                table->table[i].sock,
177                                table->table[i].eloop_data,
178                                table->table[i].user_data,
179                                table->table[i].handler);
180                 }
181                 os_free(table->table);
182         }
183 }
184
185
186 int eloop_register_read_sock(int sock, eloop_sock_handler handler,
187                              void *eloop_data, void *user_data)
188 {
189         return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
190                                    eloop_data, user_data);
191 }
192
193
194 void eloop_unregister_read_sock(int sock)
195 {
196         eloop_unregister_sock(sock, EVENT_TYPE_READ);
197 }
198
199
200 static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
201 {
202         switch (type) {
203         case EVENT_TYPE_READ:
204                 return &eloop.readers;
205         case EVENT_TYPE_WRITE:
206                 return &eloop.writers;
207         case EVENT_TYPE_EXCEPTION:
208                 return &eloop.exceptions;
209         }
210
211         return NULL;
212 }
213
214
215 int eloop_register_sock(int sock, eloop_event_type type,
216                         eloop_sock_handler handler,
217                         void *eloop_data, void *user_data)
218 {
219         struct eloop_sock_table *table;
220
221         table = eloop_get_sock_table(type);
222         return eloop_sock_table_add_sock(table, sock, handler,
223                                          eloop_data, user_data);
224 }
225
226
227 void eloop_unregister_sock(int sock, eloop_event_type type)
228 {
229         struct eloop_sock_table *table;
230
231         table = eloop_get_sock_table(type);
232         eloop_sock_table_remove_sock(table, sock);
233 }
234
235
236 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
237                            eloop_timeout_handler handler,
238                            void *eloop_data, void *user_data)
239 {
240         struct eloop_timeout *timeout, *tmp, *prev;
241
242         timeout = os_malloc(sizeof(*timeout));
243         if (timeout == NULL)
244                 return -1;
245         if (os_get_time(&timeout->time) < 0) {
246                 os_free(timeout);
247                 return -1;
248         }
249         timeout->time.sec += secs;
250         timeout->time.usec += usecs;
251         while (timeout->time.usec >= 1000000) {
252                 timeout->time.sec++;
253                 timeout->time.usec -= 1000000;
254         }
255         timeout->eloop_data = eloop_data;
256         timeout->user_data = user_data;
257         timeout->handler = handler;
258         timeout->next = NULL;
259
260         if (eloop.timeout == NULL) {
261                 eloop.timeout = timeout;
262                 return 0;
263         }
264
265         prev = NULL;
266         tmp = eloop.timeout;
267         while (tmp != NULL) {
268                 if (os_time_before(&timeout->time, &tmp->time))
269                         break;
270                 prev = tmp;
271                 tmp = tmp->next;
272         }
273
274         if (prev == NULL) {
275                 timeout->next = eloop.timeout;
276                 eloop.timeout = timeout;
277         } else {
278                 timeout->next = prev->next;
279                 prev->next = timeout;
280         }
281
282         return 0;
283 }
284
285
286 int eloop_cancel_timeout(eloop_timeout_handler handler,
287                          void *eloop_data, void *user_data)
288 {
289         struct eloop_timeout *timeout, *prev, *next;
290         int removed = 0;
291
292         prev = NULL;
293         timeout = eloop.timeout;
294         while (timeout != NULL) {
295                 next = timeout->next;
296
297                 if (timeout->handler == handler &&
298                     (timeout->eloop_data == eloop_data ||
299                      eloop_data == ELOOP_ALL_CTX) &&
300                     (timeout->user_data == user_data ||
301                      user_data == ELOOP_ALL_CTX)) {
302                         if (prev == NULL)
303                                 eloop.timeout = next;
304                         else
305                                 prev->next = next;
306                         os_free(timeout);
307                         removed++;
308                 } else
309                         prev = timeout;
310
311                 timeout = next;
312         }
313
314         return removed;
315 }
316
317
318 int eloop_is_timeout_registered(eloop_timeout_handler handler,
319                                 void *eloop_data, void *user_data)
320 {
321         struct eloop_timeout *tmp;
322
323         tmp = eloop.timeout;
324         while (tmp != NULL) {
325                 if (tmp->handler == handler &&
326                     tmp->eloop_data == eloop_data &&
327                     tmp->user_data == user_data)
328                         return 1;
329
330                 tmp = tmp->next;
331         }
332
333         return 0;
334 }
335
336
337 #ifndef CONFIG_NATIVE_WINDOWS
338 static void eloop_handle_alarm(int sig)
339 {
340         fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
341                 "seconds. Looks like there\n"
342                 "is a bug that ends up in a busy loop that "
343                 "prevents clean shutdown.\n"
344                 "Killing program forcefully.\n");
345         exit(1);
346 }
347 #endif /* CONFIG_NATIVE_WINDOWS */
348
349
350 static void eloop_handle_signal(int sig)
351 {
352         int i;
353
354 #ifndef CONFIG_NATIVE_WINDOWS
355         if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
356                 /* Use SIGALRM to break out from potential busy loops that
357                  * would not allow the program to be killed. */
358                 eloop.pending_terminate = 1;
359                 signal(SIGALRM, eloop_handle_alarm);
360                 alarm(2);
361         }
362 #endif /* CONFIG_NATIVE_WINDOWS */
363
364         eloop.signaled++;
365         for (i = 0; i < eloop.signal_count; i++) {
366                 if (eloop.signals[i].sig == sig) {
367                         eloop.signals[i].signaled++;
368                         break;
369                 }
370         }
371 }
372
373
374 static void eloop_process_pending_signals(void)
375 {
376         int i;
377
378         if (eloop.signaled == 0)
379                 return;
380         eloop.signaled = 0;
381
382         if (eloop.pending_terminate) {
383 #ifndef CONFIG_NATIVE_WINDOWS
384                 alarm(0);
385 #endif /* CONFIG_NATIVE_WINDOWS */
386                 eloop.pending_terminate = 0;
387         }
388
389         for (i = 0; i < eloop.signal_count; i++) {
390                 if (eloop.signals[i].signaled) {
391                         eloop.signals[i].signaled = 0;
392                         eloop.signals[i].handler(eloop.signals[i].sig,
393                                                  eloop.user_data,
394                                                  eloop.signals[i].user_data);
395                 }
396         }
397 }
398
399
400 int eloop_register_signal(int sig, eloop_signal_handler handler,
401                           void *user_data)
402 {
403         struct eloop_signal *tmp;
404
405         tmp = (struct eloop_signal *)
406                 os_realloc(eloop.signals,
407                            (eloop.signal_count + 1) *
408                            sizeof(struct eloop_signal));
409         if (tmp == NULL)
410                 return -1;
411
412         tmp[eloop.signal_count].sig = sig;
413         tmp[eloop.signal_count].user_data = user_data;
414         tmp[eloop.signal_count].handler = handler;
415         tmp[eloop.signal_count].signaled = 0;
416         eloop.signal_count++;
417         eloop.signals = tmp;
418         signal(sig, eloop_handle_signal);
419
420         return 0;
421 }
422
423
424 int eloop_register_signal_terminate(eloop_signal_handler handler,
425                                     void *user_data)
426 {
427         int ret = eloop_register_signal(SIGINT, handler, user_data);
428         if (ret == 0)
429                 ret = eloop_register_signal(SIGTERM, handler, user_data);
430         return ret;
431 }
432
433
434 int eloop_register_signal_reconfig(eloop_signal_handler handler,
435                                    void *user_data)
436 {
437 #ifdef CONFIG_NATIVE_WINDOWS
438         return 0;
439 #else /* CONFIG_NATIVE_WINDOWS */
440         return eloop_register_signal(SIGHUP, handler, user_data);
441 #endif /* CONFIG_NATIVE_WINDOWS */
442 }
443
444
445 void eloop_run(void)
446 {
447         fd_set *rfds, *wfds, *efds;
448         int res;
449         struct timeval _tv;
450         struct os_time tv, now;
451
452         rfds = os_malloc(sizeof(*rfds));
453         wfds = os_malloc(sizeof(*wfds));
454         efds = os_malloc(sizeof(*efds));
455         if (rfds == NULL || wfds == NULL || efds == NULL) {
456                 printf("eloop_run - malloc failed\n");
457                 goto out;
458         }
459
460         while (!eloop.terminate &&
461                (eloop.timeout || eloop.readers.count > 0 ||
462                 eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
463                 if (eloop.timeout) {
464                         os_get_time(&now);
465                         if (os_time_before(&now, &eloop.timeout->time))
466                                 os_time_sub(&eloop.timeout->time, &now, &tv);
467                         else
468                                 tv.sec = tv.usec = 0;
469 #if 0
470                         printf("next timeout in %lu.%06lu sec\n",
471                                tv.sec, tv.usec);
472 #endif
473                         _tv.tv_sec = tv.sec;
474                         _tv.tv_usec = tv.usec;
475                 }
476
477                 eloop_sock_table_set_fds(&eloop.readers, rfds);
478                 eloop_sock_table_set_fds(&eloop.writers, wfds);
479                 eloop_sock_table_set_fds(&eloop.exceptions, efds);
480                 res = select(eloop.max_sock + 1, rfds, wfds, efds,
481                              eloop.timeout ? &_tv : NULL);
482                 if (res < 0 && errno != EINTR && errno != 0) {
483                         perror("select");
484                         goto out;
485                 }
486                 eloop_process_pending_signals();
487
488                 /* check if some registered timeouts have occurred */
489                 if (eloop.timeout) {
490                         struct eloop_timeout *tmp;
491
492                         os_get_time(&now);
493                         if (!os_time_before(&now, &eloop.timeout->time)) {
494                                 tmp = eloop.timeout;
495                                 eloop.timeout = eloop.timeout->next;
496                                 tmp->handler(tmp->eloop_data,
497                                              tmp->user_data);
498                                 os_free(tmp);
499                         }
500
501                 }
502
503                 if (res <= 0)
504                         continue;
505
506                 eloop_sock_table_dispatch(&eloop.readers, rfds);
507                 eloop_sock_table_dispatch(&eloop.writers, wfds);
508                 eloop_sock_table_dispatch(&eloop.exceptions, efds);
509         }
510
511 out:
512         os_free(rfds);
513         os_free(wfds);
514         os_free(efds);
515 }
516
517
518 void eloop_terminate(void)
519 {
520         eloop.terminate = 1;
521 }
522
523
524 void eloop_destroy(void)
525 {
526         struct eloop_timeout *timeout, *prev;
527         struct os_time now;
528
529         timeout = eloop.timeout;
530         if (timeout)
531                 os_get_time(&now);
532         while (timeout != NULL) {
533                 int sec, usec;
534                 prev = timeout;
535                 timeout = timeout->next;
536                 sec = prev->time.sec - now.sec;
537                 usec = prev->time.usec - now.usec;
538                 if (prev->time.usec < now.usec) {
539                         sec--;
540                         usec += 1000000;
541                 }
542                 printf("ELOOP: remaining timeout: %d.%06d eloop_data=%p "
543                        "user_data=%p handler=%p\n",
544                        sec, usec, prev->eloop_data, prev->user_data,
545                        prev->handler);
546                 os_free(prev);
547         }
548         eloop_sock_table_destroy(&eloop.readers);
549         eloop_sock_table_destroy(&eloop.writers);
550         eloop_sock_table_destroy(&eloop.exceptions);
551         os_free(eloop.signals);
552 }
553
554
555 int eloop_terminated(void)
556 {
557         return eloop.terminate;
558 }
559
560
561 void eloop_wait_for_read_sock(int sock)
562 {
563         fd_set rfds;
564
565         if (sock < 0)
566                 return;
567
568         FD_ZERO(&rfds);
569         FD_SET(sock, &rfds);
570         select(sock + 1, &rfds, NULL, NULL, NULL);
571 }
572
573
574 void * eloop_get_user_data(void)
575 {
576         return eloop.user_data;
577 }