eloop_win.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
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
22struct eloop_sock {
23	int sock;
24	void *eloop_data;
25	void *user_data;
26	eloop_sock_handler handler;
27	WSAEVENT event;
28};
29
30struct eloop_event {
31	void *eloop_data;
32	void *user_data;
33	eloop_event_handler handler;
34	HANDLE event;
35};
36
37struct 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
45struct eloop_signal {
46	int sig;
47	void *user_data;
48	eloop_signal_handler handler;
49	int signaled;
50};
51
52struct 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
77static struct eloop_data eloop;
78
79
80int 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
101static 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
117int 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
160void 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
187int 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
216void 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
241int 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	os_time_t now_sec;
247
248	timeout = os_malloc(sizeof(*timeout));
249	if (timeout == NULL)
250		return -1;
251	os_get_time(&timeout->time);
252	now_sec = timeout->time.sec;
253	timeout->time.sec += secs;
254	if (timeout->time.sec < now_sec) {
255		/*
256		 * Integer overflow - assume long enough timeout to be assumed
257		 * to be infinite, i.e., the timeout would never happen.
258		 */
259		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
260			   "ever happen - ignore it", secs);
261		os_free(timeout);
262		return 0;
263	}
264	timeout->time.usec += usecs;
265	while (timeout->time.usec >= 1000000) {
266		timeout->time.sec++;
267		timeout->time.usec -= 1000000;
268	}
269	timeout->eloop_data = eloop_data;
270	timeout->user_data = user_data;
271	timeout->handler = handler;
272	timeout->next = NULL;
273
274	if (eloop.timeout == NULL) {
275		eloop.timeout = timeout;
276		return 0;
277	}
278
279	prev = NULL;
280	tmp = eloop.timeout;
281	while (tmp != NULL) {
282		if (os_time_before(&timeout->time, &tmp->time))
283			break;
284		prev = tmp;
285		tmp = tmp->next;
286	}
287
288	if (prev == NULL) {
289		timeout->next = eloop.timeout;
290		eloop.timeout = timeout;
291	} else {
292		timeout->next = prev->next;
293		prev->next = timeout;
294	}
295
296	return 0;
297}
298
299
300int eloop_cancel_timeout(eloop_timeout_handler handler,
301			 void *eloop_data, void *user_data)
302{
303	struct eloop_timeout *timeout, *prev, *next;
304	int removed = 0;
305
306	prev = NULL;
307	timeout = eloop.timeout;
308	while (timeout != NULL) {
309		next = timeout->next;
310
311		if (timeout->handler == handler &&
312		    (timeout->eloop_data == eloop_data ||
313		     eloop_data == ELOOP_ALL_CTX) &&
314		    (timeout->user_data == user_data ||
315		     user_data == ELOOP_ALL_CTX)) {
316			if (prev == NULL)
317				eloop.timeout = next;
318			else
319				prev->next = next;
320			os_free(timeout);
321			removed++;
322		} else
323			prev = timeout;
324
325		timeout = next;
326	}
327
328	return removed;
329}
330
331
332int eloop_is_timeout_registered(eloop_timeout_handler handler,
333				void *eloop_data, void *user_data)
334{
335	struct eloop_timeout *tmp;
336
337	tmp = eloop.timeout;
338	while (tmp != NULL) {
339		if (tmp->handler == handler &&
340		    tmp->eloop_data == eloop_data &&
341		    tmp->user_data == user_data)
342			return 1;
343
344		tmp = tmp->next;
345	}
346
347	return 0;
348}
349
350
351/* TODO: replace with suitable signal handler */
352#if 0
353static void eloop_handle_signal(int sig)
354{
355	int i;
356
357	eloop.signaled++;
358	for (i = 0; i < eloop.signal_count; i++) {
359		if (eloop.signals[i].sig == sig) {
360			eloop.signals[i].signaled++;
361			break;
362		}
363	}
364}
365#endif
366
367
368static void eloop_process_pending_signals(void)
369{
370	int i;
371
372	if (eloop.signaled == 0)
373		return;
374	eloop.signaled = 0;
375
376	if (eloop.pending_terminate) {
377		eloop.pending_terminate = 0;
378	}
379
380	for (i = 0; i < eloop.signal_count; i++) {
381		if (eloop.signals[i].signaled) {
382			eloop.signals[i].signaled = 0;
383			eloop.signals[i].handler(eloop.signals[i].sig,
384						 eloop.signals[i].user_data);
385		}
386	}
387
388	if (eloop.term_signal.signaled) {
389		eloop.term_signal.signaled = 0;
390		eloop.term_signal.handler(eloop.term_signal.sig,
391					  eloop.term_signal.user_data);
392	}
393}
394
395
396int eloop_register_signal(int sig, eloop_signal_handler handler,
397			  void *user_data)
398{
399	struct eloop_signal *tmp;
400
401	tmp = os_realloc(eloop.signals,
402			 (eloop.signal_count + 1) *
403			 sizeof(struct eloop_signal));
404	if (tmp == NULL)
405		return -1;
406
407	tmp[eloop.signal_count].sig = sig;
408	tmp[eloop.signal_count].user_data = user_data;
409	tmp[eloop.signal_count].handler = handler;
410	tmp[eloop.signal_count].signaled = 0;
411	eloop.signal_count++;
412	eloop.signals = tmp;
413
414	/* TODO: register signal handler */
415
416	return 0;
417}
418
419
420#ifndef _WIN32_WCE
421static BOOL eloop_handle_console_ctrl(DWORD type)
422{
423	switch (type) {
424	case CTRL_C_EVENT:
425	case CTRL_BREAK_EVENT:
426		eloop.signaled++;
427		eloop.term_signal.signaled++;
428		SetEvent(eloop.term_event);
429		return TRUE;
430	default:
431		return FALSE;
432	}
433}
434#endif /* _WIN32_WCE */
435
436
437int eloop_register_signal_terminate(eloop_signal_handler handler,
438				    void *user_data)
439{
440#ifndef _WIN32_WCE
441	if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) eloop_handle_console_ctrl,
442				  TRUE) == 0) {
443		printf("SetConsoleCtrlHandler() failed: %d\n",
444		       (int) GetLastError());
445		return -1;
446	}
447#endif /* _WIN32_WCE */
448
449	eloop.term_signal.handler = handler;
450	eloop.term_signal.user_data = user_data;
451
452	return 0;
453}
454
455
456int eloop_register_signal_reconfig(eloop_signal_handler handler,
457				   void *user_data)
458{
459	/* TODO */
460	return 0;
461}
462
463
464void eloop_run(void)
465{
466	struct os_time tv, now;
467	DWORD count, ret, timeout, err;
468	size_t i;
469
470	while (!eloop.terminate &&
471	       (eloop.timeout || eloop.reader_count > 0 ||
472		eloop.event_count > 0)) {
473		tv.sec = tv.usec = 0;
474		if (eloop.timeout) {
475			os_get_time(&now);
476			if (os_time_before(&now, &eloop.timeout->time))
477				os_time_sub(&eloop.timeout->time, &now, &tv);
478		}
479
480		count = 0;
481		for (i = 0; i < eloop.event_count; i++)
482			eloop.handles[count++] = eloop.events[i].event;
483
484		for (i = 0; i < eloop.reader_count; i++)
485			eloop.handles[count++] = eloop.readers[i].event;
486
487		if (eloop.term_event)
488			eloop.handles[count++] = eloop.term_event;
489
490		if (eloop.timeout)
491			timeout = tv.sec * 1000 + tv.usec / 1000;
492		else
493			timeout = INFINITE;
494
495		if (count > MAXIMUM_WAIT_OBJECTS) {
496			printf("WaitForMultipleObjects: Too many events: "
497			       "%d > %d (ignoring extra events)\n",
498			       (int) count, MAXIMUM_WAIT_OBJECTS);
499			count = MAXIMUM_WAIT_OBJECTS;
500		}
501#ifdef _WIN32_WCE
502		ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
503					     timeout);
504#else /* _WIN32_WCE */
505		ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
506					       timeout, TRUE);
507#endif /* _WIN32_WCE */
508		err = GetLastError();
509
510		eloop_process_pending_signals();
511
512		/* check if some registered timeouts have occurred */
513		if (eloop.timeout) {
514			struct eloop_timeout *tmp;
515
516			os_get_time(&now);
517			if (!os_time_before(&now, &eloop.timeout->time)) {
518				tmp = eloop.timeout;
519				eloop.timeout = eloop.timeout->next;
520				tmp->handler(tmp->eloop_data,
521					     tmp->user_data);
522				os_free(tmp);
523			}
524
525		}
526
527		if (ret == WAIT_FAILED) {
528			printf("WaitForMultipleObjects(count=%d) failed: %d\n",
529			       (int) count, (int) err);
530			os_sleep(1, 0);
531			continue;
532		}
533
534#ifndef _WIN32_WCE
535		if (ret == WAIT_IO_COMPLETION)
536			continue;
537#endif /* _WIN32_WCE */
538
539		if (ret == WAIT_TIMEOUT)
540			continue;
541
542		while (ret >= WAIT_OBJECT_0 &&
543		       ret < WAIT_OBJECT_0 + eloop.event_count) {
544			eloop.events[ret].handler(
545				eloop.events[ret].eloop_data,
546				eloop.events[ret].user_data);
547			ret = WaitForMultipleObjects(eloop.event_count,
548						     eloop.handles, FALSE, 0);
549		}
550
551		eloop.reader_table_changed = 0;
552		for (i = 0; i < eloop.reader_count; i++) {
553			WSANETWORKEVENTS events;
554			if (WSAEnumNetworkEvents(eloop.readers[i].sock,
555						 eloop.readers[i].event,
556						 &events) == 0 &&
557			    (events.lNetworkEvents & FD_READ)) {
558				eloop.readers[i].handler(
559					eloop.readers[i].sock,
560					eloop.readers[i].eloop_data,
561					eloop.readers[i].user_data);
562				if (eloop.reader_table_changed)
563					break;
564			}
565		}
566	}
567}
568
569
570void eloop_terminate(void)
571{
572	eloop.terminate = 1;
573	SetEvent(eloop.term_event);
574}
575
576
577void eloop_destroy(void)
578{
579	struct eloop_timeout *timeout, *prev;
580
581	timeout = eloop.timeout;
582	while (timeout != NULL) {
583		prev = timeout;
584		timeout = timeout->next;
585		os_free(prev);
586	}
587	os_free(eloop.readers);
588	os_free(eloop.signals);
589	if (eloop.term_event)
590		CloseHandle(eloop.term_event);
591	os_free(eloop.handles);
592	eloop.handles = NULL;
593	os_free(eloop.events);
594	eloop.events = NULL;
595}
596
597
598int eloop_terminated(void)
599{
600	return eloop.terminate;
601}
602
603
604void eloop_wait_for_read_sock(int sock)
605{
606	WSAEVENT event;
607
608	event = WSACreateEvent();
609	if (event == WSA_INVALID_EVENT) {
610		printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
611		return;
612	}
613
614	if (WSAEventSelect(sock, event, FD_READ)) {
615		printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
616		WSACloseEvent(event);
617		return ;
618	}
619
620	WaitForSingleObject(event, INFINITE);
621	WSAEventSelect(sock, event, 0);
622	WSACloseEvent(event);
623}
624