1 /* 2 * Event loop based on select() loop 3 * Copyright (c) 2002-2005, 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 17 #include "common.h" 18 #include "eloop.h" 19 20 21 struct eloop_sock { 22 int sock; 23 void *eloop_data; 24 void *user_data; 25 eloop_sock_handler handler; 26 }; 27 28 struct eloop_timeout { 29 struct os_time time; 30 void *eloop_data; 31 void *user_data; 32 eloop_timeout_handler handler; 33 struct eloop_timeout *next; 34 }; 35 36 struct eloop_signal { 37 int sig; 38 void *user_data; 39 eloop_signal_handler handler; 40 int signaled; 41 }; 42 43 struct eloop_sock_table { 44 int count; 45 struct eloop_sock *table; 46 int changed; 47 }; 48 49 struct eloop_data { 50 void *user_data; 51 52 int max_sock; 53 54 struct eloop_sock_table readers; 55 struct eloop_sock_table writers; 56 struct eloop_sock_table exceptions; 57 58 struct eloop_timeout *timeout; 59 60 int signal_count; 61 struct eloop_signal *signals; 62 int signaled; 63 int pending_terminate; 64 65 int terminate; 66 int reader_table_changed; 67 }; 68 69 static struct eloop_data eloop; 70 71 72 int eloop_init(void *user_data) 73 { 74 os_memset(&eloop, 0, sizeof(eloop)); 75 eloop.user_data = user_data; 76 return 0; 77 } 78 79 80 static int eloop_sock_table_add_sock(struct eloop_sock_table *table, 81 int sock, eloop_sock_handler handler, 82 void *eloop_data, void *user_data) 83 { 84 struct eloop_sock *tmp; 85 86 if (table == NULL) 87 return -1; 88 89 tmp = (struct eloop_sock *) 90 os_realloc(table->table, 91 (table->count + 1) * sizeof(struct eloop_sock)); 92 if (tmp == NULL) 93 return -1; 94 95 tmp[table->count].sock = sock; 96 tmp[table->count].eloop_data = eloop_data; 97 tmp[table->count].user_data = user_data; 98 tmp[table->count].handler = handler; 99 table->count++; 100 table->table = tmp; 101 if (sock > eloop.max_sock) 102 eloop.max_sock = sock; 103 table->changed = 1; 104 105 return 0; 106 } 107 108 109 static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, 110 int sock) 111 { 112 int i; 113 114 if (table == NULL || table->table == NULL || table->count == 0) 115 return; 116 117 for (i = 0; i < table->count; i++) { 118 if (table->table[i].sock == sock) 119 break; 120 } 121 if (i == table->count) 122 return; 123 if (i != table->count - 1) { 124 os_memmove(&table->table[i], &table->table[i + 1], 125 (table->count - i - 1) * 126 sizeof(struct eloop_sock)); 127 } 128 table->count--; 129 table->changed = 1; 130 } 131 132 133 static void eloop_sock_table_set_fds(struct eloop_sock_table *table, 134 fd_set *fds) 135 { 136 int i; 137 138 FD_ZERO(fds); 139 140 if (table->table == NULL) 141 return; 142 143 for (i = 0; i < table->count; i++) 144 FD_SET(table->table[i].sock, fds); 145 } 146 147 148 static void eloop_sock_table_dispatch(struct eloop_sock_table *table, 149 fd_set *fds) 150 { 151 int i; 152 153 if (table == NULL || table->table == NULL) 154 return; 155 156 table->changed = 0; 157 for (i = 0; i < table->count; i++) { 158 if (FD_ISSET(table->table[i].sock, fds)) { 159 table->table[i].handler(table->table[i].sock, 160 table->table[i].eloop_data, 161 table->table[i].user_data); 162 if (table->changed) 163 break; 164 } 165 } 166 } 167 168 169 static void eloop_sock_table_destroy(struct eloop_sock_table *table) 170 { 171 if (table) { 172 int i; 173 for (i = 0; i < table->count && table->table; i++) { 174 printf("ELOOP: remaining socket: sock=%d " 175 "eloop_data=%p user_data=%p handler=%p\n", 176 table->table[i].sock, 177 table->table[i].eloop_data, 178 table->table[i].user_data, 179 table->table[i].handler); 180 } 181 os_free(table->table); 182 } 183 } 184 185 186 int eloop_register_read_sock(int sock, eloop_sock_handler handler, 187 void *eloop_data, void *user_data) 188 { 189 return eloop_register_sock(sock, EVENT_TYPE_READ, handler, 190 eloop_data, user_data); 191 } 192 193 194 void eloop_unregister_read_sock(int sock) 195 { 196 eloop_unregister_sock(sock, EVENT_TYPE_READ); 197 } 198 199 200 static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type) 201 { 202 switch (type) { 203 case EVENT_TYPE_READ: 204 return &eloop.readers; 205 case EVENT_TYPE_WRITE: 206 return &eloop.writers; 207 case EVENT_TYPE_EXCEPTION: 208 return &eloop.exceptions; 209 } 210 211 return NULL; 212 } 213 214 215 int eloop_register_sock(int sock, eloop_event_type type, 216 eloop_sock_handler handler, 217 void *eloop_data, void *user_data) 218 { 219 struct eloop_sock_table *table; 220 221 table = eloop_get_sock_table(type); 222 return eloop_sock_table_add_sock(table, sock, handler, 223 eloop_data, user_data); 224 } 225 226 227 void eloop_unregister_sock(int sock, eloop_event_type type) 228 { 229 struct eloop_sock_table *table; 230 231 table = eloop_get_sock_table(type); 232 eloop_sock_table_remove_sock(table, sock); 233 } 234 235 236 int eloop_register_timeout(unsigned int secs, unsigned int usecs, 237 eloop_timeout_handler handler, 238 void *eloop_data, void *user_data) 239 { 240 struct eloop_timeout *timeout, *tmp, *prev; 241 242 timeout = os_malloc(sizeof(*timeout)); 243 if (timeout == NULL) 244 return -1; 245 if (os_get_time(&timeout->time) < 0) { 246 os_free(timeout); 247 return -1; 248 } 249 timeout->time.sec += secs; 250 timeout->time.usec += usecs; 251 while (timeout->time.usec >= 1000000) { 252 timeout->time.sec++; 253 timeout->time.usec -= 1000000; 254 } 255 timeout->eloop_data = eloop_data; 256 timeout->user_data = user_data; 257 timeout->handler = handler; 258 timeout->next = NULL; 259 260 if (eloop.timeout == NULL) { 261 eloop.timeout = timeout; 262 return 0; 263 } 264 265 prev = NULL; 266 tmp = eloop.timeout; 267 while (tmp != NULL) { 268 if (os_time_before(&timeout->time, &tmp->time)) 269 break; 270 prev = tmp; 271 tmp = tmp->next; 272 } 273 274 if (prev == NULL) { 275 timeout->next = eloop.timeout; 276 eloop.timeout = timeout; 277 } else { 278 timeout->next = prev->next; 279 prev->next = timeout; 280 } 281 282 return 0; 283 } 284 285 286 int eloop_cancel_timeout(eloop_timeout_handler handler, 287 void *eloop_data, void *user_data) 288 { 289 struct eloop_timeout *timeout, *prev, *next; 290 int removed = 0; 291 292 prev = NULL; 293 timeout = eloop.timeout; 294 while (timeout != NULL) { 295 next = timeout->next; 296 297 if (timeout->handler == handler && 298 (timeout->eloop_data == eloop_data || 299 eloop_data == ELOOP_ALL_CTX) && 300 (timeout->user_data == user_data || 301 user_data == ELOOP_ALL_CTX)) { 302 if (prev == NULL) 303 eloop.timeout = next; 304 else 305 prev->next = next; 306 os_free(timeout); 307 removed++; 308 } else 309 prev = timeout; 310 311 timeout = next; 312 } 313 314 return removed; 315 } 316 317 318 int eloop_is_timeout_registered(eloop_timeout_handler handler, 319 void *eloop_data, void *user_data) 320 { 321 struct eloop_timeout *tmp; 322 323 tmp = eloop.timeout; 324 while (tmp != NULL) { 325 if (tmp->handler == handler && 326 tmp->eloop_data == eloop_data && 327 tmp->user_data == user_data) 328 return 1; 329 330 tmp = tmp->next; 331 } 332 333 return 0; 334 } 335 336 337 #ifndef CONFIG_NATIVE_WINDOWS 338 static void eloop_handle_alarm(int sig) 339 { 340 fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two " 341 "seconds. Looks like there\n" 342 "is a bug that ends up in a busy loop that " 343 "prevents clean shutdown.\n" 344 "Killing program forcefully.\n"); 345 exit(1); 346 } 347 #endif /* CONFIG_NATIVE_WINDOWS */ 348 349 350 static void eloop_handle_signal(int sig) 351 { 352 int i; 353 354 #ifndef CONFIG_NATIVE_WINDOWS 355 if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { 356 /* Use SIGALRM to break out from potential busy loops that 357 * would not allow the program to be killed. */ 358 eloop.pending_terminate = 1; 359 signal(SIGALRM, eloop_handle_alarm); 360 alarm(2); 361 } 362 #endif /* CONFIG_NATIVE_WINDOWS */ 363 364 eloop.signaled++; 365 for (i = 0; i < eloop.signal_count; i++) { 366 if (eloop.signals[i].sig == sig) { 367 eloop.signals[i].signaled++; 368 break; 369 } 370 } 371 } 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 #ifndef CONFIG_NATIVE_WINDOWS 384 alarm(0); 385 #endif /* CONFIG_NATIVE_WINDOWS */ 386 eloop.pending_terminate = 0; 387 } 388 389 for (i = 0; i < eloop.signal_count; i++) { 390 if (eloop.signals[i].signaled) { 391 eloop.signals[i].signaled = 0; 392 eloop.signals[i].handler(eloop.signals[i].sig, 393 eloop.user_data, 394 eloop.signals[i].user_data); 395 } 396 } 397 } 398 399 400 int eloop_register_signal(int sig, eloop_signal_handler handler, 401 void *user_data) 402 { 403 struct eloop_signal *tmp; 404 405 tmp = (struct eloop_signal *) 406 os_realloc(eloop.signals, 407 (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 signal(sig, eloop_handle_signal); 419 420 return 0; 421 } 422 423 424 int eloop_register_signal_terminate(eloop_signal_handler handler, 425 void *user_data) 426 { 427 int ret = eloop_register_signal(SIGINT, handler, user_data); 428 if (ret == 0) 429 ret = eloop_register_signal(SIGTERM, handler, user_data); 430 return ret; 431 } 432 433 434 int eloop_register_signal_reconfig(eloop_signal_handler handler, 435 void *user_data) 436 { 437 #ifdef CONFIG_NATIVE_WINDOWS 438 return 0; 439 #else /* CONFIG_NATIVE_WINDOWS */ 440 return eloop_register_signal(SIGHUP, handler, user_data); 441 #endif /* CONFIG_NATIVE_WINDOWS */ 442 } 443 444 445 void eloop_run(void) 446 { 447 fd_set *rfds, *wfds, *efds; 448 int res; 449 struct timeval _tv; 450 struct os_time tv, now; 451 452 rfds = os_malloc(sizeof(*rfds)); 453 wfds = os_malloc(sizeof(*wfds)); 454 efds = os_malloc(sizeof(*efds)); 455 if (rfds == NULL || wfds == NULL || efds == NULL) { 456 printf("eloop_run - malloc failed\n"); 457 goto out; 458 } 459 460 while (!eloop.terminate && 461 (eloop.timeout || eloop.readers.count > 0 || 462 eloop.writers.count > 0 || eloop.exceptions.count > 0)) { 463 if (eloop.timeout) { 464 os_get_time(&now); 465 if (os_time_before(&now, &eloop.timeout->time)) 466 os_time_sub(&eloop.timeout->time, &now, &tv); 467 else 468 tv.sec = tv.usec = 0; 469 #if 0 470 printf("next timeout in %lu.%06lu sec\n", 471 tv.sec, tv.usec); 472 #endif 473 _tv.tv_sec = tv.sec; 474 _tv.tv_usec = tv.usec; 475 } 476 477 eloop_sock_table_set_fds(&eloop.readers, rfds); 478 eloop_sock_table_set_fds(&eloop.writers, wfds); 479 eloop_sock_table_set_fds(&eloop.exceptions, efds); 480 res = select(eloop.max_sock + 1, rfds, wfds, efds, 481 eloop.timeout ? &_tv : NULL); 482 if (res < 0 && errno != EINTR && errno != 0) { 483 perror("select"); 484 goto out; 485 } 486 eloop_process_pending_signals(); 487 488 /* check if some registered timeouts have occurred */ 489 if (eloop.timeout) { 490 struct eloop_timeout *tmp; 491 492 os_get_time(&now); 493 if (!os_time_before(&now, &eloop.timeout->time)) { 494 tmp = eloop.timeout; 495 eloop.timeout = eloop.timeout->next; 496 tmp->handler(tmp->eloop_data, 497 tmp->user_data); 498 os_free(tmp); 499 } 500 501 } 502 503 if (res <= 0) 504 continue; 505 506 eloop_sock_table_dispatch(&eloop.readers, rfds); 507 eloop_sock_table_dispatch(&eloop.writers, wfds); 508 eloop_sock_table_dispatch(&eloop.exceptions, efds); 509 } 510 511 out: 512 os_free(rfds); 513 os_free(wfds); 514 os_free(efds); 515 } 516 517 518 void eloop_terminate(void) 519 { 520 eloop.terminate = 1; 521 } 522 523 524 void eloop_destroy(void) 525 { 526 struct eloop_timeout *timeout, *prev; 527 struct os_time now; 528 529 timeout = eloop.timeout; 530 if (timeout) 531 os_get_time(&now); 532 while (timeout != NULL) { 533 int sec, usec; 534 prev = timeout; 535 timeout = timeout->next; 536 sec = prev->time.sec - now.sec; 537 usec = prev->time.usec - now.usec; 538 if (prev->time.usec < now.usec) { 539 sec--; 540 usec += 1000000; 541 } 542 printf("ELOOP: remaining timeout: %d.%06d eloop_data=%p " 543 "user_data=%p handler=%p\n", 544 sec, usec, prev->eloop_data, prev->user_data, 545 prev->handler); 546 os_free(prev); 547 } 548 eloop_sock_table_destroy(&eloop.readers); 549 eloop_sock_table_destroy(&eloop.writers); 550 eloop_sock_table_destroy(&eloop.exceptions); 551 os_free(eloop.signals); 552 } 553 554 555 int eloop_terminated(void) 556 { 557 return eloop.terminate; 558 } 559 560 561 void eloop_wait_for_read_sock(int sock) 562 { 563 fd_set rfds; 564 565 if (sock < 0) 566 return; 567 568 FD_ZERO(&rfds); 569 FD_SET(sock, &rfds); 570 select(sock + 1, &rfds, NULL, NULL, NULL); 571 } 572 573 574 void * eloop_get_user_data(void) 575 { 576 return eloop.user_data; 577 } 578