summaryrefslogtreecommitdiff
path: root/lib/isc/unix/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/isc/unix/socket.c')
-rw-r--r--lib/isc/unix/socket.c94
1 files changed, 79 insertions, 15 deletions
diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c
index 5e6320d821c6a..42fc47f6deaaa 100644
--- a/lib/isc/unix/socket.c
+++ b/lib/isc/unix/socket.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2016 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1998-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -394,6 +394,9 @@ struct isc__socketmgr {
/* Locked by fdlock. */
isc__socket_t **fds;
int *fdstate;
+#if defined(USE_EPOLL)
+ uint32_t *epoll_events;
+#endif
#ifdef USE_DEVPOLL
pollinfo_t *fdpollinfo;
#endif
@@ -835,15 +838,27 @@ watch_fd(isc__socketmgr_t *manager, int fd, int msg) {
return (result);
#elif defined(USE_EPOLL)
struct epoll_event event;
+ uint32_t oldevents;
+ int ret;
+ int op;
+ oldevents = manager->epoll_events[fd];
if (msg == SELECT_POKE_READ)
- event.events = EPOLLIN;
+ manager->epoll_events[fd] |= EPOLLIN;
else
- event.events = EPOLLOUT;
+ manager->epoll_events[fd] |= EPOLLOUT;
+
+ event.events = manager->epoll_events[fd];
memset(&event.data, 0, sizeof(event.data));
event.data.fd = fd;
- if (epoll_ctl(manager->epoll_fd, EPOLL_CTL_ADD, fd, &event) == -1 &&
- errno != EEXIST) {
+
+ op = (oldevents == 0U) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
+ ret = epoll_ctl(manager->epoll_fd, op, fd, &event);
+ if (ret == -1) {
+ if (errno == EEXIST)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "epoll_ctl(ADD/MOD) returned "
+ "EEXIST for fd %d", fd);
result = isc__errno2result(errno);
}
@@ -903,15 +918,21 @@ unwatch_fd(isc__socketmgr_t *manager, int fd, int msg) {
return (result);
#elif defined(USE_EPOLL)
struct epoll_event event;
+ int ret;
+ int op;
if (msg == SELECT_POKE_READ)
- event.events = EPOLLIN;
+ manager->epoll_events[fd] &= ~(EPOLLIN);
else
- event.events = EPOLLOUT;
+ manager->epoll_events[fd] &= ~(EPOLLOUT);
+
+ event.events = manager->epoll_events[fd];
memset(&event.data, 0, sizeof(event.data));
event.data.fd = fd;
- if (epoll_ctl(manager->epoll_fd, EPOLL_CTL_DEL, fd, &event) == -1 &&
- errno != ENOENT) {
+
+ op = (event.events == 0U) ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
+ ret = epoll_ctl(manager->epoll_fd, op, fd, &event);
+ if (ret == -1 && errno != ENOENT) {
char strbuf[ISC_STRERRORSIZE];
isc__strerror(errno, strbuf, sizeof(strbuf));
UNEXPECTED_ERROR(__FILE__, __LINE__,
@@ -1553,15 +1574,19 @@ build_msghdr_recv(isc__socket_t *sock, isc_socketevent_t *dev,
msg->msg_iovlen = iovcount;
#ifdef ISC_NET_BSD44MSGHDR
- msg->msg_control = NULL;
- msg->msg_controllen = 0;
- msg->msg_flags = 0;
#if defined(USE_CMSG)
if (sock->type == isc_sockettype_udp) {
msg->msg_control = sock->recvcmsgbuf;
msg->msg_controllen = sock->recvcmsgbuflen;
+ } else {
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
}
+#else
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
#endif /* USE_CMSG */
+ msg->msg_flags = 0;
#else /* ISC_NET_BSD44MSGHDR */
msg->msg_accrights = NULL;
msg->msg_accrightslen = 0;
@@ -1872,8 +1897,11 @@ doio_send(isc__socket_t *sock, isc_socketevent_t *dev) {
if (send_errno == EINTR && ++attempts < NRETRIES)
goto resend;
- if (SOFT_ERROR(send_errno))
+ if (SOFT_ERROR(send_errno)) {
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ dev->result = ISC_R_WOULDBLOCK;
return (DOIO_SOFT);
+ }
#define SOFT_OR_HARD(_system, _isc) \
if (send_errno == _system) { \
@@ -2035,7 +2063,7 @@ destroy(isc__socket_t **sockp) {
INSIST(ISC_LIST_EMPTY(sock->recv_list));
INSIST(ISC_LIST_EMPTY(sock->send_list));
INSIST(sock->connect_ev == NULL);
- REQUIRE(sock->fd == -1 || sock->fd < (int)manager->maxsocks);
+ INSIST(sock->fd >= -1 && sock->fd < (int)manager->maxsocks);
if (sock->fd >= 0) {
fd = sock->fd;
@@ -2192,8 +2220,8 @@ static void
free_socket(isc__socket_t **socketp) {
isc__socket_t *sock = *socketp;
- INSIST(sock->references == 0);
INSIST(VALID_SOCKET(sock));
+ INSIST(sock->references == 0);
INSIST(!sock->connecting);
INSIST(!sock->pending_recv);
INSIST(!sock->pending_send);
@@ -2633,6 +2661,9 @@ socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type,
LOCK(&manager->fdlock[lockid]);
manager->fds[sock->fd] = sock;
manager->fdstate[sock->fd] = MANAGED;
+#if defined(USE_EPOLL)
+ manager->epoll_events[sock->fd] = 0;
+#endif
#ifdef USE_DEVPOLL
INSIST(sock->manager->fdpollinfo[sock->fd].want_read == 0 &&
sock->manager->fdpollinfo[sock->fd].want_write == 0);
@@ -2710,6 +2741,9 @@ isc__socket_open(isc_socket_t *sock0) {
LOCK(&sock->manager->fdlock[lockid]);
sock->manager->fds[sock->fd] = sock;
sock->manager->fdstate[sock->fd] = MANAGED;
+#if defined(USE_EPOLL)
+ sock->manager->epoll_events[sock->fd] = 0;
+#endif
#ifdef USE_DEVPOLL
INSIST(sock->manager->fdpollinfo[sock->fd].want_read == 0 &&
sock->manager->fdpollinfo[sock->fd].want_write == 0);
@@ -2747,6 +2781,9 @@ isc__socket_fdwatchcreate(isc_socketmgr_t *manager0, int fd, int flags,
REQUIRE(VALID_MANAGER(manager));
REQUIRE(socketp != NULL && *socketp == NULL);
+ if (fd < 0 || (unsigned int)fd >= manager->maxsocks)
+ return (ISC_R_RANGE);
+
result = allocate_socket(manager, isc_sockettype_fdwatch, &sock);
if (result != ISC_R_SUCCESS)
return (result);
@@ -2771,6 +2808,9 @@ isc__socket_fdwatchcreate(isc_socketmgr_t *manager0, int fd, int flags,
LOCK(&manager->fdlock[lockid]);
manager->fds[sock->fd] = sock;
manager->fdstate[sock->fd] = MANAGED;
+#if defined(USE_EPOLL)
+ manager->epoll_events[sock->fd] = 0;
+#endif
UNLOCK(&manager->fdlock[lockid]);
LOCK(&manager->lock);
@@ -3310,6 +3350,9 @@ internal_accept(isc_task_t *me, isc_event_t *ev) {
LOCK(&manager->fdlock[lockid]);
manager->fds[fd] = NEWCONNSOCK(dev);
manager->fdstate[fd] = MANAGED;
+#if defined(USE_EPOLL)
+ manager->epoll_events[fd] = 0;
+#endif
UNLOCK(&manager->fdlock[lockid]);
LOCK(&manager->lock);
@@ -4260,6 +4303,15 @@ isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
result = ISC_R_NOMEMORY;
goto free_manager;
}
+#if defined(USE_EPOLL)
+ manager->epoll_events = isc_mem_get(mctx, (manager->maxsocks *
+ sizeof(uint32_t)));
+ if (manager->epoll_events == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto free_manager;
+ }
+ memset(manager->epoll_events, 0, manager->maxsocks * sizeof(uint32_t));
+#endif
manager->stats = NULL;
manager->common.methods = &socketmgrmethods;
@@ -4329,7 +4381,9 @@ isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
result = setup_watcher(mctx, manager);
if (result != ISC_R_SUCCESS)
goto cleanup;
+
memset(manager->fdstate, 0, manager->maxsocks * sizeof(int));
+
#ifdef USE_WATCHER_THREAD
/*
* Start up the select/poll thread.
@@ -4378,6 +4432,12 @@ free_manager:
isc_mem_put(mctx, manager->fdlock,
FDLOCK_COUNT * sizeof(isc_mutex_t));
}
+#if defined(USE_EPOLL)
+ if (manager->epoll_events != NULL) {
+ isc_mem_put(mctx, manager->epoll_events,
+ manager->maxsocks * sizeof(uint32_t));
+ }
+#endif
if (manager->fdstate != NULL) {
isc_mem_put(mctx, manager->fdstate,
manager->maxsocks * sizeof(int));
@@ -4493,6 +4553,10 @@ isc__socketmgr_destroy(isc_socketmgr_t **managerp) {
if (manager->fdstate[i] == CLOSE_PENDING) /* no need to lock */
(void)close(i);
+#if defined(USE_EPOLL)
+ isc_mem_put(manager->mctx, manager->epoll_events,
+ manager->maxsocks * sizeof(uint32_t));
+#endif
isc_mem_put(manager->mctx, manager->fds,
manager->maxsocks * sizeof(isc__socket_t *));
isc_mem_put(manager->mctx, manager->fdstate,