1189251Ssam/* 2189251Ssam * Event loop based on select() loop 3214734Srpaulo * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12214734Srpaulo#include "trace.h" 13214734Srpaulo#include "list.h" 14189251Ssam#include "eloop.h" 15189251Ssam 16252726Srpaulo#ifdef CONFIG_ELOOP_POLL 17252726Srpaulo#include <assert.h> 18252726Srpaulo#include <poll.h> 19252726Srpaulo#endif /* CONFIG_ELOOP_POLL */ 20189251Ssam 21252726Srpaulo 22189251Ssamstruct eloop_sock { 23189251Ssam int sock; 24189251Ssam void *eloop_data; 25189251Ssam void *user_data; 26189251Ssam eloop_sock_handler handler; 27214734Srpaulo WPA_TRACE_REF(eloop); 28214734Srpaulo WPA_TRACE_REF(user); 29214734Srpaulo WPA_TRACE_INFO 30189251Ssam}; 31189251Ssam 32189251Ssamstruct eloop_timeout { 33214734Srpaulo struct dl_list list; 34189251Ssam struct os_time time; 35189251Ssam void *eloop_data; 36189251Ssam void *user_data; 37189251Ssam eloop_timeout_handler handler; 38214734Srpaulo WPA_TRACE_REF(eloop); 39214734Srpaulo WPA_TRACE_REF(user); 40214734Srpaulo WPA_TRACE_INFO 41189251Ssam}; 42189251Ssam 43189251Ssamstruct eloop_signal { 44189251Ssam int sig; 45189251Ssam void *user_data; 46189251Ssam eloop_signal_handler handler; 47189251Ssam int signaled; 48189251Ssam}; 49189251Ssam 50189251Ssamstruct eloop_sock_table { 51189251Ssam int count; 52189251Ssam struct eloop_sock *table; 53189251Ssam int changed; 54189251Ssam}; 55189251Ssam 56189251Ssamstruct eloop_data { 57189251Ssam int max_sock; 58189251Ssam 59252726Srpaulo int count; /* sum of all table counts */ 60252726Srpaulo#ifdef CONFIG_ELOOP_POLL 61252726Srpaulo int max_pollfd_map; /* number of pollfds_map currently allocated */ 62252726Srpaulo int max_poll_fds; /* number of pollfds currently allocated */ 63252726Srpaulo struct pollfd *pollfds; 64252726Srpaulo struct pollfd **pollfds_map; 65252726Srpaulo#endif /* CONFIG_ELOOP_POLL */ 66189251Ssam struct eloop_sock_table readers; 67189251Ssam struct eloop_sock_table writers; 68189251Ssam struct eloop_sock_table exceptions; 69189251Ssam 70214734Srpaulo struct dl_list timeout; 71189251Ssam 72189251Ssam int signal_count; 73189251Ssam struct eloop_signal *signals; 74189251Ssam int signaled; 75189251Ssam int pending_terminate; 76189251Ssam 77189251Ssam int terminate; 78189251Ssam int reader_table_changed; 79189251Ssam}; 80189251Ssam 81189251Ssamstatic struct eloop_data eloop; 82189251Ssam 83189251Ssam 84214734Srpaulo#ifdef WPA_TRACE 85214734Srpaulo 86214734Srpaulostatic void eloop_sigsegv_handler(int sig) 87189251Ssam{ 88214734Srpaulo wpa_trace_show("eloop SIGSEGV"); 89214734Srpaulo abort(); 90214734Srpaulo} 91214734Srpaulo 92214734Srpaulostatic void eloop_trace_sock_add_ref(struct eloop_sock_table *table) 93214734Srpaulo{ 94214734Srpaulo int i; 95214734Srpaulo if (table == NULL || table->table == NULL) 96214734Srpaulo return; 97214734Srpaulo for (i = 0; i < table->count; i++) { 98214734Srpaulo wpa_trace_add_ref(&table->table[i], eloop, 99214734Srpaulo table->table[i].eloop_data); 100214734Srpaulo wpa_trace_add_ref(&table->table[i], user, 101214734Srpaulo table->table[i].user_data); 102214734Srpaulo } 103214734Srpaulo} 104214734Srpaulo 105214734Srpaulo 106214734Srpaulostatic void eloop_trace_sock_remove_ref(struct eloop_sock_table *table) 107214734Srpaulo{ 108214734Srpaulo int i; 109214734Srpaulo if (table == NULL || table->table == NULL) 110214734Srpaulo return; 111214734Srpaulo for (i = 0; i < table->count; i++) { 112214734Srpaulo wpa_trace_remove_ref(&table->table[i], eloop, 113214734Srpaulo table->table[i].eloop_data); 114214734Srpaulo wpa_trace_remove_ref(&table->table[i], user, 115214734Srpaulo table->table[i].user_data); 116214734Srpaulo } 117214734Srpaulo} 118214734Srpaulo 119214734Srpaulo#else /* WPA_TRACE */ 120214734Srpaulo 121214734Srpaulo#define eloop_trace_sock_add_ref(table) do { } while (0) 122214734Srpaulo#define eloop_trace_sock_remove_ref(table) do { } while (0) 123214734Srpaulo 124214734Srpaulo#endif /* WPA_TRACE */ 125214734Srpaulo 126214734Srpaulo 127214734Srpauloint eloop_init(void) 128214734Srpaulo{ 129189251Ssam os_memset(&eloop, 0, sizeof(eloop)); 130214734Srpaulo dl_list_init(&eloop.timeout); 131214734Srpaulo#ifdef WPA_TRACE 132214734Srpaulo signal(SIGSEGV, eloop_sigsegv_handler); 133214734Srpaulo#endif /* WPA_TRACE */ 134189251Ssam return 0; 135189251Ssam} 136189251Ssam 137189251Ssam 138189251Ssamstatic int eloop_sock_table_add_sock(struct eloop_sock_table *table, 139189251Ssam int sock, eloop_sock_handler handler, 140189251Ssam void *eloop_data, void *user_data) 141189251Ssam{ 142189251Ssam struct eloop_sock *tmp; 143252726Srpaulo int new_max_sock; 144189251Ssam 145252726Srpaulo if (sock > eloop.max_sock) 146252726Srpaulo new_max_sock = sock; 147252726Srpaulo else 148252726Srpaulo new_max_sock = eloop.max_sock; 149252726Srpaulo 150189251Ssam if (table == NULL) 151189251Ssam return -1; 152189251Ssam 153252726Srpaulo#ifdef CONFIG_ELOOP_POLL 154252726Srpaulo if (new_max_sock >= eloop.max_pollfd_map) { 155252726Srpaulo struct pollfd **nmap; 156252726Srpaulo nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50, 157252726Srpaulo sizeof(struct pollfd *)); 158252726Srpaulo if (nmap == NULL) 159252726Srpaulo return -1; 160252726Srpaulo 161252726Srpaulo eloop.max_pollfd_map = new_max_sock + 50; 162252726Srpaulo eloop.pollfds_map = nmap; 163252726Srpaulo } 164252726Srpaulo 165252726Srpaulo if (eloop.count + 1 > eloop.max_poll_fds) { 166252726Srpaulo struct pollfd *n; 167252726Srpaulo int nmax = eloop.count + 1 + 50; 168252726Srpaulo n = os_realloc_array(eloop.pollfds, nmax, 169252726Srpaulo sizeof(struct pollfd)); 170252726Srpaulo if (n == NULL) 171252726Srpaulo return -1; 172252726Srpaulo 173252726Srpaulo eloop.max_poll_fds = nmax; 174252726Srpaulo eloop.pollfds = n; 175252726Srpaulo } 176252726Srpaulo#endif /* CONFIG_ELOOP_POLL */ 177252726Srpaulo 178214734Srpaulo eloop_trace_sock_remove_ref(table); 179252726Srpaulo tmp = os_realloc_array(table->table, table->count + 1, 180252726Srpaulo sizeof(struct eloop_sock)); 181189251Ssam if (tmp == NULL) 182189251Ssam return -1; 183189251Ssam 184189251Ssam tmp[table->count].sock = sock; 185189251Ssam tmp[table->count].eloop_data = eloop_data; 186189251Ssam tmp[table->count].user_data = user_data; 187189251Ssam tmp[table->count].handler = handler; 188214734Srpaulo wpa_trace_record(&tmp[table->count]); 189189251Ssam table->count++; 190189251Ssam table->table = tmp; 191252726Srpaulo eloop.max_sock = new_max_sock; 192252726Srpaulo eloop.count++; 193189251Ssam table->changed = 1; 194214734Srpaulo eloop_trace_sock_add_ref(table); 195189251Ssam 196189251Ssam return 0; 197189251Ssam} 198189251Ssam 199189251Ssam 200189251Ssamstatic void eloop_sock_table_remove_sock(struct eloop_sock_table *table, 201189251Ssam int sock) 202189251Ssam{ 203189251Ssam int i; 204189251Ssam 205189251Ssam if (table == NULL || table->table == NULL || table->count == 0) 206189251Ssam return; 207189251Ssam 208189251Ssam for (i = 0; i < table->count; i++) { 209189251Ssam if (table->table[i].sock == sock) 210189251Ssam break; 211189251Ssam } 212189251Ssam if (i == table->count) 213189251Ssam return; 214214734Srpaulo eloop_trace_sock_remove_ref(table); 215189251Ssam if (i != table->count - 1) { 216189251Ssam os_memmove(&table->table[i], &table->table[i + 1], 217189251Ssam (table->count - i - 1) * 218189251Ssam sizeof(struct eloop_sock)); 219189251Ssam } 220189251Ssam table->count--; 221252726Srpaulo eloop.count--; 222189251Ssam table->changed = 1; 223214734Srpaulo eloop_trace_sock_add_ref(table); 224189251Ssam} 225189251Ssam 226189251Ssam 227252726Srpaulo#ifdef CONFIG_ELOOP_POLL 228252726Srpaulo 229252726Srpaulostatic struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx) 230252726Srpaulo{ 231252726Srpaulo if (fd < mx && fd >= 0) 232252726Srpaulo return pollfds_map[fd]; 233252726Srpaulo return NULL; 234252726Srpaulo} 235252726Srpaulo 236252726Srpaulo 237252726Srpaulostatic int eloop_sock_table_set_fds(struct eloop_sock_table *readers, 238252726Srpaulo struct eloop_sock_table *writers, 239252726Srpaulo struct eloop_sock_table *exceptions, 240252726Srpaulo struct pollfd *pollfds, 241252726Srpaulo struct pollfd **pollfds_map, 242252726Srpaulo int max_pollfd_map) 243252726Srpaulo{ 244252726Srpaulo int i; 245252726Srpaulo int nxt = 0; 246252726Srpaulo int fd; 247252726Srpaulo struct pollfd *pfd; 248252726Srpaulo 249252726Srpaulo /* Clear pollfd lookup map. It will be re-populated below. */ 250252726Srpaulo os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map); 251252726Srpaulo 252252726Srpaulo if (readers && readers->table) { 253252726Srpaulo for (i = 0; i < readers->count; i++) { 254252726Srpaulo fd = readers->table[i].sock; 255252726Srpaulo assert(fd >= 0 && fd < max_pollfd_map); 256252726Srpaulo pollfds[nxt].fd = fd; 257252726Srpaulo pollfds[nxt].events = POLLIN; 258252726Srpaulo pollfds[nxt].revents = 0; 259252726Srpaulo pollfds_map[fd] = &(pollfds[nxt]); 260252726Srpaulo nxt++; 261252726Srpaulo } 262252726Srpaulo } 263252726Srpaulo 264252726Srpaulo if (writers && writers->table) { 265252726Srpaulo for (i = 0; i < writers->count; i++) { 266252726Srpaulo /* 267252726Srpaulo * See if we already added this descriptor, update it 268252726Srpaulo * if so. 269252726Srpaulo */ 270252726Srpaulo fd = writers->table[i].sock; 271252726Srpaulo assert(fd >= 0 && fd < max_pollfd_map); 272252726Srpaulo pfd = pollfds_map[fd]; 273252726Srpaulo if (!pfd) { 274252726Srpaulo pfd = &(pollfds[nxt]); 275252726Srpaulo pfd->events = 0; 276252726Srpaulo pfd->fd = fd; 277252726Srpaulo pollfds[i].revents = 0; 278252726Srpaulo pollfds_map[fd] = pfd; 279252726Srpaulo nxt++; 280252726Srpaulo } 281252726Srpaulo pfd->events |= POLLOUT; 282252726Srpaulo } 283252726Srpaulo } 284252726Srpaulo 285252726Srpaulo /* 286252726Srpaulo * Exceptions are always checked when using poll, but I suppose it's 287252726Srpaulo * possible that someone registered a socket *only* for exception 288252726Srpaulo * handling. Set the POLLIN bit in this case. 289252726Srpaulo */ 290252726Srpaulo if (exceptions && exceptions->table) { 291252726Srpaulo for (i = 0; i < exceptions->count; i++) { 292252726Srpaulo /* 293252726Srpaulo * See if we already added this descriptor, just use it 294252726Srpaulo * if so. 295252726Srpaulo */ 296252726Srpaulo fd = exceptions->table[i].sock; 297252726Srpaulo assert(fd >= 0 && fd < max_pollfd_map); 298252726Srpaulo pfd = pollfds_map[fd]; 299252726Srpaulo if (!pfd) { 300252726Srpaulo pfd = &(pollfds[nxt]); 301252726Srpaulo pfd->events = POLLIN; 302252726Srpaulo pfd->fd = fd; 303252726Srpaulo pollfds[i].revents = 0; 304252726Srpaulo pollfds_map[fd] = pfd; 305252726Srpaulo nxt++; 306252726Srpaulo } 307252726Srpaulo } 308252726Srpaulo } 309252726Srpaulo 310252726Srpaulo return nxt; 311252726Srpaulo} 312252726Srpaulo 313252726Srpaulo 314252726Srpaulostatic int eloop_sock_table_dispatch_table(struct eloop_sock_table *table, 315252726Srpaulo struct pollfd **pollfds_map, 316252726Srpaulo int max_pollfd_map, 317252726Srpaulo short int revents) 318252726Srpaulo{ 319252726Srpaulo int i; 320252726Srpaulo struct pollfd *pfd; 321252726Srpaulo 322252726Srpaulo if (!table || !table->table) 323252726Srpaulo return 0; 324252726Srpaulo 325252726Srpaulo table->changed = 0; 326252726Srpaulo for (i = 0; i < table->count; i++) { 327252726Srpaulo pfd = find_pollfd(pollfds_map, table->table[i].sock, 328252726Srpaulo max_pollfd_map); 329252726Srpaulo if (!pfd) 330252726Srpaulo continue; 331252726Srpaulo 332252726Srpaulo if (!(pfd->revents & revents)) 333252726Srpaulo continue; 334252726Srpaulo 335252726Srpaulo table->table[i].handler(table->table[i].sock, 336252726Srpaulo table->table[i].eloop_data, 337252726Srpaulo table->table[i].user_data); 338252726Srpaulo if (table->changed) 339252726Srpaulo return 1; 340252726Srpaulo } 341252726Srpaulo 342252726Srpaulo return 0; 343252726Srpaulo} 344252726Srpaulo 345252726Srpaulo 346252726Srpaulostatic void eloop_sock_table_dispatch(struct eloop_sock_table *readers, 347252726Srpaulo struct eloop_sock_table *writers, 348252726Srpaulo struct eloop_sock_table *exceptions, 349252726Srpaulo struct pollfd **pollfds_map, 350252726Srpaulo int max_pollfd_map) 351252726Srpaulo{ 352252726Srpaulo if (eloop_sock_table_dispatch_table(readers, pollfds_map, 353252726Srpaulo max_pollfd_map, POLLIN | POLLERR | 354252726Srpaulo POLLHUP)) 355252726Srpaulo return; /* pollfds may be invalid at this point */ 356252726Srpaulo 357252726Srpaulo if (eloop_sock_table_dispatch_table(writers, pollfds_map, 358252726Srpaulo max_pollfd_map, POLLOUT)) 359252726Srpaulo return; /* pollfds may be invalid at this point */ 360252726Srpaulo 361252726Srpaulo eloop_sock_table_dispatch_table(exceptions, pollfds_map, 362252726Srpaulo max_pollfd_map, POLLERR | POLLHUP); 363252726Srpaulo} 364252726Srpaulo 365252726Srpaulo#else /* CONFIG_ELOOP_POLL */ 366252726Srpaulo 367189251Ssamstatic void eloop_sock_table_set_fds(struct eloop_sock_table *table, 368189251Ssam fd_set *fds) 369189251Ssam{ 370189251Ssam int i; 371189251Ssam 372189251Ssam FD_ZERO(fds); 373189251Ssam 374189251Ssam if (table->table == NULL) 375189251Ssam return; 376189251Ssam 377189251Ssam for (i = 0; i < table->count; i++) 378189251Ssam FD_SET(table->table[i].sock, fds); 379189251Ssam} 380189251Ssam 381189251Ssam 382189251Ssamstatic void eloop_sock_table_dispatch(struct eloop_sock_table *table, 383189251Ssam fd_set *fds) 384189251Ssam{ 385189251Ssam int i; 386189251Ssam 387189251Ssam if (table == NULL || table->table == NULL) 388189251Ssam return; 389189251Ssam 390189251Ssam table->changed = 0; 391189251Ssam for (i = 0; i < table->count; i++) { 392189251Ssam if (FD_ISSET(table->table[i].sock, fds)) { 393189251Ssam table->table[i].handler(table->table[i].sock, 394189251Ssam table->table[i].eloop_data, 395189251Ssam table->table[i].user_data); 396189251Ssam if (table->changed) 397189251Ssam break; 398189251Ssam } 399189251Ssam } 400189251Ssam} 401189251Ssam 402252726Srpaulo#endif /* CONFIG_ELOOP_POLL */ 403189251Ssam 404252726Srpaulo 405189251Ssamstatic void eloop_sock_table_destroy(struct eloop_sock_table *table) 406189251Ssam{ 407189251Ssam if (table) { 408189251Ssam int i; 409189251Ssam for (i = 0; i < table->count && table->table; i++) { 410214734Srpaulo wpa_printf(MSG_INFO, "ELOOP: remaining socket: " 411214734Srpaulo "sock=%d eloop_data=%p user_data=%p " 412214734Srpaulo "handler=%p", 413214734Srpaulo table->table[i].sock, 414214734Srpaulo table->table[i].eloop_data, 415214734Srpaulo table->table[i].user_data, 416214734Srpaulo table->table[i].handler); 417214734Srpaulo wpa_trace_dump_funcname("eloop unregistered socket " 418214734Srpaulo "handler", 419214734Srpaulo table->table[i].handler); 420214734Srpaulo wpa_trace_dump("eloop sock", &table->table[i]); 421189251Ssam } 422189251Ssam os_free(table->table); 423189251Ssam } 424189251Ssam} 425189251Ssam 426189251Ssam 427189251Ssamint eloop_register_read_sock(int sock, eloop_sock_handler handler, 428189251Ssam void *eloop_data, void *user_data) 429189251Ssam{ 430189251Ssam return eloop_register_sock(sock, EVENT_TYPE_READ, handler, 431189251Ssam eloop_data, user_data); 432189251Ssam} 433189251Ssam 434189251Ssam 435189251Ssamvoid eloop_unregister_read_sock(int sock) 436189251Ssam{ 437189251Ssam eloop_unregister_sock(sock, EVENT_TYPE_READ); 438189251Ssam} 439189251Ssam 440189251Ssam 441189251Ssamstatic struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type) 442189251Ssam{ 443189251Ssam switch (type) { 444189251Ssam case EVENT_TYPE_READ: 445189251Ssam return &eloop.readers; 446189251Ssam case EVENT_TYPE_WRITE: 447189251Ssam return &eloop.writers; 448189251Ssam case EVENT_TYPE_EXCEPTION: 449189251Ssam return &eloop.exceptions; 450189251Ssam } 451189251Ssam 452189251Ssam return NULL; 453189251Ssam} 454189251Ssam 455189251Ssam 456189251Ssamint eloop_register_sock(int sock, eloop_event_type type, 457189251Ssam eloop_sock_handler handler, 458189251Ssam void *eloop_data, void *user_data) 459189251Ssam{ 460189251Ssam struct eloop_sock_table *table; 461189251Ssam 462189251Ssam table = eloop_get_sock_table(type); 463189251Ssam return eloop_sock_table_add_sock(table, sock, handler, 464189251Ssam eloop_data, user_data); 465189251Ssam} 466189251Ssam 467189251Ssam 468189251Ssamvoid eloop_unregister_sock(int sock, eloop_event_type type) 469189251Ssam{ 470189251Ssam struct eloop_sock_table *table; 471189251Ssam 472189251Ssam table = eloop_get_sock_table(type); 473189251Ssam eloop_sock_table_remove_sock(table, sock); 474189251Ssam} 475189251Ssam 476189251Ssam 477189251Ssamint eloop_register_timeout(unsigned int secs, unsigned int usecs, 478189251Ssam eloop_timeout_handler handler, 479189251Ssam void *eloop_data, void *user_data) 480189251Ssam{ 481214734Srpaulo struct eloop_timeout *timeout, *tmp; 482252726Srpaulo os_time_t now_sec; 483189251Ssam 484214734Srpaulo timeout = os_zalloc(sizeof(*timeout)); 485189251Ssam if (timeout == NULL) 486189251Ssam return -1; 487189251Ssam if (os_get_time(&timeout->time) < 0) { 488189251Ssam os_free(timeout); 489189251Ssam return -1; 490189251Ssam } 491252726Srpaulo now_sec = timeout->time.sec; 492189251Ssam timeout->time.sec += secs; 493252726Srpaulo if (timeout->time.sec < now_sec) { 494252726Srpaulo /* 495252726Srpaulo * Integer overflow - assume long enough timeout to be assumed 496252726Srpaulo * to be infinite, i.e., the timeout would never happen. 497252726Srpaulo */ 498252726Srpaulo wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to " 499252726Srpaulo "ever happen - ignore it", secs); 500252726Srpaulo os_free(timeout); 501252726Srpaulo return 0; 502252726Srpaulo } 503189251Ssam timeout->time.usec += usecs; 504189251Ssam while (timeout->time.usec >= 1000000) { 505189251Ssam timeout->time.sec++; 506189251Ssam timeout->time.usec -= 1000000; 507189251Ssam } 508189251Ssam timeout->eloop_data = eloop_data; 509189251Ssam timeout->user_data = user_data; 510189251Ssam timeout->handler = handler; 511214734Srpaulo wpa_trace_add_ref(timeout, eloop, eloop_data); 512214734Srpaulo wpa_trace_add_ref(timeout, user, user_data); 513214734Srpaulo wpa_trace_record(timeout); 514189251Ssam 515214734Srpaulo /* Maintain timeouts in order of increasing time */ 516214734Srpaulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 517214734Srpaulo if (os_time_before(&timeout->time, &tmp->time)) { 518214734Srpaulo dl_list_add(tmp->list.prev, &timeout->list); 519214734Srpaulo return 0; 520214734Srpaulo } 521189251Ssam } 522214734Srpaulo dl_list_add_tail(&eloop.timeout, &timeout->list); 523189251Ssam 524214734Srpaulo return 0; 525214734Srpaulo} 526189251Ssam 527189251Ssam 528214734Srpaulostatic void eloop_remove_timeout(struct eloop_timeout *timeout) 529214734Srpaulo{ 530214734Srpaulo dl_list_del(&timeout->list); 531214734Srpaulo wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data); 532214734Srpaulo wpa_trace_remove_ref(timeout, user, timeout->user_data); 533214734Srpaulo os_free(timeout); 534189251Ssam} 535189251Ssam 536189251Ssam 537189251Ssamint eloop_cancel_timeout(eloop_timeout_handler handler, 538189251Ssam void *eloop_data, void *user_data) 539189251Ssam{ 540214734Srpaulo struct eloop_timeout *timeout, *prev; 541189251Ssam int removed = 0; 542189251Ssam 543214734Srpaulo dl_list_for_each_safe(timeout, prev, &eloop.timeout, 544214734Srpaulo struct eloop_timeout, list) { 545189251Ssam if (timeout->handler == handler && 546189251Ssam (timeout->eloop_data == eloop_data || 547189251Ssam eloop_data == ELOOP_ALL_CTX) && 548189251Ssam (timeout->user_data == user_data || 549189251Ssam user_data == ELOOP_ALL_CTX)) { 550214734Srpaulo eloop_remove_timeout(timeout); 551189251Ssam removed++; 552214734Srpaulo } 553189251Ssam } 554189251Ssam 555189251Ssam return removed; 556189251Ssam} 557189251Ssam 558189251Ssam 559189251Ssamint eloop_is_timeout_registered(eloop_timeout_handler handler, 560189251Ssam void *eloop_data, void *user_data) 561189251Ssam{ 562189251Ssam struct eloop_timeout *tmp; 563189251Ssam 564214734Srpaulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 565189251Ssam if (tmp->handler == handler && 566189251Ssam tmp->eloop_data == eloop_data && 567189251Ssam tmp->user_data == user_data) 568189251Ssam return 1; 569189251Ssam } 570189251Ssam 571189251Ssam return 0; 572189251Ssam} 573189251Ssam 574189251Ssam 575189251Ssam#ifndef CONFIG_NATIVE_WINDOWS 576189251Ssamstatic void eloop_handle_alarm(int sig) 577189251Ssam{ 578214734Srpaulo wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in " 579214734Srpaulo "two seconds. Looks like there\n" 580214734Srpaulo "is a bug that ends up in a busy loop that " 581214734Srpaulo "prevents clean shutdown.\n" 582214734Srpaulo "Killing program forcefully.\n"); 583189251Ssam exit(1); 584189251Ssam} 585189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 586189251Ssam 587189251Ssam 588189251Ssamstatic void eloop_handle_signal(int sig) 589189251Ssam{ 590189251Ssam int i; 591189251Ssam 592189251Ssam#ifndef CONFIG_NATIVE_WINDOWS 593189251Ssam if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { 594189251Ssam /* Use SIGALRM to break out from potential busy loops that 595189251Ssam * would not allow the program to be killed. */ 596189251Ssam eloop.pending_terminate = 1; 597189251Ssam signal(SIGALRM, eloop_handle_alarm); 598189251Ssam alarm(2); 599189251Ssam } 600189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 601189251Ssam 602189251Ssam eloop.signaled++; 603189251Ssam for (i = 0; i < eloop.signal_count; i++) { 604189251Ssam if (eloop.signals[i].sig == sig) { 605189251Ssam eloop.signals[i].signaled++; 606189251Ssam break; 607189251Ssam } 608189251Ssam } 609189251Ssam} 610189251Ssam 611189251Ssam 612189251Ssamstatic void eloop_process_pending_signals(void) 613189251Ssam{ 614189251Ssam int i; 615189251Ssam 616189251Ssam if (eloop.signaled == 0) 617189251Ssam return; 618189251Ssam eloop.signaled = 0; 619189251Ssam 620189251Ssam if (eloop.pending_terminate) { 621189251Ssam#ifndef CONFIG_NATIVE_WINDOWS 622189251Ssam alarm(0); 623189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 624189251Ssam eloop.pending_terminate = 0; 625189251Ssam } 626189251Ssam 627189251Ssam for (i = 0; i < eloop.signal_count; i++) { 628189251Ssam if (eloop.signals[i].signaled) { 629189251Ssam eloop.signals[i].signaled = 0; 630189251Ssam eloop.signals[i].handler(eloop.signals[i].sig, 631189251Ssam eloop.signals[i].user_data); 632189251Ssam } 633189251Ssam } 634189251Ssam} 635189251Ssam 636189251Ssam 637189251Ssamint eloop_register_signal(int sig, eloop_signal_handler handler, 638189251Ssam void *user_data) 639189251Ssam{ 640189251Ssam struct eloop_signal *tmp; 641189251Ssam 642252726Srpaulo tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1, 643252726Srpaulo sizeof(struct eloop_signal)); 644189251Ssam if (tmp == NULL) 645189251Ssam return -1; 646189251Ssam 647189251Ssam tmp[eloop.signal_count].sig = sig; 648189251Ssam tmp[eloop.signal_count].user_data = user_data; 649189251Ssam tmp[eloop.signal_count].handler = handler; 650189251Ssam tmp[eloop.signal_count].signaled = 0; 651189251Ssam eloop.signal_count++; 652189251Ssam eloop.signals = tmp; 653189251Ssam signal(sig, eloop_handle_signal); 654189251Ssam 655189251Ssam return 0; 656189251Ssam} 657189251Ssam 658189251Ssam 659189251Ssamint eloop_register_signal_terminate(eloop_signal_handler handler, 660189251Ssam void *user_data) 661189251Ssam{ 662189251Ssam int ret = eloop_register_signal(SIGINT, handler, user_data); 663189251Ssam if (ret == 0) 664189251Ssam ret = eloop_register_signal(SIGTERM, handler, user_data); 665189251Ssam return ret; 666189251Ssam} 667189251Ssam 668189251Ssam 669189251Ssamint eloop_register_signal_reconfig(eloop_signal_handler handler, 670189251Ssam void *user_data) 671189251Ssam{ 672189251Ssam#ifdef CONFIG_NATIVE_WINDOWS 673189251Ssam return 0; 674189251Ssam#else /* CONFIG_NATIVE_WINDOWS */ 675189251Ssam return eloop_register_signal(SIGHUP, handler, user_data); 676189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 677189251Ssam} 678189251Ssam 679189251Ssam 680189251Ssamvoid eloop_run(void) 681189251Ssam{ 682252726Srpaulo#ifdef CONFIG_ELOOP_POLL 683252726Srpaulo int num_poll_fds; 684252726Srpaulo int timeout_ms = 0; 685252726Srpaulo#else /* CONFIG_ELOOP_POLL */ 686189251Ssam fd_set *rfds, *wfds, *efds; 687252726Srpaulo struct timeval _tv; 688252726Srpaulo#endif /* CONFIG_ELOOP_POLL */ 689189251Ssam int res; 690189251Ssam struct os_time tv, now; 691189251Ssam 692252726Srpaulo#ifndef CONFIG_ELOOP_POLL 693189251Ssam rfds = os_malloc(sizeof(*rfds)); 694189251Ssam wfds = os_malloc(sizeof(*wfds)); 695189251Ssam efds = os_malloc(sizeof(*efds)); 696214734Srpaulo if (rfds == NULL || wfds == NULL || efds == NULL) 697189251Ssam goto out; 698252726Srpaulo#endif /* CONFIG_ELOOP_POLL */ 699189251Ssam 700189251Ssam while (!eloop.terminate && 701214734Srpaulo (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || 702189251Ssam eloop.writers.count > 0 || eloop.exceptions.count > 0)) { 703214734Srpaulo struct eloop_timeout *timeout; 704214734Srpaulo timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, 705214734Srpaulo list); 706214734Srpaulo if (timeout) { 707189251Ssam os_get_time(&now); 708214734Srpaulo if (os_time_before(&now, &timeout->time)) 709214734Srpaulo os_time_sub(&timeout->time, &now, &tv); 710189251Ssam else 711189251Ssam tv.sec = tv.usec = 0; 712252726Srpaulo#ifdef CONFIG_ELOOP_POLL 713252726Srpaulo timeout_ms = tv.sec * 1000 + tv.usec / 1000; 714252726Srpaulo#else /* CONFIG_ELOOP_POLL */ 715189251Ssam _tv.tv_sec = tv.sec; 716189251Ssam _tv.tv_usec = tv.usec; 717252726Srpaulo#endif /* CONFIG_ELOOP_POLL */ 718189251Ssam } 719189251Ssam 720252726Srpaulo#ifdef CONFIG_ELOOP_POLL 721252726Srpaulo num_poll_fds = eloop_sock_table_set_fds( 722252726Srpaulo &eloop.readers, &eloop.writers, &eloop.exceptions, 723252726Srpaulo eloop.pollfds, eloop.pollfds_map, 724252726Srpaulo eloop.max_pollfd_map); 725252726Srpaulo res = poll(eloop.pollfds, num_poll_fds, 726252726Srpaulo timeout ? timeout_ms : -1); 727252726Srpaulo 728252726Srpaulo if (res < 0 && errno != EINTR && errno != 0) { 729252726Srpaulo perror("poll"); 730252726Srpaulo goto out; 731252726Srpaulo } 732252726Srpaulo#else /* CONFIG_ELOOP_POLL */ 733189251Ssam eloop_sock_table_set_fds(&eloop.readers, rfds); 734189251Ssam eloop_sock_table_set_fds(&eloop.writers, wfds); 735189251Ssam eloop_sock_table_set_fds(&eloop.exceptions, efds); 736189251Ssam res = select(eloop.max_sock + 1, rfds, wfds, efds, 737214734Srpaulo timeout ? &_tv : NULL); 738189251Ssam if (res < 0 && errno != EINTR && errno != 0) { 739189251Ssam perror("select"); 740189251Ssam goto out; 741189251Ssam } 742252726Srpaulo#endif /* CONFIG_ELOOP_POLL */ 743189251Ssam eloop_process_pending_signals(); 744189251Ssam 745189251Ssam /* check if some registered timeouts have occurred */ 746214734Srpaulo timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, 747214734Srpaulo list); 748214734Srpaulo if (timeout) { 749189251Ssam os_get_time(&now); 750214734Srpaulo if (!os_time_before(&now, &timeout->time)) { 751214734Srpaulo void *eloop_data = timeout->eloop_data; 752214734Srpaulo void *user_data = timeout->user_data; 753214734Srpaulo eloop_timeout_handler handler = 754214734Srpaulo timeout->handler; 755214734Srpaulo eloop_remove_timeout(timeout); 756214734Srpaulo handler(eloop_data, user_data); 757189251Ssam } 758189251Ssam 759189251Ssam } 760189251Ssam 761189251Ssam if (res <= 0) 762189251Ssam continue; 763189251Ssam 764252726Srpaulo#ifdef CONFIG_ELOOP_POLL 765252726Srpaulo eloop_sock_table_dispatch(&eloop.readers, &eloop.writers, 766252726Srpaulo &eloop.exceptions, eloop.pollfds_map, 767252726Srpaulo eloop.max_pollfd_map); 768252726Srpaulo#else /* CONFIG_ELOOP_POLL */ 769189251Ssam eloop_sock_table_dispatch(&eloop.readers, rfds); 770189251Ssam eloop_sock_table_dispatch(&eloop.writers, wfds); 771189251Ssam eloop_sock_table_dispatch(&eloop.exceptions, efds); 772252726Srpaulo#endif /* CONFIG_ELOOP_POLL */ 773189251Ssam } 774189251Ssam 775189251Ssamout: 776252726Srpaulo#ifndef CONFIG_ELOOP_POLL 777189251Ssam os_free(rfds); 778189251Ssam os_free(wfds); 779189251Ssam os_free(efds); 780252726Srpaulo#endif /* CONFIG_ELOOP_POLL */ 781252726Srpaulo return; 782189251Ssam} 783189251Ssam 784189251Ssam 785189251Ssamvoid eloop_terminate(void) 786189251Ssam{ 787189251Ssam eloop.terminate = 1; 788189251Ssam} 789189251Ssam 790189251Ssam 791189251Ssamvoid eloop_destroy(void) 792189251Ssam{ 793189251Ssam struct eloop_timeout *timeout, *prev; 794189251Ssam struct os_time now; 795189251Ssam 796214734Srpaulo os_get_time(&now); 797214734Srpaulo dl_list_for_each_safe(timeout, prev, &eloop.timeout, 798214734Srpaulo struct eloop_timeout, list) { 799189251Ssam int sec, usec; 800214734Srpaulo sec = timeout->time.sec - now.sec; 801214734Srpaulo usec = timeout->time.usec - now.usec; 802214734Srpaulo if (timeout->time.usec < now.usec) { 803189251Ssam sec--; 804189251Ssam usec += 1000000; 805189251Ssam } 806214734Srpaulo wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d " 807214734Srpaulo "eloop_data=%p user_data=%p handler=%p", 808214734Srpaulo sec, usec, timeout->eloop_data, timeout->user_data, 809214734Srpaulo timeout->handler); 810214734Srpaulo wpa_trace_dump_funcname("eloop unregistered timeout handler", 811214734Srpaulo timeout->handler); 812214734Srpaulo wpa_trace_dump("eloop timeout", timeout); 813214734Srpaulo eloop_remove_timeout(timeout); 814189251Ssam } 815189251Ssam eloop_sock_table_destroy(&eloop.readers); 816189251Ssam eloop_sock_table_destroy(&eloop.writers); 817189251Ssam eloop_sock_table_destroy(&eloop.exceptions); 818189251Ssam os_free(eloop.signals); 819252726Srpaulo 820252726Srpaulo#ifdef CONFIG_ELOOP_POLL 821252726Srpaulo os_free(eloop.pollfds); 822252726Srpaulo os_free(eloop.pollfds_map); 823252726Srpaulo#endif /* CONFIG_ELOOP_POLL */ 824189251Ssam} 825189251Ssam 826189251Ssam 827189251Ssamint eloop_terminated(void) 828189251Ssam{ 829189251Ssam return eloop.terminate; 830189251Ssam} 831189251Ssam 832189251Ssam 833189251Ssamvoid eloop_wait_for_read_sock(int sock) 834189251Ssam{ 835252726Srpaulo#ifdef CONFIG_ELOOP_POLL 836252726Srpaulo struct pollfd pfd; 837252726Srpaulo 838252726Srpaulo if (sock < 0) 839252726Srpaulo return; 840252726Srpaulo 841252726Srpaulo os_memset(&pfd, 0, sizeof(pfd)); 842252726Srpaulo pfd.fd = sock; 843252726Srpaulo pfd.events = POLLIN; 844252726Srpaulo 845252726Srpaulo poll(&pfd, 1, -1); 846252726Srpaulo#else /* CONFIG_ELOOP_POLL */ 847189251Ssam fd_set rfds; 848189251Ssam 849189251Ssam if (sock < 0) 850189251Ssam return; 851189251Ssam 852189251Ssam FD_ZERO(&rfds); 853189251Ssam FD_SET(sock, &rfds); 854189251Ssam select(sock + 1, &rfds, NULL, NULL, NULL); 855252726Srpaulo#endif /* CONFIG_ELOOP_POLL */ 856189251Ssam} 857