Home | History | Annotate | Download | only in utils
      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 		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 	if (ret == 0)
    431 		ret = eloop_register_signal(SIGSEGV, handler, user_data);
    432 	return ret;
    433 }
    434 
    435 
    436 int eloop_register_signal_reconfig(eloop_signal_handler handler,
    437 				   void *user_data)
    438 {
    439 #ifdef CONFIG_NATIVE_WINDOWS
    440 	return 0;
    441 #else /* CONFIG_NATIVE_WINDOWS */
    442 	return eloop_register_signal(SIGHUP, handler, user_data);
    443 #endif /* CONFIG_NATIVE_WINDOWS */
    444 }
    445 
    446 
    447 void eloop_run(void)
    448 {
    449 	fd_set *rfds, *wfds, *efds;
    450 	int res;
    451 	struct timeval _tv;
    452 	struct os_time tv, now;
    453 
    454 	rfds = os_malloc(sizeof(*rfds));
    455 	wfds = os_malloc(sizeof(*wfds));
    456 	efds = os_malloc(sizeof(*efds));
    457 	if (rfds == NULL || wfds == NULL || efds == NULL) {
    458 		printf("eloop_run - malloc failed\n");
    459 		goto out;
    460 	}
    461 
    462 	while (!eloop.terminate &&
    463 	       (eloop.timeout || eloop.readers.count > 0 ||
    464 		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
    465 		if (eloop.timeout) {
    466 			os_get_time(&now);
    467 			if (os_time_before(&now, &eloop.timeout->time))
    468 				os_time_sub(&eloop.timeout->time, &now, &tv);
    469 			else
    470 				tv.sec = tv.usec = 0;
    471 #if 0
    472 			printf("next timeout in %lu.%06lu sec\n",
    473 			       tv.sec, tv.usec);
    474 #endif
    475 			_tv.tv_sec = tv.sec;
    476 			_tv.tv_usec = tv.usec;
    477 		}
    478 
    479 		eloop_sock_table_set_fds(&eloop.readers, rfds);
    480 		eloop_sock_table_set_fds(&eloop.writers, wfds);
    481 		eloop_sock_table_set_fds(&eloop.exceptions, efds);
    482 		res = select(eloop.max_sock + 1, rfds, wfds, efds,
    483 			     eloop.timeout ? &_tv : NULL);
    484 		if (res < 0 && errno != EINTR && errno != 0) {
    485 			perror("select");
    486 			goto out;
    487 		}
    488 		eloop_process_pending_signals();
    489 
    490 		/* check if some registered timeouts have occurred */
    491 		if (eloop.timeout) {
    492 			struct eloop_timeout *tmp;
    493 
    494 			os_get_time(&now);
    495 			if (!os_time_before(&now, &eloop.timeout->time)) {
    496 				tmp = eloop.timeout;
    497 				eloop.timeout = eloop.timeout->next;
    498 				tmp->handler(tmp->eloop_data,
    499 					     tmp->user_data);
    500 				os_free(tmp);
    501 			}
    502 
    503 		}
    504 
    505 		if (res <= 0)
    506 			continue;
    507 
    508 		eloop_sock_table_dispatch(&eloop.readers, rfds);
    509 		eloop_sock_table_dispatch(&eloop.writers, wfds);
    510 		eloop_sock_table_dispatch(&eloop.exceptions, efds);
    511 	}
    512 
    513 out:
    514 	os_free(rfds);
    515 	os_free(wfds);
    516 	os_free(efds);
    517 }
    518 
    519 
    520 void eloop_terminate(void)
    521 {
    522 	eloop.terminate = 1;
    523 }
    524 
    525 
    526 void eloop_destroy(void)
    527 {
    528 	struct eloop_timeout *timeout, *prev;
    529 	struct os_time now;
    530 
    531 	timeout = eloop.timeout;
    532 	if (timeout)
    533 		os_get_time(&now);
    534 	while (timeout != NULL) {
    535 		int sec, usec;
    536 		prev = timeout;
    537 		timeout = timeout->next;
    538 		sec = prev->time.sec - now.sec;
    539 		usec = prev->time.usec - now.usec;
    540 		if (prev->time.usec < now.usec) {
    541 			sec--;
    542 			usec += 1000000;
    543 		}
    544 		printf("ELOOP: remaining timeout: %d.%06d eloop_data=%p "
    545 		       "user_data=%p handler=%p\n",
    546 		       sec, usec, prev->eloop_data, prev->user_data,
    547 		       prev->handler);
    548 		os_free(prev);
    549 	}
    550 	eloop_sock_table_destroy(&eloop.readers);
    551 	eloop_sock_table_destroy(&eloop.writers);
    552 	eloop_sock_table_destroy(&eloop.exceptions);
    553 	os_free(eloop.signals);
    554 }
    555 
    556 
    557 int eloop_terminated(void)
    558 {
    559 	return eloop.terminate;
    560 }
    561 
    562 
    563 void eloop_wait_for_read_sock(int sock)
    564 {
    565 	fd_set rfds;
    566 
    567 	if (sock < 0)
    568 		return;
    569 
    570 	FD_ZERO(&rfds);
    571 	FD_SET(sock, &rfds);
    572 	select(sock + 1, &rfds, NULL, NULL, NULL);
    573 }
    574 
    575 
    576 void * eloop_get_user_data(void)
    577 {
    578 	return eloop.user_data;
    579 }
    580