* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: socket.c,v 1.183 2001/01/23 21:07:12 bwelling Exp $ */
+/* $Id: socket.c,v 1.184 2001/01/25 22:25:10 neild Exp $ */
#include <config.h>
#undef USE_CMSG
#endif
+/*
+ * Determine the size of the control data buffer.
+ */
+#if USE_CMSG
+
+#ifdef ISC_PLATFORM_HAVEIPV6
+#define CMSG_BUF_V6_SIZE (CMSG_SPACE(sizeof(struct in6_pktinfo)))
+#else
+#define CMSG_BUF_V6_SIZE 0
+#endif
+
+#ifdef SO_TIMESTAMP
+#define CMSG_BUF_TS_SIZE (CMSG_SPACE(sizeof(struct timeval)))
+#else
+#define CMSG_BUF_TS_SIZE 0
+#endif
+
+#define CMSG_BUF_SIZE (CMSG_BUF_V6_SIZE + CMSG_BUF_TS_SIZE)
+
+#endif /* USE_CMSG */
+
struct isc_socket {
/* Not locked. */
unsigned int magic;
#ifdef ISC_NET_RECVOVERFLOW
unsigned char overflow; /* used for MSG_TRUNC fake */
#endif
-#ifdef USE_CMSG
- unsigned char *cmsg;
- unsigned int cmsglen;
-#endif
};
#define SOCKET_MANAGER_MAGIC 0x494f6d67U /* IOmg */
static void internal_send(isc_task_t *, isc_event_t *);
static void process_cmsg(isc_socket_t *, struct msghdr *, isc_socketevent_t *);
static void build_msghdr_send(isc_socket_t *, isc_socketevent_t *,
- struct msghdr *, struct iovec *, size_t *);
+ struct msghdr *, char *cmsg,
+ struct iovec *, size_t *);
static void build_msghdr_recv(isc_socket_t *, isc_socketevent_t *,
- struct msghdr *, struct iovec *, size_t *);
+ struct msghdr *, char *cmsg,
+ struct iovec *, size_t *);
#define SELECT_POKE_SHUTDOWN (-1)
#define SELECT_POKE_NOTHING (-2)
+#define SELECT_POKE_READ (-3)
+#define SELECT_POKE_ACCEPT (-3) /* Same as _READ */
+#define SELECT_POKE_WRITE (-4)
+#define SELECT_POKE_CONNECT (-4) /* Same as _WRITE */
+#define SELECT_POKE_CLOSE (-5)
#define SOCK_DEAD(s) ((s)->references == 0)
}
static void
-wakeup_socket(isc_socketmgr_t *manager, int fd) {
- isc_event_t *ev2;
- isc_socketevent_t *rev;
+wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) {
isc_socket_t *sock;
/*
- * This is a wakeup on a socket. Look at the event queue for both
- * read and write, and decide if we need to watch on it now or not.
+ * This is a wakeup on a socket. If the socket is not in the
+ * process of being closed, start watching it for either reads
+ * or writes.
*/
INSIST(fd < FD_SETSIZE);
* have already queued up the internal event on a task's
* queue, clear the bit. Otherwise, set it.
*/
- rev = ISC_LIST_HEAD(sock->recv_list);
- ev2 = (isc_event_t *) ISC_LIST_HEAD(sock->accept_list);
- if ((rev == NULL && ev2 == NULL)
- || sock->pending_recv || sock->pending_accept)
- FD_CLR(sock->fd, &manager->read_fds);
- else
+ if (msg == SELECT_POKE_READ)
FD_SET(sock->fd, &manager->read_fds);
-
- rev = ISC_LIST_HEAD(sock->send_list);
- if ((rev == NULL || sock->pending_send) && !sock->connecting)
- FD_CLR(sock->fd, &manager->write_fds);
- else
+ if (msg == SELECT_POKE_WRITE)
FD_SET(sock->fd, &manager->write_fds);
}
#ifdef ISC_PLATFORM_USETHREADS
/*
* Poke the select loop when there is something for us to do.
- * We assume that if a write completes here, it will be inserted into the
- * queue fully. That is, we will not get partial writes.
+ * The write is required (by POSIX) to complete. That is, we
+ * will not get partial writes.
*/
static void
-select_poke(isc_socketmgr_t *mgr, int msg) {
+select_poke(isc_socketmgr_t *mgr, int fd, int msg) {
int cc;
+ int buf[2];
+
+ buf[0] = fd;
+ buf[1] = msg;
do {
- cc = write(mgr->pipe_fds[1], &msg, sizeof(int));
+ cc = write(mgr->pipe_fds[1], buf, sizeof(buf));
} while (cc < 0 && SOFT_ERROR(errno));
if (cc < 0)
"during watcher poke: %s"),
strerror(errno));
- INSIST(cc == sizeof(int));
+ INSIST(cc == sizeof(buf));
}
/*
* Read a message on the internal fd.
*/
-static int
-select_readmsg(isc_socketmgr_t *mgr) {
- int msg;
+static void
+select_readmsg(isc_socketmgr_t *mgr, int *fd, int *msg) {
+ int buf[2];
int cc;
- cc = read(mgr->pipe_fds[0], &msg, sizeof(int));
+ cc = read(mgr->pipe_fds[0], buf, sizeof(buf));
if (cc < 0) {
+ *msg = SELECT_POKE_NOTHING;
if (SOFT_ERROR(errno))
- return (SELECT_POKE_NOTHING);
+ return;
FATAL_ERROR(__FILE__, __LINE__,
isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
"during watcher poke: %s"),
strerror(errno));
- return (SELECT_POKE_NOTHING);
+ return;
}
+ INSIST(cc == sizeof(buf));
- return (msg);
+ *fd = buf[0];
+ *msg = buf[1];
}
#else /* ISC_PLATFORM_USETHREADS */
/*
* Update the state of the socketmgr when something changes.
*/
static void
-select_poke(isc_socketmgr_t *manager, int msg) {
+select_poke(isc_socketmgr_t *manager, int fd, int msg) {
if (msg == SELECT_POKE_SHUTDOWN)
return;
- else if (msg >= 0)
- wakeup_socket(manager, msg);
+ else if (fd >= 0)
+ wakeup_socket(manager, fd, msg);
return;
}
#endif /* ISC_PLATFORM_USETHREADS */
}
/*
- * Construct an iov array and attach it to the msghdr passed in. Return
- * 0 on success, non-zero on failure. This is the SEND constructor, which
- * will used the used region of the buffer (if using a buffer list) or
- * will use the internal region (if a single buffer I/O is requested).
+ * Construct an iov array and attach it to the msghdr passed in. This is
+ * the SEND constructor, which will use the used region of the buffer
+ * (if using a buffer list) or will use the internal region (if a single
+ * buffer I/O is requested).
*
* Nothing can be NULL, and the done event must list at least one buffer
* on the buffer linked list for this function to be meaningful.
*/
static void
build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
- struct msghdr *msg, struct iovec *iov, size_t *write_countp)
+ struct msghdr *msg, char *cmsg,
+ struct iovec *iov, size_t *write_countp)
{
unsigned int iovcount;
isc_buffer_t *buffer;
size_t write_count;
size_t skip_count;
+#ifndef USE_CMSG
+ UNUSED(cmsg);
+#endif
+
memset(msg, 0, sizeof (*msg));
if (sock->type == isc_sockettype_udp) {
msg->msg_control = NULL;
msg->msg_controllen = 0;
msg->msg_flags = 0;
-#if defined(USE_CMSG)
+#ifdef USE_CMSG
if ((sock->type == isc_sockettype_udp)
&& ((dev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0)) {
struct cmsghdr *cmsgp;
dev->pktinfo.ipi6_ifindex);
msg->msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
- msg->msg_control = (void *)sock->cmsg;
+ msg->msg_control = (void *)cmsg;
- cmsgp = (struct cmsghdr *)sock->cmsg;
+ cmsgp = (struct cmsghdr *)cmsg;
cmsgp->cmsg_level = IPPROTO_IPV6;
cmsgp->cmsg_type = IPV6_PKTINFO;
cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
}
/*
- * Construct an iov array and attach it to the msghdr passed in. Return
- * 0 on success, non-zero on failure. This is the RECV constructor, which
- * will use the avialable region of the buffer (if using a buffer list) or
- * will use the internal region (if a single buffer I/O is requested).
+ * Construct an iov array and attach it to the msghdr passed in. This is
+ * the RECV constructor, which will use the avialable region of the buffer
+ * (if using a buffer list) or will use the internal region (if a single
+ * buffer I/O is requested).
*
* Nothing can be NULL, and the done event must list at least one buffer
* on the buffer linked list for this function to be meaningful.
*/
static void
build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev,
- struct msghdr *msg, struct iovec *iov, size_t *read_countp)
+ struct msghdr *msg, char *cmsg,
+ struct iovec *iov, size_t *read_countp)
{
unsigned int iovcount;
isc_buffer_t *buffer;
isc_region_t available;
size_t read_count;
+#ifndef USE_CMSG
+ UNUSED(cmsg);
+#endif
+
memset(msg, 0, sizeof (struct msghdr));
if (sock->type == isc_sockettype_udp) {
msg->msg_flags = 0;
#if defined(USE_CMSG)
if (sock->type == isc_sockettype_udp) {
- msg->msg_control = (void *)sock->cmsg;
- msg->msg_controllen = sock->cmsglen;
+ msg->msg_control = cmsg;
+ msg->msg_controllen = CMSG_BUF_SIZE;
}
#endif /* USE_CMSG */
#else /* ISC_NET_BSD44MSGHDR */
size_t actual_count;
struct msghdr msghdr;
isc_buffer_t *buffer;
+#if USE_CMSG
+ char cmsg[CMSG_BUF_SIZE];
+#else
+ char *cmsg = NULL;
+#endif
- build_msghdr_recv(sock, dev, &msghdr, iov, &read_count);
+ build_msghdr_recv(sock, dev, &msghdr, cmsg, iov, &read_count);
#if defined(ISC_SOCKET_DEBUG)
dump_msg(&msghdr);
size_t write_count;
struct msghdr msghdr;
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+#if USE_CMSG
+ char cmsg[CMSG_BUF_SIZE];
+#else
+ char *cmsg = NULL;
+#endif
- build_msghdr_send(sock, dev, &msghdr, iov, &write_count);
+ build_msghdr_send(sock, dev, &msghdr, cmsg, iov, &write_count);
cc = sendmsg(sock->fd, &msghdr, 0);
*/
manager->fds[sock->fd] = NULL;
manager->fdstate[sock->fd] = CLOSE_PENDING;
- select_poke(manager, sock->fd);
+ select_poke(manager, sock->fd, SELECT_POKE_CLOSE);
ISC_LIST_UNLINK(manager->socklist, sock, link);
#ifdef ISC_PLATFORM_USETHREADS
if (sock == NULL)
return (ISC_R_NOMEMORY);
-#if USE_CMSG /* Let's hope the OSs are sane, and pad correctly XXXMLG */
- sock->cmsglen = 0;
-#ifdef ISC_PLATFORM_HAVEIPV6
- sock->cmsglen += CMSG_SPACE(sizeof(struct in6_pktinfo));
-#endif
-#ifdef SO_TIMESTAMP
- sock->cmsglen += CMSG_SPACE(sizeof(struct timeval));
-#endif
- sock->cmsg = isc_mem_get(manager->mctx, sock->cmsglen);
- if (sock->cmsg == NULL) {
- ret = ISC_R_NOMEMORY;
- goto err1;
- }
-#endif
-
ret = ISC_R_UNEXPECTED;
sock->magic = 0;
isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
ISC_MSG_FAILED, "failed"));
ret = ISC_R_UNEXPECTED;
- goto err2;
+ goto error;
}
/*
return (ISC_R_SUCCESS);
- err2: /* cmsg allocated */
-#ifdef USE_CMSG
- isc_mem_put(manager->mctx, sock->cmsg, sock->cmsglen);
- sock->cmsglen = 0;
- sock->cmsg = NULL;
- err1: /* socket allocated */
-#endif
- isc_mem_put(manager->mctx, sock, sizeof *sock);
+ error: /* socket allocated */
return (ret);
}
DESTROYLOCK(&sock->lock);
-#ifdef USE_CMSG
- isc_mem_put(sock->manager->mctx, sock->cmsg, sock->cmsglen);
-#endif
isc_mem_put(sock->manager->mctx, sock, sizeof *sock);
*socketp = NULL;
}
/*
- * Create a new 'type' socket managed by 'manager'. The sockets
- * parameters are specified by 'expires' and 'interval'. Events
+ * Create a new 'type' socket managed by 'manager'. Events
* will be posted to 'task' and when dispatched 'action' will be
* called with 'arg' as the arg value. The new socket is returned
* in 'socketp'.
* If the event to be sent is on a list, remove it before sending. If
* asked to, send and detach from the socket as well.
*
- * Caller must have the socket locked.
+ * Caller must have the socket locked if the event is attached to the socket.
*/
static void
send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev,
/*
* See comments for send_recvdone_event() above.
*
- * Caller must have the socket locked.
+ * Caller must have the socket locked if the event is attached to the socket.
*/
static void
send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev,
(void *)&addrlen);
if (fd < 0) {
if (SOFT_ERROR(errno)) {
- select_poke(sock->manager, sock->fd);
+ select_poke(sock->manager, sock->fd,
+ SELECT_POKE_ACCEPT);
UNLOCK(&sock->lock);
return;
}
* Poke watcher if there are more pending accepts.
*/
if (!ISC_LIST_EMPTY(sock->accept_list))
- select_poke(sock->manager, sock->fd);
+ select_poke(sock->manager, sock->fd, SELECT_POKE_ACCEPT);
UNLOCK(&sock->lock);
* read of 0 means the remote end was closed.
* Run through the event queue and dispatch all
* the events with an EOF result code. This will
- * set the EOF flag in markers as well, but
+ * set the EOF flag in markers as well, but
* that's really ok.
*/
do {
poke:
if (!ISC_LIST_EMPTY(sock->recv_list))
- select_poke(sock->manager, sock->fd);
+ select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
UNLOCK(&sock->lock);
}
poke:
if (!ISC_LIST_EMPTY(sock->send_list))
- select_poke(sock->manager, sock->fd);
+ select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
UNLOCK(&sock->lock);
}
int cc;
fd_set readfds;
fd_set writefds;
- int msg;
+ int msg, fd;
int maxfd;
/*
*/
if (FD_ISSET(ctlfd, &readfds)) {
for (;;) {
- msg = select_readmsg(manager);
+ select_readmsg(manager, &fd, &msg);
manager_log(manager, IOEVENT,
isc_msgcat_get(isc_msgcat,
break;
/*
- * handle shutdown message. We really should
+ * Handle shutdown message. We really should
* jump out of this loop right away, but
* it doesn't matter if we have to do a little
* more work first.
* and decide if we need to watch on it now
* or not.
*/
- if (msg >= 0)
- wakeup_socket(manager, msg);
+ wakeup_socket(manager, fd, msg);
}
}
* half of the pipe, which will send EOF to the read half.
* This is currently a no-op in the non-threaded case.
*/
- select_poke(manager, SELECT_POKE_SHUTDOWN);
+ select_poke(manager, 0, SELECT_POKE_SHUTDOWN);
#ifdef ISC_PLATFORM_USETHREADS
/*
isc_socketevent_t *dev;
isc_socketmgr_t *manager;
isc_task_t *ntask = NULL;
- isc_boolean_t was_empty;
unsigned int iocount;
isc_buffer_t *buffer;
+ int io_state;
+ isc_boolean_t have_lock = ISC_FALSE;
REQUIRE(VALID_SOCKET(sock));
REQUIRE(buflist != NULL);
iocount = isc_bufferlist_availablecount(buflist);
REQUIRE(iocount > 0);
- LOCK(&sock->lock);
-
INSIST(sock->bound);
dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg);
if (dev == NULL) {
- UNLOCK(&sock->lock);
return (ISC_R_NOMEMORY);
}
buffer = ISC_LIST_HEAD(*buflist);
}
- /*
- * If the read queue is empty, try to do the I/O right now.
- */
- was_empty = ISC_LIST_EMPTY(sock->recv_list);
- if (!was_empty)
- goto queue;
+ if (sock->type == isc_sockettype_udp) {
+ io_state = doio_recv(sock, dev);
+ } else {
+ LOCK(&sock->lock);
+ have_lock = ISC_TRUE;
- switch (doio_recv(sock, dev)) {
+ if (ISC_LIST_EMPTY(sock->recv_list))
+ io_state = doio_recv(sock, dev);
+ else
+ io_state = DOIO_SOFT;
+ }
+
+ switch (io_state) {
case DOIO_SOFT:
- goto queue;
+ /*
+ * We couldn't read all or part of the request right now, so
+ * queue it.
+ *
+ * Attach to socket and to task
+ */
+ isc_task_attach(task, &ntask);
+ dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+ if (!have_lock) {
+ LOCK(&sock->lock);
+ have_lock = ISC_TRUE;
+ }
+
+ /*
+ * Enqueue the request. If the socket was previously not being
+ * watched, poke the watcher to start paying attention to it.
+ */
+ if (ISC_LIST_EMPTY(sock->recv_list))
+ select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
+ ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
+
+ socket_log(sock, NULL, EVENT, NULL, 0, 0,
+ "isc_socket_recvv: event %p -> task %p",
+ dev, ntask);
+
+ break;
case DOIO_EOF:
send_recvdone_event(sock, &dev, ISC_R_EOF);
- UNLOCK(&sock->lock);
- return (ISC_R_SUCCESS);
+ break;
case DOIO_HARD:
case DOIO_SUCCESS:
- UNLOCK(&sock->lock);
- return (ISC_R_SUCCESS);
+ break;
}
- queue:
- /*
- * We couldn't read all or part of the request right now, so queue
- * it.
- *
- * Attach to socket and to task
- */
- isc_task_attach(task, &ntask);
- dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
-
- /*
- * Enqueue the request. If the socket was previously not being
- * watched, poke the watcher to start paying attention to it.
- */
- ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
- if (was_empty)
- select_poke(sock->manager, sock->fd);
-
- socket_log(sock, NULL, EVENT, NULL, 0, 0,
- "isc_socket_recvv: event %p -> task %p", dev, ntask);
+ if (have_lock)
+ UNLOCK(&sock->lock);
- UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
}
isc_socketevent_t *dev;
isc_socketmgr_t *manager;
isc_task_t *ntask = NULL;
- isc_boolean_t was_empty;
+ isc_boolean_t have_lock = ISC_FALSE;
+ int io_state;
REQUIRE(VALID_SOCKET(sock));
REQUIRE(region != NULL);
manager = sock->manager;
REQUIRE(VALID_MANAGER(manager));
- LOCK(&sock->lock);
-
INSIST(sock->bound);
dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg);
if (dev == NULL) {
- UNLOCK(&sock->lock);
return (ISC_R_NOMEMORY);
}
dev->region = *region;
dev->ev_sender = task;
+ if (sock->type == isc_sockettype_udp) {
+ io_state = doio_recv(sock, dev);
+ } else {
+ LOCK(&sock->lock);
+ have_lock = ISC_TRUE;
- /*
- * If the read queue is empty, try to do the I/O right now.
- */
- was_empty = ISC_LIST_EMPTY(sock->recv_list);
- if (!was_empty)
- goto queue;
+ if (ISC_LIST_EMPTY(sock->recv_list))
+ io_state = doio_recv(sock, dev);
+ else
+ io_state = DOIO_SOFT;
+ }
- switch (doio_recv(sock, dev)) {
+ switch (io_state) {
case DOIO_SOFT:
- goto queue;
+ /*
+ * We couldn't read all or part of the request right now, so
+ * queue it.
+ *
+ * Attach to socket and to task
+ */
+ isc_task_attach(task, &ntask);
+ dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+ if (!have_lock) {
+ LOCK(&sock->lock);
+ have_lock = ISC_TRUE;
+ }
+
+ /*
+ * Enqueue the request. If the socket was previously not being
+ * watched, poke the watcher to start paying attention to it.
+ */
+ if (ISC_LIST_EMPTY(sock->recv_list))
+ select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
+ ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
+
+ socket_log(sock, NULL, EVENT, NULL, 0, 0,
+ "isc_socket_recv: event %p -> task %p",
+ dev, ntask);
+
+ break;
case DOIO_EOF:
send_recvdone_event(sock, &dev, ISC_R_EOF);
- UNLOCK(&sock->lock);
- return (ISC_R_SUCCESS);
+ break;
case DOIO_HARD:
case DOIO_SUCCESS:
- UNLOCK(&sock->lock);
- return (ISC_R_SUCCESS);
+ break;
}
- queue:
- /*
- * We couldn't read all or part of the request right now, so queue
- * it.
- *
- * Attach to socket and to task.
- */
- isc_task_attach(task, &ntask);
- dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
-
- /*
- * Enqueue the request. If the socket was previously not being
- * watched, poke the watcher to start paying attention to it.
- */
- ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
- if (was_empty)
- select_poke(sock->manager, sock->fd);
-
- socket_log(sock, NULL, EVENT, NULL, 0, 0,
- "isc_socket_recv: event %p -> task %p", dev, ntask);
+ if (have_lock)
+ UNLOCK(&sock->lock);
- UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
}
isc_socketevent_t *dev;
isc_socketmgr_t *manager;
isc_task_t *ntask = NULL;
- isc_boolean_t was_empty;
+ isc_boolean_t have_lock = ISC_FALSE;
+ int io_state;
REQUIRE(VALID_SOCKET(sock));
REQUIRE(region != NULL);
manager = sock->manager;
REQUIRE(VALID_MANAGER(manager));
- LOCK(&sock->lock);
-
INSIST(sock->bound);
dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
if (dev == NULL) {
- UNLOCK(&sock->lock);
return (ISC_R_NOMEMORY);
}
dev->pktinfo.ipi6_ifindex = 0;
}
- /*
- * If the write queue is empty, try to do the I/O right now.
- */
- was_empty = ISC_LIST_EMPTY(sock->send_list);
- if (!was_empty)
- goto queue;
+ if (sock->type == isc_sockettype_udp) {
+ io_state = doio_send(sock, dev);
+ } else {
+ LOCK(&sock->lock);
+ have_lock = ISC_TRUE;
- switch (doio_send(sock, dev)) {
+ if (ISC_LIST_EMPTY(sock->send_list))
+ io_state = doio_send(sock, dev);
+ else
+ io_state = DOIO_SOFT;
+ }
+
+ switch (io_state) {
case DOIO_SOFT:
- goto queue;
+ /*
+ * We couldn't send all or part of the request right now, so
+ * queue it.
+ */
+ isc_task_attach(task, &ntask);
+ dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+ if (!have_lock) {
+ LOCK(&sock->lock);
+ have_lock = ISC_TRUE;
+ }
+
+ /*
+ * Enqueue the request. If the socket was previously not being
+ * watched, poke the watcher to start paying attention to it.
+ */
+ if (ISC_LIST_EMPTY(sock->send_list))
+ select_poke(sock->manager, sock->fd,
+ SELECT_POKE_WRITE);
+ ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
+
+ socket_log(sock, NULL, EVENT, NULL, 0, 0,
+ "isc_socket_sendto: event %p -> task %p",
+ dev, ntask);
+
+ break;
case DOIO_HARD:
case DOIO_SUCCESS:
- UNLOCK(&sock->lock);
- return (ISC_R_SUCCESS);
+ break;
}
- queue:
- /*
- * We couldn't send all or part of the request right now, so queue
- * it.
- */
- isc_task_attach(task, &ntask);
- dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
-
- /*
- * Enqueue the request. If the socket was previously not being
- * watched, poke the watcher to start paying attention to it.
- */
- ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
- if (was_empty)
- select_poke(sock->manager, sock->fd);
-
- socket_log(sock, NULL, EVENT, NULL, 0, 0,
- "isc_socket_sendto: event %p -> task %p", dev, ntask);
+ if (have_lock)
+ UNLOCK(&sock->lock);
- UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
}
isc_socketevent_t *dev;
isc_socketmgr_t *manager;
isc_task_t *ntask = NULL;
- isc_boolean_t was_empty;
unsigned int iocount;
isc_buffer_t *buffer;
+ int io_state;
+ isc_boolean_t have_lock = ISC_FALSE;
REQUIRE(VALID_SOCKET(sock));
REQUIRE(buflist != NULL);
iocount = isc_bufferlist_usedcount(buflist);
REQUIRE(iocount > 0);
- LOCK(&sock->lock);
-
dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
if (dev == NULL) {
- UNLOCK(&sock->lock);
return (ISC_R_NOMEMORY);
}
buffer = ISC_LIST_HEAD(*buflist);
}
- /*
- * If the read queue is empty, try to do the I/O right now.
- */
- was_empty = ISC_LIST_EMPTY(sock->send_list);
- if (!was_empty)
- goto queue;
+ if (sock->type == isc_sockettype_udp) {
+ io_state = doio_send(sock, dev);
+ } else {
+ LOCK(&sock->lock);
+ have_lock = ISC_TRUE;
+
+ if (ISC_LIST_EMPTY(sock->send_list))
+ io_state = doio_send(sock, dev);
+ else
+ io_state = DOIO_SOFT;
+ }
- switch (doio_send(sock, dev)) {
+ switch (io_state) {
case DOIO_SOFT:
- goto queue;
+ /*
+ * We couldn't send all or part of the request right now, so
+ * queue it.
+ */
+ isc_task_attach(task, &ntask);
+ dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+ if (!have_lock) {
+ LOCK(&sock->lock);
+ have_lock = ISC_TRUE;
+ }
+
+ /*
+ * Enqueue the request. If the socket was previously not being
+ * watched, poke the watcher to start paying attention to it.
+ */
+ if (ISC_LIST_EMPTY(sock->send_list))
+ select_poke(sock->manager, sock->fd,
+ SELECT_POKE_WRITE);
+ ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
+
+ socket_log(sock, NULL, EVENT, NULL, 0, 0,
+ "isc_socket_sendtov: event %p -> task %p",
+ dev, ntask);
+
+ break;
case DOIO_HARD:
case DOIO_SUCCESS:
- UNLOCK(&sock->lock);
- return (ISC_R_SUCCESS);
+ break;
}
- queue:
- /*
- * We couldn't send all or part of the request right now, so queue
- * it.
- */
- isc_task_attach(task, &ntask);
- dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
-
- /*
- * Enqueue the request. If the socket was previously not being
- * watched, poke the watcher to start paying attention to it.
- */
- ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
- if (was_empty)
- select_poke(sock->manager, sock->fd);
-
- socket_log(sock, NULL, EVENT, NULL, 0, 0,
- "isc_socket_sendtov: event %p -> task %p", dev, ntask);
+ if (have_lock)
+ UNLOCK(&sock->lock);
- UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
}
ISC_LIST_ENQUEUE(sock->accept_list, dev, ev_link);
if (do_poke)
- select_poke(manager, sock->fd);
+ select_poke(manager, sock->fd, SELECT_POKE_ACCEPT);
UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
* bit of time waking it up now or later won't matter all that much.
*/
if (sock->connect_ev == NULL)
- select_poke(manager, sock->fd);
+ select_poke(manager, sock->fd, SELECT_POKE_CONNECT);
sock->connect_ev = dev;
*/
if (SOFT_ERROR(errno) || errno == EINPROGRESS) {
sock->connecting = 1;
- select_poke(sock->manager, sock->fd);
+ select_poke(sock->manager, sock->fd,
+ SELECT_POKE_CONNECT);
UNLOCK(&sock->lock);
return;
}
}
- /*
- * Need to guess if we need to poke or not... XXX
- */
- select_poke(sock->manager, sock->fd);
-
UNLOCK(&sock->lock);
}