16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer  * Event loop based on select() loop
33ff40c12SJohn Marino  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
76d49e1aeSJan Lentfer  */
86d49e1aeSJan Lentfer 
96d49e1aeSJan Lentfer #include "includes.h"
10*a1157835SDaniel Fojt #include <assert.h>
116d49e1aeSJan Lentfer 
126d49e1aeSJan Lentfer #include "common.h"
133ff40c12SJohn Marino #include "trace.h"
143ff40c12SJohn Marino #include "list.h"
156d49e1aeSJan Lentfer #include "eloop.h"
166d49e1aeSJan Lentfer 
17*a1157835SDaniel Fojt #if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_EPOLL)
18*a1157835SDaniel Fojt #error Do not define both of poll and epoll
19*a1157835SDaniel Fojt #endif
20*a1157835SDaniel Fojt 
21*a1157835SDaniel Fojt #if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_KQUEUE)
22*a1157835SDaniel Fojt #error Do not define both of poll and kqueue
23*a1157835SDaniel Fojt #endif
24*a1157835SDaniel Fojt 
25*a1157835SDaniel Fojt #if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) && \
26*a1157835SDaniel Fojt     !defined(CONFIG_ELOOP_KQUEUE)
27*a1157835SDaniel Fojt #define CONFIG_ELOOP_SELECT
28*a1157835SDaniel Fojt #endif
29*a1157835SDaniel Fojt 
303ff40c12SJohn Marino #ifdef CONFIG_ELOOP_POLL
313ff40c12SJohn Marino #include <poll.h>
323ff40c12SJohn Marino #endif /* CONFIG_ELOOP_POLL */
333ff40c12SJohn Marino 
34*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_EPOLL
35*a1157835SDaniel Fojt #include <sys/epoll.h>
36*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
37*a1157835SDaniel Fojt 
38*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
39*a1157835SDaniel Fojt #include <sys/event.h>
40*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
416d49e1aeSJan Lentfer 
426d49e1aeSJan Lentfer struct eloop_sock {
436d49e1aeSJan Lentfer 	int sock;
446d49e1aeSJan Lentfer 	void *eloop_data;
456d49e1aeSJan Lentfer 	void *user_data;
466d49e1aeSJan Lentfer 	eloop_sock_handler handler;
473ff40c12SJohn Marino 	WPA_TRACE_REF(eloop);
483ff40c12SJohn Marino 	WPA_TRACE_REF(user);
493ff40c12SJohn Marino 	WPA_TRACE_INFO
506d49e1aeSJan Lentfer };
516d49e1aeSJan Lentfer 
526d49e1aeSJan Lentfer struct eloop_timeout {
533ff40c12SJohn Marino 	struct dl_list list;
543ff40c12SJohn Marino 	struct os_reltime time;
556d49e1aeSJan Lentfer 	void *eloop_data;
566d49e1aeSJan Lentfer 	void *user_data;
576d49e1aeSJan Lentfer 	eloop_timeout_handler handler;
583ff40c12SJohn Marino 	WPA_TRACE_REF(eloop);
593ff40c12SJohn Marino 	WPA_TRACE_REF(user);
603ff40c12SJohn Marino 	WPA_TRACE_INFO
616d49e1aeSJan Lentfer };
626d49e1aeSJan Lentfer 
636d49e1aeSJan Lentfer struct eloop_signal {
646d49e1aeSJan Lentfer 	int sig;
656d49e1aeSJan Lentfer 	void *user_data;
666d49e1aeSJan Lentfer 	eloop_signal_handler handler;
676d49e1aeSJan Lentfer 	int signaled;
686d49e1aeSJan Lentfer };
696d49e1aeSJan Lentfer 
706d49e1aeSJan Lentfer struct eloop_sock_table {
716d49e1aeSJan Lentfer 	int count;
726d49e1aeSJan Lentfer 	struct eloop_sock *table;
73*a1157835SDaniel Fojt 	eloop_event_type type;
746d49e1aeSJan Lentfer 	int changed;
756d49e1aeSJan Lentfer };
766d49e1aeSJan Lentfer 
776d49e1aeSJan Lentfer struct eloop_data {
786d49e1aeSJan Lentfer 	int max_sock;
796d49e1aeSJan Lentfer 
803ff40c12SJohn Marino 	int count; /* sum of all table counts */
813ff40c12SJohn Marino #ifdef CONFIG_ELOOP_POLL
823ff40c12SJohn Marino 	int max_pollfd_map; /* number of pollfds_map currently allocated */
833ff40c12SJohn Marino 	int max_poll_fds; /* number of pollfds currently allocated */
843ff40c12SJohn Marino 	struct pollfd *pollfds;
853ff40c12SJohn Marino 	struct pollfd **pollfds_map;
863ff40c12SJohn Marino #endif /* CONFIG_ELOOP_POLL */
87*a1157835SDaniel Fojt #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
88*a1157835SDaniel Fojt 	int max_fd;
89*a1157835SDaniel Fojt 	struct eloop_sock *fd_table;
90*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
91*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_EPOLL
92*a1157835SDaniel Fojt 	int epollfd;
93*a1157835SDaniel Fojt 	int epoll_max_event_num;
94*a1157835SDaniel Fojt 	struct epoll_event *epoll_events;
95*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
96*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
97*a1157835SDaniel Fojt 	int kqueuefd;
98*a1157835SDaniel Fojt 	int kqueue_nevents;
99*a1157835SDaniel Fojt 	struct kevent *kqueue_events;
100*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
1016d49e1aeSJan Lentfer 	struct eloop_sock_table readers;
1026d49e1aeSJan Lentfer 	struct eloop_sock_table writers;
1036d49e1aeSJan Lentfer 	struct eloop_sock_table exceptions;
1046d49e1aeSJan Lentfer 
1053ff40c12SJohn Marino 	struct dl_list timeout;
1066d49e1aeSJan Lentfer 
1076d49e1aeSJan Lentfer 	int signal_count;
1086d49e1aeSJan Lentfer 	struct eloop_signal *signals;
1096d49e1aeSJan Lentfer 	int signaled;
1106d49e1aeSJan Lentfer 	int pending_terminate;
1116d49e1aeSJan Lentfer 
1126d49e1aeSJan Lentfer 	int terminate;
1136d49e1aeSJan Lentfer };
1146d49e1aeSJan Lentfer 
1156d49e1aeSJan Lentfer static struct eloop_data eloop;
1166d49e1aeSJan Lentfer 
1176d49e1aeSJan Lentfer 
1183ff40c12SJohn Marino #ifdef WPA_TRACE
1193ff40c12SJohn Marino 
eloop_sigsegv_handler(int sig)1203ff40c12SJohn Marino static void eloop_sigsegv_handler(int sig)
1213ff40c12SJohn Marino {
1223ff40c12SJohn Marino 	wpa_trace_show("eloop SIGSEGV");
1233ff40c12SJohn Marino 	abort();
1243ff40c12SJohn Marino }
1253ff40c12SJohn Marino 
eloop_trace_sock_add_ref(struct eloop_sock_table * table)1263ff40c12SJohn Marino static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
1273ff40c12SJohn Marino {
1283ff40c12SJohn Marino 	int i;
1293ff40c12SJohn Marino 	if (table == NULL || table->table == NULL)
1303ff40c12SJohn Marino 		return;
1313ff40c12SJohn Marino 	for (i = 0; i < table->count; i++) {
1323ff40c12SJohn Marino 		wpa_trace_add_ref(&table->table[i], eloop,
1333ff40c12SJohn Marino 				  table->table[i].eloop_data);
1343ff40c12SJohn Marino 		wpa_trace_add_ref(&table->table[i], user,
1353ff40c12SJohn Marino 				  table->table[i].user_data);
1363ff40c12SJohn Marino 	}
1373ff40c12SJohn Marino }
1383ff40c12SJohn Marino 
1393ff40c12SJohn Marino 
eloop_trace_sock_remove_ref(struct eloop_sock_table * table)1403ff40c12SJohn Marino static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
1413ff40c12SJohn Marino {
1423ff40c12SJohn Marino 	int i;
1433ff40c12SJohn Marino 	if (table == NULL || table->table == NULL)
1443ff40c12SJohn Marino 		return;
1453ff40c12SJohn Marino 	for (i = 0; i < table->count; i++) {
1463ff40c12SJohn Marino 		wpa_trace_remove_ref(&table->table[i], eloop,
1473ff40c12SJohn Marino 				     table->table[i].eloop_data);
1483ff40c12SJohn Marino 		wpa_trace_remove_ref(&table->table[i], user,
1493ff40c12SJohn Marino 				     table->table[i].user_data);
1503ff40c12SJohn Marino 	}
1513ff40c12SJohn Marino }
1523ff40c12SJohn Marino 
1533ff40c12SJohn Marino #else /* WPA_TRACE */
1543ff40c12SJohn Marino 
1553ff40c12SJohn Marino #define eloop_trace_sock_add_ref(table) do { } while (0)
1563ff40c12SJohn Marino #define eloop_trace_sock_remove_ref(table) do { } while (0)
1573ff40c12SJohn Marino 
1583ff40c12SJohn Marino #endif /* WPA_TRACE */
1593ff40c12SJohn Marino 
1603ff40c12SJohn Marino 
eloop_init(void)1613ff40c12SJohn Marino int eloop_init(void)
1626d49e1aeSJan Lentfer {
1636d49e1aeSJan Lentfer 	os_memset(&eloop, 0, sizeof(eloop));
1643ff40c12SJohn Marino 	dl_list_init(&eloop.timeout);
165*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_EPOLL
166*a1157835SDaniel Fojt 	eloop.epollfd = epoll_create1(0);
167*a1157835SDaniel Fojt 	if (eloop.epollfd < 0) {
168*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s",
169*a1157835SDaniel Fojt 			   __func__, strerror(errno));
170*a1157835SDaniel Fojt 		return -1;
171*a1157835SDaniel Fojt 	}
172*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
173*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
174*a1157835SDaniel Fojt 	eloop.kqueuefd = kqueue();
175*a1157835SDaniel Fojt 	if (eloop.kqueuefd < 0) {
176*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
177*a1157835SDaniel Fojt 			   __func__, strerror(errno));
178*a1157835SDaniel Fojt 		return -1;
179*a1157835SDaniel Fojt 	}
180*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
181*a1157835SDaniel Fojt #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
182*a1157835SDaniel Fojt 	eloop.readers.type = EVENT_TYPE_READ;
183*a1157835SDaniel Fojt 	eloop.writers.type = EVENT_TYPE_WRITE;
184*a1157835SDaniel Fojt 	eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
185*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
1863ff40c12SJohn Marino #ifdef WPA_TRACE
1873ff40c12SJohn Marino 	signal(SIGSEGV, eloop_sigsegv_handler);
1883ff40c12SJohn Marino #endif /* WPA_TRACE */
1896d49e1aeSJan Lentfer 	return 0;
1906d49e1aeSJan Lentfer }
1916d49e1aeSJan Lentfer 
1926d49e1aeSJan Lentfer 
193*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_EPOLL
eloop_sock_queue(int sock,eloop_event_type type)194*a1157835SDaniel Fojt static int eloop_sock_queue(int sock, eloop_event_type type)
195*a1157835SDaniel Fojt {
196*a1157835SDaniel Fojt 	struct epoll_event ev;
197*a1157835SDaniel Fojt 
198*a1157835SDaniel Fojt 	os_memset(&ev, 0, sizeof(ev));
199*a1157835SDaniel Fojt 	switch (type) {
200*a1157835SDaniel Fojt 	case EVENT_TYPE_READ:
201*a1157835SDaniel Fojt 		ev.events = EPOLLIN;
202*a1157835SDaniel Fojt 		break;
203*a1157835SDaniel Fojt 	case EVENT_TYPE_WRITE:
204*a1157835SDaniel Fojt 		ev.events = EPOLLOUT;
205*a1157835SDaniel Fojt 		break;
206*a1157835SDaniel Fojt 	/*
207*a1157835SDaniel Fojt 	 * Exceptions are always checked when using epoll, but I suppose it's
208*a1157835SDaniel Fojt 	 * possible that someone registered a socket *only* for exception
209*a1157835SDaniel Fojt 	 * handling.
210*a1157835SDaniel Fojt 	 */
211*a1157835SDaniel Fojt 	case EVENT_TYPE_EXCEPTION:
212*a1157835SDaniel Fojt 		ev.events = EPOLLERR | EPOLLHUP;
213*a1157835SDaniel Fojt 		break;
214*a1157835SDaniel Fojt 	}
215*a1157835SDaniel Fojt 	ev.data.fd = sock;
216*a1157835SDaniel Fojt 	if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
217*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d failed: %s",
218*a1157835SDaniel Fojt 			   __func__, sock, strerror(errno));
219*a1157835SDaniel Fojt 		return -1;
220*a1157835SDaniel Fojt 	}
221*a1157835SDaniel Fojt 	return 0;
222*a1157835SDaniel Fojt }
223*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
224*a1157835SDaniel Fojt 
225*a1157835SDaniel Fojt 
226*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
227*a1157835SDaniel Fojt 
event_type_kevent_filter(eloop_event_type type)228*a1157835SDaniel Fojt static short event_type_kevent_filter(eloop_event_type type)
229*a1157835SDaniel Fojt {
230*a1157835SDaniel Fojt 	switch (type) {
231*a1157835SDaniel Fojt 	case EVENT_TYPE_READ:
232*a1157835SDaniel Fojt 		return EVFILT_READ;
233*a1157835SDaniel Fojt 	case EVENT_TYPE_WRITE:
234*a1157835SDaniel Fojt 		return EVFILT_WRITE;
235*a1157835SDaniel Fojt 	default:
236*a1157835SDaniel Fojt 		return 0;
237*a1157835SDaniel Fojt 	}
238*a1157835SDaniel Fojt }
239*a1157835SDaniel Fojt 
240*a1157835SDaniel Fojt 
eloop_sock_queue(int sock,eloop_event_type type)241*a1157835SDaniel Fojt static int eloop_sock_queue(int sock, eloop_event_type type)
242*a1157835SDaniel Fojt {
243*a1157835SDaniel Fojt 	struct kevent ke;
244*a1157835SDaniel Fojt 
245*a1157835SDaniel Fojt 	EV_SET(&ke, sock, event_type_kevent_filter(type), EV_ADD, 0, 0, 0);
246*a1157835SDaniel Fojt 	if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) {
247*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d failed: %s",
248*a1157835SDaniel Fojt 			   __func__, sock, strerror(errno));
249*a1157835SDaniel Fojt 		return -1;
250*a1157835SDaniel Fojt 	}
251*a1157835SDaniel Fojt 	return 0;
252*a1157835SDaniel Fojt }
253*a1157835SDaniel Fojt 
254*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
255*a1157835SDaniel Fojt 
256*a1157835SDaniel Fojt 
eloop_sock_table_add_sock(struct eloop_sock_table * table,int sock,eloop_sock_handler handler,void * eloop_data,void * user_data)2576d49e1aeSJan Lentfer static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
2586d49e1aeSJan Lentfer                                      int sock, eloop_sock_handler handler,
2596d49e1aeSJan Lentfer                                      void *eloop_data, void *user_data)
2606d49e1aeSJan Lentfer {
261*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_EPOLL
262*a1157835SDaniel Fojt 	struct epoll_event *temp_events;
263*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
264*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
265*a1157835SDaniel Fojt 	struct kevent *temp_events;
266*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
267*a1157835SDaniel Fojt #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
268*a1157835SDaniel Fojt 	struct eloop_sock *temp_table;
269*a1157835SDaniel Fojt 	int next;
270*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
2716d49e1aeSJan Lentfer 	struct eloop_sock *tmp;
2723ff40c12SJohn Marino 	int new_max_sock;
2733ff40c12SJohn Marino 
2743ff40c12SJohn Marino 	if (sock > eloop.max_sock)
2753ff40c12SJohn Marino 		new_max_sock = sock;
2763ff40c12SJohn Marino 	else
2773ff40c12SJohn Marino 		new_max_sock = eloop.max_sock;
2786d49e1aeSJan Lentfer 
2796d49e1aeSJan Lentfer 	if (table == NULL)
2806d49e1aeSJan Lentfer 		return -1;
2816d49e1aeSJan Lentfer 
2823ff40c12SJohn Marino #ifdef CONFIG_ELOOP_POLL
2833ff40c12SJohn Marino 	if (new_max_sock >= eloop.max_pollfd_map) {
2843ff40c12SJohn Marino 		struct pollfd **nmap;
2853ff40c12SJohn Marino 		nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
2863ff40c12SJohn Marino 					sizeof(struct pollfd *));
2873ff40c12SJohn Marino 		if (nmap == NULL)
2883ff40c12SJohn Marino 			return -1;
2893ff40c12SJohn Marino 
2903ff40c12SJohn Marino 		eloop.max_pollfd_map = new_max_sock + 50;
2913ff40c12SJohn Marino 		eloop.pollfds_map = nmap;
2923ff40c12SJohn Marino 	}
2933ff40c12SJohn Marino 
2943ff40c12SJohn Marino 	if (eloop.count + 1 > eloop.max_poll_fds) {
2953ff40c12SJohn Marino 		struct pollfd *n;
2963ff40c12SJohn Marino 		int nmax = eloop.count + 1 + 50;
2973ff40c12SJohn Marino 		n = os_realloc_array(eloop.pollfds, nmax,
2983ff40c12SJohn Marino 				     sizeof(struct pollfd));
2993ff40c12SJohn Marino 		if (n == NULL)
3003ff40c12SJohn Marino 			return -1;
3013ff40c12SJohn Marino 
3023ff40c12SJohn Marino 		eloop.max_poll_fds = nmax;
3033ff40c12SJohn Marino 		eloop.pollfds = n;
3043ff40c12SJohn Marino 	}
3053ff40c12SJohn Marino #endif /* CONFIG_ELOOP_POLL */
306*a1157835SDaniel Fojt #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
307*a1157835SDaniel Fojt 	if (new_max_sock >= eloop.max_fd) {
308*a1157835SDaniel Fojt 		next = new_max_sock + 16;
309*a1157835SDaniel Fojt 		temp_table = os_realloc_array(eloop.fd_table, next,
310*a1157835SDaniel Fojt 					      sizeof(struct eloop_sock));
311*a1157835SDaniel Fojt 		if (temp_table == NULL)
312*a1157835SDaniel Fojt 			return -1;
313*a1157835SDaniel Fojt 
314*a1157835SDaniel Fojt 		eloop.max_fd = next;
315*a1157835SDaniel Fojt 		eloop.fd_table = temp_table;
316*a1157835SDaniel Fojt 	}
317*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
318*a1157835SDaniel Fojt 
319*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_EPOLL
320*a1157835SDaniel Fojt 	if (eloop.count + 1 > eloop.epoll_max_event_num) {
321*a1157835SDaniel Fojt 		next = eloop.epoll_max_event_num == 0 ? 8 :
322*a1157835SDaniel Fojt 			eloop.epoll_max_event_num * 2;
323*a1157835SDaniel Fojt 		temp_events = os_realloc_array(eloop.epoll_events, next,
324*a1157835SDaniel Fojt 					       sizeof(struct epoll_event));
325*a1157835SDaniel Fojt 		if (temp_events == NULL) {
326*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR, "%s: malloc for epoll failed: %s",
327*a1157835SDaniel Fojt 				   __func__, strerror(errno));
328*a1157835SDaniel Fojt 			return -1;
329*a1157835SDaniel Fojt 		}
330*a1157835SDaniel Fojt 
331*a1157835SDaniel Fojt 		eloop.epoll_max_event_num = next;
332*a1157835SDaniel Fojt 		eloop.epoll_events = temp_events;
333*a1157835SDaniel Fojt 	}
334*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
335*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
336*a1157835SDaniel Fojt 	if (eloop.count + 1 > eloop.kqueue_nevents) {
337*a1157835SDaniel Fojt 		next = eloop.kqueue_nevents == 0 ? 8 : eloop.kqueue_nevents * 2;
338*a1157835SDaniel Fojt 		temp_events = os_malloc(next * sizeof(*temp_events));
339*a1157835SDaniel Fojt 		if (!temp_events) {
340*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
341*a1157835SDaniel Fojt 				   "%s: malloc for kqueue failed: %s",
342*a1157835SDaniel Fojt 				   __func__, strerror(errno));
343*a1157835SDaniel Fojt 			return -1;
344*a1157835SDaniel Fojt 		}
345*a1157835SDaniel Fojt 
346*a1157835SDaniel Fojt 		os_free(eloop.kqueue_events);
347*a1157835SDaniel Fojt 		eloop.kqueue_events = temp_events;
348*a1157835SDaniel Fojt 		eloop.kqueue_nevents = next;
349*a1157835SDaniel Fojt 	}
350*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
3513ff40c12SJohn Marino 
3523ff40c12SJohn Marino 	eloop_trace_sock_remove_ref(table);
3533ff40c12SJohn Marino 	tmp = os_realloc_array(table->table, table->count + 1,
3543ff40c12SJohn Marino 			       sizeof(struct eloop_sock));
355*a1157835SDaniel Fojt 	if (tmp == NULL) {
356*a1157835SDaniel Fojt 		eloop_trace_sock_add_ref(table);
3576d49e1aeSJan Lentfer 		return -1;
358*a1157835SDaniel Fojt 	}
3596d49e1aeSJan Lentfer 
3606d49e1aeSJan Lentfer 	tmp[table->count].sock = sock;
3616d49e1aeSJan Lentfer 	tmp[table->count].eloop_data = eloop_data;
3626d49e1aeSJan Lentfer 	tmp[table->count].user_data = user_data;
3636d49e1aeSJan Lentfer 	tmp[table->count].handler = handler;
3643ff40c12SJohn Marino 	wpa_trace_record(&tmp[table->count]);
3656d49e1aeSJan Lentfer 	table->count++;
3666d49e1aeSJan Lentfer 	table->table = tmp;
3673ff40c12SJohn Marino 	eloop.max_sock = new_max_sock;
3683ff40c12SJohn Marino 	eloop.count++;
3696d49e1aeSJan Lentfer 	table->changed = 1;
3703ff40c12SJohn Marino 	eloop_trace_sock_add_ref(table);
3716d49e1aeSJan Lentfer 
372*a1157835SDaniel Fojt #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
373*a1157835SDaniel Fojt 	if (eloop_sock_queue(sock, table->type) < 0)
374*a1157835SDaniel Fojt 		return -1;
375*a1157835SDaniel Fojt 	os_memcpy(&eloop.fd_table[sock], &table->table[table->count - 1],
376*a1157835SDaniel Fojt 		  sizeof(struct eloop_sock));
377*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
3786d49e1aeSJan Lentfer 	return 0;
3796d49e1aeSJan Lentfer }
3806d49e1aeSJan Lentfer 
3816d49e1aeSJan Lentfer 
eloop_sock_table_remove_sock(struct eloop_sock_table * table,int sock)3826d49e1aeSJan Lentfer static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
3836d49e1aeSJan Lentfer                                          int sock)
3846d49e1aeSJan Lentfer {
385*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
386*a1157835SDaniel Fojt 	struct kevent ke;
387*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
3886d49e1aeSJan Lentfer 	int i;
3896d49e1aeSJan Lentfer 
3906d49e1aeSJan Lentfer 	if (table == NULL || table->table == NULL || table->count == 0)
3916d49e1aeSJan Lentfer 		return;
3926d49e1aeSJan Lentfer 
3936d49e1aeSJan Lentfer 	for (i = 0; i < table->count; i++) {
3946d49e1aeSJan Lentfer 		if (table->table[i].sock == sock)
3956d49e1aeSJan Lentfer 			break;
3966d49e1aeSJan Lentfer 	}
3976d49e1aeSJan Lentfer 	if (i == table->count)
3986d49e1aeSJan Lentfer 		return;
3993ff40c12SJohn Marino 	eloop_trace_sock_remove_ref(table);
4006d49e1aeSJan Lentfer 	if (i != table->count - 1) {
4016d49e1aeSJan Lentfer 		os_memmove(&table->table[i], &table->table[i + 1],
4026d49e1aeSJan Lentfer 			   (table->count - i - 1) *
4036d49e1aeSJan Lentfer 			   sizeof(struct eloop_sock));
4046d49e1aeSJan Lentfer 	}
4056d49e1aeSJan Lentfer 	table->count--;
4063ff40c12SJohn Marino 	eloop.count--;
4076d49e1aeSJan Lentfer 	table->changed = 1;
4083ff40c12SJohn Marino 	eloop_trace_sock_add_ref(table);
409*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_EPOLL
410*a1157835SDaniel Fojt 	if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) {
411*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d failed: %s",
412*a1157835SDaniel Fojt 			   __func__, sock, strerror(errno));
413*a1157835SDaniel Fojt 		return;
414*a1157835SDaniel Fojt 	}
415*a1157835SDaniel Fojt 	os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
416*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
417*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
418*a1157835SDaniel Fojt 	EV_SET(&ke, sock, event_type_kevent_filter(table->type), EV_DELETE, 0,
419*a1157835SDaniel Fojt 	       0, 0);
420*a1157835SDaniel Fojt 	if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) < 0) {
421*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d failed: %s",
422*a1157835SDaniel Fojt 			   __func__, sock, strerror(errno));
423*a1157835SDaniel Fojt 		return;
424*a1157835SDaniel Fojt 	}
425*a1157835SDaniel Fojt 	os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
426*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
4276d49e1aeSJan Lentfer }
4286d49e1aeSJan Lentfer 
4296d49e1aeSJan Lentfer 
4303ff40c12SJohn Marino #ifdef CONFIG_ELOOP_POLL
4313ff40c12SJohn Marino 
find_pollfd(struct pollfd ** pollfds_map,int fd,int mx)4323ff40c12SJohn Marino static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
4333ff40c12SJohn Marino {
4343ff40c12SJohn Marino 	if (fd < mx && fd >= 0)
4353ff40c12SJohn Marino 		return pollfds_map[fd];
4363ff40c12SJohn Marino 	return NULL;
4373ff40c12SJohn Marino }
4383ff40c12SJohn Marino 
4393ff40c12SJohn Marino 
eloop_sock_table_set_fds(struct eloop_sock_table * readers,struct eloop_sock_table * writers,struct eloop_sock_table * exceptions,struct pollfd * pollfds,struct pollfd ** pollfds_map,int max_pollfd_map)4403ff40c12SJohn Marino static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
4413ff40c12SJohn Marino 				    struct eloop_sock_table *writers,
4423ff40c12SJohn Marino 				    struct eloop_sock_table *exceptions,
4433ff40c12SJohn Marino 				    struct pollfd *pollfds,
4443ff40c12SJohn Marino 				    struct pollfd **pollfds_map,
4453ff40c12SJohn Marino 				    int max_pollfd_map)
4463ff40c12SJohn Marino {
4473ff40c12SJohn Marino 	int i;
4483ff40c12SJohn Marino 	int nxt = 0;
4493ff40c12SJohn Marino 	int fd;
4503ff40c12SJohn Marino 	struct pollfd *pfd;
4513ff40c12SJohn Marino 
4523ff40c12SJohn Marino 	/* Clear pollfd lookup map. It will be re-populated below. */
4533ff40c12SJohn Marino 	os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
4543ff40c12SJohn Marino 
4553ff40c12SJohn Marino 	if (readers && readers->table) {
4563ff40c12SJohn Marino 		for (i = 0; i < readers->count; i++) {
4573ff40c12SJohn Marino 			fd = readers->table[i].sock;
4583ff40c12SJohn Marino 			assert(fd >= 0 && fd < max_pollfd_map);
4593ff40c12SJohn Marino 			pollfds[nxt].fd = fd;
4603ff40c12SJohn Marino 			pollfds[nxt].events = POLLIN;
4613ff40c12SJohn Marino 			pollfds[nxt].revents = 0;
4623ff40c12SJohn Marino 			pollfds_map[fd] = &(pollfds[nxt]);
4633ff40c12SJohn Marino 			nxt++;
4643ff40c12SJohn Marino 		}
4653ff40c12SJohn Marino 	}
4663ff40c12SJohn Marino 
4673ff40c12SJohn Marino 	if (writers && writers->table) {
4683ff40c12SJohn Marino 		for (i = 0; i < writers->count; i++) {
4693ff40c12SJohn Marino 			/*
4703ff40c12SJohn Marino 			 * See if we already added this descriptor, update it
4713ff40c12SJohn Marino 			 * if so.
4723ff40c12SJohn Marino 			 */
4733ff40c12SJohn Marino 			fd = writers->table[i].sock;
4743ff40c12SJohn Marino 			assert(fd >= 0 && fd < max_pollfd_map);
4753ff40c12SJohn Marino 			pfd = pollfds_map[fd];
4763ff40c12SJohn Marino 			if (!pfd) {
4773ff40c12SJohn Marino 				pfd = &(pollfds[nxt]);
4783ff40c12SJohn Marino 				pfd->events = 0;
4793ff40c12SJohn Marino 				pfd->fd = fd;
4803ff40c12SJohn Marino 				pollfds[i].revents = 0;
4813ff40c12SJohn Marino 				pollfds_map[fd] = pfd;
4823ff40c12SJohn Marino 				nxt++;
4833ff40c12SJohn Marino 			}
4843ff40c12SJohn Marino 			pfd->events |= POLLOUT;
4853ff40c12SJohn Marino 		}
4863ff40c12SJohn Marino 	}
4873ff40c12SJohn Marino 
4883ff40c12SJohn Marino 	/*
4893ff40c12SJohn Marino 	 * Exceptions are always checked when using poll, but I suppose it's
4903ff40c12SJohn Marino 	 * possible that someone registered a socket *only* for exception
4913ff40c12SJohn Marino 	 * handling. Set the POLLIN bit in this case.
4923ff40c12SJohn Marino 	 */
4933ff40c12SJohn Marino 	if (exceptions && exceptions->table) {
4943ff40c12SJohn Marino 		for (i = 0; i < exceptions->count; i++) {
4953ff40c12SJohn Marino 			/*
4963ff40c12SJohn Marino 			 * See if we already added this descriptor, just use it
4973ff40c12SJohn Marino 			 * if so.
4983ff40c12SJohn Marino 			 */
4993ff40c12SJohn Marino 			fd = exceptions->table[i].sock;
5003ff40c12SJohn Marino 			assert(fd >= 0 && fd < max_pollfd_map);
5013ff40c12SJohn Marino 			pfd = pollfds_map[fd];
5023ff40c12SJohn Marino 			if (!pfd) {
5033ff40c12SJohn Marino 				pfd = &(pollfds[nxt]);
5043ff40c12SJohn Marino 				pfd->events = POLLIN;
5053ff40c12SJohn Marino 				pfd->fd = fd;
5063ff40c12SJohn Marino 				pollfds[i].revents = 0;
5073ff40c12SJohn Marino 				pollfds_map[fd] = pfd;
5083ff40c12SJohn Marino 				nxt++;
5093ff40c12SJohn Marino 			}
5103ff40c12SJohn Marino 		}
5113ff40c12SJohn Marino 	}
5123ff40c12SJohn Marino 
5133ff40c12SJohn Marino 	return nxt;
5143ff40c12SJohn Marino }
5153ff40c12SJohn Marino 
5163ff40c12SJohn Marino 
eloop_sock_table_dispatch_table(struct eloop_sock_table * table,struct pollfd ** pollfds_map,int max_pollfd_map,short int revents)5173ff40c12SJohn Marino static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
5183ff40c12SJohn Marino 					   struct pollfd **pollfds_map,
5193ff40c12SJohn Marino 					   int max_pollfd_map,
5203ff40c12SJohn Marino 					   short int revents)
5213ff40c12SJohn Marino {
5223ff40c12SJohn Marino 	int i;
5233ff40c12SJohn Marino 	struct pollfd *pfd;
5243ff40c12SJohn Marino 
5253ff40c12SJohn Marino 	if (!table || !table->table)
5263ff40c12SJohn Marino 		return 0;
5273ff40c12SJohn Marino 
5283ff40c12SJohn Marino 	table->changed = 0;
5293ff40c12SJohn Marino 	for (i = 0; i < table->count; i++) {
5303ff40c12SJohn Marino 		pfd = find_pollfd(pollfds_map, table->table[i].sock,
5313ff40c12SJohn Marino 				  max_pollfd_map);
5323ff40c12SJohn Marino 		if (!pfd)
5333ff40c12SJohn Marino 			continue;
5343ff40c12SJohn Marino 
5353ff40c12SJohn Marino 		if (!(pfd->revents & revents))
5363ff40c12SJohn Marino 			continue;
5373ff40c12SJohn Marino 
5383ff40c12SJohn Marino 		table->table[i].handler(table->table[i].sock,
5393ff40c12SJohn Marino 					table->table[i].eloop_data,
5403ff40c12SJohn Marino 					table->table[i].user_data);
5413ff40c12SJohn Marino 		if (table->changed)
5423ff40c12SJohn Marino 			return 1;
5433ff40c12SJohn Marino 	}
5443ff40c12SJohn Marino 
5453ff40c12SJohn Marino 	return 0;
5463ff40c12SJohn Marino }
5473ff40c12SJohn Marino 
5483ff40c12SJohn Marino 
eloop_sock_table_dispatch(struct eloop_sock_table * readers,struct eloop_sock_table * writers,struct eloop_sock_table * exceptions,struct pollfd ** pollfds_map,int max_pollfd_map)5493ff40c12SJohn Marino static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
5503ff40c12SJohn Marino 				      struct eloop_sock_table *writers,
5513ff40c12SJohn Marino 				      struct eloop_sock_table *exceptions,
5523ff40c12SJohn Marino 				      struct pollfd **pollfds_map,
5533ff40c12SJohn Marino 				      int max_pollfd_map)
5543ff40c12SJohn Marino {
5553ff40c12SJohn Marino 	if (eloop_sock_table_dispatch_table(readers, pollfds_map,
5563ff40c12SJohn Marino 					    max_pollfd_map, POLLIN | POLLERR |
5573ff40c12SJohn Marino 					    POLLHUP))
5583ff40c12SJohn Marino 		return; /* pollfds may be invalid at this point */
5593ff40c12SJohn Marino 
5603ff40c12SJohn Marino 	if (eloop_sock_table_dispatch_table(writers, pollfds_map,
5613ff40c12SJohn Marino 					    max_pollfd_map, POLLOUT))
5623ff40c12SJohn Marino 		return; /* pollfds may be invalid at this point */
5633ff40c12SJohn Marino 
5643ff40c12SJohn Marino 	eloop_sock_table_dispatch_table(exceptions, pollfds_map,
5653ff40c12SJohn Marino 					max_pollfd_map, POLLERR | POLLHUP);
5663ff40c12SJohn Marino }
5673ff40c12SJohn Marino 
568*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_POLL */
569*a1157835SDaniel Fojt 
570*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_SELECT
5713ff40c12SJohn Marino 
eloop_sock_table_set_fds(struct eloop_sock_table * table,fd_set * fds)5726d49e1aeSJan Lentfer static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
5736d49e1aeSJan Lentfer 				     fd_set *fds)
5746d49e1aeSJan Lentfer {
5756d49e1aeSJan Lentfer 	int i;
5766d49e1aeSJan Lentfer 
5776d49e1aeSJan Lentfer 	FD_ZERO(fds);
5786d49e1aeSJan Lentfer 
5796d49e1aeSJan Lentfer 	if (table->table == NULL)
5806d49e1aeSJan Lentfer 		return;
5816d49e1aeSJan Lentfer 
582*a1157835SDaniel Fojt 	for (i = 0; i < table->count; i++) {
583*a1157835SDaniel Fojt 		assert(table->table[i].sock >= 0);
5846d49e1aeSJan Lentfer 		FD_SET(table->table[i].sock, fds);
5856d49e1aeSJan Lentfer 	}
586*a1157835SDaniel Fojt }
5876d49e1aeSJan Lentfer 
5886d49e1aeSJan Lentfer 
eloop_sock_table_dispatch(struct eloop_sock_table * table,fd_set * fds)5896d49e1aeSJan Lentfer static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
5906d49e1aeSJan Lentfer 				      fd_set *fds)
5916d49e1aeSJan Lentfer {
5926d49e1aeSJan Lentfer 	int i;
5936d49e1aeSJan Lentfer 
5946d49e1aeSJan Lentfer 	if (table == NULL || table->table == NULL)
5956d49e1aeSJan Lentfer 		return;
5966d49e1aeSJan Lentfer 
5976d49e1aeSJan Lentfer 	table->changed = 0;
5986d49e1aeSJan Lentfer 	for (i = 0; i < table->count; i++) {
5996d49e1aeSJan Lentfer 		if (FD_ISSET(table->table[i].sock, fds)) {
6006d49e1aeSJan Lentfer 			table->table[i].handler(table->table[i].sock,
6016d49e1aeSJan Lentfer 						table->table[i].eloop_data,
6026d49e1aeSJan Lentfer 						table->table[i].user_data);
6036d49e1aeSJan Lentfer 			if (table->changed)
6046d49e1aeSJan Lentfer 				break;
6056d49e1aeSJan Lentfer 		}
6066d49e1aeSJan Lentfer 	}
6076d49e1aeSJan Lentfer }
6086d49e1aeSJan Lentfer 
609*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_SELECT */
610*a1157835SDaniel Fojt 
611*a1157835SDaniel Fojt 
612*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_EPOLL
eloop_sock_table_dispatch(struct epoll_event * events,int nfds)613*a1157835SDaniel Fojt static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
614*a1157835SDaniel Fojt {
615*a1157835SDaniel Fojt 	struct eloop_sock *table;
616*a1157835SDaniel Fojt 	int i;
617*a1157835SDaniel Fojt 
618*a1157835SDaniel Fojt 	for (i = 0; i < nfds; i++) {
619*a1157835SDaniel Fojt 		table = &eloop.fd_table[events[i].data.fd];
620*a1157835SDaniel Fojt 		if (table->handler == NULL)
621*a1157835SDaniel Fojt 			continue;
622*a1157835SDaniel Fojt 		table->handler(table->sock, table->eloop_data,
623*a1157835SDaniel Fojt 			       table->user_data);
624*a1157835SDaniel Fojt 		if (eloop.readers.changed ||
625*a1157835SDaniel Fojt 		    eloop.writers.changed ||
626*a1157835SDaniel Fojt 		    eloop.exceptions.changed)
627*a1157835SDaniel Fojt 			break;
628*a1157835SDaniel Fojt 	}
629*a1157835SDaniel Fojt }
630*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
631*a1157835SDaniel Fojt 
632*a1157835SDaniel Fojt 
633*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
634*a1157835SDaniel Fojt 
eloop_sock_table_dispatch(struct kevent * events,int nfds)635*a1157835SDaniel Fojt static void eloop_sock_table_dispatch(struct kevent *events, int nfds)
636*a1157835SDaniel Fojt {
637*a1157835SDaniel Fojt 	struct eloop_sock *table;
638*a1157835SDaniel Fojt 	int i;
639*a1157835SDaniel Fojt 
640*a1157835SDaniel Fojt 	for (i = 0; i < nfds; i++) {
641*a1157835SDaniel Fojt 		table = &eloop.fd_table[events[i].ident];
642*a1157835SDaniel Fojt 		if (table->handler == NULL)
643*a1157835SDaniel Fojt 			continue;
644*a1157835SDaniel Fojt 		table->handler(table->sock, table->eloop_data,
645*a1157835SDaniel Fojt 			       table->user_data);
646*a1157835SDaniel Fojt 		if (eloop.readers.changed ||
647*a1157835SDaniel Fojt 		    eloop.writers.changed ||
648*a1157835SDaniel Fojt 		    eloop.exceptions.changed)
649*a1157835SDaniel Fojt 			break;
650*a1157835SDaniel Fojt 	}
651*a1157835SDaniel Fojt }
652*a1157835SDaniel Fojt 
653*a1157835SDaniel Fojt 
eloop_sock_table_requeue(struct eloop_sock_table * table)654*a1157835SDaniel Fojt static int eloop_sock_table_requeue(struct eloop_sock_table *table)
655*a1157835SDaniel Fojt {
656*a1157835SDaniel Fojt 	int i, r;
657*a1157835SDaniel Fojt 
658*a1157835SDaniel Fojt 	r = 0;
659*a1157835SDaniel Fojt 	for (i = 0; i < table->count && table->table; i++) {
660*a1157835SDaniel Fojt 		if (eloop_sock_queue(table->table[i].sock, table->type) == -1)
661*a1157835SDaniel Fojt 			r = -1;
662*a1157835SDaniel Fojt 	}
663*a1157835SDaniel Fojt 	return r;
664*a1157835SDaniel Fojt }
665*a1157835SDaniel Fojt 
666*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
667*a1157835SDaniel Fojt 
668*a1157835SDaniel Fojt 
eloop_sock_requeue(void)669*a1157835SDaniel Fojt int eloop_sock_requeue(void)
670*a1157835SDaniel Fojt {
671*a1157835SDaniel Fojt 	int r = 0;
672*a1157835SDaniel Fojt 
673*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
674*a1157835SDaniel Fojt 	close(eloop.kqueuefd);
675*a1157835SDaniel Fojt 	eloop.kqueuefd = kqueue();
676*a1157835SDaniel Fojt 	if (eloop.kqueuefd < 0) {
677*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
678*a1157835SDaniel Fojt 			   __func__, strerror(errno));
679*a1157835SDaniel Fojt 		return -1;
680*a1157835SDaniel Fojt 	}
681*a1157835SDaniel Fojt 
682*a1157835SDaniel Fojt 	if (eloop_sock_table_requeue(&eloop.readers) < 0)
683*a1157835SDaniel Fojt 		r = -1;
684*a1157835SDaniel Fojt 	if (eloop_sock_table_requeue(&eloop.writers) < 0)
685*a1157835SDaniel Fojt 		r = -1;
686*a1157835SDaniel Fojt 	if (eloop_sock_table_requeue(&eloop.exceptions) < 0)
687*a1157835SDaniel Fojt 		r = -1;
688*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
689*a1157835SDaniel Fojt 
690*a1157835SDaniel Fojt 	return r;
691*a1157835SDaniel Fojt }
6923ff40c12SJohn Marino 
6936d49e1aeSJan Lentfer 
eloop_sock_table_destroy(struct eloop_sock_table * table)6946d49e1aeSJan Lentfer static void eloop_sock_table_destroy(struct eloop_sock_table *table)
6956d49e1aeSJan Lentfer {
6966d49e1aeSJan Lentfer 	if (table) {
6976d49e1aeSJan Lentfer 		int i;
6986d49e1aeSJan Lentfer 		for (i = 0; i < table->count && table->table; i++) {
6993ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
7003ff40c12SJohn Marino 				   "sock=%d eloop_data=%p user_data=%p "
7013ff40c12SJohn Marino 				   "handler=%p",
7026d49e1aeSJan Lentfer 				   table->table[i].sock,
7036d49e1aeSJan Lentfer 				   table->table[i].eloop_data,
7046d49e1aeSJan Lentfer 				   table->table[i].user_data,
7056d49e1aeSJan Lentfer 				   table->table[i].handler);
7063ff40c12SJohn Marino 			wpa_trace_dump_funcname("eloop unregistered socket "
7073ff40c12SJohn Marino 						"handler",
7083ff40c12SJohn Marino 						table->table[i].handler);
7093ff40c12SJohn Marino 			wpa_trace_dump("eloop sock", &table->table[i]);
7106d49e1aeSJan Lentfer 		}
7116d49e1aeSJan Lentfer 		os_free(table->table);
7126d49e1aeSJan Lentfer 	}
7136d49e1aeSJan Lentfer }
7146d49e1aeSJan Lentfer 
7156d49e1aeSJan Lentfer 
eloop_register_read_sock(int sock,eloop_sock_handler handler,void * eloop_data,void * user_data)7166d49e1aeSJan Lentfer int eloop_register_read_sock(int sock, eloop_sock_handler handler,
7176d49e1aeSJan Lentfer 			     void *eloop_data, void *user_data)
7186d49e1aeSJan Lentfer {
7196d49e1aeSJan Lentfer 	return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
7206d49e1aeSJan Lentfer 				   eloop_data, user_data);
7216d49e1aeSJan Lentfer }
7226d49e1aeSJan Lentfer 
7236d49e1aeSJan Lentfer 
eloop_unregister_read_sock(int sock)7246d49e1aeSJan Lentfer void eloop_unregister_read_sock(int sock)
7256d49e1aeSJan Lentfer {
7266d49e1aeSJan Lentfer 	eloop_unregister_sock(sock, EVENT_TYPE_READ);
7276d49e1aeSJan Lentfer }
7286d49e1aeSJan Lentfer 
7296d49e1aeSJan Lentfer 
eloop_get_sock_table(eloop_event_type type)7306d49e1aeSJan Lentfer static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
7316d49e1aeSJan Lentfer {
7326d49e1aeSJan Lentfer 	switch (type) {
7336d49e1aeSJan Lentfer 	case EVENT_TYPE_READ:
7346d49e1aeSJan Lentfer 		return &eloop.readers;
7356d49e1aeSJan Lentfer 	case EVENT_TYPE_WRITE:
7366d49e1aeSJan Lentfer 		return &eloop.writers;
7376d49e1aeSJan Lentfer 	case EVENT_TYPE_EXCEPTION:
7386d49e1aeSJan Lentfer 		return &eloop.exceptions;
7396d49e1aeSJan Lentfer 	}
7406d49e1aeSJan Lentfer 
7416d49e1aeSJan Lentfer 	return NULL;
7426d49e1aeSJan Lentfer }
7436d49e1aeSJan Lentfer 
7446d49e1aeSJan Lentfer 
eloop_register_sock(int sock,eloop_event_type type,eloop_sock_handler handler,void * eloop_data,void * user_data)7456d49e1aeSJan Lentfer int eloop_register_sock(int sock, eloop_event_type type,
7466d49e1aeSJan Lentfer 			eloop_sock_handler handler,
7476d49e1aeSJan Lentfer 			void *eloop_data, void *user_data)
7486d49e1aeSJan Lentfer {
7496d49e1aeSJan Lentfer 	struct eloop_sock_table *table;
7506d49e1aeSJan Lentfer 
751*a1157835SDaniel Fojt 	assert(sock >= 0);
7526d49e1aeSJan Lentfer 	table = eloop_get_sock_table(type);
7536d49e1aeSJan Lentfer 	return eloop_sock_table_add_sock(table, sock, handler,
7546d49e1aeSJan Lentfer 					 eloop_data, user_data);
7556d49e1aeSJan Lentfer }
7566d49e1aeSJan Lentfer 
7576d49e1aeSJan Lentfer 
eloop_unregister_sock(int sock,eloop_event_type type)7586d49e1aeSJan Lentfer void eloop_unregister_sock(int sock, eloop_event_type type)
7596d49e1aeSJan Lentfer {
7606d49e1aeSJan Lentfer 	struct eloop_sock_table *table;
7616d49e1aeSJan Lentfer 
7626d49e1aeSJan Lentfer 	table = eloop_get_sock_table(type);
7636d49e1aeSJan Lentfer 	eloop_sock_table_remove_sock(table, sock);
7646d49e1aeSJan Lentfer }
7656d49e1aeSJan Lentfer 
7666d49e1aeSJan Lentfer 
eloop_register_timeout(unsigned int secs,unsigned int usecs,eloop_timeout_handler handler,void * eloop_data,void * user_data)7676d49e1aeSJan Lentfer int eloop_register_timeout(unsigned int secs, unsigned int usecs,
7686d49e1aeSJan Lentfer 			   eloop_timeout_handler handler,
7696d49e1aeSJan Lentfer 			   void *eloop_data, void *user_data)
7706d49e1aeSJan Lentfer {
7713ff40c12SJohn Marino 	struct eloop_timeout *timeout, *tmp;
7723ff40c12SJohn Marino 	os_time_t now_sec;
7736d49e1aeSJan Lentfer 
7743ff40c12SJohn Marino 	timeout = os_zalloc(sizeof(*timeout));
7756d49e1aeSJan Lentfer 	if (timeout == NULL)
7766d49e1aeSJan Lentfer 		return -1;
7773ff40c12SJohn Marino 	if (os_get_reltime(&timeout->time) < 0) {
7786d49e1aeSJan Lentfer 		os_free(timeout);
7796d49e1aeSJan Lentfer 		return -1;
7806d49e1aeSJan Lentfer 	}
7813ff40c12SJohn Marino 	now_sec = timeout->time.sec;
7826d49e1aeSJan Lentfer 	timeout->time.sec += secs;
7833ff40c12SJohn Marino 	if (timeout->time.sec < now_sec) {
7843ff40c12SJohn Marino 		/*
7853ff40c12SJohn Marino 		 * Integer overflow - assume long enough timeout to be assumed
7863ff40c12SJohn Marino 		 * to be infinite, i.e., the timeout would never happen.
7873ff40c12SJohn Marino 		 */
7883ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
7893ff40c12SJohn Marino 			   "ever happen - ignore it", secs);
7903ff40c12SJohn Marino 		os_free(timeout);
7913ff40c12SJohn Marino 		return 0;
7923ff40c12SJohn Marino 	}
7936d49e1aeSJan Lentfer 	timeout->time.usec += usecs;
7946d49e1aeSJan Lentfer 	while (timeout->time.usec >= 1000000) {
7956d49e1aeSJan Lentfer 		timeout->time.sec++;
7966d49e1aeSJan Lentfer 		timeout->time.usec -= 1000000;
7976d49e1aeSJan Lentfer 	}
7986d49e1aeSJan Lentfer 	timeout->eloop_data = eloop_data;
7996d49e1aeSJan Lentfer 	timeout->user_data = user_data;
8006d49e1aeSJan Lentfer 	timeout->handler = handler;
8013ff40c12SJohn Marino 	wpa_trace_add_ref(timeout, eloop, eloop_data);
8023ff40c12SJohn Marino 	wpa_trace_add_ref(timeout, user, user_data);
8033ff40c12SJohn Marino 	wpa_trace_record(timeout);
8046d49e1aeSJan Lentfer 
8053ff40c12SJohn Marino 	/* Maintain timeouts in order of increasing time */
8063ff40c12SJohn Marino 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
8073ff40c12SJohn Marino 		if (os_reltime_before(&timeout->time, &tmp->time)) {
8083ff40c12SJohn Marino 			dl_list_add(tmp->list.prev, &timeout->list);
8093ff40c12SJohn Marino 			return 0;
8103ff40c12SJohn Marino 		}
8113ff40c12SJohn Marino 	}
8123ff40c12SJohn Marino 	dl_list_add_tail(&eloop.timeout, &timeout->list);
8133ff40c12SJohn Marino 
8146d49e1aeSJan Lentfer 	return 0;
8156d49e1aeSJan Lentfer }
8166d49e1aeSJan Lentfer 
8176d49e1aeSJan Lentfer 
eloop_remove_timeout(struct eloop_timeout * timeout)8183ff40c12SJohn Marino static void eloop_remove_timeout(struct eloop_timeout *timeout)
8193ff40c12SJohn Marino {
8203ff40c12SJohn Marino 	dl_list_del(&timeout->list);
8213ff40c12SJohn Marino 	wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
8223ff40c12SJohn Marino 	wpa_trace_remove_ref(timeout, user, timeout->user_data);
8233ff40c12SJohn Marino 	os_free(timeout);
8246d49e1aeSJan Lentfer }
8256d49e1aeSJan Lentfer 
8266d49e1aeSJan Lentfer 
eloop_cancel_timeout(eloop_timeout_handler handler,void * eloop_data,void * user_data)8276d49e1aeSJan Lentfer int eloop_cancel_timeout(eloop_timeout_handler handler,
8286d49e1aeSJan Lentfer 			 void *eloop_data, void *user_data)
8296d49e1aeSJan Lentfer {
8303ff40c12SJohn Marino 	struct eloop_timeout *timeout, *prev;
8316d49e1aeSJan Lentfer 	int removed = 0;
8326d49e1aeSJan Lentfer 
8333ff40c12SJohn Marino 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
8343ff40c12SJohn Marino 			      struct eloop_timeout, list) {
8356d49e1aeSJan Lentfer 		if (timeout->handler == handler &&
8366d49e1aeSJan Lentfer 		    (timeout->eloop_data == eloop_data ||
8376d49e1aeSJan Lentfer 		     eloop_data == ELOOP_ALL_CTX) &&
8386d49e1aeSJan Lentfer 		    (timeout->user_data == user_data ||
8396d49e1aeSJan Lentfer 		     user_data == ELOOP_ALL_CTX)) {
8403ff40c12SJohn Marino 			eloop_remove_timeout(timeout);
8416d49e1aeSJan Lentfer 			removed++;
8423ff40c12SJohn Marino 		}
8436d49e1aeSJan Lentfer 	}
8446d49e1aeSJan Lentfer 
8456d49e1aeSJan Lentfer 	return removed;
8466d49e1aeSJan Lentfer }
8476d49e1aeSJan Lentfer 
8486d49e1aeSJan Lentfer 
eloop_cancel_timeout_one(eloop_timeout_handler handler,void * eloop_data,void * user_data,struct os_reltime * remaining)8493ff40c12SJohn Marino int eloop_cancel_timeout_one(eloop_timeout_handler handler,
8503ff40c12SJohn Marino 			     void *eloop_data, void *user_data,
8513ff40c12SJohn Marino 			     struct os_reltime *remaining)
8523ff40c12SJohn Marino {
8533ff40c12SJohn Marino 	struct eloop_timeout *timeout, *prev;
8543ff40c12SJohn Marino 	int removed = 0;
8553ff40c12SJohn Marino 	struct os_reltime now;
8563ff40c12SJohn Marino 
8573ff40c12SJohn Marino 	os_get_reltime(&now);
8583ff40c12SJohn Marino 	remaining->sec = remaining->usec = 0;
8593ff40c12SJohn Marino 
8603ff40c12SJohn Marino 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
8613ff40c12SJohn Marino 			      struct eloop_timeout, list) {
8623ff40c12SJohn Marino 		if (timeout->handler == handler &&
8633ff40c12SJohn Marino 		    (timeout->eloop_data == eloop_data) &&
8643ff40c12SJohn Marino 		    (timeout->user_data == user_data)) {
8653ff40c12SJohn Marino 			removed = 1;
8663ff40c12SJohn Marino 			if (os_reltime_before(&now, &timeout->time))
8673ff40c12SJohn Marino 				os_reltime_sub(&timeout->time, &now, remaining);
8683ff40c12SJohn Marino 			eloop_remove_timeout(timeout);
8693ff40c12SJohn Marino 			break;
8703ff40c12SJohn Marino 		}
8713ff40c12SJohn Marino 	}
8723ff40c12SJohn Marino 	return removed;
8733ff40c12SJohn Marino }
8743ff40c12SJohn Marino 
8753ff40c12SJohn Marino 
eloop_is_timeout_registered(eloop_timeout_handler handler,void * eloop_data,void * user_data)8766d49e1aeSJan Lentfer int eloop_is_timeout_registered(eloop_timeout_handler handler,
8776d49e1aeSJan Lentfer 				void *eloop_data, void *user_data)
8786d49e1aeSJan Lentfer {
8796d49e1aeSJan Lentfer 	struct eloop_timeout *tmp;
8806d49e1aeSJan Lentfer 
8813ff40c12SJohn Marino 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
8826d49e1aeSJan Lentfer 		if (tmp->handler == handler &&
8836d49e1aeSJan Lentfer 		    tmp->eloop_data == eloop_data &&
8846d49e1aeSJan Lentfer 		    tmp->user_data == user_data)
8856d49e1aeSJan Lentfer 			return 1;
8866d49e1aeSJan Lentfer 	}
8876d49e1aeSJan Lentfer 
8886d49e1aeSJan Lentfer 	return 0;
8896d49e1aeSJan Lentfer }
8906d49e1aeSJan Lentfer 
8916d49e1aeSJan Lentfer 
eloop_deplete_timeout(unsigned int req_secs,unsigned int req_usecs,eloop_timeout_handler handler,void * eloop_data,void * user_data)8923ff40c12SJohn Marino int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
8933ff40c12SJohn Marino 			  eloop_timeout_handler handler, void *eloop_data,
8943ff40c12SJohn Marino 			  void *user_data)
8953ff40c12SJohn Marino {
8963ff40c12SJohn Marino 	struct os_reltime now, requested, remaining;
8973ff40c12SJohn Marino 	struct eloop_timeout *tmp;
8983ff40c12SJohn Marino 
8993ff40c12SJohn Marino 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
9003ff40c12SJohn Marino 		if (tmp->handler == handler &&
9013ff40c12SJohn Marino 		    tmp->eloop_data == eloop_data &&
9023ff40c12SJohn Marino 		    tmp->user_data == user_data) {
9033ff40c12SJohn Marino 			requested.sec = req_secs;
9043ff40c12SJohn Marino 			requested.usec = req_usecs;
9053ff40c12SJohn Marino 			os_get_reltime(&now);
9063ff40c12SJohn Marino 			os_reltime_sub(&tmp->time, &now, &remaining);
9073ff40c12SJohn Marino 			if (os_reltime_before(&requested, &remaining)) {
9083ff40c12SJohn Marino 				eloop_cancel_timeout(handler, eloop_data,
9093ff40c12SJohn Marino 						     user_data);
9103ff40c12SJohn Marino 				eloop_register_timeout(requested.sec,
9113ff40c12SJohn Marino 						       requested.usec,
9123ff40c12SJohn Marino 						       handler, eloop_data,
9133ff40c12SJohn Marino 						       user_data);
9143ff40c12SJohn Marino 				return 1;
9153ff40c12SJohn Marino 			}
9163ff40c12SJohn Marino 			return 0;
9173ff40c12SJohn Marino 		}
9183ff40c12SJohn Marino 	}
9193ff40c12SJohn Marino 
9203ff40c12SJohn Marino 	return -1;
9213ff40c12SJohn Marino }
9223ff40c12SJohn Marino 
9233ff40c12SJohn Marino 
eloop_replenish_timeout(unsigned int req_secs,unsigned int req_usecs,eloop_timeout_handler handler,void * eloop_data,void * user_data)9243ff40c12SJohn Marino int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
9253ff40c12SJohn Marino 			    eloop_timeout_handler handler, void *eloop_data,
9263ff40c12SJohn Marino 			    void *user_data)
9273ff40c12SJohn Marino {
9283ff40c12SJohn Marino 	struct os_reltime now, requested, remaining;
9293ff40c12SJohn Marino 	struct eloop_timeout *tmp;
9303ff40c12SJohn Marino 
9313ff40c12SJohn Marino 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
9323ff40c12SJohn Marino 		if (tmp->handler == handler &&
9333ff40c12SJohn Marino 		    tmp->eloop_data == eloop_data &&
9343ff40c12SJohn Marino 		    tmp->user_data == user_data) {
9353ff40c12SJohn Marino 			requested.sec = req_secs;
9363ff40c12SJohn Marino 			requested.usec = req_usecs;
9373ff40c12SJohn Marino 			os_get_reltime(&now);
9383ff40c12SJohn Marino 			os_reltime_sub(&tmp->time, &now, &remaining);
9393ff40c12SJohn Marino 			if (os_reltime_before(&remaining, &requested)) {
9403ff40c12SJohn Marino 				eloop_cancel_timeout(handler, eloop_data,
9413ff40c12SJohn Marino 						     user_data);
9423ff40c12SJohn Marino 				eloop_register_timeout(requested.sec,
9433ff40c12SJohn Marino 						       requested.usec,
9443ff40c12SJohn Marino 						       handler, eloop_data,
9453ff40c12SJohn Marino 						       user_data);
9463ff40c12SJohn Marino 				return 1;
9473ff40c12SJohn Marino 			}
9483ff40c12SJohn Marino 			return 0;
9493ff40c12SJohn Marino 		}
9503ff40c12SJohn Marino 	}
9513ff40c12SJohn Marino 
9523ff40c12SJohn Marino 	return -1;
9533ff40c12SJohn Marino }
9543ff40c12SJohn Marino 
9553ff40c12SJohn Marino 
9566d49e1aeSJan Lentfer #ifndef CONFIG_NATIVE_WINDOWS
eloop_handle_alarm(int sig)9576d49e1aeSJan Lentfer static void eloop_handle_alarm(int sig)
9586d49e1aeSJan Lentfer {
9593ff40c12SJohn Marino 	wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
9603ff40c12SJohn Marino 		   "two seconds. Looks like there\n"
9616d49e1aeSJan Lentfer 		   "is a bug that ends up in a busy loop that "
9626d49e1aeSJan Lentfer 		   "prevents clean shutdown.\n"
9636d49e1aeSJan Lentfer 		   "Killing program forcefully.\n");
9646d49e1aeSJan Lentfer 	exit(1);
9656d49e1aeSJan Lentfer }
9666d49e1aeSJan Lentfer #endif /* CONFIG_NATIVE_WINDOWS */
9676d49e1aeSJan Lentfer 
9686d49e1aeSJan Lentfer 
eloop_handle_signal(int sig)9696d49e1aeSJan Lentfer static void eloop_handle_signal(int sig)
9706d49e1aeSJan Lentfer {
9716d49e1aeSJan Lentfer 	int i;
9726d49e1aeSJan Lentfer 
9736d49e1aeSJan Lentfer #ifndef CONFIG_NATIVE_WINDOWS
9746d49e1aeSJan Lentfer 	if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
9756d49e1aeSJan Lentfer 		/* Use SIGALRM to break out from potential busy loops that
9766d49e1aeSJan Lentfer 		 * would not allow the program to be killed. */
9776d49e1aeSJan Lentfer 		eloop.pending_terminate = 1;
9786d49e1aeSJan Lentfer 		signal(SIGALRM, eloop_handle_alarm);
9796d49e1aeSJan Lentfer 		alarm(2);
9806d49e1aeSJan Lentfer 	}
9816d49e1aeSJan Lentfer #endif /* CONFIG_NATIVE_WINDOWS */
9826d49e1aeSJan Lentfer 
9836d49e1aeSJan Lentfer 	eloop.signaled++;
9846d49e1aeSJan Lentfer 	for (i = 0; i < eloop.signal_count; i++) {
9856d49e1aeSJan Lentfer 		if (eloop.signals[i].sig == sig) {
9866d49e1aeSJan Lentfer 			eloop.signals[i].signaled++;
9876d49e1aeSJan Lentfer 			break;
9886d49e1aeSJan Lentfer 		}
9896d49e1aeSJan Lentfer 	}
9906d49e1aeSJan Lentfer }
9916d49e1aeSJan Lentfer 
9926d49e1aeSJan Lentfer 
eloop_process_pending_signals(void)9936d49e1aeSJan Lentfer static void eloop_process_pending_signals(void)
9946d49e1aeSJan Lentfer {
9956d49e1aeSJan Lentfer 	int i;
9966d49e1aeSJan Lentfer 
9976d49e1aeSJan Lentfer 	if (eloop.signaled == 0)
9986d49e1aeSJan Lentfer 		return;
9996d49e1aeSJan Lentfer 	eloop.signaled = 0;
10006d49e1aeSJan Lentfer 
10016d49e1aeSJan Lentfer 	if (eloop.pending_terminate) {
10026d49e1aeSJan Lentfer #ifndef CONFIG_NATIVE_WINDOWS
10036d49e1aeSJan Lentfer 		alarm(0);
10046d49e1aeSJan Lentfer #endif /* CONFIG_NATIVE_WINDOWS */
10056d49e1aeSJan Lentfer 		eloop.pending_terminate = 0;
10066d49e1aeSJan Lentfer 	}
10076d49e1aeSJan Lentfer 
10086d49e1aeSJan Lentfer 	for (i = 0; i < eloop.signal_count; i++) {
10096d49e1aeSJan Lentfer 		if (eloop.signals[i].signaled) {
10106d49e1aeSJan Lentfer 			eloop.signals[i].signaled = 0;
10116d49e1aeSJan Lentfer 			eloop.signals[i].handler(eloop.signals[i].sig,
10126d49e1aeSJan Lentfer 						 eloop.signals[i].user_data);
10136d49e1aeSJan Lentfer 		}
10146d49e1aeSJan Lentfer 	}
10156d49e1aeSJan Lentfer }
10166d49e1aeSJan Lentfer 
10176d49e1aeSJan Lentfer 
eloop_register_signal(int sig,eloop_signal_handler handler,void * user_data)10186d49e1aeSJan Lentfer int eloop_register_signal(int sig, eloop_signal_handler handler,
10196d49e1aeSJan Lentfer 			  void *user_data)
10206d49e1aeSJan Lentfer {
10216d49e1aeSJan Lentfer 	struct eloop_signal *tmp;
10226d49e1aeSJan Lentfer 
10233ff40c12SJohn Marino 	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
10246d49e1aeSJan Lentfer 			       sizeof(struct eloop_signal));
10256d49e1aeSJan Lentfer 	if (tmp == NULL)
10266d49e1aeSJan Lentfer 		return -1;
10276d49e1aeSJan Lentfer 
10286d49e1aeSJan Lentfer 	tmp[eloop.signal_count].sig = sig;
10296d49e1aeSJan Lentfer 	tmp[eloop.signal_count].user_data = user_data;
10306d49e1aeSJan Lentfer 	tmp[eloop.signal_count].handler = handler;
10316d49e1aeSJan Lentfer 	tmp[eloop.signal_count].signaled = 0;
10326d49e1aeSJan Lentfer 	eloop.signal_count++;
10336d49e1aeSJan Lentfer 	eloop.signals = tmp;
10346d49e1aeSJan Lentfer 	signal(sig, eloop_handle_signal);
10356d49e1aeSJan Lentfer 
10366d49e1aeSJan Lentfer 	return 0;
10376d49e1aeSJan Lentfer }
10386d49e1aeSJan Lentfer 
10396d49e1aeSJan Lentfer 
eloop_register_signal_terminate(eloop_signal_handler handler,void * user_data)10406d49e1aeSJan Lentfer int eloop_register_signal_terminate(eloop_signal_handler handler,
10416d49e1aeSJan Lentfer 				    void *user_data)
10426d49e1aeSJan Lentfer {
10436d49e1aeSJan Lentfer 	int ret = eloop_register_signal(SIGINT, handler, user_data);
10446d49e1aeSJan Lentfer 	if (ret == 0)
10456d49e1aeSJan Lentfer 		ret = eloop_register_signal(SIGTERM, handler, user_data);
10466d49e1aeSJan Lentfer 	return ret;
10476d49e1aeSJan Lentfer }
10486d49e1aeSJan Lentfer 
10496d49e1aeSJan Lentfer 
eloop_register_signal_reconfig(eloop_signal_handler handler,void * user_data)10506d49e1aeSJan Lentfer int eloop_register_signal_reconfig(eloop_signal_handler handler,
10516d49e1aeSJan Lentfer 				   void *user_data)
10526d49e1aeSJan Lentfer {
10536d49e1aeSJan Lentfer #ifdef CONFIG_NATIVE_WINDOWS
10546d49e1aeSJan Lentfer 	return 0;
10556d49e1aeSJan Lentfer #else /* CONFIG_NATIVE_WINDOWS */
10566d49e1aeSJan Lentfer 	return eloop_register_signal(SIGHUP, handler, user_data);
10576d49e1aeSJan Lentfer #endif /* CONFIG_NATIVE_WINDOWS */
10586d49e1aeSJan Lentfer }
10596d49e1aeSJan Lentfer 
10606d49e1aeSJan Lentfer 
eloop_run(void)10616d49e1aeSJan Lentfer void eloop_run(void)
10626d49e1aeSJan Lentfer {
10633ff40c12SJohn Marino #ifdef CONFIG_ELOOP_POLL
10643ff40c12SJohn Marino 	int num_poll_fds;
10653ff40c12SJohn Marino 	int timeout_ms = 0;
1066*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_POLL */
1067*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_SELECT
10686d49e1aeSJan Lentfer 	fd_set *rfds, *wfds, *efds;
10696d49e1aeSJan Lentfer 	struct timeval _tv;
1070*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_SELECT */
1071*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_EPOLL
1072*a1157835SDaniel Fojt 	int timeout_ms = -1;
1073*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
1074*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
1075*a1157835SDaniel Fojt 	struct timespec ts;
1076*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
10773ff40c12SJohn Marino 	int res;
10783ff40c12SJohn Marino 	struct os_reltime tv, now;
10796d49e1aeSJan Lentfer 
1080*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_SELECT
10816d49e1aeSJan Lentfer 	rfds = os_malloc(sizeof(*rfds));
10826d49e1aeSJan Lentfer 	wfds = os_malloc(sizeof(*wfds));
10836d49e1aeSJan Lentfer 	efds = os_malloc(sizeof(*efds));
10843ff40c12SJohn Marino 	if (rfds == NULL || wfds == NULL || efds == NULL)
10856d49e1aeSJan Lentfer 		goto out;
1086*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_SELECT */
10876d49e1aeSJan Lentfer 
10886d49e1aeSJan Lentfer 	while (!eloop.terminate &&
10893ff40c12SJohn Marino 	       (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
10906d49e1aeSJan Lentfer 		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
10913ff40c12SJohn Marino 		struct eloop_timeout *timeout;
1092*a1157835SDaniel Fojt 
1093*a1157835SDaniel Fojt 		if (eloop.pending_terminate) {
1094*a1157835SDaniel Fojt 			/*
1095*a1157835SDaniel Fojt 			 * This may happen in some corner cases where a signal
1096*a1157835SDaniel Fojt 			 * is received during a blocking operation. We need to
1097*a1157835SDaniel Fojt 			 * process the pending signals and exit if requested to
1098*a1157835SDaniel Fojt 			 * avoid hitting the SIGALRM limit if the blocking
1099*a1157835SDaniel Fojt 			 * operation took more than two seconds.
1100*a1157835SDaniel Fojt 			 */
1101*a1157835SDaniel Fojt 			eloop_process_pending_signals();
1102*a1157835SDaniel Fojt 			if (eloop.terminate)
1103*a1157835SDaniel Fojt 				break;
1104*a1157835SDaniel Fojt 		}
1105*a1157835SDaniel Fojt 
11063ff40c12SJohn Marino 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
11073ff40c12SJohn Marino 					list);
11083ff40c12SJohn Marino 		if (timeout) {
11093ff40c12SJohn Marino 			os_get_reltime(&now);
11103ff40c12SJohn Marino 			if (os_reltime_before(&now, &timeout->time))
11113ff40c12SJohn Marino 				os_reltime_sub(&timeout->time, &now, &tv);
11126d49e1aeSJan Lentfer 			else
11136d49e1aeSJan Lentfer 				tv.sec = tv.usec = 0;
1114*a1157835SDaniel Fojt #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
11153ff40c12SJohn Marino 			timeout_ms = tv.sec * 1000 + tv.usec / 1000;
1116*a1157835SDaniel Fojt #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
1117*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_SELECT
11186d49e1aeSJan Lentfer 			_tv.tv_sec = tv.sec;
11196d49e1aeSJan Lentfer 			_tv.tv_usec = tv.usec;
1120*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_SELECT */
1121*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
1122*a1157835SDaniel Fojt 			ts.tv_sec = tv.sec;
1123*a1157835SDaniel Fojt 			ts.tv_nsec = tv.usec * 1000L;
1124*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
11256d49e1aeSJan Lentfer 		}
11266d49e1aeSJan Lentfer 
11273ff40c12SJohn Marino #ifdef CONFIG_ELOOP_POLL
11283ff40c12SJohn Marino 		num_poll_fds = eloop_sock_table_set_fds(
11293ff40c12SJohn Marino 			&eloop.readers, &eloop.writers, &eloop.exceptions,
11303ff40c12SJohn Marino 			eloop.pollfds, eloop.pollfds_map,
11313ff40c12SJohn Marino 			eloop.max_pollfd_map);
11323ff40c12SJohn Marino 		res = poll(eloop.pollfds, num_poll_fds,
11333ff40c12SJohn Marino 			   timeout ? timeout_ms : -1);
1134*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_POLL */
1135*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_SELECT
11366d49e1aeSJan Lentfer 		eloop_sock_table_set_fds(&eloop.readers, rfds);
11376d49e1aeSJan Lentfer 		eloop_sock_table_set_fds(&eloop.writers, wfds);
11386d49e1aeSJan Lentfer 		eloop_sock_table_set_fds(&eloop.exceptions, efds);
11396d49e1aeSJan Lentfer 		res = select(eloop.max_sock + 1, rfds, wfds, efds,
11403ff40c12SJohn Marino 			     timeout ? &_tv : NULL);
1141*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_SELECT */
1142*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_EPOLL
1143*a1157835SDaniel Fojt 		if (eloop.count == 0) {
1144*a1157835SDaniel Fojt 			res = 0;
1145*a1157835SDaniel Fojt 		} else {
1146*a1157835SDaniel Fojt 			res = epoll_wait(eloop.epollfd, eloop.epoll_events,
1147*a1157835SDaniel Fojt 					 eloop.count, timeout_ms);
1148*a1157835SDaniel Fojt 		}
1149*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
1150*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
1151*a1157835SDaniel Fojt 		if (eloop.count == 0) {
1152*a1157835SDaniel Fojt 			res = 0;
1153*a1157835SDaniel Fojt 		} else {
1154*a1157835SDaniel Fojt 			res = kevent(eloop.kqueuefd, NULL, 0,
1155*a1157835SDaniel Fojt 				     eloop.kqueue_events, eloop.kqueue_nevents,
1156*a1157835SDaniel Fojt 				     timeout ? &ts : NULL);
1157*a1157835SDaniel Fojt 		}
1158*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
11596d49e1aeSJan Lentfer 		if (res < 0 && errno != EINTR && errno != 0) {
1160*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR, "eloop: %s: %s",
1161*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_POLL
1162*a1157835SDaniel Fojt 				   "poll"
1163*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_POLL */
1164*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_SELECT
1165*a1157835SDaniel Fojt 				   "select"
1166*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_SELECT */
1167*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_EPOLL
1168*a1157835SDaniel Fojt 				   "epoll"
1169*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
1170*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
1171*a1157835SDaniel Fojt 				   "kqueue"
1172*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EKQUEUE */
1173*a1157835SDaniel Fojt 
1174*a1157835SDaniel Fojt 				   , strerror(errno));
11756d49e1aeSJan Lentfer 			goto out;
11766d49e1aeSJan Lentfer 		}
1177*a1157835SDaniel Fojt 
1178*a1157835SDaniel Fojt 		eloop.readers.changed = 0;
1179*a1157835SDaniel Fojt 		eloop.writers.changed = 0;
1180*a1157835SDaniel Fojt 		eloop.exceptions.changed = 0;
1181*a1157835SDaniel Fojt 
11826d49e1aeSJan Lentfer 		eloop_process_pending_signals();
11836d49e1aeSJan Lentfer 
1184*a1157835SDaniel Fojt 
11856d49e1aeSJan Lentfer 		/* check if some registered timeouts have occurred */
11863ff40c12SJohn Marino 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
11873ff40c12SJohn Marino 					list);
11883ff40c12SJohn Marino 		if (timeout) {
11893ff40c12SJohn Marino 			os_get_reltime(&now);
11903ff40c12SJohn Marino 			if (!os_reltime_before(&now, &timeout->time)) {
11913ff40c12SJohn Marino 				void *eloop_data = timeout->eloop_data;
11923ff40c12SJohn Marino 				void *user_data = timeout->user_data;
11933ff40c12SJohn Marino 				eloop_timeout_handler handler =
11943ff40c12SJohn Marino 					timeout->handler;
11953ff40c12SJohn Marino 				eloop_remove_timeout(timeout);
11963ff40c12SJohn Marino 				handler(eloop_data, user_data);
11976d49e1aeSJan Lentfer 			}
11986d49e1aeSJan Lentfer 
11996d49e1aeSJan Lentfer 		}
12006d49e1aeSJan Lentfer 
12016d49e1aeSJan Lentfer 		if (res <= 0)
12026d49e1aeSJan Lentfer 			continue;
12036d49e1aeSJan Lentfer 
1204*a1157835SDaniel Fojt 		if (eloop.readers.changed ||
1205*a1157835SDaniel Fojt 		    eloop.writers.changed ||
1206*a1157835SDaniel Fojt 		    eloop.exceptions.changed) {
1207*a1157835SDaniel Fojt 			 /*
1208*a1157835SDaniel Fojt 			  * Sockets may have been closed and reopened with the
1209*a1157835SDaniel Fojt 			  * same FD in the signal or timeout handlers, so we
1210*a1157835SDaniel Fojt 			  * must skip the previous results and check again
1211*a1157835SDaniel Fojt 			  * whether any of the currently registered sockets have
1212*a1157835SDaniel Fojt 			  * events.
1213*a1157835SDaniel Fojt 			  */
1214*a1157835SDaniel Fojt 			continue;
1215*a1157835SDaniel Fojt 		}
1216*a1157835SDaniel Fojt 
12173ff40c12SJohn Marino #ifdef CONFIG_ELOOP_POLL
12183ff40c12SJohn Marino 		eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
12193ff40c12SJohn Marino 					  &eloop.exceptions, eloop.pollfds_map,
12203ff40c12SJohn Marino 					  eloop.max_pollfd_map);
1221*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_POLL */
1222*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_SELECT
12236d49e1aeSJan Lentfer 		eloop_sock_table_dispatch(&eloop.readers, rfds);
12246d49e1aeSJan Lentfer 		eloop_sock_table_dispatch(&eloop.writers, wfds);
12256d49e1aeSJan Lentfer 		eloop_sock_table_dispatch(&eloop.exceptions, efds);
1226*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_SELECT */
1227*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_EPOLL
1228*a1157835SDaniel Fojt 		eloop_sock_table_dispatch(eloop.epoll_events, res);
1229*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
1230*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
1231*a1157835SDaniel Fojt 		eloop_sock_table_dispatch(eloop.kqueue_events, res);
1232*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
12336d49e1aeSJan Lentfer 	}
12346d49e1aeSJan Lentfer 
12353ff40c12SJohn Marino 	eloop.terminate = 0;
12366d49e1aeSJan Lentfer out:
1237*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_SELECT
12386d49e1aeSJan Lentfer 	os_free(rfds);
12396d49e1aeSJan Lentfer 	os_free(wfds);
12406d49e1aeSJan Lentfer 	os_free(efds);
1241*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_SELECT */
12423ff40c12SJohn Marino 	return;
12436d49e1aeSJan Lentfer }
12446d49e1aeSJan Lentfer 
12456d49e1aeSJan Lentfer 
eloop_terminate(void)12466d49e1aeSJan Lentfer void eloop_terminate(void)
12476d49e1aeSJan Lentfer {
12486d49e1aeSJan Lentfer 	eloop.terminate = 1;
12496d49e1aeSJan Lentfer }
12506d49e1aeSJan Lentfer 
12516d49e1aeSJan Lentfer 
eloop_destroy(void)12526d49e1aeSJan Lentfer void eloop_destroy(void)
12536d49e1aeSJan Lentfer {
12546d49e1aeSJan Lentfer 	struct eloop_timeout *timeout, *prev;
12553ff40c12SJohn Marino 	struct os_reltime now;
12566d49e1aeSJan Lentfer 
12573ff40c12SJohn Marino 	os_get_reltime(&now);
12583ff40c12SJohn Marino 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
12593ff40c12SJohn Marino 			      struct eloop_timeout, list) {
12606d49e1aeSJan Lentfer 		int sec, usec;
12613ff40c12SJohn Marino 		sec = timeout->time.sec - now.sec;
12623ff40c12SJohn Marino 		usec = timeout->time.usec - now.usec;
12633ff40c12SJohn Marino 		if (timeout->time.usec < now.usec) {
12646d49e1aeSJan Lentfer 			sec--;
12656d49e1aeSJan Lentfer 			usec += 1000000;
12666d49e1aeSJan Lentfer 		}
12673ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
12683ff40c12SJohn Marino 			   "eloop_data=%p user_data=%p handler=%p",
12693ff40c12SJohn Marino 			   sec, usec, timeout->eloop_data, timeout->user_data,
12703ff40c12SJohn Marino 			   timeout->handler);
12713ff40c12SJohn Marino 		wpa_trace_dump_funcname("eloop unregistered timeout handler",
12723ff40c12SJohn Marino 					timeout->handler);
12733ff40c12SJohn Marino 		wpa_trace_dump("eloop timeout", timeout);
12743ff40c12SJohn Marino 		eloop_remove_timeout(timeout);
12756d49e1aeSJan Lentfer 	}
12766d49e1aeSJan Lentfer 	eloop_sock_table_destroy(&eloop.readers);
12776d49e1aeSJan Lentfer 	eloop_sock_table_destroy(&eloop.writers);
12786d49e1aeSJan Lentfer 	eloop_sock_table_destroy(&eloop.exceptions);
12796d49e1aeSJan Lentfer 	os_free(eloop.signals);
12803ff40c12SJohn Marino 
12813ff40c12SJohn Marino #ifdef CONFIG_ELOOP_POLL
12823ff40c12SJohn Marino 	os_free(eloop.pollfds);
12833ff40c12SJohn Marino 	os_free(eloop.pollfds_map);
12843ff40c12SJohn Marino #endif /* CONFIG_ELOOP_POLL */
1285*a1157835SDaniel Fojt #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
1286*a1157835SDaniel Fojt 	os_free(eloop.fd_table);
1287*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
1288*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_EPOLL
1289*a1157835SDaniel Fojt 	os_free(eloop.epoll_events);
1290*a1157835SDaniel Fojt 	close(eloop.epollfd);
1291*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_EPOLL */
1292*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
1293*a1157835SDaniel Fojt 	os_free(eloop.kqueue_events);
1294*a1157835SDaniel Fojt 	close(eloop.kqueuefd);
1295*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
12966d49e1aeSJan Lentfer }
12976d49e1aeSJan Lentfer 
12986d49e1aeSJan Lentfer 
eloop_terminated(void)12996d49e1aeSJan Lentfer int eloop_terminated(void)
13006d49e1aeSJan Lentfer {
1301*a1157835SDaniel Fojt 	return eloop.terminate || eloop.pending_terminate;
13026d49e1aeSJan Lentfer }
13036d49e1aeSJan Lentfer 
13046d49e1aeSJan Lentfer 
eloop_wait_for_read_sock(int sock)13056d49e1aeSJan Lentfer void eloop_wait_for_read_sock(int sock)
13066d49e1aeSJan Lentfer {
13073ff40c12SJohn Marino #ifdef CONFIG_ELOOP_POLL
13083ff40c12SJohn Marino 	struct pollfd pfd;
13093ff40c12SJohn Marino 
13103ff40c12SJohn Marino 	if (sock < 0)
13113ff40c12SJohn Marino 		return;
13123ff40c12SJohn Marino 
13133ff40c12SJohn Marino 	os_memset(&pfd, 0, sizeof(pfd));
13143ff40c12SJohn Marino 	pfd.fd = sock;
13153ff40c12SJohn Marino 	pfd.events = POLLIN;
13163ff40c12SJohn Marino 
13173ff40c12SJohn Marino 	poll(&pfd, 1, -1);
1318*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_POLL */
1319*a1157835SDaniel Fojt #if defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL)
1320*a1157835SDaniel Fojt 	/*
1321*a1157835SDaniel Fojt 	 * We can use epoll() here. But epoll() requres 4 system calls.
1322*a1157835SDaniel Fojt 	 * epoll_create1(), epoll_ctl() for ADD, epoll_wait, and close() for
1323*a1157835SDaniel Fojt 	 * epoll fd. So select() is better for performance here.
1324*a1157835SDaniel Fojt 	 */
13256d49e1aeSJan Lentfer 	fd_set rfds;
13266d49e1aeSJan Lentfer 
13276d49e1aeSJan Lentfer 	if (sock < 0)
13286d49e1aeSJan Lentfer 		return;
13296d49e1aeSJan Lentfer 
13306d49e1aeSJan Lentfer 	FD_ZERO(&rfds);
13316d49e1aeSJan Lentfer 	FD_SET(sock, &rfds);
13326d49e1aeSJan Lentfer 	select(sock + 1, &rfds, NULL, NULL, NULL);
1333*a1157835SDaniel Fojt #endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */
1334*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_KQUEUE
1335*a1157835SDaniel Fojt 	int kfd;
1336*a1157835SDaniel Fojt 	struct kevent ke1, ke2;
1337*a1157835SDaniel Fojt 
1338*a1157835SDaniel Fojt 	kfd = kqueue();
1339*a1157835SDaniel Fojt 	if (kfd == -1)
1340*a1157835SDaniel Fojt 		return;
1341*a1157835SDaniel Fojt 	EV_SET(&ke1, sock, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
1342*a1157835SDaniel Fojt 	kevent(kfd, &ke1, 1, &ke2, 1, NULL);
1343*a1157835SDaniel Fojt 	close(kfd);
1344*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_KQUEUE */
13456d49e1aeSJan Lentfer }
1346*a1157835SDaniel Fojt 
1347*a1157835SDaniel Fojt #ifdef CONFIG_ELOOP_SELECT
1348*a1157835SDaniel Fojt #undef CONFIG_ELOOP_SELECT
1349*a1157835SDaniel Fojt #endif /* CONFIG_ELOOP_SELECT */
1350