diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h index 56c66396ce..50ba2c42a4 100644 --- a/lib/isc/include/isc/socket.h +++ b/lib/isc/include/isc/socket.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: socket.h,v 1.53 2001/02/12 21:43:17 bwelling Exp $ */ +/* $Id: socket.h,v 1.54 2001/03/06 01:23:02 bwelling Exp $ */ #ifndef ISC_SOCKET_H #define ISC_SOCKET_H 1 @@ -167,6 +167,7 @@ typedef enum { * Flags for isc_socket_send() and isc_socket_recv() calls. */ #define ISC_SOCKFLAG_IMMEDIATE 0x00000001 /* send event only if needed */ +#define ISC_SOCKFLAG_NORETRY 0x00000002 /* drop failed UDP sends */ /*** *** Socket and Socket Manager Functions @@ -569,12 +570,20 @@ isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region, * expected to be initialized. * * For isc_socket_sendto2(): - * The only defined value for 'flags' is ISC_SOCKFLAG_IMMEDIATE. If - * set and the operation completes, the return value will be - * ISC_R_SUCCESS and the event will be filled in and not sent. If the - * operation does not complete, the return value will be - * ISC_R_INPROGRESS and the event will be sent when the operation - * completes. + * The only defined values for 'flags' are ISC_SOCKFLAG_IMMEDIATE + * and ISC_SOCKFLAG_NORETRY. + * + * If ISC_SOCKFLAG_IMMEDIATE is set and the operation completes, the + * return value will be ISC_R_SUCCESS and the event will be filled + * in and not sent. If the operation does not complete, the return + * value will be ISC_R_INPROGRESS and the event will be sent when + * the operation completes. + * + * ISC_SOCKFLAG_NORETRY can only be set for UDP sockets. If set + * and the send operation fails due to a transient error, the send + * will not be retried and the error will be indicated in the event. + * Using this option along with ISC_SOCKFLAG_IMMEDIATE allows the caller + * to specify a region that is allocated on the stack. * * Requires: * diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index 05e28b4ed3..f58e0676b4 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: socket.c,v 1.193 2001/02/24 23:51:09 gson Exp $ */ +/* $Id: socket.c,v 1.194 2001/03/06 01:23:03 bwelling Exp $ */ #include @@ -151,6 +151,11 @@ typedef isc_event_t intev_t; #endif /* USE_CMSG */ +/* + * The number of times a send operation is repeated if the result is EINTR. + */ +#define NRETRIES 10 + struct isc_socket { /* Not locked. */ unsigned int magic; @@ -1002,15 +1007,20 @@ doio_send(isc_socket_t *sock, isc_socketevent_t *dev) { #else char *cmsg = NULL; #endif + int attempts = 0; build_msghdr_send(sock, dev, &msghdr, cmsg, iov, &write_count); + resend: cc = sendmsg(sock->fd, &msghdr, 0); /* * Check for error or block condition. */ if (cc < 0) { + if (errno == EINTR && ++attempts < NRETRIES) + goto resend; + if (SOFT_ERROR(errno)) return (DOIO_SOFT); @@ -2476,33 +2486,36 @@ socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, case DOIO_SOFT: /* * We couldn't send all or part of the request right now, so - * queue it. + * queue it unless ISC_SOCKFLAG_NORETRY is set. */ - isc_task_attach(task, &ntask); - dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED; + if ((flags & ISC_SOCKFLAG_NORETRY) == 0) { + isc_task_attach(task, &ntask); + dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED; - if (!have_lock) { - LOCK(&sock->lock); - have_lock = ISC_TRUE; + 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, + "socket_send: event %p -> task %p", + dev, ntask); + + if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0) + result = ISC_R_INPROGRESS; + break; } - /* - * 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, - "socket_send: event %p -> task %p", - dev, ntask); - - if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0) - result = ISC_R_INPROGRESS; - break; - case DOIO_HARD: case DOIO_SUCCESS: if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0) @@ -2609,6 +2622,9 @@ isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region, isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, isc_socketevent_t *event, unsigned int flags) { + REQUIRE((flags & ~(ISC_SOCKFLAG_IMMEDIATE|ISC_SOCKFLAG_NORETRY)) == 0); + if ((flags & ISC_SOCKFLAG_NORETRY) != 0) + REQUIRE(sock->type == isc_sockettype_udp); event->ev_sender = sock; event->result = ISC_R_UNEXPECTED; ISC_LIST_INIT(event->bufferlist);