eloop: Fix cases where a socket is reopened from a timeout/signal handler
It was possible for a registered eloop socket handler to be unregistered and re-registered for a re-opened socket with the same fd from a timeout or signal handler. If such a case happened with the old socket having a pending event waiting for processing, some eloop combinations could end up calling the new handler function with the new socket and get stuck waiting for an event that has not yet happened on the new socket. This happened with timeout and signal handlers with all eloop.c types. In addition to that, the epoll case could also trigger this when a socket handler re-registered a re-opened socket. Fix these by checking whether there has been socket handler changes during processing and break the processing round by going back to select/poll/epoll for an updated result if any changes are done during the eloop handler calls before processing the old socket results. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
569f8f9b87
commit
7c524a64c1
1 changed files with 22 additions and 7 deletions
|
@ -61,11 +61,8 @@ struct eloop_signal {
|
||||||
struct eloop_sock_table {
|
struct eloop_sock_table {
|
||||||
int count;
|
int count;
|
||||||
struct eloop_sock *table;
|
struct eloop_sock *table;
|
||||||
#ifdef CONFIG_ELOOP_EPOLL
|
|
||||||
eloop_event_type type;
|
eloop_event_type type;
|
||||||
#else /* CONFIG_ELOOP_EPOLL */
|
|
||||||
int changed;
|
int changed;
|
||||||
#endif /* CONFIG_ELOOP_EPOLL */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct eloop_data {
|
struct eloop_data {
|
||||||
|
@ -256,9 +253,7 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
|
||||||
table->table = tmp;
|
table->table = tmp;
|
||||||
eloop.max_sock = new_max_sock;
|
eloop.max_sock = new_max_sock;
|
||||||
eloop.count++;
|
eloop.count++;
|
||||||
#ifndef CONFIG_ELOOP_EPOLL
|
|
||||||
table->changed = 1;
|
table->changed = 1;
|
||||||
#endif /* CONFIG_ELOOP_EPOLL */
|
|
||||||
eloop_trace_sock_add_ref(table);
|
eloop_trace_sock_add_ref(table);
|
||||||
|
|
||||||
#ifdef CONFIG_ELOOP_EPOLL
|
#ifdef CONFIG_ELOOP_EPOLL
|
||||||
|
@ -314,9 +309,7 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
|
||||||
}
|
}
|
||||||
table->count--;
|
table->count--;
|
||||||
eloop.count--;
|
eloop.count--;
|
||||||
#ifndef CONFIG_ELOOP_EPOLL
|
|
||||||
table->changed = 1;
|
table->changed = 1;
|
||||||
#endif /* CONFIG_ELOOP_EPOLL */
|
|
||||||
eloop_trace_sock_add_ref(table);
|
eloop_trace_sock_add_ref(table);
|
||||||
#ifdef CONFIG_ELOOP_EPOLL
|
#ifdef CONFIG_ELOOP_EPOLL
|
||||||
if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) {
|
if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) {
|
||||||
|
@ -523,6 +516,10 @@ static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
|
||||||
continue;
|
continue;
|
||||||
table->handler(table->sock, table->eloop_data,
|
table->handler(table->sock, table->eloop_data,
|
||||||
table->user_data);
|
table->user_data);
|
||||||
|
if (eloop.readers.changed ||
|
||||||
|
eloop.writers.changed ||
|
||||||
|
eloop.exceptions.changed)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_ELOOP_EPOLL */
|
#endif /* CONFIG_ELOOP_EPOLL */
|
||||||
|
@ -991,6 +988,11 @@ void eloop_run(void)
|
||||||
, strerror(errno));
|
, strerror(errno));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eloop.readers.changed = 0;
|
||||||
|
eloop.writers.changed = 0;
|
||||||
|
eloop.exceptions.changed = 0;
|
||||||
|
|
||||||
eloop_process_pending_signals();
|
eloop_process_pending_signals();
|
||||||
|
|
||||||
/* check if some registered timeouts have occurred */
|
/* check if some registered timeouts have occurred */
|
||||||
|
@ -1012,6 +1014,19 @@ void eloop_run(void)
|
||||||
if (res <= 0)
|
if (res <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (eloop.readers.changed ||
|
||||||
|
eloop.writers.changed ||
|
||||||
|
eloop.exceptions.changed) {
|
||||||
|
/*
|
||||||
|
* Sockets may have been closed and reopened with the
|
||||||
|
* same FD in the signal or timeout handlers, so we
|
||||||
|
* must skip the previous results and check again
|
||||||
|
* whether any of the currently registered sockets have
|
||||||
|
* events.
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_ELOOP_POLL
|
#ifdef CONFIG_ELOOP_POLL
|
||||||
eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
|
eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
|
||||||
&eloop.exceptions, eloop.pollfds_map,
|
&eloop.exceptions, eloop.pollfds_map,
|
||||||
|
|
Loading…
Reference in a new issue