blob: eda412f1b50feb10dd27e222ef46f18a7857875c [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * Event loop based on Windows events and WaitForMultipleObjects
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10#include <winsock2.h>
11
12#include "common.h"
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080013#include "list.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014#include "eloop.h"
15
16
17struct eloop_sock {
18 int sock;
19 void *eloop_data;
20 void *user_data;
21 eloop_sock_handler handler;
22 WSAEVENT event;
23};
24
25struct eloop_event {
26 void *eloop_data;
27 void *user_data;
28 eloop_event_handler handler;
29 HANDLE event;
30};
31
32struct eloop_timeout {
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080033 struct dl_list list;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070034 struct os_time time;
35 void *eloop_data;
36 void *user_data;
37 eloop_timeout_handler handler;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070038};
39
40struct eloop_signal {
41 int sig;
42 void *user_data;
43 eloop_signal_handler handler;
44 int signaled;
45};
46
47struct eloop_data {
48 int max_sock;
49 size_t reader_count;
50 struct eloop_sock *readers;
51
52 size_t event_count;
53 struct eloop_event *events;
54
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080055 struct dl_list timeout;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070056
57 int signal_count;
58 struct eloop_signal *signals;
59 int signaled;
60 int pending_terminate;
61
62 int terminate;
63 int reader_table_changed;
64
65 struct eloop_signal term_signal;
66 HANDLE term_event;
67
68 HANDLE *handles;
69 size_t num_handles;
70};
71
72static struct eloop_data eloop;
73
74
75int eloop_init(void)
76{
77 os_memset(&eloop, 0, sizeof(eloop));
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080078 dl_list_init(&eloop.timeout);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070079 eloop.num_handles = 1;
80 eloop.handles = os_malloc(eloop.num_handles *
81 sizeof(eloop.handles[0]));
82 if (eloop.handles == NULL)
83 return -1;
84
85 eloop.term_event = CreateEvent(NULL, FALSE, FALSE, NULL);
86 if (eloop.term_event == NULL) {
87 printf("CreateEvent() failed: %d\n",
88 (int) GetLastError());
89 os_free(eloop.handles);
90 return -1;
91 }
92
93 return 0;
94}
95
96
97static int eloop_prepare_handles(void)
98{
99 HANDLE *n;
100
101 if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8)
102 return 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700103 n = os_realloc_array(eloop.handles, eloop.num_handles * 2,
104 sizeof(eloop.handles[0]));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700105 if (n == NULL)
106 return -1;
107 eloop.handles = n;
108 eloop.num_handles *= 2;
109 return 0;
110}
111
112
113int eloop_register_read_sock(int sock, eloop_sock_handler handler,
114 void *eloop_data, void *user_data)
115{
116 WSAEVENT event;
117 struct eloop_sock *tmp;
118
119 if (eloop_prepare_handles())
120 return -1;
121
122 event = WSACreateEvent();
123 if (event == WSA_INVALID_EVENT) {
124 printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
125 return -1;
126 }
127
128 if (WSAEventSelect(sock, event, FD_READ)) {
129 printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
130 WSACloseEvent(event);
131 return -1;
132 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700133 tmp = os_realloc_array(eloop.readers, eloop.reader_count + 1,
134 sizeof(struct eloop_sock));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700135 if (tmp == NULL) {
136 WSAEventSelect(sock, event, 0);
137 WSACloseEvent(event);
138 return -1;
139 }
140
141 tmp[eloop.reader_count].sock = sock;
142 tmp[eloop.reader_count].eloop_data = eloop_data;
143 tmp[eloop.reader_count].user_data = user_data;
144 tmp[eloop.reader_count].handler = handler;
145 tmp[eloop.reader_count].event = event;
146 eloop.reader_count++;
147 eloop.readers = tmp;
148 if (sock > eloop.max_sock)
149 eloop.max_sock = sock;
150 eloop.reader_table_changed = 1;
151
152 return 0;
153}
154
155
156void eloop_unregister_read_sock(int sock)
157{
158 size_t i;
159
160 if (eloop.readers == NULL || eloop.reader_count == 0)
161 return;
162
163 for (i = 0; i < eloop.reader_count; i++) {
164 if (eloop.readers[i].sock == sock)
165 break;
166 }
167 if (i == eloop.reader_count)
168 return;
169
170 WSAEventSelect(eloop.readers[i].sock, eloop.readers[i].event, 0);
171 WSACloseEvent(eloop.readers[i].event);
172
173 if (i != eloop.reader_count - 1) {
174 os_memmove(&eloop.readers[i], &eloop.readers[i + 1],
175 (eloop.reader_count - i - 1) *
176 sizeof(struct eloop_sock));
177 }
178 eloop.reader_count--;
179 eloop.reader_table_changed = 1;
180}
181
182
183int eloop_register_event(void *event, size_t event_size,
184 eloop_event_handler handler,
185 void *eloop_data, void *user_data)
186{
187 struct eloop_event *tmp;
188 HANDLE h = event;
189
190 if (event_size != sizeof(HANDLE) || h == INVALID_HANDLE_VALUE)
191 return -1;
192
193 if (eloop_prepare_handles())
194 return -1;
195
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700196 tmp = os_realloc_array(eloop.events, eloop.event_count + 1,
197 sizeof(struct eloop_event));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700198 if (tmp == NULL)
199 return -1;
200
201 tmp[eloop.event_count].eloop_data = eloop_data;
202 tmp[eloop.event_count].user_data = user_data;
203 tmp[eloop.event_count].handler = handler;
204 tmp[eloop.event_count].event = h;
205 eloop.event_count++;
206 eloop.events = tmp;
207
208 return 0;
209}
210
211
212void eloop_unregister_event(void *event, size_t event_size)
213{
214 size_t i;
215 HANDLE h = event;
216
217 if (eloop.events == NULL || eloop.event_count == 0 ||
218 event_size != sizeof(HANDLE))
219 return;
220
221 for (i = 0; i < eloop.event_count; i++) {
222 if (eloop.events[i].event == h)
223 break;
224 }
225 if (i == eloop.event_count)
226 return;
227
228 if (i != eloop.event_count - 1) {
229 os_memmove(&eloop.events[i], &eloop.events[i + 1],
230 (eloop.event_count - i - 1) *
231 sizeof(struct eloop_event));
232 }
233 eloop.event_count--;
234}
235
236
237int eloop_register_timeout(unsigned int secs, unsigned int usecs,
238 eloop_timeout_handler handler,
239 void *eloop_data, void *user_data)
240{
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800241 struct eloop_timeout *timeout, *tmp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700242 os_time_t now_sec;
243
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800244 timeout = os_zalloc(sizeof(*timeout));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700245 if (timeout == NULL)
246 return -1;
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800247 if (os_get_time(&timeout->time) < 0) {
248 os_free(timeout);
249 return -1;
250 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700251 now_sec = timeout->time.sec;
252 timeout->time.sec += secs;
253 if (timeout->time.sec < now_sec) {
254 /*
255 * Integer overflow - assume long enough timeout to be assumed
256 * to be infinite, i.e., the timeout would never happen.
257 */
258 wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
259 "ever happen - ignore it", secs);
260 os_free(timeout);
261 return 0;
262 }
263 timeout->time.usec += usecs;
264 while (timeout->time.usec >= 1000000) {
265 timeout->time.sec++;
266 timeout->time.usec -= 1000000;
267 }
268 timeout->eloop_data = eloop_data;
269 timeout->user_data = user_data;
270 timeout->handler = handler;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700271
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800272 /* Maintain timeouts in order of increasing time */
273 dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
274 if (os_time_before(&timeout->time, &tmp->time)) {
275 dl_list_add(tmp->list.prev, &timeout->list);
276 return 0;
277 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700278 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800279 dl_list_add_tail(&eloop.timeout, &timeout->list);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700280
281 return 0;
282}
283
284
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800285static void eloop_remove_timeout(struct eloop_timeout *timeout)
286{
287 dl_list_del(&timeout->list);
288 os_free(timeout);
289}
290
291
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700292int eloop_cancel_timeout(eloop_timeout_handler handler,
293 void *eloop_data, void *user_data)
294{
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800295 struct eloop_timeout *timeout, *prev;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700296 int removed = 0;
297
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800298 dl_list_for_each_safe(timeout, prev, &eloop.timeout,
299 struct eloop_timeout, list) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700300 if (timeout->handler == handler &&
301 (timeout->eloop_data == eloop_data ||
302 eloop_data == ELOOP_ALL_CTX) &&
303 (timeout->user_data == user_data ||
304 user_data == ELOOP_ALL_CTX)) {
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800305 eloop_remove_timeout(timeout);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700306 removed++;
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800307 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700308 }
309
310 return removed;
311}
312
313
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800314int eloop_cancel_timeout_one(eloop_timeout_handler handler,
315 void *eloop_data, void *user_data,
316 struct os_time *remaining)
317{
318 struct eloop_timeout *timeout, *prev;
319 int removed = 0;
320 struct os_time now;
321
322 os_get_time(&now);
323 remaining->sec = remaining->usec = 0;
324
325 dl_list_for_each_safe(timeout, prev, &eloop.timeout,
326 struct eloop_timeout, list) {
327 if (timeout->handler == handler &&
328 (timeout->eloop_data == eloop_data) &&
329 (timeout->user_data == user_data)) {
330 removed = 1;
331 if (os_time_before(&now, &timeout->time))
332 os_time_sub(&timeout->time, &now, remaining);
333 eloop_remove_timeout(timeout);
334 break;
335 }
336 }
337 return removed;
338}
339
340
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700341int eloop_is_timeout_registered(eloop_timeout_handler handler,
342 void *eloop_data, void *user_data)
343{
344 struct eloop_timeout *tmp;
345
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800346 dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700347 if (tmp->handler == handler &&
348 tmp->eloop_data == eloop_data &&
349 tmp->user_data == user_data)
350 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700351 }
352
353 return 0;
354}
355
356
357/* TODO: replace with suitable signal handler */
358#if 0
359static void eloop_handle_signal(int sig)
360{
361 int i;
362
363 eloop.signaled++;
364 for (i = 0; i < eloop.signal_count; i++) {
365 if (eloop.signals[i].sig == sig) {
366 eloop.signals[i].signaled++;
367 break;
368 }
369 }
370}
371#endif
372
373
374static 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 eloop.pending_terminate = 0;
384 }
385
386 for (i = 0; i < eloop.signal_count; i++) {
387 if (eloop.signals[i].signaled) {
388 eloop.signals[i].signaled = 0;
389 eloop.signals[i].handler(eloop.signals[i].sig,
390 eloop.signals[i].user_data);
391 }
392 }
393
394 if (eloop.term_signal.signaled) {
395 eloop.term_signal.signaled = 0;
396 eloop.term_signal.handler(eloop.term_signal.sig,
397 eloop.term_signal.user_data);
398 }
399}
400
401
402int eloop_register_signal(int sig, eloop_signal_handler handler,
403 void *user_data)
404{
405 struct eloop_signal *tmp;
406
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700407 tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
408 sizeof(struct eloop_signal));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700409 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
419 /* TODO: register signal handler */
420
421 return 0;
422}
423
424
425#ifndef _WIN32_WCE
426static BOOL eloop_handle_console_ctrl(DWORD type)
427{
428 switch (type) {
429 case CTRL_C_EVENT:
430 case CTRL_BREAK_EVENT:
431 eloop.signaled++;
432 eloop.term_signal.signaled++;
433 SetEvent(eloop.term_event);
434 return TRUE;
435 default:
436 return FALSE;
437 }
438}
439#endif /* _WIN32_WCE */
440
441
442int eloop_register_signal_terminate(eloop_signal_handler handler,
443 void *user_data)
444{
445#ifndef _WIN32_WCE
446 if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) eloop_handle_console_ctrl,
447 TRUE) == 0) {
448 printf("SetConsoleCtrlHandler() failed: %d\n",
449 (int) GetLastError());
450 return -1;
451 }
452#endif /* _WIN32_WCE */
453
454 eloop.term_signal.handler = handler;
455 eloop.term_signal.user_data = user_data;
456
457 return 0;
458}
459
460
461int eloop_register_signal_reconfig(eloop_signal_handler handler,
462 void *user_data)
463{
464 /* TODO */
465 return 0;
466}
467
468
469void eloop_run(void)
470{
471 struct os_time tv, now;
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800472 DWORD count, ret, timeout_val, err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700473 size_t i;
474
475 while (!eloop.terminate &&
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800476 (!dl_list_empty(&eloop.timeout) || eloop.reader_count > 0 ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700477 eloop.event_count > 0)) {
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800478 struct eloop_timeout *timeout;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700479 tv.sec = tv.usec = 0;
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800480 timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
481 list);
482 if (timeout) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700483 os_get_time(&now);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800484 if (os_time_before(&now, &timeout->time))
485 os_time_sub(&timeout->time, &now, &tv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700486 }
487
488 count = 0;
489 for (i = 0; i < eloop.event_count; i++)
490 eloop.handles[count++] = eloop.events[i].event;
491
492 for (i = 0; i < eloop.reader_count; i++)
493 eloop.handles[count++] = eloop.readers[i].event;
494
495 if (eloop.term_event)
496 eloop.handles[count++] = eloop.term_event;
497
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800498 if (timeout)
499 timeout_val = tv.sec * 1000 + tv.usec / 1000;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700500 else
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800501 timeout_val = INFINITE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700502
503 if (count > MAXIMUM_WAIT_OBJECTS) {
504 printf("WaitForMultipleObjects: Too many events: "
505 "%d > %d (ignoring extra events)\n",
506 (int) count, MAXIMUM_WAIT_OBJECTS);
507 count = MAXIMUM_WAIT_OBJECTS;
508 }
509#ifdef _WIN32_WCE
510 ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800511 timeout_val);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700512#else /* _WIN32_WCE */
513 ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800514 timeout_val, TRUE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700515#endif /* _WIN32_WCE */
516 err = GetLastError();
517
518 eloop_process_pending_signals();
519
520 /* check if some registered timeouts have occurred */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800521 timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
522 list);
523 if (timeout) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700524 os_get_time(&now);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800525 if (!os_time_before(&now, &timeout->time)) {
526 void *eloop_data = timeout->eloop_data;
527 void *user_data = timeout->user_data;
528 eloop_timeout_handler handler =
529 timeout->handler;
530 eloop_remove_timeout(timeout);
531 handler(eloop_data, user_data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700532 }
533
534 }
535
536 if (ret == WAIT_FAILED) {
537 printf("WaitForMultipleObjects(count=%d) failed: %d\n",
538 (int) count, (int) err);
539 os_sleep(1, 0);
540 continue;
541 }
542
543#ifndef _WIN32_WCE
544 if (ret == WAIT_IO_COMPLETION)
545 continue;
546#endif /* _WIN32_WCE */
547
548 if (ret == WAIT_TIMEOUT)
549 continue;
550
551 while (ret >= WAIT_OBJECT_0 &&
552 ret < WAIT_OBJECT_0 + eloop.event_count) {
553 eloop.events[ret].handler(
554 eloop.events[ret].eloop_data,
555 eloop.events[ret].user_data);
556 ret = WaitForMultipleObjects(eloop.event_count,
557 eloop.handles, FALSE, 0);
558 }
559
560 eloop.reader_table_changed = 0;
561 for (i = 0; i < eloop.reader_count; i++) {
562 WSANETWORKEVENTS events;
563 if (WSAEnumNetworkEvents(eloop.readers[i].sock,
564 eloop.readers[i].event,
565 &events) == 0 &&
566 (events.lNetworkEvents & FD_READ)) {
567 eloop.readers[i].handler(
568 eloop.readers[i].sock,
569 eloop.readers[i].eloop_data,
570 eloop.readers[i].user_data);
571 if (eloop.reader_table_changed)
572 break;
573 }
574 }
575 }
576}
577
578
579void eloop_terminate(void)
580{
581 eloop.terminate = 1;
582 SetEvent(eloop.term_event);
583}
584
585
586void eloop_destroy(void)
587{
588 struct eloop_timeout *timeout, *prev;
589
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800590 dl_list_for_each_safe(timeout, prev, &eloop.timeout,
591 struct eloop_timeout, list) {
592 eloop_remove_timeout(timeout);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700593 }
594 os_free(eloop.readers);
595 os_free(eloop.signals);
596 if (eloop.term_event)
597 CloseHandle(eloop.term_event);
598 os_free(eloop.handles);
599 eloop.handles = NULL;
600 os_free(eloop.events);
601 eloop.events = NULL;
602}
603
604
605int eloop_terminated(void)
606{
607 return eloop.terminate;
608}
609
610
611void eloop_wait_for_read_sock(int sock)
612{
613 WSAEVENT event;
614
615 event = WSACreateEvent();
616 if (event == WSA_INVALID_EVENT) {
617 printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
618 return;
619 }
620
621 if (WSAEventSelect(sock, event, FD_READ)) {
622 printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
623 WSACloseEvent(event);
624 return ;
625 }
626
627 WaitForSingleObject(event, INFINITE);
628 WSAEventSelect(sock, event, 0);
629 WSACloseEvent(event);
630}