]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa_supplicant/eloop.c
This commit was generated by cvs2svn to compensate for changes in r168609,
[FreeBSD/FreeBSD.git] / contrib / wpa_supplicant / eloop.c
1 /*
2  * Event loop based on select() loop
3  * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <sys/time.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 #include <errno.h>
22 #include <signal.h>
23
24 #ifdef CONFIG_NATIVE_WINDOWS
25 #include "common.h"
26 #endif /* CONFIG_NATIVE_WINDOWS */
27
28 #include "eloop.h"
29
30
31 struct eloop_sock {
32         int sock;
33         void *eloop_data;
34         void *user_data;
35         void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
36 };
37
38 struct eloop_timeout {
39         struct timeval time;
40         void *eloop_data;
41         void *user_data;
42         void (*handler)(void *eloop_ctx, void *sock_ctx);
43         struct eloop_timeout *next;
44 };
45
46 struct eloop_signal {
47         int sig;
48         void *user_data;
49         void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
50         int signaled;
51 };
52
53 struct eloop_data {
54         void *user_data;
55
56         int max_sock, reader_count;
57         struct eloop_sock *readers;
58
59         struct eloop_timeout *timeout;
60
61         int signal_count;
62         struct eloop_signal *signals;
63         int signaled;
64         int pending_terminate;
65
66         int terminate;
67 };
68
69 static struct eloop_data eloop;
70
71
72 void eloop_init(void *user_data)
73 {
74         memset(&eloop, 0, sizeof(eloop));
75         eloop.user_data = user_data;
76 }
77
78
79 int eloop_register_read_sock(int sock,
80                              void (*handler)(int sock, void *eloop_ctx,
81                                              void *sock_ctx),
82                              void *eloop_data, void *user_data)
83 {
84         struct eloop_sock *tmp;
85
86         tmp = (struct eloop_sock *)
87                 realloc(eloop.readers,
88                         (eloop.reader_count + 1) * sizeof(struct eloop_sock));
89         if (tmp == NULL)
90                 return -1;
91
92         tmp[eloop.reader_count].sock = sock;
93         tmp[eloop.reader_count].eloop_data = eloop_data;
94         tmp[eloop.reader_count].user_data = user_data;
95         tmp[eloop.reader_count].handler = handler;
96         eloop.reader_count++;
97         eloop.readers = tmp;
98         if (sock > eloop.max_sock)
99                 eloop.max_sock = sock;
100
101         return 0;
102 }
103
104
105 void eloop_unregister_read_sock(int sock)
106 {
107         int i;
108
109         if (eloop.readers == NULL || eloop.reader_count == 0)
110                 return;
111
112         for (i = 0; i < eloop.reader_count; i++) {
113                 if (eloop.readers[i].sock == sock)
114                         break;
115         }
116         if (i == eloop.reader_count)
117                 return;
118         if (i != eloop.reader_count - 1) {
119                 memmove(&eloop.readers[i], &eloop.readers[i + 1],
120                         (eloop.reader_count - i - 1) *
121                         sizeof(struct eloop_sock));
122         }
123         eloop.reader_count--;
124 }
125
126
127 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
128                            void (*handler)(void *eloop_ctx, void *timeout_ctx),
129                            void *eloop_data, void *user_data)
130 {
131         struct eloop_timeout *timeout, *tmp, *prev;
132
133         timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
134         if (timeout == NULL)
135                 return -1;
136         gettimeofday(&timeout->time, NULL);
137         timeout->time.tv_sec += secs;
138         timeout->time.tv_usec += usecs;
139         while (timeout->time.tv_usec >= 1000000) {
140                 timeout->time.tv_sec++;
141                 timeout->time.tv_usec -= 1000000;
142         }
143         timeout->eloop_data = eloop_data;
144         timeout->user_data = user_data;
145         timeout->handler = handler;
146         timeout->next = NULL;
147
148         if (eloop.timeout == NULL) {
149                 eloop.timeout = timeout;
150                 return 0;
151         }
152
153         prev = NULL;
154         tmp = eloop.timeout;
155         while (tmp != NULL) {
156                 if (timercmp(&timeout->time, &tmp->time, <))
157                         break;
158                 prev = tmp;
159                 tmp = tmp->next;
160         }
161
162         if (prev == NULL) {
163                 timeout->next = eloop.timeout;
164                 eloop.timeout = timeout;
165         } else {
166                 timeout->next = prev->next;
167                 prev->next = timeout;
168         }
169
170         return 0;
171 }
172
173
174 int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
175                          void *eloop_data, void *user_data)
176 {
177         struct eloop_timeout *timeout, *prev, *next;
178         int removed = 0;
179
180         prev = NULL;
181         timeout = eloop.timeout;
182         while (timeout != NULL) {
183                 next = timeout->next;
184
185                 if (timeout->handler == handler &&
186                     (timeout->eloop_data == eloop_data ||
187                      eloop_data == ELOOP_ALL_CTX) &&
188                     (timeout->user_data == user_data ||
189                      user_data == ELOOP_ALL_CTX)) {
190                         if (prev == NULL)
191                                 eloop.timeout = next;
192                         else
193                                 prev->next = next;
194                         free(timeout);
195                         removed++;
196                 } else
197                         prev = timeout;
198
199                 timeout = next;
200         }
201
202         return removed;
203 }
204
205
206 #ifndef CONFIG_NATIVE_WINDOWS
207 static void eloop_handle_alarm(int sig)
208 {
209         fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
210                 "seconds. Looks like there\n"
211                 "is a bug that ends up in a busy loop that "
212                 "prevents clean shutdown.\n"
213                 "Killing program forcefully.\n");
214         exit(1);
215 }
216 #endif /* CONFIG_NATIVE_WINDOWS */
217
218
219 static void eloop_handle_signal(int sig)
220 {
221         int i;
222
223 #ifndef CONFIG_NATIVE_WINDOWS
224         if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
225                 /* Use SIGALRM to break out from potential busy loops that
226                  * would not allow the program to be killed. */
227                 eloop.pending_terminate = 1;
228                 signal(SIGALRM, eloop_handle_alarm);
229                 alarm(2);
230         }
231 #endif /* CONFIG_NATIVE_WINDOWS */
232
233         eloop.signaled++;
234         for (i = 0; i < eloop.signal_count; i++) {
235                 if (eloop.signals[i].sig == sig) {
236                         eloop.signals[i].signaled++;
237                         break;
238                 }
239         }
240 }
241
242
243 static void eloop_process_pending_signals(void)
244 {
245         int i;
246
247         if (eloop.signaled == 0)
248                 return;
249         eloop.signaled = 0;
250
251         if (eloop.pending_terminate) {
252 #ifndef CONFIG_NATIVE_WINDOWS
253                 alarm(0);
254 #endif /* CONFIG_NATIVE_WINDOWS */
255                 eloop.pending_terminate = 0;
256         }
257
258         for (i = 0; i < eloop.signal_count; i++) {
259                 if (eloop.signals[i].signaled) {
260                         eloop.signals[i].signaled = 0;
261                         eloop.signals[i].handler(eloop.signals[i].sig,
262                                                  eloop.user_data,
263                                                  eloop.signals[i].user_data);
264                 }
265         }
266 }
267
268
269 int eloop_register_signal(int sig,
270                           void (*handler)(int sig, void *eloop_ctx,
271                                           void *signal_ctx),
272                           void *user_data)
273 {
274         struct eloop_signal *tmp;
275
276         tmp = (struct eloop_signal *)
277                 realloc(eloop.signals,
278                         (eloop.signal_count + 1) *
279                         sizeof(struct eloop_signal));
280         if (tmp == NULL)
281                 return -1;
282
283         tmp[eloop.signal_count].sig = sig;
284         tmp[eloop.signal_count].user_data = user_data;
285         tmp[eloop.signal_count].handler = handler;
286         tmp[eloop.signal_count].signaled = 0;
287         eloop.signal_count++;
288         eloop.signals = tmp;
289         signal(sig, eloop_handle_signal);
290
291         return 0;
292 }
293
294
295 void eloop_run(void)
296 {
297         fd_set *rfds;
298         int i, res;
299         struct timeval tv, now;
300
301         rfds = malloc(sizeof(*rfds));
302         if (rfds == NULL) {
303                 printf("eloop_run - malloc failed\n");
304                 return;
305         }
306
307         while (!eloop.terminate &&
308                 (eloop.timeout || eloop.reader_count > 0)) {
309                 if (eloop.timeout) {
310                         gettimeofday(&now, NULL);
311                         if (timercmp(&now, &eloop.timeout->time, <))
312                                 timersub(&eloop.timeout->time, &now, &tv);
313                         else
314                                 tv.tv_sec = tv.tv_usec = 0;
315 #if 0
316                         printf("next timeout in %lu.%06lu sec\n",
317                                tv.tv_sec, tv.tv_usec);
318 #endif
319                 }
320
321                 FD_ZERO(rfds);
322                 for (i = 0; i < eloop.reader_count; i++)
323                         FD_SET(eloop.readers[i].sock, rfds);
324                 res = select(eloop.max_sock + 1, rfds, NULL, NULL,
325                              eloop.timeout ? &tv : NULL);
326                 if (res < 0 && errno != EINTR) {
327                         perror("select");
328                         free(rfds);
329                         return;
330                 }
331                 eloop_process_pending_signals();
332
333                 /* check if some registered timeouts have occurred */
334                 if (eloop.timeout) {
335                         struct eloop_timeout *tmp;
336
337                         gettimeofday(&now, NULL);
338                         if (!timercmp(&now, &eloop.timeout->time, <)) {
339                                 tmp = eloop.timeout;
340                                 eloop.timeout = eloop.timeout->next;
341                                 tmp->handler(tmp->eloop_data,
342                                              tmp->user_data);
343                                 free(tmp);
344                         }
345
346                 }
347
348                 if (res <= 0)
349                         continue;
350
351                 for (i = 0; i < eloop.reader_count; i++) {
352                         if (FD_ISSET(eloop.readers[i].sock, rfds)) {
353                                 eloop.readers[i].handler(
354                                         eloop.readers[i].sock,
355                                         eloop.readers[i].eloop_data,
356                                         eloop.readers[i].user_data);
357                         }
358                 }
359         }
360
361         free(rfds);
362 }
363
364
365 void eloop_terminate(void)
366 {
367         eloop.terminate = 1;
368 }
369
370
371 void eloop_destroy(void)
372 {
373         struct eloop_timeout *timeout, *prev;
374
375         timeout = eloop.timeout;
376         while (timeout != NULL) {
377                 prev = timeout;
378                 timeout = timeout->next;
379                 free(prev);
380         }
381         free(eloop.readers);
382         free(eloop.signals);
383 }
384
385
386 int eloop_terminated(void)
387 {
388         return eloop.terminate;
389 }