• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
eloop_init(void * user_data)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 
eloop_sock_table_add_sock(struct eloop_sock_table * table,int sock,eloop_sock_handler handler,void * eloop_data,void * user_data)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 
eloop_sock_table_remove_sock(struct eloop_sock_table * table,int sock)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 
eloop_sock_table_set_fds(struct eloop_sock_table * table,fd_set * fds)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 
eloop_sock_table_dispatch(struct eloop_sock_table * table,fd_set * fds)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 
eloop_sock_table_destroy(struct eloop_sock_table * table)169 static void eloop_sock_table_destroy(struct eloop_sock_table *table)
170 {
171 	if (table)
172 		os_free(table->table);
173 }
174 
175 
eloop_register_read_sock(int sock,eloop_sock_handler handler,void * eloop_data,void * user_data)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 
eloop_unregister_read_sock(int sock)184 void eloop_unregister_read_sock(int sock)
185 {
186 	eloop_unregister_sock(sock, EVENT_TYPE_READ);
187 }
188 
189 
eloop_get_sock_table(eloop_event_type type)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 
eloop_register_sock(int sock,eloop_event_type type,eloop_sock_handler handler,void * eloop_data,void * user_data)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 
eloop_unregister_sock(int sock,eloop_event_type type)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 
eloop_register_timeout(unsigned int secs,unsigned int usecs,eloop_timeout_handler handler,void * eloop_data,void * user_data)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 
eloop_cancel_timeout(eloop_timeout_handler handler,void * eloop_data,void * user_data)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 
eloop_is_timeout_registered(eloop_timeout_handler handler,void * eloop_data,void * user_data)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
eloop_handle_alarm(int sig)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 
eloop_handle_signal(int sig)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 
eloop_process_pending_signals(void)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 
eloop_register_signal(int sig,eloop_signal_handler handler,void * user_data)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 
eloop_register_signal_terminate(eloop_signal_handler handler,void * user_data)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 	return ret;
421 }
422 
423 
eloop_register_signal_reconfig(eloop_signal_handler handler,void * user_data)424 int eloop_register_signal_reconfig(eloop_signal_handler handler,
425 				   void *user_data)
426 {
427 #ifdef CONFIG_NATIVE_WINDOWS
428 	return 0;
429 #else /* CONFIG_NATIVE_WINDOWS */
430 	return eloop_register_signal(SIGHUP, handler, user_data);
431 #endif /* CONFIG_NATIVE_WINDOWS */
432 }
433 
434 
eloop_run(void)435 void eloop_run(void)
436 {
437 	fd_set *rfds, *wfds, *efds;
438 	int res;
439 	struct timeval _tv;
440 	struct os_time tv, now;
441 
442 	rfds = os_malloc(sizeof(*rfds));
443 	wfds = os_malloc(sizeof(*wfds));
444 	efds = os_malloc(sizeof(*efds));
445 	if (rfds == NULL || wfds == NULL || efds == NULL) {
446 		printf("eloop_run - malloc failed\n");
447 		goto out;
448 	}
449 
450 	while (!eloop.terminate &&
451 	       (eloop.timeout || eloop.readers.count > 0 ||
452 		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
453 		if (eloop.timeout) {
454 			os_get_time(&now);
455 			if (os_time_before(&now, &eloop.timeout->time))
456 				os_time_sub(&eloop.timeout->time, &now, &tv);
457 			else
458 				tv.sec = tv.usec = 0;
459 #if 0
460 			printf("next timeout in %lu.%06lu sec\n",
461 			       tv.sec, tv.usec);
462 #endif
463 			_tv.tv_sec = tv.sec;
464 			_tv.tv_usec = tv.usec;
465 		}
466 
467 		eloop_sock_table_set_fds(&eloop.readers, rfds);
468 		eloop_sock_table_set_fds(&eloop.writers, wfds);
469 		eloop_sock_table_set_fds(&eloop.exceptions, efds);
470 		res = select(eloop.max_sock + 1, rfds, wfds, efds,
471 			     eloop.timeout ? &_tv : NULL);
472 		if (res < 0 && errno != EINTR && errno != 0) {
473 			perror("select");
474 			goto out;
475 		}
476 		eloop_process_pending_signals();
477 
478 		/* check if some registered timeouts have occurred */
479 		if (eloop.timeout) {
480 			struct eloop_timeout *tmp;
481 
482 			os_get_time(&now);
483 			if (!os_time_before(&now, &eloop.timeout->time)) {
484 				tmp = eloop.timeout;
485 				eloop.timeout = eloop.timeout->next;
486 				tmp->handler(tmp->eloop_data,
487 					     tmp->user_data);
488 				os_free(tmp);
489 			}
490 
491 		}
492 
493 		if (res <= 0)
494 			continue;
495 
496 		eloop_sock_table_dispatch(&eloop.readers, rfds);
497 		eloop_sock_table_dispatch(&eloop.writers, wfds);
498 		eloop_sock_table_dispatch(&eloop.exceptions, efds);
499 	}
500 
501 out:
502 	os_free(rfds);
503 	os_free(wfds);
504 	os_free(efds);
505 }
506 
507 
eloop_terminate(void)508 void eloop_terminate(void)
509 {
510 	eloop.terminate = 1;
511 }
512 
513 
eloop_destroy(void)514 void eloop_destroy(void)
515 {
516 	struct eloop_timeout *timeout, *prev;
517 
518 	timeout = eloop.timeout;
519 	while (timeout != NULL) {
520 		prev = timeout;
521 		timeout = timeout->next;
522 		os_free(prev);
523 	}
524 	eloop_sock_table_destroy(&eloop.readers);
525 	eloop_sock_table_destroy(&eloop.writers);
526 	eloop_sock_table_destroy(&eloop.exceptions);
527 	os_free(eloop.signals);
528 }
529 
530 
eloop_terminated(void)531 int eloop_terminated(void)
532 {
533 	return eloop.terminate;
534 }
535 
536 
eloop_wait_for_read_sock(int sock)537 void eloop_wait_for_read_sock(int sock)
538 {
539 	fd_set rfds;
540 
541 	if (sock < 0)
542 		return;
543 
544 	FD_ZERO(&rfds);
545 	FD_SET(sock, &rfds);
546 	select(sock + 1, &rfds, NULL, NULL, NULL);
547 }
548 
549 
eloop_get_user_data(void)550 void * eloop_get_user_data(void)
551 {
552 	return eloop.user_data;
553 }
554