1/*
2 * Event loop - empty template (basic structure, but no OS specific operations)
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	void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
26};
27
28struct eloop_timeout {
29	struct os_time time;
30	void *eloop_data;
31	void *user_data;
32	void (*handler)(void *eloop_ctx, void *sock_ctx);
33	struct eloop_timeout *next;
34};
35
36struct eloop_signal {
37	int sig;
38	void *user_data;
39	void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
40	int signaled;
41};
42
43struct eloop_data {
44	void *user_data;
45
46	int max_sock, reader_count;
47	struct eloop_sock *readers;
48
49	struct eloop_timeout *timeout;
50
51	int signal_count;
52	struct eloop_signal *signals;
53	int signaled;
54	int pending_terminate;
55
56	int terminate;
57	int reader_table_changed;
58};
59
60static struct eloop_data eloop;
61
62
63int eloop_init(void *user_data)
64{
65	memset(&eloop, 0, sizeof(eloop));
66	eloop.user_data = user_data;
67	return 0;
68}
69
70
71int eloop_register_read_sock(int sock,
72			     void (*handler)(int sock, void *eloop_ctx,
73					     void *sock_ctx),
74			     void *eloop_data, void *user_data)
75{
76	struct eloop_sock *tmp;
77
78	tmp = (struct eloop_sock *)
79		realloc(eloop.readers,
80			(eloop.reader_count + 1) * sizeof(struct eloop_sock));
81	if (tmp == NULL)
82		return -1;
83
84	tmp[eloop.reader_count].sock = sock;
85	tmp[eloop.reader_count].eloop_data = eloop_data;
86	tmp[eloop.reader_count].user_data = user_data;
87	tmp[eloop.reader_count].handler = handler;
88	eloop.reader_count++;
89	eloop.readers = tmp;
90	if (sock > eloop.max_sock)
91		eloop.max_sock = sock;
92	eloop.reader_table_changed = 1;
93
94	return 0;
95}
96
97
98void eloop_unregister_read_sock(int sock)
99{
100	int i;
101
102	if (eloop.readers == NULL || eloop.reader_count == 0)
103		return;
104
105	for (i = 0; i < eloop.reader_count; i++) {
106		if (eloop.readers[i].sock == sock)
107			break;
108	}
109	if (i == eloop.reader_count)
110		return;
111	if (i != eloop.reader_count - 1) {
112		memmove(&eloop.readers[i], &eloop.readers[i + 1],
113			(eloop.reader_count - i - 1) *
114			sizeof(struct eloop_sock));
115	}
116	eloop.reader_count--;
117	eloop.reader_table_changed = 1;
118}
119
120
121int eloop_register_timeout(unsigned int secs, unsigned int usecs,
122			   void (*handler)(void *eloop_ctx, void *timeout_ctx),
123			   void *eloop_data, void *user_data)
124{
125	struct eloop_timeout *timeout, *tmp, *prev;
126
127	timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
128	if (timeout == NULL)
129		return -1;
130	os_get_time(&timeout->time);
131	timeout->time.sec += secs;
132	timeout->time.usec += usecs;
133	while (timeout->time.usec >= 1000000) {
134		timeout->time.sec++;
135		timeout->time.usec -= 1000000;
136	}
137	timeout->eloop_data = eloop_data;
138	timeout->user_data = user_data;
139	timeout->handler = handler;
140	timeout->next = NULL;
141
142	if (eloop.timeout == NULL) {
143		eloop.timeout = timeout;
144		return 0;
145	}
146
147	prev = NULL;
148	tmp = eloop.timeout;
149	while (tmp != NULL) {
150		if (os_time_before(&timeout->time, &tmp->time))
151			break;
152		prev = tmp;
153		tmp = tmp->next;
154	}
155
156	if (prev == NULL) {
157		timeout->next = eloop.timeout;
158		eloop.timeout = timeout;
159	} else {
160		timeout->next = prev->next;
161		prev->next = timeout;
162	}
163
164	return 0;
165}
166
167
168int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
169			 void *eloop_data, void *user_data)
170{
171	struct eloop_timeout *timeout, *prev, *next;
172	int removed = 0;
173
174	prev = NULL;
175	timeout = eloop.timeout;
176	while (timeout != NULL) {
177		next = timeout->next;
178
179		if (timeout->handler == handler &&
180		    (timeout->eloop_data == eloop_data ||
181		     eloop_data == ELOOP_ALL_CTX) &&
182		    (timeout->user_data == user_data ||
183		     user_data == ELOOP_ALL_CTX)) {
184			if (prev == NULL)
185				eloop.timeout = next;
186			else
187				prev->next = next;
188			free(timeout);
189			removed++;
190		} else
191			prev = timeout;
192
193		timeout = next;
194	}
195
196	return removed;
197}
198
199
200int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx,
201						void *timeout_ctx),
202				void *eloop_data, void *user_data)
203{
204	struct eloop_timeout *tmp;
205
206	tmp = eloop.timeout;
207	while (tmp != NULL) {
208		if (tmp->handler == handler &&
209		    tmp->eloop_data == eloop_data &&
210		    tmp->user_data == user_data)
211			return 1;
212
213		tmp = tmp->next;
214	}
215
216	return 0;
217}
218
219
220/* TODO: replace with suitable signal handler */
221#if 0
222static void eloop_handle_signal(int sig)
223{
224	int i;
225
226	eloop.signaled++;
227	for (i = 0; i < eloop.signal_count; i++) {
228		if (eloop.signals[i].sig == sig) {
229			eloop.signals[i].signaled++;
230			break;
231		}
232	}
233}
234#endif
235
236
237static void eloop_process_pending_signals(void)
238{
239	int i;
240
241	if (eloop.signaled == 0)
242		return;
243	eloop.signaled = 0;
244
245	if (eloop.pending_terminate) {
246		eloop.pending_terminate = 0;
247	}
248
249	for (i = 0; i < eloop.signal_count; i++) {
250		if (eloop.signals[i].signaled) {
251			eloop.signals[i].signaled = 0;
252			eloop.signals[i].handler(eloop.signals[i].sig,
253						 eloop.user_data,
254						 eloop.signals[i].user_data);
255		}
256	}
257}
258
259
260int eloop_register_signal(int sig,
261			  void (*handler)(int sig, void *eloop_ctx,
262					  void *signal_ctx),
263			  void *user_data)
264{
265	struct eloop_signal *tmp;
266
267	tmp = (struct eloop_signal *)
268		realloc(eloop.signals,
269			(eloop.signal_count + 1) *
270			sizeof(struct eloop_signal));
271	if (tmp == NULL)
272		return -1;
273
274	tmp[eloop.signal_count].sig = sig;
275	tmp[eloop.signal_count].user_data = user_data;
276	tmp[eloop.signal_count].handler = handler;
277	tmp[eloop.signal_count].signaled = 0;
278	eloop.signal_count++;
279	eloop.signals = tmp;
280
281	/* TODO: register signal handler */
282
283	return 0;
284}
285
286
287int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx,
288						    void *signal_ctx),
289				    void *user_data)
290{
291#if 0
292	/* TODO: for example */
293	int ret = eloop_register_signal(SIGINT, handler, user_data);
294	if (ret == 0)
295		ret = eloop_register_signal(SIGTERM, handler, user_data);
296	return ret;
297#endif
298	return 0;
299}
300
301
302int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx,
303						   void *signal_ctx),
304				   void *user_data)
305{
306#if 0
307	/* TODO: for example */
308	return eloop_register_signal(SIGHUP, handler, user_data);
309#endif
310	return 0;
311}
312
313
314void eloop_run(void)
315{
316	int i;
317	struct os_time tv, now;
318
319	while (!eloop.terminate &&
320		(eloop.timeout || eloop.reader_count > 0)) {
321		if (eloop.timeout) {
322			os_get_time(&now);
323			if (os_time_before(&now, &eloop.timeout->time))
324				os_time_sub(&eloop.timeout->time, &now, &tv);
325			else
326				tv.sec = tv.usec = 0;
327		}
328
329		/*
330		 * TODO: wait for any event (read socket ready, timeout (tv),
331		 * signal
332		 */
333		os_sleep(1, 0); /* just a dummy wait for testing */
334
335		eloop_process_pending_signals();
336
337		/* check if some registered timeouts have occurred */
338		if (eloop.timeout) {
339			struct eloop_timeout *tmp;
340
341			os_get_time(&now);
342			if (!os_time_before(&now, &eloop.timeout->time)) {
343				tmp = eloop.timeout;
344				eloop.timeout = eloop.timeout->next;
345				tmp->handler(tmp->eloop_data,
346					     tmp->user_data);
347				free(tmp);
348			}
349
350		}
351
352		eloop.reader_table_changed = 0;
353		for (i = 0; i < eloop.reader_count; i++) {
354			/*
355			 * TODO: call each handler that has pending data to
356			 * read
357			 */
358			if (0 /* TODO: eloop.readers[i].sock ready */) {
359				eloop.readers[i].handler(
360					eloop.readers[i].sock,
361					eloop.readers[i].eloop_data,
362					eloop.readers[i].user_data);
363				if (eloop.reader_table_changed)
364					break;
365			}
366		}
367	}
368}
369
370
371void eloop_terminate(void)
372{
373	eloop.terminate = 1;
374}
375
376
377void eloop_destroy(void)
378{
379	struct eloop_timeout *timeout, *prev;
380
381	timeout = eloop.timeout;
382	while (timeout != NULL) {
383		prev = timeout;
384		timeout = timeout->next;
385		free(prev);
386	}
387	free(eloop.readers);
388	free(eloop.signals);
389}
390
391
392int eloop_terminated(void)
393{
394	return eloop.terminate;
395}
396
397
398void eloop_wait_for_read_sock(int sock)
399{
400	/*
401	 * TODO: wait for the file descriptor to have something available for
402	 * reading
403	 */
404}
405
406
407void * eloop_get_user_data(void)
408{
409	return eloop.user_data;
410}
411