xref: /netbsd/external/bsd/wpa/dist/src/utils/eloop_win.c (revision 6550d01e)
1 /*
2  * Event loop based on Windows events and WaitForMultipleObjects
3  * Copyright (c) 2002-2006, 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 #include <winsock2.h>
17 
18 #include "common.h"
19 #include "eloop.h"
20 
21 
22 struct eloop_sock {
23 	int sock;
24 	void *eloop_data;
25 	void *user_data;
26 	eloop_sock_handler handler;
27 	WSAEVENT event;
28 };
29 
30 struct eloop_event {
31 	void *eloop_data;
32 	void *user_data;
33 	eloop_event_handler handler;
34 	HANDLE event;
35 };
36 
37 struct eloop_timeout {
38 	struct os_time time;
39 	void *eloop_data;
40 	void *user_data;
41 	eloop_timeout_handler handler;
42 	struct eloop_timeout *next;
43 };
44 
45 struct eloop_signal {
46 	int sig;
47 	void *user_data;
48 	eloop_signal_handler handler;
49 	int signaled;
50 };
51 
52 struct eloop_data {
53 	int max_sock;
54 	size_t reader_count;
55 	struct eloop_sock *readers;
56 
57 	size_t event_count;
58 	struct eloop_event *events;
59 
60 	struct eloop_timeout *timeout;
61 
62 	int signal_count;
63 	struct eloop_signal *signals;
64 	int signaled;
65 	int pending_terminate;
66 
67 	int terminate;
68 	int reader_table_changed;
69 
70 	struct eloop_signal term_signal;
71 	HANDLE term_event;
72 
73 	HANDLE *handles;
74 	size_t num_handles;
75 };
76 
77 static struct eloop_data eloop;
78 
79 
80 int eloop_init(void)
81 {
82 	os_memset(&eloop, 0, sizeof(eloop));
83 	eloop.num_handles = 1;
84 	eloop.handles = os_malloc(eloop.num_handles *
85 				  sizeof(eloop.handles[0]));
86 	if (eloop.handles == NULL)
87 		return -1;
88 
89 	eloop.term_event = CreateEvent(NULL, FALSE, FALSE, NULL);
90 	if (eloop.term_event == NULL) {
91 		printf("CreateEvent() failed: %d\n",
92 		       (int) GetLastError());
93 		os_free(eloop.handles);
94 		return -1;
95 	}
96 
97 	return 0;
98 }
99 
100 
101 static int eloop_prepare_handles(void)
102 {
103 	HANDLE *n;
104 
105 	if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8)
106 		return 0;
107 	n = os_realloc(eloop.handles,
108 		       eloop.num_handles * 2 * sizeof(eloop.handles[0]));
109 	if (n == NULL)
110 		return -1;
111 	eloop.handles = n;
112 	eloop.num_handles *= 2;
113 	return 0;
114 }
115 
116 
117 int eloop_register_read_sock(int sock, eloop_sock_handler handler,
118 			     void *eloop_data, void *user_data)
119 {
120 	WSAEVENT event;
121 	struct eloop_sock *tmp;
122 
123 	if (eloop_prepare_handles())
124 		return -1;
125 
126 	event = WSACreateEvent();
127 	if (event == WSA_INVALID_EVENT) {
128 		printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
129 		return -1;
130 	}
131 
132 	if (WSAEventSelect(sock, event, FD_READ)) {
133 		printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
134 		WSACloseEvent(event);
135 		return -1;
136 	}
137 	tmp = os_realloc(eloop.readers,
138 			 (eloop.reader_count + 1) * sizeof(struct eloop_sock));
139 	if (tmp == NULL) {
140 		WSAEventSelect(sock, event, 0);
141 		WSACloseEvent(event);
142 		return -1;
143 	}
144 
145 	tmp[eloop.reader_count].sock = sock;
146 	tmp[eloop.reader_count].eloop_data = eloop_data;
147 	tmp[eloop.reader_count].user_data = user_data;
148 	tmp[eloop.reader_count].handler = handler;
149 	tmp[eloop.reader_count].event = event;
150 	eloop.reader_count++;
151 	eloop.readers = tmp;
152 	if (sock > eloop.max_sock)
153 		eloop.max_sock = sock;
154 	eloop.reader_table_changed = 1;
155 
156 	return 0;
157 }
158 
159 
160 void eloop_unregister_read_sock(int sock)
161 {
162 	size_t i;
163 
164 	if (eloop.readers == NULL || eloop.reader_count == 0)
165 		return;
166 
167 	for (i = 0; i < eloop.reader_count; i++) {
168 		if (eloop.readers[i].sock == sock)
169 			break;
170 	}
171 	if (i == eloop.reader_count)
172 		return;
173 
174 	WSAEventSelect(eloop.readers[i].sock, eloop.readers[i].event, 0);
175 	WSACloseEvent(eloop.readers[i].event);
176 
177 	if (i != eloop.reader_count - 1) {
178 		os_memmove(&eloop.readers[i], &eloop.readers[i + 1],
179 			   (eloop.reader_count - i - 1) *
180 			   sizeof(struct eloop_sock));
181 	}
182 	eloop.reader_count--;
183 	eloop.reader_table_changed = 1;
184 }
185 
186 
187 int eloop_register_event(void *event, size_t event_size,
188 			 eloop_event_handler handler,
189 			 void *eloop_data, void *user_data)
190 {
191 	struct eloop_event *tmp;
192 	HANDLE h = event;
193 
194 	if (event_size != sizeof(HANDLE) || h == INVALID_HANDLE_VALUE)
195 		return -1;
196 
197 	if (eloop_prepare_handles())
198 		return -1;
199 
200 	tmp = os_realloc(eloop.events,
201 			 (eloop.event_count + 1) * sizeof(struct eloop_event));
202 	if (tmp == NULL)
203 		return -1;
204 
205 	tmp[eloop.event_count].eloop_data = eloop_data;
206 	tmp[eloop.event_count].user_data = user_data;
207 	tmp[eloop.event_count].handler = handler;
208 	tmp[eloop.event_count].event = h;
209 	eloop.event_count++;
210 	eloop.events = tmp;
211 
212 	return 0;
213 }
214 
215 
216 void eloop_unregister_event(void *event, size_t event_size)
217 {
218 	size_t i;
219 	HANDLE h = event;
220 
221 	if (eloop.events == NULL || eloop.event_count == 0 ||
222 	    event_size != sizeof(HANDLE))
223 		return;
224 
225 	for (i = 0; i < eloop.event_count; i++) {
226 		if (eloop.events[i].event == h)
227 			break;
228 	}
229 	if (i == eloop.event_count)
230 		return;
231 
232 	if (i != eloop.event_count - 1) {
233 		os_memmove(&eloop.events[i], &eloop.events[i + 1],
234 			   (eloop.event_count - i - 1) *
235 			   sizeof(struct eloop_event));
236 	}
237 	eloop.event_count--;
238 }
239 
240 
241 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
242 			   eloop_timeout_handler handler,
243 			   void *eloop_data, void *user_data)
244 {
245 	struct eloop_timeout *timeout, *tmp, *prev;
246 
247 	timeout = os_malloc(sizeof(*timeout));
248 	if (timeout == NULL)
249 		return -1;
250 	os_get_time(&timeout->time);
251 	timeout->time.sec += secs;
252 	timeout->time.usec += usecs;
253 	while (timeout->time.usec >= 1000000) {
254 		timeout->time.sec++;
255 		timeout->time.usec -= 1000000;
256 	}
257 	timeout->eloop_data = eloop_data;
258 	timeout->user_data = user_data;
259 	timeout->handler = handler;
260 	timeout->next = NULL;
261 
262 	if (eloop.timeout == NULL) {
263 		eloop.timeout = timeout;
264 		return 0;
265 	}
266 
267 	prev = NULL;
268 	tmp = eloop.timeout;
269 	while (tmp != NULL) {
270 		if (os_time_before(&timeout->time, &tmp->time))
271 			break;
272 		prev = tmp;
273 		tmp = tmp->next;
274 	}
275 
276 	if (prev == NULL) {
277 		timeout->next = eloop.timeout;
278 		eloop.timeout = timeout;
279 	} else {
280 		timeout->next = prev->next;
281 		prev->next = timeout;
282 	}
283 
284 	return 0;
285 }
286 
287 
288 int eloop_cancel_timeout(eloop_timeout_handler handler,
289 			 void *eloop_data, void *user_data)
290 {
291 	struct eloop_timeout *timeout, *prev, *next;
292 	int removed = 0;
293 
294 	prev = NULL;
295 	timeout = eloop.timeout;
296 	while (timeout != NULL) {
297 		next = timeout->next;
298 
299 		if (timeout->handler == handler &&
300 		    (timeout->eloop_data == eloop_data ||
301 		     eloop_data == ELOOP_ALL_CTX) &&
302 		    (timeout->user_data == user_data ||
303 		     user_data == ELOOP_ALL_CTX)) {
304 			if (prev == NULL)
305 				eloop.timeout = next;
306 			else
307 				prev->next = next;
308 			os_free(timeout);
309 			removed++;
310 		} else
311 			prev = timeout;
312 
313 		timeout = next;
314 	}
315 
316 	return removed;
317 }
318 
319 
320 int eloop_is_timeout_registered(eloop_timeout_handler handler,
321 				void *eloop_data, void *user_data)
322 {
323 	struct eloop_timeout *tmp;
324 
325 	tmp = eloop.timeout;
326 	while (tmp != NULL) {
327 		if (tmp->handler == handler &&
328 		    tmp->eloop_data == eloop_data &&
329 		    tmp->user_data == user_data)
330 			return 1;
331 
332 		tmp = tmp->next;
333 	}
334 
335 	return 0;
336 }
337 
338 
339 /* TODO: replace with suitable signal handler */
340 #if 0
341 static void eloop_handle_signal(int sig)
342 {
343 	int i;
344 
345 	eloop.signaled++;
346 	for (i = 0; i < eloop.signal_count; i++) {
347 		if (eloop.signals[i].sig == sig) {
348 			eloop.signals[i].signaled++;
349 			break;
350 		}
351 	}
352 }
353 #endif
354 
355 
356 static void eloop_process_pending_signals(void)
357 {
358 	int i;
359 
360 	if (eloop.signaled == 0)
361 		return;
362 	eloop.signaled = 0;
363 
364 	if (eloop.pending_terminate) {
365 		eloop.pending_terminate = 0;
366 	}
367 
368 	for (i = 0; i < eloop.signal_count; i++) {
369 		if (eloop.signals[i].signaled) {
370 			eloop.signals[i].signaled = 0;
371 			eloop.signals[i].handler(eloop.signals[i].sig,
372 						 eloop.signals[i].user_data);
373 		}
374 	}
375 
376 	if (eloop.term_signal.signaled) {
377 		eloop.term_signal.signaled = 0;
378 		eloop.term_signal.handler(eloop.term_signal.sig,
379 					  eloop.term_signal.user_data);
380 	}
381 }
382 
383 
384 int eloop_register_signal(int sig, eloop_signal_handler handler,
385 			  void *user_data)
386 {
387 	struct eloop_signal *tmp;
388 
389 	tmp = os_realloc(eloop.signals,
390 			 (eloop.signal_count + 1) *
391 			 sizeof(struct eloop_signal));
392 	if (tmp == NULL)
393 		return -1;
394 
395 	tmp[eloop.signal_count].sig = sig;
396 	tmp[eloop.signal_count].user_data = user_data;
397 	tmp[eloop.signal_count].handler = handler;
398 	tmp[eloop.signal_count].signaled = 0;
399 	eloop.signal_count++;
400 	eloop.signals = tmp;
401 
402 	/* TODO: register signal handler */
403 
404 	return 0;
405 }
406 
407 
408 #ifndef _WIN32_WCE
409 static BOOL eloop_handle_console_ctrl(DWORD type)
410 {
411 	switch (type) {
412 	case CTRL_C_EVENT:
413 	case CTRL_BREAK_EVENT:
414 		eloop.signaled++;
415 		eloop.term_signal.signaled++;
416 		SetEvent(eloop.term_event);
417 		return TRUE;
418 	default:
419 		return FALSE;
420 	}
421 }
422 #endif /* _WIN32_WCE */
423 
424 
425 int eloop_register_signal_terminate(eloop_signal_handler handler,
426 				    void *user_data)
427 {
428 #ifndef _WIN32_WCE
429 	if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) eloop_handle_console_ctrl,
430 				  TRUE) == 0) {
431 		printf("SetConsoleCtrlHandler() failed: %d\n",
432 		       (int) GetLastError());
433 		return -1;
434 	}
435 #endif /* _WIN32_WCE */
436 
437 	eloop.term_signal.handler = handler;
438 	eloop.term_signal.user_data = user_data;
439 
440 	return 0;
441 }
442 
443 
444 int eloop_register_signal_reconfig(eloop_signal_handler handler,
445 				   void *user_data)
446 {
447 	/* TODO */
448 	return 0;
449 }
450 
451 
452 void eloop_run(void)
453 {
454 	struct os_time tv, now;
455 	DWORD count, ret, timeout, err;
456 	size_t i;
457 
458 	while (!eloop.terminate &&
459 	       (eloop.timeout || eloop.reader_count > 0 ||
460 		eloop.event_count > 0)) {
461 		tv.sec = tv.usec = 0;
462 		if (eloop.timeout) {
463 			os_get_time(&now);
464 			if (os_time_before(&now, &eloop.timeout->time))
465 				os_time_sub(&eloop.timeout->time, &now, &tv);
466 		}
467 
468 		count = 0;
469 		for (i = 0; i < eloop.event_count; i++)
470 			eloop.handles[count++] = eloop.events[i].event;
471 
472 		for (i = 0; i < eloop.reader_count; i++)
473 			eloop.handles[count++] = eloop.readers[i].event;
474 
475 		if (eloop.term_event)
476 			eloop.handles[count++] = eloop.term_event;
477 
478 		if (eloop.timeout)
479 			timeout = tv.sec * 1000 + tv.usec / 1000;
480 		else
481 			timeout = INFINITE;
482 
483 		if (count > MAXIMUM_WAIT_OBJECTS) {
484 			printf("WaitForMultipleObjects: Too many events: "
485 			       "%d > %d (ignoring extra events)\n",
486 			       (int) count, MAXIMUM_WAIT_OBJECTS);
487 			count = MAXIMUM_WAIT_OBJECTS;
488 		}
489 #ifdef _WIN32_WCE
490 		ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
491 					     timeout);
492 #else /* _WIN32_WCE */
493 		ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
494 					       timeout, TRUE);
495 #endif /* _WIN32_WCE */
496 		err = GetLastError();
497 
498 		eloop_process_pending_signals();
499 
500 		/* check if some registered timeouts have occurred */
501 		if (eloop.timeout) {
502 			struct eloop_timeout *tmp;
503 
504 			os_get_time(&now);
505 			if (!os_time_before(&now, &eloop.timeout->time)) {
506 				tmp = eloop.timeout;
507 				eloop.timeout = eloop.timeout->next;
508 				tmp->handler(tmp->eloop_data,
509 					     tmp->user_data);
510 				os_free(tmp);
511 			}
512 
513 		}
514 
515 		if (ret == WAIT_FAILED) {
516 			printf("WaitForMultipleObjects(count=%d) failed: %d\n",
517 			       (int) count, (int) err);
518 			os_sleep(1, 0);
519 			continue;
520 		}
521 
522 #ifndef _WIN32_WCE
523 		if (ret == WAIT_IO_COMPLETION)
524 			continue;
525 #endif /* _WIN32_WCE */
526 
527 		if (ret == WAIT_TIMEOUT)
528 			continue;
529 
530 		while (ret >= WAIT_OBJECT_0 &&
531 		       ret < WAIT_OBJECT_0 + eloop.event_count) {
532 			eloop.events[ret].handler(
533 				eloop.events[ret].eloop_data,
534 				eloop.events[ret].user_data);
535 			ret = WaitForMultipleObjects(eloop.event_count,
536 						     eloop.handles, FALSE, 0);
537 		}
538 
539 		eloop.reader_table_changed = 0;
540 		for (i = 0; i < eloop.reader_count; i++) {
541 			WSANETWORKEVENTS events;
542 			if (WSAEnumNetworkEvents(eloop.readers[i].sock,
543 						 eloop.readers[i].event,
544 						 &events) == 0 &&
545 			    (events.lNetworkEvents & FD_READ)) {
546 				eloop.readers[i].handler(
547 					eloop.readers[i].sock,
548 					eloop.readers[i].eloop_data,
549 					eloop.readers[i].user_data);
550 				if (eloop.reader_table_changed)
551 					break;
552 			}
553 		}
554 	}
555 }
556 
557 
558 void eloop_terminate(void)
559 {
560 	eloop.terminate = 1;
561 	SetEvent(eloop.term_event);
562 }
563 
564 
565 void eloop_destroy(void)
566 {
567 	struct eloop_timeout *timeout, *prev;
568 
569 	timeout = eloop.timeout;
570 	while (timeout != NULL) {
571 		prev = timeout;
572 		timeout = timeout->next;
573 		os_free(prev);
574 	}
575 	os_free(eloop.readers);
576 	os_free(eloop.signals);
577 	if (eloop.term_event)
578 		CloseHandle(eloop.term_event);
579 	os_free(eloop.handles);
580 	eloop.handles = NULL;
581 	os_free(eloop.events);
582 	eloop.events = NULL;
583 }
584 
585 
586 int eloop_terminated(void)
587 {
588 	return eloop.terminate;
589 }
590 
591 
592 void eloop_wait_for_read_sock(int sock)
593 {
594 	WSAEVENT event;
595 
596 	event = WSACreateEvent();
597 	if (event == WSA_INVALID_EVENT) {
598 		printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
599 		return;
600 	}
601 
602 	if (WSAEventSelect(sock, event, FD_READ)) {
603 		printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
604 		WSACloseEvent(event);
605 		return ;
606 	}
607 
608 	WaitForSingleObject(event, INFINITE);
609 	WSAEventSelect(sock, event, 0);
610 	WSACloseEvent(event);
611 }
612