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