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 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 79static struct eloop_data eloop; 80 81 82int 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 104static 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 120int 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 163void 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 190int 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 219void 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 244int 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 291int 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 323int 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 344static 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 359static 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 389int 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 414static 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 430int 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 449int eloop_register_signal_reconfig(eloop_signal_handler handler, 450 void *user_data) 451{ 452 /* TODO */ 453 return 0; 454} 455 456 457int eloop_register_signal_reassociate(eloop_signal_handler handler, 458 void *user_data) 459{ 460 /* TODO */ 461 return 0; 462} 463 464 465void eloop_run(void) 466{ 467 struct os_time tv, now; 468 DWORD count, ret, timeout, err; 469 size_t i; 470 471 while (!eloop.terminate && 472 (eloop.timeout || eloop.reader_count > 0 || 473 eloop.event_count > 0)) { 474 tv.sec = tv.usec = 0; 475 if (eloop.timeout) { 476 os_get_time(&now); 477 if (os_time_before(&now, &eloop.timeout->time)) 478 os_time_sub(&eloop.timeout->time, &now, &tv); 479 } 480 481 count = 0; 482 for (i = 0; i < eloop.event_count; i++) 483 eloop.handles[count++] = eloop.events[i].event; 484 485 for (i = 0; i < eloop.reader_count; i++) 486 eloop.handles[count++] = eloop.readers[i].event; 487 488 if (eloop.term_event) 489 eloop.handles[count++] = eloop.term_event; 490 491 if (eloop.timeout) 492 timeout = tv.sec * 1000 + tv.usec / 1000; 493 else 494 timeout = INFINITE; 495 496 if (count > MAXIMUM_WAIT_OBJECTS) { 497 printf("WaitForMultipleObjects: Too many events: " 498 "%d > %d (ignoring extra events)\n", 499 (int) count, MAXIMUM_WAIT_OBJECTS); 500 count = MAXIMUM_WAIT_OBJECTS; 501 } 502#ifdef _WIN32_WCE 503 ret = WaitForMultipleObjects(count, eloop.handles, FALSE, 504 timeout); 505#else /* _WIN32_WCE */ 506 ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE, 507 timeout, TRUE); 508#endif /* _WIN32_WCE */ 509 err = GetLastError(); 510 511 eloop_process_pending_signals(); 512 513 /* check if some registered timeouts have occurred */ 514 if (eloop.timeout) { 515 struct eloop_timeout *tmp; 516 517 os_get_time(&now); 518 if (!os_time_before(&now, &eloop.timeout->time)) { 519 tmp = eloop.timeout; 520 eloop.timeout = eloop.timeout->next; 521 tmp->handler(tmp->eloop_data, 522 tmp->user_data); 523 os_free(tmp); 524 } 525 526 } 527 528 if (ret == WAIT_FAILED) { 529 printf("WaitForMultipleObjects(count=%d) failed: %d\n", 530 (int) count, (int) err); 531 os_sleep(1, 0); 532 continue; 533 } 534 535#ifndef _WIN32_WCE 536 if (ret == WAIT_IO_COMPLETION) 537 continue; 538#endif /* _WIN32_WCE */ 539 540 if (ret == WAIT_TIMEOUT) 541 continue; 542 543 while (ret >= WAIT_OBJECT_0 && 544 ret < WAIT_OBJECT_0 + eloop.event_count) { 545 eloop.events[ret].handler( 546 eloop.events[ret].eloop_data, 547 eloop.events[ret].user_data); 548 ret = WaitForMultipleObjects(eloop.event_count, 549 eloop.handles, FALSE, 0); 550 } 551 552 eloop.reader_table_changed = 0; 553 for (i = 0; i < eloop.reader_count; i++) { 554 WSANETWORKEVENTS events; 555 if (WSAEnumNetworkEvents(eloop.readers[i].sock, 556 eloop.readers[i].event, 557 &events) == 0 && 558 (events.lNetworkEvents & FD_READ)) { 559 eloop.readers[i].handler( 560 eloop.readers[i].sock, 561 eloop.readers[i].eloop_data, 562 eloop.readers[i].user_data); 563 if (eloop.reader_table_changed) 564 break; 565 } 566 } 567 } 568} 569 570 571void eloop_terminate(void) 572{ 573 eloop.terminate = 1; 574 SetEvent(eloop.term_event); 575} 576 577 578void eloop_destroy(void) 579{ 580 struct eloop_timeout *timeout, *prev; 581 582 timeout = eloop.timeout; 583 while (timeout != NULL) { 584 prev = timeout; 585 timeout = timeout->next; 586 os_free(prev); 587 } 588 os_free(eloop.readers); 589 os_free(eloop.signals); 590 if (eloop.term_event) 591 CloseHandle(eloop.term_event); 592 os_free(eloop.handles); 593 eloop.handles = NULL; 594 os_free(eloop.events); 595 eloop.events = NULL; 596} 597 598 599int eloop_terminated(void) 600{ 601 return eloop.terminate; 602} 603 604 605void eloop_wait_for_read_sock(int sock) 606{ 607 WSAEVENT event; 608 609 event = WSACreateEvent(); 610 if (event == WSA_INVALID_EVENT) { 611 printf("WSACreateEvent() failed: %d\n", WSAGetLastError()); 612 return; 613 } 614 615 if (WSAEventSelect(sock, event, FD_READ)) { 616 printf("WSAEventSelect() failed: %d\n", WSAGetLastError()); 617 WSACloseEvent(event); 618 return ; 619 } 620 621 WaitForSingleObject(event, INFINITE); 622 WSAEventSelect(sock, event, 0); 623 WSACloseEvent(event); 624} 625 626 627void * eloop_get_user_data(void) 628{ 629 return eloop.user_data; 630} 631