139beb93cSSam Leffler /* 239beb93cSSam Leffler * Event loop based on select() loop 3*e28a4053SRui Paulo * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 539beb93cSSam Leffler * This program is free software; you can redistribute it and/or modify 639beb93cSSam Leffler * it under the terms of the GNU General Public License version 2 as 739beb93cSSam Leffler * published by the Free Software Foundation. 839beb93cSSam Leffler * 939beb93cSSam Leffler * Alternatively, this software may be distributed under the terms of BSD 1039beb93cSSam Leffler * license. 1139beb93cSSam Leffler * 1239beb93cSSam Leffler * See README and COPYING for more details. 1339beb93cSSam Leffler */ 1439beb93cSSam Leffler 1539beb93cSSam Leffler #include "includes.h" 1639beb93cSSam Leffler 1739beb93cSSam Leffler #include "common.h" 18*e28a4053SRui Paulo #include "trace.h" 19*e28a4053SRui Paulo #include "list.h" 2039beb93cSSam Leffler #include "eloop.h" 2139beb93cSSam Leffler 2239beb93cSSam Leffler 2339beb93cSSam Leffler struct eloop_sock { 2439beb93cSSam Leffler int sock; 2539beb93cSSam Leffler void *eloop_data; 2639beb93cSSam Leffler void *user_data; 2739beb93cSSam Leffler eloop_sock_handler handler; 28*e28a4053SRui Paulo WPA_TRACE_REF(eloop); 29*e28a4053SRui Paulo WPA_TRACE_REF(user); 30*e28a4053SRui Paulo WPA_TRACE_INFO 3139beb93cSSam Leffler }; 3239beb93cSSam Leffler 3339beb93cSSam Leffler struct eloop_timeout { 34*e28a4053SRui Paulo struct dl_list list; 3539beb93cSSam Leffler struct os_time time; 3639beb93cSSam Leffler void *eloop_data; 3739beb93cSSam Leffler void *user_data; 3839beb93cSSam Leffler eloop_timeout_handler handler; 39*e28a4053SRui Paulo WPA_TRACE_REF(eloop); 40*e28a4053SRui Paulo WPA_TRACE_REF(user); 41*e28a4053SRui Paulo WPA_TRACE_INFO 4239beb93cSSam Leffler }; 4339beb93cSSam Leffler 4439beb93cSSam Leffler struct eloop_signal { 4539beb93cSSam Leffler int sig; 4639beb93cSSam Leffler void *user_data; 4739beb93cSSam Leffler eloop_signal_handler handler; 4839beb93cSSam Leffler int signaled; 4939beb93cSSam Leffler }; 5039beb93cSSam Leffler 5139beb93cSSam Leffler struct eloop_sock_table { 5239beb93cSSam Leffler int count; 5339beb93cSSam Leffler struct eloop_sock *table; 5439beb93cSSam Leffler int changed; 5539beb93cSSam Leffler }; 5639beb93cSSam Leffler 5739beb93cSSam Leffler struct eloop_data { 5839beb93cSSam Leffler int max_sock; 5939beb93cSSam Leffler 6039beb93cSSam Leffler struct eloop_sock_table readers; 6139beb93cSSam Leffler struct eloop_sock_table writers; 6239beb93cSSam Leffler struct eloop_sock_table exceptions; 6339beb93cSSam Leffler 64*e28a4053SRui Paulo struct dl_list timeout; 6539beb93cSSam Leffler 6639beb93cSSam Leffler int signal_count; 6739beb93cSSam Leffler struct eloop_signal *signals; 6839beb93cSSam Leffler int signaled; 6939beb93cSSam Leffler int pending_terminate; 7039beb93cSSam Leffler 7139beb93cSSam Leffler int terminate; 7239beb93cSSam Leffler int reader_table_changed; 7339beb93cSSam Leffler }; 7439beb93cSSam Leffler 7539beb93cSSam Leffler static struct eloop_data eloop; 7639beb93cSSam Leffler 7739beb93cSSam Leffler 78*e28a4053SRui Paulo #ifdef WPA_TRACE 79*e28a4053SRui Paulo 80*e28a4053SRui Paulo static void eloop_sigsegv_handler(int sig) 81*e28a4053SRui Paulo { 82*e28a4053SRui Paulo wpa_trace_show("eloop SIGSEGV"); 83*e28a4053SRui Paulo abort(); 84*e28a4053SRui Paulo } 85*e28a4053SRui Paulo 86*e28a4053SRui Paulo static void eloop_trace_sock_add_ref(struct eloop_sock_table *table) 87*e28a4053SRui Paulo { 88*e28a4053SRui Paulo int i; 89*e28a4053SRui Paulo if (table == NULL || table->table == NULL) 90*e28a4053SRui Paulo return; 91*e28a4053SRui Paulo for (i = 0; i < table->count; i++) { 92*e28a4053SRui Paulo wpa_trace_add_ref(&table->table[i], eloop, 93*e28a4053SRui Paulo table->table[i].eloop_data); 94*e28a4053SRui Paulo wpa_trace_add_ref(&table->table[i], user, 95*e28a4053SRui Paulo table->table[i].user_data); 96*e28a4053SRui Paulo } 97*e28a4053SRui Paulo } 98*e28a4053SRui Paulo 99*e28a4053SRui Paulo 100*e28a4053SRui Paulo static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table) 101*e28a4053SRui Paulo { 102*e28a4053SRui Paulo int i; 103*e28a4053SRui Paulo if (table == NULL || table->table == NULL) 104*e28a4053SRui Paulo return; 105*e28a4053SRui Paulo for (i = 0; i < table->count; i++) { 106*e28a4053SRui Paulo wpa_trace_remove_ref(&table->table[i], eloop, 107*e28a4053SRui Paulo table->table[i].eloop_data); 108*e28a4053SRui Paulo wpa_trace_remove_ref(&table->table[i], user, 109*e28a4053SRui Paulo table->table[i].user_data); 110*e28a4053SRui Paulo } 111*e28a4053SRui Paulo } 112*e28a4053SRui Paulo 113*e28a4053SRui Paulo #else /* WPA_TRACE */ 114*e28a4053SRui Paulo 115*e28a4053SRui Paulo #define eloop_trace_sock_add_ref(table) do { } while (0) 116*e28a4053SRui Paulo #define eloop_trace_sock_remove_ref(table) do { } while (0) 117*e28a4053SRui Paulo 118*e28a4053SRui Paulo #endif /* WPA_TRACE */ 119*e28a4053SRui Paulo 120*e28a4053SRui Paulo 121*e28a4053SRui Paulo int eloop_init(void) 12239beb93cSSam Leffler { 12339beb93cSSam Leffler os_memset(&eloop, 0, sizeof(eloop)); 124*e28a4053SRui Paulo dl_list_init(&eloop.timeout); 125*e28a4053SRui Paulo #ifdef WPA_TRACE 126*e28a4053SRui Paulo signal(SIGSEGV, eloop_sigsegv_handler); 127*e28a4053SRui Paulo #endif /* WPA_TRACE */ 12839beb93cSSam Leffler return 0; 12939beb93cSSam Leffler } 13039beb93cSSam Leffler 13139beb93cSSam Leffler 13239beb93cSSam Leffler static int eloop_sock_table_add_sock(struct eloop_sock_table *table, 13339beb93cSSam Leffler int sock, eloop_sock_handler handler, 13439beb93cSSam Leffler void *eloop_data, void *user_data) 13539beb93cSSam Leffler { 13639beb93cSSam Leffler struct eloop_sock *tmp; 13739beb93cSSam Leffler 13839beb93cSSam Leffler if (table == NULL) 13939beb93cSSam Leffler return -1; 14039beb93cSSam Leffler 141*e28a4053SRui Paulo eloop_trace_sock_remove_ref(table); 14239beb93cSSam Leffler tmp = (struct eloop_sock *) 14339beb93cSSam Leffler os_realloc(table->table, 14439beb93cSSam Leffler (table->count + 1) * sizeof(struct eloop_sock)); 14539beb93cSSam Leffler if (tmp == NULL) 14639beb93cSSam Leffler return -1; 14739beb93cSSam Leffler 14839beb93cSSam Leffler tmp[table->count].sock = sock; 14939beb93cSSam Leffler tmp[table->count].eloop_data = eloop_data; 15039beb93cSSam Leffler tmp[table->count].user_data = user_data; 15139beb93cSSam Leffler tmp[table->count].handler = handler; 152*e28a4053SRui Paulo wpa_trace_record(&tmp[table->count]); 15339beb93cSSam Leffler table->count++; 15439beb93cSSam Leffler table->table = tmp; 15539beb93cSSam Leffler if (sock > eloop.max_sock) 15639beb93cSSam Leffler eloop.max_sock = sock; 15739beb93cSSam Leffler table->changed = 1; 158*e28a4053SRui Paulo eloop_trace_sock_add_ref(table); 15939beb93cSSam Leffler 16039beb93cSSam Leffler return 0; 16139beb93cSSam Leffler } 16239beb93cSSam Leffler 16339beb93cSSam Leffler 16439beb93cSSam Leffler static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, 16539beb93cSSam Leffler int sock) 16639beb93cSSam Leffler { 16739beb93cSSam Leffler int i; 16839beb93cSSam Leffler 16939beb93cSSam Leffler if (table == NULL || table->table == NULL || table->count == 0) 17039beb93cSSam Leffler return; 17139beb93cSSam Leffler 17239beb93cSSam Leffler for (i = 0; i < table->count; i++) { 17339beb93cSSam Leffler if (table->table[i].sock == sock) 17439beb93cSSam Leffler break; 17539beb93cSSam Leffler } 17639beb93cSSam Leffler if (i == table->count) 17739beb93cSSam Leffler return; 178*e28a4053SRui Paulo eloop_trace_sock_remove_ref(table); 17939beb93cSSam Leffler if (i != table->count - 1) { 18039beb93cSSam Leffler os_memmove(&table->table[i], &table->table[i + 1], 18139beb93cSSam Leffler (table->count - i - 1) * 18239beb93cSSam Leffler sizeof(struct eloop_sock)); 18339beb93cSSam Leffler } 18439beb93cSSam Leffler table->count--; 18539beb93cSSam Leffler table->changed = 1; 186*e28a4053SRui Paulo eloop_trace_sock_add_ref(table); 18739beb93cSSam Leffler } 18839beb93cSSam Leffler 18939beb93cSSam Leffler 19039beb93cSSam Leffler static void eloop_sock_table_set_fds(struct eloop_sock_table *table, 19139beb93cSSam Leffler fd_set *fds) 19239beb93cSSam Leffler { 19339beb93cSSam Leffler int i; 19439beb93cSSam Leffler 19539beb93cSSam Leffler FD_ZERO(fds); 19639beb93cSSam Leffler 19739beb93cSSam Leffler if (table->table == NULL) 19839beb93cSSam Leffler return; 19939beb93cSSam Leffler 20039beb93cSSam Leffler for (i = 0; i < table->count; i++) 20139beb93cSSam Leffler FD_SET(table->table[i].sock, fds); 20239beb93cSSam Leffler } 20339beb93cSSam Leffler 20439beb93cSSam Leffler 20539beb93cSSam Leffler static void eloop_sock_table_dispatch(struct eloop_sock_table *table, 20639beb93cSSam Leffler fd_set *fds) 20739beb93cSSam Leffler { 20839beb93cSSam Leffler int i; 20939beb93cSSam Leffler 21039beb93cSSam Leffler if (table == NULL || table->table == NULL) 21139beb93cSSam Leffler return; 21239beb93cSSam Leffler 21339beb93cSSam Leffler table->changed = 0; 21439beb93cSSam Leffler for (i = 0; i < table->count; i++) { 21539beb93cSSam Leffler if (FD_ISSET(table->table[i].sock, fds)) { 21639beb93cSSam Leffler table->table[i].handler(table->table[i].sock, 21739beb93cSSam Leffler table->table[i].eloop_data, 21839beb93cSSam Leffler table->table[i].user_data); 21939beb93cSSam Leffler if (table->changed) 22039beb93cSSam Leffler break; 22139beb93cSSam Leffler } 22239beb93cSSam Leffler } 22339beb93cSSam Leffler } 22439beb93cSSam Leffler 22539beb93cSSam Leffler 22639beb93cSSam Leffler static void eloop_sock_table_destroy(struct eloop_sock_table *table) 22739beb93cSSam Leffler { 22839beb93cSSam Leffler if (table) { 22939beb93cSSam Leffler int i; 23039beb93cSSam Leffler for (i = 0; i < table->count && table->table; i++) { 231*e28a4053SRui Paulo wpa_printf(MSG_INFO, "ELOOP: remaining socket: " 232*e28a4053SRui Paulo "sock=%d eloop_data=%p user_data=%p " 233*e28a4053SRui Paulo "handler=%p", 23439beb93cSSam Leffler table->table[i].sock, 23539beb93cSSam Leffler table->table[i].eloop_data, 23639beb93cSSam Leffler table->table[i].user_data, 23739beb93cSSam Leffler table->table[i].handler); 238*e28a4053SRui Paulo wpa_trace_dump_funcname("eloop unregistered socket " 239*e28a4053SRui Paulo "handler", 240*e28a4053SRui Paulo table->table[i].handler); 241*e28a4053SRui Paulo wpa_trace_dump("eloop sock", &table->table[i]); 24239beb93cSSam Leffler } 24339beb93cSSam Leffler os_free(table->table); 24439beb93cSSam Leffler } 24539beb93cSSam Leffler } 24639beb93cSSam Leffler 24739beb93cSSam Leffler 24839beb93cSSam Leffler int eloop_register_read_sock(int sock, eloop_sock_handler handler, 24939beb93cSSam Leffler void *eloop_data, void *user_data) 25039beb93cSSam Leffler { 25139beb93cSSam Leffler return eloop_register_sock(sock, EVENT_TYPE_READ, handler, 25239beb93cSSam Leffler eloop_data, user_data); 25339beb93cSSam Leffler } 25439beb93cSSam Leffler 25539beb93cSSam Leffler 25639beb93cSSam Leffler void eloop_unregister_read_sock(int sock) 25739beb93cSSam Leffler { 25839beb93cSSam Leffler eloop_unregister_sock(sock, EVENT_TYPE_READ); 25939beb93cSSam Leffler } 26039beb93cSSam Leffler 26139beb93cSSam Leffler 26239beb93cSSam Leffler static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type) 26339beb93cSSam Leffler { 26439beb93cSSam Leffler switch (type) { 26539beb93cSSam Leffler case EVENT_TYPE_READ: 26639beb93cSSam Leffler return &eloop.readers; 26739beb93cSSam Leffler case EVENT_TYPE_WRITE: 26839beb93cSSam Leffler return &eloop.writers; 26939beb93cSSam Leffler case EVENT_TYPE_EXCEPTION: 27039beb93cSSam Leffler return &eloop.exceptions; 27139beb93cSSam Leffler } 27239beb93cSSam Leffler 27339beb93cSSam Leffler return NULL; 27439beb93cSSam Leffler } 27539beb93cSSam Leffler 27639beb93cSSam Leffler 27739beb93cSSam Leffler int eloop_register_sock(int sock, eloop_event_type type, 27839beb93cSSam Leffler eloop_sock_handler handler, 27939beb93cSSam Leffler void *eloop_data, void *user_data) 28039beb93cSSam Leffler { 28139beb93cSSam Leffler struct eloop_sock_table *table; 28239beb93cSSam Leffler 28339beb93cSSam Leffler table = eloop_get_sock_table(type); 28439beb93cSSam Leffler return eloop_sock_table_add_sock(table, sock, handler, 28539beb93cSSam Leffler eloop_data, user_data); 28639beb93cSSam Leffler } 28739beb93cSSam Leffler 28839beb93cSSam Leffler 28939beb93cSSam Leffler void eloop_unregister_sock(int sock, eloop_event_type type) 29039beb93cSSam Leffler { 29139beb93cSSam Leffler struct eloop_sock_table *table; 29239beb93cSSam Leffler 29339beb93cSSam Leffler table = eloop_get_sock_table(type); 29439beb93cSSam Leffler eloop_sock_table_remove_sock(table, sock); 29539beb93cSSam Leffler } 29639beb93cSSam Leffler 29739beb93cSSam Leffler 29839beb93cSSam Leffler int eloop_register_timeout(unsigned int secs, unsigned int usecs, 29939beb93cSSam Leffler eloop_timeout_handler handler, 30039beb93cSSam Leffler void *eloop_data, void *user_data) 30139beb93cSSam Leffler { 302*e28a4053SRui Paulo struct eloop_timeout *timeout, *tmp; 30339beb93cSSam Leffler 304*e28a4053SRui Paulo timeout = os_zalloc(sizeof(*timeout)); 30539beb93cSSam Leffler if (timeout == NULL) 30639beb93cSSam Leffler return -1; 30739beb93cSSam Leffler if (os_get_time(&timeout->time) < 0) { 30839beb93cSSam Leffler os_free(timeout); 30939beb93cSSam Leffler return -1; 31039beb93cSSam Leffler } 31139beb93cSSam Leffler timeout->time.sec += secs; 31239beb93cSSam Leffler timeout->time.usec += usecs; 31339beb93cSSam Leffler while (timeout->time.usec >= 1000000) { 31439beb93cSSam Leffler timeout->time.sec++; 31539beb93cSSam Leffler timeout->time.usec -= 1000000; 31639beb93cSSam Leffler } 31739beb93cSSam Leffler timeout->eloop_data = eloop_data; 31839beb93cSSam Leffler timeout->user_data = user_data; 31939beb93cSSam Leffler timeout->handler = handler; 320*e28a4053SRui Paulo wpa_trace_add_ref(timeout, eloop, eloop_data); 321*e28a4053SRui Paulo wpa_trace_add_ref(timeout, user, user_data); 322*e28a4053SRui Paulo wpa_trace_record(timeout); 32339beb93cSSam Leffler 324*e28a4053SRui Paulo /* Maintain timeouts in order of increasing time */ 325*e28a4053SRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 326*e28a4053SRui Paulo if (os_time_before(&timeout->time, &tmp->time)) { 327*e28a4053SRui Paulo dl_list_add(tmp->list.prev, &timeout->list); 328*e28a4053SRui Paulo return 0; 329*e28a4053SRui Paulo } 330*e28a4053SRui Paulo } 331*e28a4053SRui Paulo dl_list_add_tail(&eloop.timeout, &timeout->list); 332*e28a4053SRui Paulo 33339beb93cSSam Leffler return 0; 33439beb93cSSam Leffler } 33539beb93cSSam Leffler 33639beb93cSSam Leffler 337*e28a4053SRui Paulo static void eloop_remove_timeout(struct eloop_timeout *timeout) 338*e28a4053SRui Paulo { 339*e28a4053SRui Paulo dl_list_del(&timeout->list); 340*e28a4053SRui Paulo wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data); 341*e28a4053SRui Paulo wpa_trace_remove_ref(timeout, user, timeout->user_data); 342*e28a4053SRui Paulo os_free(timeout); 34339beb93cSSam Leffler } 34439beb93cSSam Leffler 34539beb93cSSam Leffler 34639beb93cSSam Leffler int eloop_cancel_timeout(eloop_timeout_handler handler, 34739beb93cSSam Leffler void *eloop_data, void *user_data) 34839beb93cSSam Leffler { 349*e28a4053SRui Paulo struct eloop_timeout *timeout, *prev; 35039beb93cSSam Leffler int removed = 0; 35139beb93cSSam Leffler 352*e28a4053SRui Paulo dl_list_for_each_safe(timeout, prev, &eloop.timeout, 353*e28a4053SRui Paulo struct eloop_timeout, list) { 35439beb93cSSam Leffler if (timeout->handler == handler && 35539beb93cSSam Leffler (timeout->eloop_data == eloop_data || 35639beb93cSSam Leffler eloop_data == ELOOP_ALL_CTX) && 35739beb93cSSam Leffler (timeout->user_data == user_data || 35839beb93cSSam Leffler user_data == ELOOP_ALL_CTX)) { 359*e28a4053SRui Paulo eloop_remove_timeout(timeout); 36039beb93cSSam Leffler removed++; 361*e28a4053SRui Paulo } 36239beb93cSSam Leffler } 36339beb93cSSam Leffler 36439beb93cSSam Leffler return removed; 36539beb93cSSam Leffler } 36639beb93cSSam Leffler 36739beb93cSSam Leffler 36839beb93cSSam Leffler int eloop_is_timeout_registered(eloop_timeout_handler handler, 36939beb93cSSam Leffler void *eloop_data, void *user_data) 37039beb93cSSam Leffler { 37139beb93cSSam Leffler struct eloop_timeout *tmp; 37239beb93cSSam Leffler 373*e28a4053SRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 37439beb93cSSam Leffler if (tmp->handler == handler && 37539beb93cSSam Leffler tmp->eloop_data == eloop_data && 37639beb93cSSam Leffler tmp->user_data == user_data) 37739beb93cSSam Leffler return 1; 37839beb93cSSam Leffler } 37939beb93cSSam Leffler 38039beb93cSSam Leffler return 0; 38139beb93cSSam Leffler } 38239beb93cSSam Leffler 38339beb93cSSam Leffler 38439beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS 38539beb93cSSam Leffler static void eloop_handle_alarm(int sig) 38639beb93cSSam Leffler { 387*e28a4053SRui Paulo wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in " 388*e28a4053SRui Paulo "two seconds. Looks like there\n" 38939beb93cSSam Leffler "is a bug that ends up in a busy loop that " 39039beb93cSSam Leffler "prevents clean shutdown.\n" 39139beb93cSSam Leffler "Killing program forcefully.\n"); 39239beb93cSSam Leffler exit(1); 39339beb93cSSam Leffler } 39439beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */ 39539beb93cSSam Leffler 39639beb93cSSam Leffler 39739beb93cSSam Leffler static void eloop_handle_signal(int sig) 39839beb93cSSam Leffler { 39939beb93cSSam Leffler int i; 40039beb93cSSam Leffler 40139beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS 40239beb93cSSam Leffler if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { 40339beb93cSSam Leffler /* Use SIGALRM to break out from potential busy loops that 40439beb93cSSam Leffler * would not allow the program to be killed. */ 40539beb93cSSam Leffler eloop.pending_terminate = 1; 40639beb93cSSam Leffler signal(SIGALRM, eloop_handle_alarm); 40739beb93cSSam Leffler alarm(2); 40839beb93cSSam Leffler } 40939beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */ 41039beb93cSSam Leffler 41139beb93cSSam Leffler eloop.signaled++; 41239beb93cSSam Leffler for (i = 0; i < eloop.signal_count; i++) { 41339beb93cSSam Leffler if (eloop.signals[i].sig == sig) { 41439beb93cSSam Leffler eloop.signals[i].signaled++; 41539beb93cSSam Leffler break; 41639beb93cSSam Leffler } 41739beb93cSSam Leffler } 41839beb93cSSam Leffler } 41939beb93cSSam Leffler 42039beb93cSSam Leffler 42139beb93cSSam Leffler static void eloop_process_pending_signals(void) 42239beb93cSSam Leffler { 42339beb93cSSam Leffler int i; 42439beb93cSSam Leffler 42539beb93cSSam Leffler if (eloop.signaled == 0) 42639beb93cSSam Leffler return; 42739beb93cSSam Leffler eloop.signaled = 0; 42839beb93cSSam Leffler 42939beb93cSSam Leffler if (eloop.pending_terminate) { 43039beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS 43139beb93cSSam Leffler alarm(0); 43239beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */ 43339beb93cSSam Leffler eloop.pending_terminate = 0; 43439beb93cSSam Leffler } 43539beb93cSSam Leffler 43639beb93cSSam Leffler for (i = 0; i < eloop.signal_count; i++) { 43739beb93cSSam Leffler if (eloop.signals[i].signaled) { 43839beb93cSSam Leffler eloop.signals[i].signaled = 0; 43939beb93cSSam Leffler eloop.signals[i].handler(eloop.signals[i].sig, 44039beb93cSSam Leffler eloop.signals[i].user_data); 44139beb93cSSam Leffler } 44239beb93cSSam Leffler } 44339beb93cSSam Leffler } 44439beb93cSSam Leffler 44539beb93cSSam Leffler 44639beb93cSSam Leffler int eloop_register_signal(int sig, eloop_signal_handler handler, 44739beb93cSSam Leffler void *user_data) 44839beb93cSSam Leffler { 44939beb93cSSam Leffler struct eloop_signal *tmp; 45039beb93cSSam Leffler 45139beb93cSSam Leffler tmp = (struct eloop_signal *) 45239beb93cSSam Leffler os_realloc(eloop.signals, 45339beb93cSSam Leffler (eloop.signal_count + 1) * 45439beb93cSSam Leffler sizeof(struct eloop_signal)); 45539beb93cSSam Leffler if (tmp == NULL) 45639beb93cSSam Leffler return -1; 45739beb93cSSam Leffler 45839beb93cSSam Leffler tmp[eloop.signal_count].sig = sig; 45939beb93cSSam Leffler tmp[eloop.signal_count].user_data = user_data; 46039beb93cSSam Leffler tmp[eloop.signal_count].handler = handler; 46139beb93cSSam Leffler tmp[eloop.signal_count].signaled = 0; 46239beb93cSSam Leffler eloop.signal_count++; 46339beb93cSSam Leffler eloop.signals = tmp; 46439beb93cSSam Leffler signal(sig, eloop_handle_signal); 46539beb93cSSam Leffler 46639beb93cSSam Leffler return 0; 46739beb93cSSam Leffler } 46839beb93cSSam Leffler 46939beb93cSSam Leffler 47039beb93cSSam Leffler int eloop_register_signal_terminate(eloop_signal_handler handler, 47139beb93cSSam Leffler void *user_data) 47239beb93cSSam Leffler { 47339beb93cSSam Leffler int ret = eloop_register_signal(SIGINT, handler, user_data); 47439beb93cSSam Leffler if (ret == 0) 47539beb93cSSam Leffler ret = eloop_register_signal(SIGTERM, handler, user_data); 47639beb93cSSam Leffler return ret; 47739beb93cSSam Leffler } 47839beb93cSSam Leffler 47939beb93cSSam Leffler 48039beb93cSSam Leffler int eloop_register_signal_reconfig(eloop_signal_handler handler, 48139beb93cSSam Leffler void *user_data) 48239beb93cSSam Leffler { 48339beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS 48439beb93cSSam Leffler return 0; 48539beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */ 48639beb93cSSam Leffler return eloop_register_signal(SIGHUP, handler, user_data); 48739beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */ 48839beb93cSSam Leffler } 48939beb93cSSam Leffler 49039beb93cSSam Leffler 49139beb93cSSam Leffler void eloop_run(void) 49239beb93cSSam Leffler { 49339beb93cSSam Leffler fd_set *rfds, *wfds, *efds; 49439beb93cSSam Leffler int res; 49539beb93cSSam Leffler struct timeval _tv; 49639beb93cSSam Leffler struct os_time tv, now; 49739beb93cSSam Leffler 49839beb93cSSam Leffler rfds = os_malloc(sizeof(*rfds)); 49939beb93cSSam Leffler wfds = os_malloc(sizeof(*wfds)); 50039beb93cSSam Leffler efds = os_malloc(sizeof(*efds)); 501*e28a4053SRui Paulo if (rfds == NULL || wfds == NULL || efds == NULL) 50239beb93cSSam Leffler goto out; 50339beb93cSSam Leffler 50439beb93cSSam Leffler while (!eloop.terminate && 505*e28a4053SRui Paulo (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || 50639beb93cSSam Leffler eloop.writers.count > 0 || eloop.exceptions.count > 0)) { 507*e28a4053SRui Paulo struct eloop_timeout *timeout; 508*e28a4053SRui Paulo timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, 509*e28a4053SRui Paulo list); 510*e28a4053SRui Paulo if (timeout) { 51139beb93cSSam Leffler os_get_time(&now); 512*e28a4053SRui Paulo if (os_time_before(&now, &timeout->time)) 513*e28a4053SRui Paulo os_time_sub(&timeout->time, &now, &tv); 51439beb93cSSam Leffler else 51539beb93cSSam Leffler tv.sec = tv.usec = 0; 51639beb93cSSam Leffler _tv.tv_sec = tv.sec; 51739beb93cSSam Leffler _tv.tv_usec = tv.usec; 51839beb93cSSam Leffler } 51939beb93cSSam Leffler 52039beb93cSSam Leffler eloop_sock_table_set_fds(&eloop.readers, rfds); 52139beb93cSSam Leffler eloop_sock_table_set_fds(&eloop.writers, wfds); 52239beb93cSSam Leffler eloop_sock_table_set_fds(&eloop.exceptions, efds); 52339beb93cSSam Leffler res = select(eloop.max_sock + 1, rfds, wfds, efds, 524*e28a4053SRui Paulo timeout ? &_tv : NULL); 52539beb93cSSam Leffler if (res < 0 && errno != EINTR && errno != 0) { 52639beb93cSSam Leffler perror("select"); 52739beb93cSSam Leffler goto out; 52839beb93cSSam Leffler } 52939beb93cSSam Leffler eloop_process_pending_signals(); 53039beb93cSSam Leffler 53139beb93cSSam Leffler /* check if some registered timeouts have occurred */ 532*e28a4053SRui Paulo timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, 533*e28a4053SRui Paulo list); 534*e28a4053SRui Paulo if (timeout) { 53539beb93cSSam Leffler os_get_time(&now); 536*e28a4053SRui Paulo if (!os_time_before(&now, &timeout->time)) { 537*e28a4053SRui Paulo void *eloop_data = timeout->eloop_data; 538*e28a4053SRui Paulo void *user_data = timeout->user_data; 539*e28a4053SRui Paulo eloop_timeout_handler handler = 540*e28a4053SRui Paulo timeout->handler; 541*e28a4053SRui Paulo eloop_remove_timeout(timeout); 542*e28a4053SRui Paulo handler(eloop_data, user_data); 54339beb93cSSam Leffler } 54439beb93cSSam Leffler 54539beb93cSSam Leffler } 54639beb93cSSam Leffler 54739beb93cSSam Leffler if (res <= 0) 54839beb93cSSam Leffler continue; 54939beb93cSSam Leffler 55039beb93cSSam Leffler eloop_sock_table_dispatch(&eloop.readers, rfds); 55139beb93cSSam Leffler eloop_sock_table_dispatch(&eloop.writers, wfds); 55239beb93cSSam Leffler eloop_sock_table_dispatch(&eloop.exceptions, efds); 55339beb93cSSam Leffler } 55439beb93cSSam Leffler 55539beb93cSSam Leffler out: 55639beb93cSSam Leffler os_free(rfds); 55739beb93cSSam Leffler os_free(wfds); 55839beb93cSSam Leffler os_free(efds); 55939beb93cSSam Leffler } 56039beb93cSSam Leffler 56139beb93cSSam Leffler 56239beb93cSSam Leffler void eloop_terminate(void) 56339beb93cSSam Leffler { 56439beb93cSSam Leffler eloop.terminate = 1; 56539beb93cSSam Leffler } 56639beb93cSSam Leffler 56739beb93cSSam Leffler 56839beb93cSSam Leffler void eloop_destroy(void) 56939beb93cSSam Leffler { 57039beb93cSSam Leffler struct eloop_timeout *timeout, *prev; 57139beb93cSSam Leffler struct os_time now; 57239beb93cSSam Leffler 57339beb93cSSam Leffler os_get_time(&now); 574*e28a4053SRui Paulo dl_list_for_each_safe(timeout, prev, &eloop.timeout, 575*e28a4053SRui Paulo struct eloop_timeout, list) { 57639beb93cSSam Leffler int sec, usec; 577*e28a4053SRui Paulo sec = timeout->time.sec - now.sec; 578*e28a4053SRui Paulo usec = timeout->time.usec - now.usec; 579*e28a4053SRui Paulo if (timeout->time.usec < now.usec) { 58039beb93cSSam Leffler sec--; 58139beb93cSSam Leffler usec += 1000000; 58239beb93cSSam Leffler } 583*e28a4053SRui Paulo wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d " 584*e28a4053SRui Paulo "eloop_data=%p user_data=%p handler=%p", 585*e28a4053SRui Paulo sec, usec, timeout->eloop_data, timeout->user_data, 586*e28a4053SRui Paulo timeout->handler); 587*e28a4053SRui Paulo wpa_trace_dump_funcname("eloop unregistered timeout handler", 588*e28a4053SRui Paulo timeout->handler); 589*e28a4053SRui Paulo wpa_trace_dump("eloop timeout", timeout); 590*e28a4053SRui Paulo eloop_remove_timeout(timeout); 59139beb93cSSam Leffler } 59239beb93cSSam Leffler eloop_sock_table_destroy(&eloop.readers); 59339beb93cSSam Leffler eloop_sock_table_destroy(&eloop.writers); 59439beb93cSSam Leffler eloop_sock_table_destroy(&eloop.exceptions); 59539beb93cSSam Leffler os_free(eloop.signals); 59639beb93cSSam Leffler } 59739beb93cSSam Leffler 59839beb93cSSam Leffler 59939beb93cSSam Leffler int eloop_terminated(void) 60039beb93cSSam Leffler { 60139beb93cSSam Leffler return eloop.terminate; 60239beb93cSSam Leffler } 60339beb93cSSam Leffler 60439beb93cSSam Leffler 60539beb93cSSam Leffler void eloop_wait_for_read_sock(int sock) 60639beb93cSSam Leffler { 60739beb93cSSam Leffler fd_set rfds; 60839beb93cSSam Leffler 60939beb93cSSam Leffler if (sock < 0) 61039beb93cSSam Leffler return; 61139beb93cSSam Leffler 61239beb93cSSam Leffler FD_ZERO(&rfds); 61339beb93cSSam Leffler FD_SET(sock, &rfds); 61439beb93cSSam Leffler select(sock + 1, &rfds, NULL, NULL, NULL); 61539beb93cSSam Leffler } 616