Home | History | Annotate | Download | only in utils
      1 /*
      2  * Event loop based on Windows events and WaitForMultipleObjects
      3  * Copyright (c) 2002-2009, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "includes.h"
     10 #include <winsock2.h>
     11 
     12 #include "common.h"
     13 #include "list.h"
     14 #include "eloop.h"
     15 
     16 
     17 struct eloop_sock {
     18 	int sock;
     19 	void *eloop_data;
     20 	void *user_data;
     21 	eloop_sock_handler handler;
     22 	WSAEVENT event;
     23 };
     24 
     25 struct eloop_event {
     26 	void *eloop_data;
     27 	void *user_data;
     28 	eloop_event_handler handler;
     29 	HANDLE event;
     30 };
     31 
     32 struct eloop_timeout {
     33 	struct dl_list list;
     34 	struct os_time time;
     35 	void *eloop_data;
     36 	void *user_data;
     37 	eloop_timeout_handler handler;
     38 };
     39 
     40 struct eloop_signal {
     41 	int sig;
     42 	void *user_data;
     43 	eloop_signal_handler handler;
     44 	int signaled;
     45 };
     46 
     47 struct 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 
     55 	struct dl_list timeout;
     56 
     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 
     72 static struct eloop_data eloop;
     73 
     74 
     75 int eloop_init(void)
     76 {
     77 	os_memset(&eloop, 0, sizeof(eloop));
     78 	dl_list_init(&eloop.timeout);
     79 	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 
     97 static 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;
    103 	n = os_realloc_array(eloop.handles, eloop.num_handles * 2,
    104 			     sizeof(eloop.handles[0]));
    105 	if (n == NULL)
    106 		return -1;
    107 	eloop.handles = n;
    108 	eloop.num_handles *= 2;
    109 	return 0;
    110 }
    111 
    112 
    113 int 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 	}
    133 	tmp = os_realloc_array(eloop.readers, eloop.reader_count + 1,
    134 			       sizeof(struct eloop_sock));
    135 	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 
    156 void 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 
    183 int 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 
    196 	tmp = os_realloc_array(eloop.events, eloop.event_count + 1,
    197 			       sizeof(struct eloop_event));
    198 	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 
    212 void 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 
    237 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
    238 			   eloop_timeout_handler handler,
    239 			   void *eloop_data, void *user_data)
    240 {
    241 	struct eloop_timeout *timeout, *tmp;
    242 	os_time_t now_sec;
    243 
    244 	timeout = os_zalloc(sizeof(*timeout));
    245 	if (timeout == NULL)
    246 		return -1;
    247 	if (os_get_time(&timeout->time) < 0) {
    248 		os_free(timeout);
    249 		return -1;
    250 	}
    251 	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;
    271 
    272 	/* 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 		}
    278 	}
    279 	dl_list_add_tail(&eloop.timeout, &timeout->list);
    280 
    281 	return 0;
    282 }
    283 
    284 
    285 static void eloop_remove_timeout(struct eloop_timeout *timeout)
    286 {
    287 	dl_list_del(&timeout->list);
    288 	os_free(timeout);
    289 }
    290 
    291 
    292 int eloop_cancel_timeout(eloop_timeout_handler handler,
    293 			 void *eloop_data, void *user_data)
    294 {
    295 	struct eloop_timeout *timeout, *prev;
    296 	int removed = 0;
    297 
    298 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
    299 			      struct eloop_timeout, list) {
    300 		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)) {
    305 			eloop_remove_timeout(timeout);
    306 			removed++;
    307 		}
    308 	}
    309 
    310 	return removed;
    311 }
    312 
    313 
    314 int 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 
    341 int eloop_is_timeout_registered(eloop_timeout_handler handler,
    342 				void *eloop_data, void *user_data)
    343 {
    344 	struct eloop_timeout *tmp;
    345 
    346 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
    347 		if (tmp->handler == handler &&
    348 		    tmp->eloop_data == eloop_data &&
    349 		    tmp->user_data == user_data)
    350 			return 1;
    351 	}
    352 
    353 	return 0;
    354 }
    355 
    356 
    357 /* TODO: replace with suitable signal handler */
    358 #if 0
    359 static 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 
    374 static 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 
    402 int eloop_register_signal(int sig, eloop_signal_handler handler,
    403 			  void *user_data)
    404 {
    405 	struct eloop_signal *tmp;
    406 
    407 	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
    408 			       sizeof(struct eloop_signal));
    409 	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
    426 static 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 
    442 int 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 
    461 int eloop_register_signal_reconfig(eloop_signal_handler handler,
    462 				   void *user_data)
    463 {
    464 	/* TODO */
    465 	return 0;
    466 }
    467 
    468 
    469 void eloop_run(void)
    470 {
    471 	struct os_time tv, now;
    472 	DWORD count, ret, timeout_val, err;
    473 	size_t i;
    474 
    475 	while (!eloop.terminate &&
    476 	       (!dl_list_empty(&eloop.timeout) || eloop.reader_count > 0 ||
    477 		eloop.event_count > 0)) {
    478 		struct eloop_timeout *timeout;
    479 		tv.sec = tv.usec = 0;
    480 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
    481 					list);
    482 		if (timeout) {
    483 			os_get_time(&now);
    484 			if (os_time_before(&now, &timeout->time))
    485 				os_time_sub(&timeout->time, &now, &tv);
    486 		}
    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 
    498 		if (timeout)
    499 			timeout_val = tv.sec * 1000 + tv.usec / 1000;
    500 		else
    501 			timeout_val = INFINITE;
    502 
    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,
    511 					     timeout_val);
    512 #else /* _WIN32_WCE */
    513 		ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
    514 					       timeout_val, TRUE);
    515 #endif /* _WIN32_WCE */
    516 		err = GetLastError();
    517 
    518 		eloop_process_pending_signals();
    519 
    520 		/* check if some registered timeouts have occurred */
    521 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
    522 					list);
    523 		if (timeout) {
    524 			os_get_time(&now);
    525 			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);
    532 			}
    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 
    579 void eloop_terminate(void)
    580 {
    581 	eloop.terminate = 1;
    582 	SetEvent(eloop.term_event);
    583 }
    584 
    585 
    586 void eloop_destroy(void)
    587 {
    588 	struct eloop_timeout *timeout, *prev;
    589 
    590 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
    591 			      struct eloop_timeout, list) {
    592 		eloop_remove_timeout(timeout);
    593 	}
    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 
    605 int eloop_terminated(void)
    606 {
    607 	return eloop.terminate;
    608 }
    609 
    610 
    611 void 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 }
    631