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