mirror of
https://github.com/isc-projects/bind9.git
synced 2026-02-26 03:11:56 -05:00
deal with partial writes correctly
This commit is contained in:
parent
ad4f276061
commit
3467456ae4
1 changed files with 79 additions and 68 deletions
|
|
@ -188,10 +188,12 @@ static void internal_connect(isc_task_t *, isc_event_t *);
|
|||
static void internal_recv(isc_task_t *, isc_event_t *);
|
||||
static void internal_send(isc_task_t *, isc_event_t *);
|
||||
static void process_cmsg(isc_socket_t *, struct msghdr *, isc_socketevent_t *);
|
||||
static int build_msghdr_send(isc_socketevent_t *, struct msghdr *,
|
||||
struct iovec *, unsigned int maxiov);
|
||||
static int build_msghdr_recv(isc_socketevent_t *, struct msghdr *,
|
||||
struct iovec *, unsigned int maxiov);
|
||||
static int build_msghdr_send(isc_socket_t *, isc_socketevent_t *,
|
||||
struct msghdr *, struct iovec *, unsigned int,
|
||||
size_t *);
|
||||
static int build_msghdr_recv(isc_socket_t *, isc_socketevent_t *,
|
||||
struct msghdr *, struct iovec *, unsigned int,
|
||||
unsigned int *);
|
||||
|
||||
#define SELECT_POKE_SHUTDOWN (-1)
|
||||
#define SELECT_POKE_NOTHING (-2)
|
||||
|
|
@ -303,25 +305,50 @@ process_cmsg(isc_socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev)
|
|||
* on the buffer linked list for this function to be meaningful.
|
||||
*/
|
||||
static int
|
||||
build_msghdr_send(isc_socketevent_t *dev, struct msghdr *msg,
|
||||
struct iovec *iov, unsigned int maxiov)
|
||||
build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
|
||||
struct msghdr *msg, struct iovec *iov, unsigned int maxiov,
|
||||
size_t *write_countp)
|
||||
{
|
||||
unsigned int iovcount;
|
||||
isc_buffer_t *buffer;
|
||||
isc_region_t used;
|
||||
size_t write_count;
|
||||
size_t skip_count;
|
||||
|
||||
memset(msg, 0, sizeof (struct msghdr));
|
||||
|
||||
if (sock->type == isc_sockettype_udp) {
|
||||
msg->msg_name = (void *)&dev->address.type.sa;
|
||||
msg->msg_namelen = dev->address.length;
|
||||
}
|
||||
|
||||
buffer = ISC_LIST_HEAD(dev->bufferlist);
|
||||
write_count = 0;
|
||||
skip_count = 0;
|
||||
|
||||
/*
|
||||
* Single buffer I/O?
|
||||
* Single buffer I/O? Skip what we've done so far in this region.
|
||||
*/
|
||||
if (buffer == NULL) {
|
||||
iov[0].iov_base = (void *)dev->region.base;
|
||||
iov[0].iov_len = dev->region.length;
|
||||
write_count = dev->region.length - dev->n;
|
||||
iov[0].iov_base = (void *)(dev->region.base + dev->n);
|
||||
iov[0].iov_len = write_count;
|
||||
msg->msg_iov = iov;
|
||||
msg->msg_iovlen = 1;
|
||||
|
||||
return (0);
|
||||
goto config;
|
||||
}
|
||||
|
||||
/*
|
||||
* Multibuffer I/O.
|
||||
* Skip the data in the buffer list that we have already written.
|
||||
*/
|
||||
while (buffer != NULL) {
|
||||
isc_buffer_used(buffer, &used);
|
||||
if (skip_count < used.length)
|
||||
break;
|
||||
skip_count -= used.length;
|
||||
buffer = ISC_LIST_NEXT(buffer, link);
|
||||
}
|
||||
|
||||
iovcount = 0;
|
||||
|
|
@ -330,9 +357,13 @@ build_msghdr_send(isc_socketevent_t *dev, struct msghdr *msg,
|
|||
return (-1);
|
||||
|
||||
isc_buffer_used(buffer, &used);
|
||||
|
||||
if (used.length > 0) {
|
||||
iov[iovcount].iov_base = (void *)used.base;
|
||||
iov[iovcount].iov_len = used.length;
|
||||
iov[iovcount].iov_base = (void *)(used.base
|
||||
+ skip_count);
|
||||
iov[iovcount].iov_len = used.length - skip_count;
|
||||
write_count += (used.length - skip_count);
|
||||
skip_count = 0;
|
||||
iovcount++;
|
||||
}
|
||||
buffer = ISC_LIST_NEXT(buffer, link);
|
||||
|
|
@ -341,9 +372,37 @@ build_msghdr_send(isc_socketevent_t *dev, struct msghdr *msg,
|
|||
msg->msg_iov = iov;
|
||||
msg->msg_iovlen = iovcount;
|
||||
|
||||
config:
|
||||
#ifdef ISC_NET_BSD44MSGHDR
|
||||
msg->msg_control = NULL;
|
||||
msg->msg_controllen = 0;
|
||||
msg->msg_flags = 0;
|
||||
#else
|
||||
msg->msg_accrights = NULL;
|
||||
msg->msg_accrightslen = 0;
|
||||
#endif
|
||||
|
||||
if (write_countp != NULL)
|
||||
*write_countp = write_count;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
set_dev_address(isc_sockaddr_t *address, isc_socket_t *sock,
|
||||
isc_socketevent_t *dev)
|
||||
{
|
||||
if (sock->type == isc_sockettype_udp) {
|
||||
if (address != NULL)
|
||||
dev->address = *address;
|
||||
else
|
||||
dev->address = sock->address;
|
||||
} else if (sock->type == isc_sockettype_tcp) {
|
||||
INSIST(address == NULL);
|
||||
dev->address = sock->address;
|
||||
}
|
||||
}
|
||||
|
||||
static isc_socketevent_t *
|
||||
allocate_socketevent(isc_socket_t *sock, isc_eventtype_t eventtype,
|
||||
isc_taskaction_t action, void *arg)
|
||||
|
|
@ -1199,27 +1258,8 @@ internal_send(isc_task_t *me, isc_event_t *ev)
|
|||
* It must be a write request. Try to satisfy it as best
|
||||
* we can.
|
||||
*/
|
||||
write_count = dev->region.length - dev->n;
|
||||
iov[0].iov_base = (void *)(dev->region.base + dev->n);
|
||||
iov[0].iov_len = write_count;
|
||||
|
||||
memset(&msghdr, 0, sizeof (msghdr));
|
||||
if (sock->type == isc_sockettype_udp) {
|
||||
msghdr.msg_name = (void *)&dev->address.type.sa;
|
||||
msghdr.msg_namelen = dev->address.length;
|
||||
}
|
||||
|
||||
msghdr.msg_iov = iov;
|
||||
msghdr.msg_iovlen = 1;
|
||||
|
||||
#ifdef ISC_NET_BSD44MSGHDR
|
||||
msghdr.msg_control = NULL;
|
||||
msghdr.msg_controllen = 0;
|
||||
msghdr.msg_flags = 0;
|
||||
#else
|
||||
msghdr.msg_accrights = NULL;
|
||||
msghdr.msg_accrightslen = 0;
|
||||
#endif
|
||||
build_msghdr_send(sock, dev, &msghdr, iov,
|
||||
ISC_SOCKET_MAXSCATTERGATHER, &write_count);
|
||||
|
||||
cc = sendmsg(sock->fd, &msghdr, 0);
|
||||
|
||||
|
|
@ -1917,6 +1957,7 @@ isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
|
|||
isc_boolean_t was_empty;
|
||||
struct msghdr msghdr;
|
||||
struct iovec iov[ISC_SOCKET_MAXSCATTERGATHER];
|
||||
size_t write_count;
|
||||
|
||||
REQUIRE(VALID_SOCKET(sock));
|
||||
REQUIRE(region != NULL);
|
||||
|
|
@ -1935,52 +1976,22 @@ isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
|
|||
UNLOCK(&sock->lock);
|
||||
return (ISC_R_NOMEMORY);
|
||||
}
|
||||
ISC_LINK_INIT(dev, link);
|
||||
ISC_LIST_INIT(dev->bufferlist);
|
||||
|
||||
dev->result = ISC_R_SUCCESS;
|
||||
dev->minimum = region->length;
|
||||
dev->n = 0;
|
||||
dev->region = *region;
|
||||
|
||||
was_empty = ISC_LIST_EMPTY(sock->send_list);
|
||||
|
||||
if (sock->type == isc_sockettype_udp) {
|
||||
if (address != NULL)
|
||||
dev->address = *address;
|
||||
else
|
||||
dev->address = sock->address;
|
||||
} else if (sock->type == isc_sockettype_tcp) {
|
||||
INSIST(address == NULL);
|
||||
dev->address = sock->address;
|
||||
}
|
||||
set_dev_address(address, sock, dev);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
iov[0].iov_base = (void *)(dev->region.base);
|
||||
iov[0].iov_len = dev->region.length;
|
||||
|
||||
memset(&msghdr, 0, sizeof (msghdr));
|
||||
if (sock->type == isc_sockettype_udp) {
|
||||
msghdr.msg_name = (void *)&dev->address.type.sa;
|
||||
msghdr.msg_namelen = dev->address.length;
|
||||
}
|
||||
|
||||
msghdr.msg_iov = iov;
|
||||
msghdr.msg_iovlen = 1;
|
||||
|
||||
#ifdef ISC_NET_BSD44MSGHDR
|
||||
msghdr.msg_control = NULL;
|
||||
msghdr.msg_controllen = 0;
|
||||
msghdr.msg_flags = 0;
|
||||
#else
|
||||
msghdr.msg_accrights = NULL;
|
||||
msghdr.msg_accrightslen = 0;
|
||||
#endif
|
||||
build_msghdr_send(sock, dev, &msghdr,
|
||||
iov, ISC_SOCKET_MAXSCATTERGATHER, &write_count);
|
||||
|
||||
cc = sendmsg(sock->fd, &msghdr, 0);
|
||||
|
||||
|
|
@ -2029,7 +2040,7 @@ isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
|
|||
/*
|
||||
* Partial writes need to be queued
|
||||
*/
|
||||
if ((size_t)cc != dev->region.length)
|
||||
if ((size_t)cc != write_count)
|
||||
goto queue;
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in a new issue