1 /* 2 * Event loop based on select() loop 3 * Copyright (c) 2002-2005, Jouni Malinen <j (at) 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 os_free(table->table); 173 } 174 175 176 int eloop_register_read_sock(int sock, eloop_sock_handler handler, 177 void *eloop_data, void *user_data) 178 { 179 return eloop_register_sock(sock, EVENT_TYPE_READ, handler, 180 eloop_data, user_data); 181 } 182 183 184 void eloop_unregister_read_sock(int sock) 185 { 186 eloop_unregister_sock(sock, EVENT_TYPE_READ); 187 } 188 189 190 static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type) 191 { 192 switch (type) { 193 case EVENT_TYPE_READ: 194 return &eloop.readers; 195 case EVENT_TYPE_WRITE: 196 return &eloop.writers; 197 case EVENT_TYPE_EXCEPTION: 198 return &eloop.exceptions; 199 } 200 201 return NULL; 202 } 203 204 205 int eloop_register_sock(int sock, eloop_event_type type, 206 eloop_sock_handler handler, 207 void *eloop_data, void *user_data) 208 { 209 struct eloop_sock_table *table; 210 211 table = eloop_get_sock_table(type); 212 return eloop_sock_table_add_sock(table, sock, handler, 213 eloop_data, user_data); 214 } 215 216 217 void eloop_unregister_sock(int sock, eloop_event_type type) 218 { 219 struct eloop_sock_table *table; 220 221 table = eloop_get_sock_table(type); 222 eloop_sock_table_remove_sock(table, sock); 223 } 224 225 226 int eloop_register_timeout(unsigned int secs, unsigned int usecs, 227 eloop_timeout_handler handler, 228 void *eloop_data, void *user_data) 229 { 230 struct eloop_timeout *timeout, *tmp, *prev; 231 232 timeout = os_malloc(sizeof(*timeout)); 233 if (timeout == NULL) 234 return -1; 235 if (os_get_time(&timeout->time) < 0) { 236 os_free(timeout); 237 return -1; 238 } 239 timeout->time.sec += secs; 240 timeout->time.usec += usecs; 241 while (timeout->time.usec >= 1000000) { 242 timeout->time.sec++; 243 timeout->time.usec -= 1000000; 244 } 245 timeout->eloop_data = eloop_data; 246 timeout->user_data = user_data; 247 timeout->handler = handler; 248 timeout->next = NULL; 249 250 if (eloop.timeout == NULL) { 251 eloop.timeout = timeout; 252 return 0; 253 } 254 255 prev = NULL; 256 tmp = eloop.timeout; 257 while (tmp != NULL) { 258 if (os_time_before(&timeout->time, &tmp->time)) 259 break; 260 prev = tmp; 261 tmp = tmp->next; 262 } 263 264 if (prev == NULL) { 265 timeout->next = eloop.timeout; 266 eloop.timeout = timeout; 267 } else { 268 timeout->next = prev->next; 269 prev->next = timeout; 270 } 271 272 return 0; 273 } 274 275 276 int eloop_cancel_timeout(eloop_timeout_handler handler, 277 void *eloop_data, void *user_data) 278 { 279 struct eloop_timeout *timeout, *prev, *next; 280 int removed = 0; 281 282 prev = NULL; 283 timeout = eloop.timeout; 284 while (timeout != NULL) { 285 next = timeout->next; 286 287 if (timeout->handler == handler && 288 (timeout->eloop_data == eloop_data || 289 eloop_data == ELOOP_ALL_CTX) && 290 (timeout->user_data == user_data || 291 user_data == ELOOP_ALL_CTX)) { 292 if (prev == NULL) 293 eloop.timeout = next; 294 else 295 prev->next = next; 296 os_free(timeout); 297 removed++; 298 } else 299 prev = timeout; 300 301 timeout = next; 302 } 303 304 return removed; 305 } 306 307 308 int eloop_is_timeout_registered(eloop_timeout_handler handler, 309 void *eloop_data, void *user_data) 310 { 311 struct eloop_timeout *tmp; 312 313 tmp = eloop.timeout; 314 while (tmp != NULL) { 315 if (tmp->handler == handler && 316 tmp->eloop_data == eloop_data && 317 tmp->user_data == user_data) 318 return 1; 319 320 tmp = tmp->next; 321 } 322 323 return 0; 324 } 325 326 327 #ifndef CONFIG_NATIVE_WINDOWS 328 static void eloop_handle_alarm(int sig) 329 { 330 fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two " 331 "seconds. Looks like there\n" 332 "is a bug that ends up in a busy loop that " 333 "prevents clean shutdown.\n" 334 "Killing program forcefully.\n"); 335 exit(1); 336 } 337 #endif /* CONFIG_NATIVE_WINDOWS */ 338 339 340 static void eloop_handle_signal(int sig) 341 { 342 int i; 343 344 #ifndef CONFIG_NATIVE_WINDOWS 345 if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { 346 /* Use SIGALRM to break out from potential busy loops that 347 * would not allow the program to be killed. */ 348 eloop.pending_terminate = 1; 349 signal(SIGALRM, eloop_handle_alarm); 350 alarm(2); 351 } 352 #endif /* CONFIG_NATIVE_WINDOWS */ 353 354 eloop.signaled++; 355 for (i = 0; i < eloop.signal_count; i++) { 356 if (eloop.signals[i].sig == sig) { 357 eloop.signals[i].signaled++; 358 break; 359 } 360 } 361 } 362 363 364 static void eloop_process_pending_signals(void) 365 { 366 int i; 367 368 if (eloop.signaled == 0) 369 return; 370 eloop.signaled = 0; 371 372 if (eloop.pending_terminate) { 373 #ifndef CONFIG_NATIVE_WINDOWS 374 alarm(0); 375 #endif /* CONFIG_NATIVE_WINDOWS */ 376 eloop.pending_terminate = 0; 377 } 378 379 for (i = 0; i < eloop.signal_count; i++) { 380 if (eloop.signals[i].signaled) { 381 eloop.signals[i].signaled = 0; 382 eloop.signals[i].handler(eloop.signals[i].sig, 383 eloop.user_data, 384 eloop.signals[i].user_data); 385 } 386 } 387 } 388 389 390 int eloop_register_signal(int sig, eloop_signal_handler handler, 391 void *user_data) 392 { 393 struct eloop_signal *tmp; 394 395 tmp = (struct eloop_signal *) 396 os_realloc(eloop.signals, 397 (eloop.signal_count + 1) * 398 sizeof(struct eloop_signal)); 399 if (tmp == NULL) 400 return -1; 401 402 tmp[eloop.signal_count].sig = sig; 403 tmp[eloop.signal_count].user_data = user_data; 404 tmp[eloop.signal_count].handler = handler; 405 tmp[eloop.signal_count].signaled = 0; 406 eloop.signal_count++; 407 eloop.signals = tmp; 408 signal(sig, eloop_handle_signal); 409 410 return 0; 411 } 412 413 414 int eloop_register_signal_terminate(eloop_signal_handler handler, 415 void *user_data) 416 { 417 int ret = eloop_register_signal(SIGINT, handler, user_data); 418 if (ret == 0) 419 ret = eloop_register_signal(SIGTERM, handler, user_data); 420 if (ret == 0) 421 ret = eloop_register_signal(SIGSEGV, handler, user_data); 422 return ret; 423 } 424 425 426 int eloop_register_signal_reconfig(eloop_signal_handler handler, 427 void *user_data) 428 { 429 #ifdef CONFIG_NATIVE_WINDOWS 430 return 0; 431 #else /* CONFIG_NATIVE_WINDOWS */ 432 return eloop_register_signal(SIGHUP, handler, user_data); 433 #endif /* CONFIG_NATIVE_WINDOWS */ 434 } 435 436 437 void eloop_run(void) 438 { 439 fd_set *rfds, *wfds, *efds; 440 int res; 441 struct timeval _tv; 442 struct os_time tv, now; 443 444 rfds = os_malloc(sizeof(*rfds)); 445 wfds = os_malloc(sizeof(*wfds)); 446 efds = os_malloc(sizeof(*efds)); 447 if (rfds == NULL || wfds == NULL || efds == NULL) { 448 printf("eloop_run - malloc failed\n"); 449 goto out; 450 } 451 452 while (!eloop.terminate && 453 (eloop.timeout || eloop.readers.count > 0 || 454 eloop.writers.count > 0 || eloop.exceptions.count > 0)) { 455 if (eloop.timeout) { 456 os_get_time(&now); 457 if (os_time_before(&now, &eloop.timeout->time)) 458 os_time_sub(&eloop.timeout->time, &now, &tv); 459 else 460 tv.sec = tv.usec = 0; 461 #if 0 462 printf("next timeout in %lu.%06lu sec\n", 463 tv.sec, tv.usec); 464 #endif 465 _tv.tv_sec = tv.sec; 466 _tv.tv_usec = tv.usec; 467 } 468 469 eloop_sock_table_set_fds(&eloop.readers, rfds); 470 eloop_sock_table_set_fds(&eloop.writers, wfds); 471 eloop_sock_table_set_fds(&eloop.exceptions, efds); 472 res = select(eloop.max_sock + 1, rfds, wfds, efds, 473 eloop.timeout ? &_tv : NULL); 474 if (res < 0 && errno != EINTR && errno != 0) { 475 perror("select"); 476 goto out; 477 } 478 eloop_process_pending_signals(); 479 480 /* check if some registered timeouts have occurred */ 481 if (eloop.timeout) { 482 struct eloop_timeout *tmp; 483 484 os_get_time(&now); 485 if (!os_time_before(&now, &eloop.timeout->time)) { 486 tmp = eloop.timeout; 487 eloop.timeout = eloop.timeout->next; 488 tmp->handler(tmp->eloop_data, 489 tmp->user_data); 490 os_free(tmp); 491 } 492 493 } 494 495 if (res <= 0) 496 continue; 497 498 eloop_sock_table_dispatch(&eloop.readers, rfds); 499 eloop_sock_table_dispatch(&eloop.writers, wfds); 500 eloop_sock_table_dispatch(&eloop.exceptions, efds); 501 } 502 503 out: 504 os_free(rfds); 505 os_free(wfds); 506 os_free(efds); 507 } 508 509 510 void eloop_terminate(void) 511 { 512 eloop.terminate = 1; 513 } 514 515 516 void eloop_destroy(void) 517 { 518 struct eloop_timeout *timeout, *prev; 519 520 timeout = eloop.timeout; 521 while (timeout != NULL) { 522 prev = timeout; 523 timeout = timeout->next; 524 os_free(prev); 525 } 526 eloop_sock_table_destroy(&eloop.readers); 527 eloop_sock_table_destroy(&eloop.writers); 528 eloop_sock_table_destroy(&eloop.exceptions); 529 os_free(eloop.signals); 530 } 531 532 533 int eloop_terminated(void) 534 { 535 return eloop.terminate; 536 } 537 538 539 void eloop_wait_for_read_sock(int sock) 540 { 541 fd_set rfds; 542 543 if (sock < 0) 544 return; 545 546 FD_ZERO(&rfds); 547 FD_SET(sock, &rfds); 548 select(sock + 1, &rfds, NULL, NULL, NULL); 549 } 550 551 552 void * eloop_get_user_data(void) 553 { 554 return eloop.user_data; 555 } 556