diff options
| author | Martin Willi <martin@revosec.ch> | 2014-11-21 12:49:07 +0100 |
|---|---|---|
| committer | Martin Willi <martin@revosec.ch> | 2014-11-21 12:49:07 +0100 |
| commit | f6f3b0db1154cf0f97f2b26757ae7c42f5629bf3 (patch) | |
| tree | 5fdb42930d1c23d5ace96af3f74865571a90b234 /src/libcharon/plugins/socket_default/socket_default_socket.c | |
| parent | e796b88e86a719c03d551318dda359b373496ce5 (diff) | |
| parent | 89f19ef8763f2139b080efa2de019914e84f7cad (diff) | |
| download | strongswan-f6f3b0db1154cf0f97f2b26757ae7c42f5629bf3.tar.bz2 strongswan-f6f3b0db1154cf0f97f2b26757ae7c42f5629bf3.tar.xz | |
Merge branch 'poll'
Replace relevant uses of select() by poll(). poll(2) avoids the difficulties
we have with more than 1024 open file descriptors, and seems to be fairly
portable.
Fixes #757.
Diffstat (limited to 'src/libcharon/plugins/socket_default/socket_default_socket.c')
| -rw-r--r-- | src/libcharon/plugins/socket_default/socket_default_socket.c | 76 |
1 files changed, 29 insertions, 47 deletions
diff --git a/src/libcharon/plugins/socket_default/socket_default_socket.c b/src/libcharon/plugins/socket_default/socket_default_socket.c index 9cc39955b..30e50d2d2 100644 --- a/src/libcharon/plugins/socket_default/socket_default_socket.c +++ b/src/libcharon/plugins/socket_default/socket_default_socket.c @@ -141,6 +141,11 @@ struct private_socket_default_socket_t { * TRUE if the source address should be set on outbound packets */ bool set_source; + + /** + * A counter to implement round-robin selection of read sockets + */ + u_int rr_counter; }; METHOD(socket_t, receiver, status_t, @@ -150,66 +155,43 @@ METHOD(socket_t, receiver, status_t, chunk_t data; packet_t *pkt; host_t *source = NULL, *dest = NULL; - int bytes_read = 0; + int i, rr, index, bytes_read = 0, selected = -1; bool oldstate; - - fd_set rfds; - int max_fd = 0, selected = 0; u_int16_t port = 0; - - FD_ZERO(&rfds); - - if (this->ipv4 != -1) - { - FD_SET(this->ipv4, &rfds); - max_fd = max(max_fd, this->ipv4); - } - if (this->ipv4_natt != -1) - { - FD_SET(this->ipv4_natt, &rfds); - max_fd = max(max_fd, this->ipv4_natt); - } - if (this->ipv6 != -1) - { - FD_SET(this->ipv6, &rfds); - max_fd = max(max_fd, this->ipv6); - } - if (this->ipv6_natt != -1) - { - FD_SET(this->ipv6_natt, &rfds); - max_fd = max(max_fd, this->ipv6_natt); - } + struct pollfd pfd[] = { + { .fd = this->ipv4, .events = POLLIN }, + { .fd = this->ipv4_natt, .events = POLLIN }, + { .fd = this->ipv6, .events = POLLIN }, + { .fd = this->ipv6_natt, .events = POLLIN }, + }; + int ports[] = { + /* port numbers assocaited to pollfds */ + this->port, this->natt, this->port, this->natt, + }; DBG2(DBG_NET, "waiting for data on sockets"); oldstate = thread_cancelability(TRUE); - if (select(max_fd + 1, &rfds, NULL, NULL, NULL) <= 0) + if (poll(pfd, countof(pfd), -1) <= 0) { thread_cancelability(oldstate); return FAILED; } thread_cancelability(oldstate); - if (this->ipv4 != -1 && FD_ISSET(this->ipv4, &rfds)) + rr = this->rr_counter++; + for (i = 0; i < countof(pfd); i++) { - port = this->port; - selected = this->ipv4; - } - if (this->ipv4_natt != -1 && FD_ISSET(this->ipv4_natt, &rfds)) - { - port = this->natt; - selected = this->ipv4_natt; - } - if (this->ipv6 != -1 && FD_ISSET(this->ipv6, &rfds)) - { - port = this->port; - selected = this->ipv6; - } - if (this->ipv6_natt != -1 && FD_ISSET(this->ipv6_natt, &rfds)) - { - port = this->natt; - selected = this->ipv6_natt; + /* To serve all ports with equal priority, we use a round-robin + * scheme to choose the one to process in this invocation */ + index = (rr + i) % countof(pfd); + if (pfd[index].revents & POLLIN) + { + selected = pfd[index].fd; + port = ports[index]; + break; + } } - if (selected) + if (selected != -1) { struct msghdr msg; struct cmsghdr *cmsgptr; |
