2406. [bug] Sockets could be closed too early, leading to

			inconsistent states in the socket module. [RT #18298]
parent 749739f4
2406. [bug] Sockets could be closed too early, leading to
inconsistent states in the socket module. [RT #18298]
2405. [cleanup] The default value for dnssec-validation was changed to 2405. [cleanup] The default value for dnssec-validation was changed to
"yes" in 9.5.0-P1 and all subsequent releases; this "yes" in 9.5.0-P1 and all subsequent releases; this
was inadvertently omitted from CHANGES at the time. was inadvertently omitted from CHANGES at the time.
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE. * PERFORMANCE OF THIS SOFTWARE.
*/ */
/* $Id: socket.c,v 1.294 2008/07/24 09:50:21 fdupont Exp $ */ /* $Id: socket.c,v 1.295 2008/08/01 19:04:02 jinmei Exp $ */
/*! \file */ /*! \file */
...@@ -333,7 +333,6 @@ static isc_socketmgr_t *socketmgr = NULL; ...@@ -333,7 +333,6 @@ static isc_socketmgr_t *socketmgr = NULL;
#define CLOSED 0 /* this one must be zero */ #define CLOSED 0 /* this one must be zero */
#define MANAGED 1 #define MANAGED 1
#define CLOSE_PENDING 2 #define CLOSE_PENDING 2
#define MANAGER_CLOSE_PENDING 3
/* /*
* send() and recv() iovec counts * send() and recv() iovec counts
...@@ -589,7 +588,6 @@ unwatch_fd(isc_socketmgr_t *manager, int fd, int msg) { ...@@ -589,7 +588,6 @@ unwatch_fd(isc_socketmgr_t *manager, int fd, int msg) {
static void static void
wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) { wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) {
isc_result_t result; isc_result_t result;
isc_boolean_t needclose;
int lockid = FDLOCK_ID(fd); int lockid = FDLOCK_ID(fd);
/* /*
...@@ -600,11 +598,18 @@ wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) { ...@@ -600,11 +598,18 @@ wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) {
INSIST(fd >= 0 && fd < (int)manager->maxsocks); INSIST(fd >= 0 && fd < (int)manager->maxsocks);
LOCK(&manager->fdlock[lockid]); if (msg == SELECT_POKE_CLOSE) {
if (manager->fdstate[fd] == CLOSE_PENDING /* No one should be updating fdstate, so no need to lock it */
|| manager->fdstate[fd] == MANAGER_CLOSE_PENDING) { INSIST(manager->fdstate[fd] == CLOSE_PENDING);
needclose = ISC_TF(manager->fdstate[fd] == CLOSE_PENDING);
manager->fdstate[fd] = CLOSED; manager->fdstate[fd] = CLOSED;
(void)unwatch_fd(manager, fd, SELECT_POKE_READ);
(void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
(void)close(fd);
return;
}
LOCK(&manager->fdlock[lockid]);
if (manager->fdstate[fd] == CLOSE_PENDING) {
UNLOCK(&manager->fdlock[lockid]); UNLOCK(&manager->fdlock[lockid]);
/* /*
...@@ -617,8 +622,6 @@ wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) { ...@@ -617,8 +622,6 @@ wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) {
*/ */
(void)unwatch_fd(manager, fd, SELECT_POKE_READ); (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
(void)unwatch_fd(manager, fd, SELECT_POKE_WRITE); (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
if (needclose)
(void)close(fd);
return; return;
} }
if (manager->fdstate[fd] != MANAGED) { if (manager->fdstate[fd] != MANAGED) {
...@@ -1520,11 +1523,24 @@ closesocket(isc_socketmgr_t *manager, isc_sockettype_t type, int fd) { ...@@ -1520,11 +1523,24 @@ closesocket(isc_socketmgr_t *manager, isc_sockettype_t type, int fd) {
LOCK(&manager->fdlock[lockid]); LOCK(&manager->fdlock[lockid]);
manager->fds[fd] = NULL; manager->fds[fd] = NULL;
if (type == isc_sockettype_fdwatch) if (type == isc_sockettype_fdwatch)
manager->fdstate[fd] = MANAGER_CLOSE_PENDING; manager->fdstate[fd] = CLOSED;
else else
manager->fdstate[fd] = CLOSE_PENDING; manager->fdstate[fd] = CLOSE_PENDING;
UNLOCK(&manager->fdlock[lockid]); UNLOCK(&manager->fdlock[lockid]);
select_poke(manager, fd, SELECT_POKE_CLOSE); if (type == isc_sockettype_fdwatch) {
/*
* The caller may close the socket once this function returns,
* and `fd' may be reassigned for a new socket. So we do
* unwatch_fd() here, rather than defer it via select_poke().
* Note: this may complicate data protection among threads and
* may reduce performance due to additional locks. One way to
* solve this would be to dup() the watched descriptor, but we
* take a simpler approach at this moment.
*/
(void)unwatch_fd(manager, fd, SELECT_POKE_READ);
(void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
} else
select_poke(manager, fd, SELECT_POKE_CLOSE);
/* /*
* update manager->maxfd here (XXX: this should be implemented more * update manager->maxfd here (XXX: this should be implemented more
...@@ -2255,15 +2271,7 @@ dispatch_recv(isc_socket_t *sock) { ...@@ -2255,15 +2271,7 @@ dispatch_recv(isc_socket_t *sock) {
isc_socketevent_t *ev; isc_socketevent_t *ev;
isc_task_t *sender; isc_task_t *sender;
#if 0
/*
* XXXJT: this assertion seems to strong, but leave it here for
* reference.
*/
INSIST(!sock->pending_recv); INSIST(!sock->pending_recv);
#endif
if (sock->pending_recv != 0)
return;
if (sock->type != isc_sockettype_fdwatch) { if (sock->type != isc_sockettype_fdwatch) {
ev = ISC_LIST_HEAD(sock->recv_list); ev = ISC_LIST_HEAD(sock->recv_list);
...@@ -2880,23 +2888,17 @@ process_fd(isc_socketmgr_t *manager, int fd, isc_boolean_t readable, ...@@ -2880,23 +2888,17 @@ process_fd(isc_socketmgr_t *manager, int fd, isc_boolean_t readable,
{ {
isc_socket_t *sock; isc_socket_t *sock;
isc_boolean_t unlock_sock; isc_boolean_t unlock_sock;
isc_boolean_t needclose;
int lockid = FDLOCK_ID(fd); int lockid = FDLOCK_ID(fd);
/* /*
* If we need to close the socket, do it now. * If the socket is going to be closed, don't do more I/O.
*/ */
LOCK(&manager->fdlock[lockid]); LOCK(&manager->fdlock[lockid]);
if (manager->fdstate[fd] == CLOSE_PENDING if (manager->fdstate[fd] == CLOSE_PENDING) {
|| manager->fdstate[fd] == MANAGER_CLOSE_PENDING) {
needclose = ISC_TF(manager->fdstate[fd] == CLOSE_PENDING);
manager->fdstate[fd] = CLOSED;
UNLOCK(&manager->fdlock[lockid]); UNLOCK(&manager->fdlock[lockid]);
(void)unwatch_fd(manager, fd, SELECT_POKE_READ); (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
(void)unwatch_fd(manager, fd, SELECT_POKE_WRITE); (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
if (needclose)
(void)close(fd);
return; return;
} }
...@@ -2946,6 +2948,9 @@ process_fds(isc_socketmgr_t *manager, struct kevent *events, int nevents) { ...@@ -2946,6 +2948,9 @@ process_fds(isc_socketmgr_t *manager, struct kevent *events, int nevents) {
int i; int i;
isc_boolean_t readable, writable; isc_boolean_t readable, writable;
isc_boolean_t done = ISC_FALSE; isc_boolean_t done = ISC_FALSE;
#ifdef ISC_PLATFORM_USETHREADS
isc_boolean_t have_ctlevent = ISC_FALSE;
#endif
if (nevents == manager->nevents) { if (nevents == manager->nevents) {
/* /*
...@@ -2963,7 +2968,7 @@ process_fds(isc_socketmgr_t *manager, struct kevent *events, int nevents) { ...@@ -2963,7 +2968,7 @@ process_fds(isc_socketmgr_t *manager, struct kevent *events, int nevents) {
REQUIRE(events[i].ident < manager->maxsocks); REQUIRE(events[i].ident < manager->maxsocks);
#ifdef ISC_PLATFORM_USETHREADS #ifdef ISC_PLATFORM_USETHREADS
if (events[i].ident == (uintptr_t)manager->pipe_fds[0]) { if (events[i].ident == (uintptr_t)manager->pipe_fds[0]) {
done = process_ctlfd(manager); have_ctlevent = ISC_TRUE;
continue; continue;
} }
#endif #endif
...@@ -2972,6 +2977,11 @@ process_fds(isc_socketmgr_t *manager, struct kevent *events, int nevents) { ...@@ -2972,6 +2977,11 @@ process_fds(isc_socketmgr_t *manager, struct kevent *events, int nevents) {
process_fd(manager, events[i].ident, readable, writable); process_fd(manager, events[i].ident, readable, writable);
} }
#ifdef ISC_PLATFORM_USETHREADS
if (have_ctlevent)
done = process_ctlfd(manager);
#endif
return (done); return (done);
} }
#elif defined(USE_EPOLL) #elif defined(USE_EPOLL)
...@@ -2979,6 +2989,9 @@ static isc_boolean_t ...@@ -2979,6 +2989,9 @@ static isc_boolean_t
process_fds(isc_socketmgr_t *manager, struct epoll_event *events, int nevents) { process_fds(isc_socketmgr_t *manager, struct epoll_event *events, int nevents) {
int i; int i;
isc_boolean_t done = ISC_FALSE; isc_boolean_t done = ISC_FALSE;
#ifdef ISC_PLATFORM_USETHREADS
isc_boolean_t have_ctlevent = ISC_FALSE;
#endif
if (nevents == manager->nevents) { if (nevents == manager->nevents) {
manager_log(manager, ISC_LOGCATEGORY_GENERAL, manager_log(manager, ISC_LOGCATEGORY_GENERAL,
...@@ -2991,7 +3004,7 @@ process_fds(isc_socketmgr_t *manager, struct epoll_event *events, int nevents) { ...@@ -2991,7 +3004,7 @@ process_fds(isc_socketmgr_t *manager, struct epoll_event *events, int nevents) {
REQUIRE(events[i].data.fd < (int)manager->maxsocks); REQUIRE(events[i].data.fd < (int)manager->maxsocks);
#ifdef ISC_PLATFORM_USETHREADS #ifdef ISC_PLATFORM_USETHREADS
if (events[i].data.fd == manager->pipe_fds[0]) { if (events[i].data.fd == manager->pipe_fds[0]) {
done = process_ctlfd(manager); have_ctlevent = ISC_TRUE;
continue; continue;
} }
#endif #endif
...@@ -3011,6 +3024,11 @@ process_fds(isc_socketmgr_t *manager, struct epoll_event *events, int nevents) { ...@@ -3011,6 +3024,11 @@ process_fds(isc_socketmgr_t *manager, struct epoll_event *events, int nevents) {
(events[i].events & EPOLLOUT) != 0); (events[i].events & EPOLLOUT) != 0);
} }
#ifdef ISC_PLATFORM_USETHREADS
if (have_ctlevent)
done = process_ctlfd(manager);
#endif
return (done); return (done);
} }
#elif defined(USE_DEVPOLL) #elif defined(USE_DEVPOLL)
...@@ -3018,6 +3036,9 @@ static isc_boolean_t ...@@ -3018,6 +3036,9 @@ static isc_boolean_t
process_fds(isc_socketmgr_t *manager, struct pollfd *events, int nevents) { process_fds(isc_socketmgr_t *manager, struct pollfd *events, int nevents) {
int i; int i;
isc_boolean_t done = ISC_FALSE; isc_boolean_t done = ISC_FALSE;
#ifdef ISC_PLATFORM_USETHREADS
isc_boolean_t have_ctlevent = ISC_FALSE;
#endif
if (nevents == manager->nevents) { if (nevents == manager->nevents) {
manager_log(manager, ISC_LOGCATEGORY_GENERAL, manager_log(manager, ISC_LOGCATEGORY_GENERAL,
...@@ -3030,7 +3051,7 @@ process_fds(isc_socketmgr_t *manager, struct pollfd *events, int nevents) { ...@@ -3030,7 +3051,7 @@ process_fds(isc_socketmgr_t *manager, struct pollfd *events, int nevents) {
REQUIRE(events[i].fd < (int)manager->maxsocks); REQUIRE(events[i].fd < (int)manager->maxsocks);
#ifdef ISC_PLATFORM_USETHREADS #ifdef ISC_PLATFORM_USETHREADS
if (events[i].fd == manager->pipe_fds[0]) { if (events[i].fd == manager->pipe_fds[0]) {
done = process_ctlfd(manager); have_ctlevent = ISC_TRUE;
continue; continue;
} }
#endif #endif
...@@ -3039,6 +3060,11 @@ process_fds(isc_socketmgr_t *manager, struct pollfd *events, int nevents) { ...@@ -3039,6 +3060,11 @@ process_fds(isc_socketmgr_t *manager, struct pollfd *events, int nevents) {
(events[i].events & POLLOUT) != 0); (events[i].events & POLLOUT) != 0);
} }
#ifdef ISC_PLATFORM_USETHREADS
if (have_ctlevent)
done = process_ctlfd(manager);
#endif
return (done); return (done);
} }
#elif defined(USE_SELECT) #elif defined(USE_SELECT)
...@@ -3172,13 +3198,13 @@ watcher(void *uap) { ...@@ -3172,13 +3198,13 @@ watcher(void *uap) {
#if defined(USE_KQUEUE) || defined (USE_EPOLL) || defined (USE_DEVPOLL) #if defined(USE_KQUEUE) || defined (USE_EPOLL) || defined (USE_DEVPOLL)
done = process_fds(manager, manager->events, cc); done = process_fds(manager, manager->events, cc);
#elif defined(USE_SELECT) #elif defined(USE_SELECT)
process_fds(manager, maxfd, &readfds, &writefds);
/* /*
* Process reads on internal, control fd. * Process reads on internal, control fd.
*/ */
if (FD_ISSET(ctlfd, &readfds)) if (FD_ISSET(ctlfd, &readfds))
done = process_ctlfd(manager); done = process_ctlfd(manager);
process_fds(manager, maxfd, &readfds, &writefds);
#endif #endif
} }
...@@ -3684,7 +3710,7 @@ socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, ...@@ -3684,7 +3710,7 @@ socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
* Enqueue the request. If the socket was previously not being * Enqueue the request. If the socket was previously not being
* watched, poke the watcher to start paying attention to it. * watched, poke the watcher to start paying attention to it.
*/ */
if (ISC_LIST_EMPTY(sock->recv_list)) if (ISC_LIST_EMPTY(sock->recv_list) && !sock->pending_recv)
select_poke(sock->manager, sock->fd, SELECT_POKE_READ); select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link); ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
...@@ -3881,7 +3907,8 @@ socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, ...@@ -3881,7 +3907,8 @@ socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
* not being watched, poke the watcher to start * not being watched, poke the watcher to start
* paying attention to it. * paying attention to it.
*/ */
if (ISC_LIST_EMPTY(sock->send_list)) if (ISC_LIST_EMPTY(sock->send_list) &&
!sock->pending_send)
select_poke(sock->manager, sock->fd, select_poke(sock->manager, sock->fd,
SELECT_POKE_WRITE); SELECT_POKE_WRITE);
ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link); ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment