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
21struct eloop_sock {
22	int sock;
23	void *eloop_data;
24	void *user_data;
25	eloop_sock_handler handler;
26};
27
28struct 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
36struct eloop_signal {
37	int sig;
38	void *user_data;
39	eloop_signal_handler handler;
40	int signaled;
41};
42
43struct eloop_sock_table {
44	int count;
45	struct eloop_sock *table;
46	int changed;
47};
48
49struct 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
69static struct eloop_data eloop;
70
71
72int 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
80static 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
109static 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
133static 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
148static 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
169static void eloop_sock_table_destroy(struct eloop_sock_table *table)
170{
171	if (table)
172		os_free(table->table);
173}
174
175
176int 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
184void eloop_unregister_read_sock(int sock)
185{
186	eloop_unregister_sock(sock, EVENT_TYPE_READ);
187}
188
189
190static 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
205int 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
217void 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
226int 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
276int 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
308int 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
328static 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
340static 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
364static 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
390int 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
414int 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	if (ret == 0)
421		ret = eloop_register_signal(SIGSEGV, handler, user_data);
422	return ret;
423}
424
425
426int eloop_register_signal_reconfig(eloop_signal_handler handler,
427				   void *user_data)
428{
429#ifdef CONFIG_NATIVE_WINDOWS
430	return 0;
431#else /* CONFIG_NATIVE_WINDOWS */
432	return eloop_register_signal(SIGHUP, handler, user_data);
433#endif /* CONFIG_NATIVE_WINDOWS */
434}
435
436
437void eloop_run(void)
438{
439	fd_set *rfds, *wfds, *efds;
440	int res;
441	struct timeval _tv;
442	struct os_time tv, now;
443
444	rfds = os_malloc(sizeof(*rfds));
445	wfds = os_malloc(sizeof(*wfds));
446	efds = os_malloc(sizeof(*efds));
447	if (rfds == NULL || wfds == NULL || efds == NULL) {
448		printf("eloop_run - malloc failed\n");
449		goto out;
450	}
451
452	while (!eloop.terminate &&
453	       (eloop.timeout || eloop.readers.count > 0 ||
454		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
455		if (eloop.timeout) {
456			os_get_time(&now);
457			if (os_time_before(&now, &eloop.timeout->time))
458				os_time_sub(&eloop.timeout->time, &now, &tv);
459			else
460				tv.sec = tv.usec = 0;
461#if 0
462			printf("next timeout in %lu.%06lu sec\n",
463			       tv.sec, tv.usec);
464#endif
465			_tv.tv_sec = tv.sec;
466			_tv.tv_usec = tv.usec;
467		}
468
469		eloop_sock_table_set_fds(&eloop.readers, rfds);
470		eloop_sock_table_set_fds(&eloop.writers, wfds);
471		eloop_sock_table_set_fds(&eloop.exceptions, efds);
472		res = select(eloop.max_sock + 1, rfds, wfds, efds,
473			     eloop.timeout ? &_tv : NULL);
474		if (res < 0 && errno != EINTR && errno != 0) {
475			perror("select");
476			goto out;
477		}
478		eloop_process_pending_signals();
479
480		/* check if some registered timeouts have occurred */
481		if (eloop.timeout) {
482			struct eloop_timeout *tmp;
483
484			os_get_time(&now);
485			if (!os_time_before(&now, &eloop.timeout->time)) {
486				tmp = eloop.timeout;
487				eloop.timeout = eloop.timeout->next;
488				tmp->handler(tmp->eloop_data,
489					     tmp->user_data);
490				os_free(tmp);
491			}
492
493		}
494
495		if (res <= 0)
496			continue;
497
498		eloop_sock_table_dispatch(&eloop.readers, rfds);
499		eloop_sock_table_dispatch(&eloop.writers, wfds);
500		eloop_sock_table_dispatch(&eloop.exceptions, efds);
501	}
502
503out:
504	os_free(rfds);
505	os_free(wfds);
506	os_free(efds);
507}
508
509
510void eloop_terminate(void)
511{
512	eloop.terminate = 1;
513}
514
515
516void eloop_destroy(void)
517{
518	struct eloop_timeout *timeout, *prev;
519
520	timeout = eloop.timeout;
521	while (timeout != NULL) {
522		prev = timeout;
523		timeout = timeout->next;
524		os_free(prev);
525	}
526	eloop_sock_table_destroy(&eloop.readers);
527	eloop_sock_table_destroy(&eloop.writers);
528	eloop_sock_table_destroy(&eloop.exceptions);
529	os_free(eloop.signals);
530}
531
532
533int eloop_terminated(void)
534{
535	return eloop.terminate;
536}
537
538
539void eloop_wait_for_read_sock(int sock)
540{
541	fd_set rfds;
542
543	if (sock < 0)
544		return;
545
546	FD_ZERO(&rfds);
547	FD_SET(sock, &rfds);
548	select(sock + 1, &rfds, NULL, NULL, NULL);
549}
550
551
552void * eloop_get_user_data(void)
553{
554	return eloop.user_data;
555}
556