diff options
Diffstat (limited to 'src/libcharon/plugins')
-rw-r--r-- | src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c | 110 |
1 files changed, 56 insertions, 54 deletions
diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c index 6ce1d4eb0..830954e11 100644 --- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c +++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c @@ -131,35 +131,6 @@ static void deliver_plain(private_kernel_libipsec_router_t *this, } /** - * Create an FD set covering all TUN devices and the read end of the notify pipe - */ -static int collect_fds(private_kernel_libipsec_router_t *this, fd_set *fds) -{ - enumerator_t *enumerator; - tun_entry_t *entry; - int maxfd; - - FD_ZERO(fds); - FD_SET(this->notify[0], fds); - maxfd = this->notify[0]; - - FD_SET(this->tun.fd, fds); - maxfd = max(maxfd, this->tun.fd); - - this->lock->read_lock(this->lock); - enumerator = this->tuns->create_enumerator(this->tuns); - while (enumerator->enumerate(enumerator, NULL, &entry)) - { - FD_SET(entry->fd, fds); - maxfd = max(maxfd, entry->fd); - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - - return maxfd + 1; -} - -/** * Read and process outbound plaintext packet for the given TUN device */ static void process_plain(tun_device_t *tun) @@ -183,29 +154,20 @@ static void process_plain(tun_device_t *tun) } /** - * Handle waiting data for any TUN device + * Find flagged revents in a pollfd set by fd */ -static void handle_tuns(private_kernel_libipsec_router_t *this, fd_set *fds) +static int find_revents(struct pollfd *pfd, int count, int fd) { - enumerator_t *enumerator; - tun_entry_t *entry; + int i; - if (FD_ISSET(this->tun.fd, fds)) + for (i = 0; i < count; i++) { - process_plain(this->tun.tun); - } - - this->lock->read_lock(this->lock); - enumerator = this->tuns->create_enumerator(this->tuns); - while (enumerator->enumerate(enumerator, NULL, &entry)) - { - if (FD_ISSET(entry->fd, fds)) + if (pfd[i].fd == fd) { - process_plain(entry->tun); + return pfd[i].revents; } } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); + return 0; } /** @@ -213,28 +175,68 @@ static void handle_tuns(private_kernel_libipsec_router_t *this, fd_set *fds) */ static job_requeue_t handle_plain(private_kernel_libipsec_router_t *this) { + enumerator_t *enumerator; + tun_entry_t *entry; bool oldstate; - fd_set fds; - int maxfd; + int count = 0; + char buf[1]; + struct pollfd *pfd; + + this->lock->read_lock(this->lock); - maxfd = collect_fds(this, &fds); + pfd = alloca(sizeof(*pfd) * (this->tuns->get_count(this->tuns) + 2)); + pfd[count].fd = this->notify[0]; + pfd[count].events = POLLIN; + count++; + pfd[count].fd = this->tun.fd; + pfd[count].events = POLLIN; + count++; + + enumerator = this->tuns->create_enumerator(this->tuns); + while (enumerator->enumerate(enumerator, NULL, &entry)) + { + pfd[count].fd = entry->fd; + pfd[count].events = POLLIN; + count++; + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); oldstate = thread_cancelability(TRUE); - if (select(maxfd, &fds, NULL, NULL, NULL) <= 0) + if (poll(pfd, count, -1) <= 0) { thread_cancelability(oldstate); return JOB_REQUEUE_FAIR; } thread_cancelability(oldstate); - if (FD_ISSET(this->notify[0], &fds)) - { /* list of TUN devices changed, read notification data, rebuild FDs */ - char buf[1]; - while (read(this->notify[0], &buf, sizeof(buf)) == sizeof(buf)); + if (pfd[0].revents & POLLIN) + { + /* list of TUN devices changed, read notification data, rebuild FDs */ + while (read(this->notify[0], &buf, sizeof(buf)) == sizeof(buf)) + { + /* nop */ + } return JOB_REQUEUE_DIRECT; } - handle_tuns(this, &fds); + if (pfd[1].revents & POLLIN) + { + process_plain(this->tun.tun); + } + + this->lock->read_lock(this->lock); + enumerator = this->tuns->create_enumerator(this->tuns); + while (enumerator->enumerate(enumerator, NULL, &entry)) + { + if (find_revents(pfd, count, entry->fd) & POLLIN) + { + process_plain(entry->tun); + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + return JOB_REQUEUE_DIRECT; } |