2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-03 08:05:21 +00:00

common path for sending, too

This commit is contained in:
Michael Graff
1999-09-03 01:18:45 +00:00
parent ad76b9d585
commit e823f5d408

View File

@@ -177,8 +177,8 @@ struct isc_socketmgr {
static void send_recvdone_event(isc_socket_t *, isc_socketevent_t **, static void send_recvdone_event(isc_socket_t *, isc_socketevent_t **,
isc_result_t); isc_result_t);
static void send_senddone_event(isc_socket_t *, isc_task_t **, static void send_senddone_event(isc_socket_t *, isc_socketevent_t **,
isc_socketevent_t **, isc_result_t, int); isc_result_t);
static void free_socket(isc_socket_t **); static void free_socket(isc_socket_t **);
static isc_result_t allocate_socket(isc_socketmgr_t *, isc_sockettype_t, static isc_result_t allocate_socket(isc_socketmgr_t *, isc_sockettype_t,
isc_socket_t **); isc_socket_t **);
@@ -188,12 +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_recv(isc_task_t *, isc_event_t *);
static void internal_send(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 void process_cmsg(isc_socket_t *, struct msghdr *, isc_socketevent_t *);
static int build_msghdr_send(isc_socket_t *, isc_socketevent_t *, static void build_msghdr_send(isc_socket_t *, isc_socketevent_t *,
struct msghdr *, struct iovec *, unsigned int, struct msghdr *, struct iovec *, unsigned int,
size_t *); size_t *);
static int build_msghdr_recv(isc_socket_t *, isc_socketevent_t *, static void build_msghdr_recv(isc_socket_t *, isc_socketevent_t *,
struct msghdr *, struct iovec *, unsigned int, struct msghdr *, struct iovec *, unsigned int,
size_t *); size_t *);
#define SELECT_POKE_SHUTDOWN (-1) #define SELECT_POKE_SHUTDOWN (-1)
#define SELECT_POKE_NOTHING (-2) #define SELECT_POKE_NOTHING (-2)
@@ -307,7 +307,7 @@ process_cmsg(isc_socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev)
* If write_countp != NULL, *write_countp will hold the number of bytes * If write_countp != NULL, *write_countp will hold the number of bytes
* this transaction can send. * this transaction can send.
*/ */
static int static void
build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev, build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
struct msghdr *msg, struct iovec *iov, unsigned int maxiov, struct msghdr *msg, struct iovec *iov, unsigned int maxiov,
size_t *write_countp) size_t *write_countp)
@@ -358,8 +358,7 @@ build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
} }
while (buffer != NULL) { while (buffer != NULL) {
if (iovcount == maxiov) INSIST(iovcount < maxiov);
return (-1);
isc_buffer_used(buffer, &used); isc_buffer_used(buffer, &used);
@@ -391,8 +390,6 @@ build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
if (write_countp != NULL) if (write_countp != NULL)
*write_countp = write_count; *write_countp = write_count;
return (0);
} }
/* /*
@@ -407,7 +404,7 @@ build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
* If read_countp != NULL, *read_countp will hold the number of bytes * If read_countp != NULL, *read_countp will hold the number of bytes
* this transaction can receive. * this transaction can receive.
*/ */
static int static void
build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev, build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev,
struct msghdr *msg, struct iovec *iov, unsigned int maxiov, struct msghdr *msg, struct iovec *iov, unsigned int maxiov,
size_t *read_countp) size_t *read_countp)
@@ -458,8 +455,7 @@ build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev,
iovcount = 0; iovcount = 0;
while (buffer != NULL) { while (buffer != NULL) {
if (iovcount == maxiov) INSIST(iovcount < maxiov);
return (-1);
isc_buffer_available(buffer, &available); isc_buffer_available(buffer, &available);
@@ -487,8 +483,6 @@ build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev,
if (read_countp != NULL) if (read_countp != NULL)
*read_countp = read_count; *read_countp = read_count;
return (0);
} }
static void static void
@@ -530,11 +524,12 @@ allocate_socketevent(isc_socket_t *sock, isc_eventtype_t eventtype,
return (ev); return (ev);
} }
#define DOIO_SUCCESS 0 #define DOIO_SUCCESS 0 /* i/o ok, event sent */
#define DOIO_SOFT 1 #define DOIO_SOFT 1 /* i/o ok, soft error, no event sent */
#define DOIO_HARD 2 #define DOIO_HARD 2 /* i/o error, event sent */
#define DOIO_EOF 3 #define DOIO_EOF 3 /* EOF, no event sent */
#define DOIO_UNEXPECTED (-1) #define DOIO_UNEXPECTED (-1) /* bad stuff, no event sent */
static int static int
doio_recv(isc_socket_t *sock, isc_socketevent_t *dev) doio_recv(isc_socket_t *sock, isc_socketevent_t *dev)
{ {
@@ -543,10 +538,8 @@ doio_recv(isc_socket_t *sock, isc_socketevent_t *dev)
size_t read_count; size_t read_count;
struct msghdr msghdr; struct msghdr msghdr;
if (build_msghdr_recv(sock, dev, &msghdr, iov, build_msghdr_recv(sock, dev, &msghdr, iov,
ISC_SOCKET_MAXSCATTERGATHER, &read_count) ISC_SOCKET_MAXSCATTERGATHER, &read_count);
!= 0)
return (DOIO_UNEXPECTED); /* XXX Need better errors! */
cc = recvmsg(sock->fd, &msghdr, 0); cc = recvmsg(sock->fd, &msghdr, 0);
if (sock->type == isc_sockettype_udp) if (sock->type == isc_sockettype_udp)
@@ -567,9 +560,9 @@ doio_recv(isc_socket_t *sock, isc_socketevent_t *dev)
if (sock->type == isc_sockettype_tcp) \ if (sock->type == isc_sockettype_tcp) \
sock->recv_result = _isc; \ sock->recv_result = _isc; \
send_recvdone_event(sock, &dev, _isc); \ send_recvdone_event(sock, &dev, _isc); \
return (DOIO_HARD); \
} \ } \
select_poke(sock->manager, sock->fd); \ return (DOIO_SOFT); \
return (DOIO_HARD); \
} }
SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED); SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED);
@@ -582,7 +575,7 @@ doio_recv(isc_socket_t *sock, isc_socketevent_t *dev)
*/ */
if (errno == ENOBUFS) { if (errno == ENOBUFS) {
send_recvdone_event(sock, &dev, ISC_R_UNEXPECTED); send_recvdone_event(sock, &dev, ISC_R_UNEXPECTED);
return (DOIO_SOFT); return (DOIO_HARD);
} }
sock->recv_result = ISC_R_UNEXPECTED; sock->recv_result = ISC_R_UNEXPECTED;
@@ -622,7 +615,87 @@ doio_recv(isc_socket_t *sock, isc_socketevent_t *dev)
* full reads are posted, or partials if partials are ok. * full reads are posted, or partials if partials are ok.
*/ */
send_recvdone_event(sock, &dev, ISC_R_SUCCESS); send_recvdone_event(sock, &dev, ISC_R_SUCCESS);
return (DOIO_SUCCESS);
}
static int
doio_send(isc_socket_t *sock, isc_socketevent_t *dev)
{
int cc;
struct iovec iov[ISC_SOCKET_MAXSCATTERGATHER];
size_t write_count;
struct msghdr msghdr;
build_msghdr_send(sock, dev, &msghdr, iov,
ISC_SOCKET_MAXSCATTERGATHER, &write_count);
cc = sendmsg(sock->fd, &msghdr, 0);
/*
* check for error or block condition
*/
if (cc < 0) {
if (SOFT_ERROR(errno))
return (DOIO_SOFT);
#define SOFT_OR_HARD(_system, _isc) \
if (errno == _system) { \
if (sock->connected) { \
if (sock->type == isc_sockettype_tcp) \
sock->send_result = _isc; \
send_senddone_event(sock, &dev, _isc); \
return (DOIO_HARD); \
} \
return (DOIO_SOFT); \
}
SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED);
SOFT_OR_HARD(ENETUNREACH, ISC_R_NETUNREACH);
SOFT_OR_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH);
#undef SOFT_OR_HARD
/*
* This might not be a permanent error.
*/
if (errno == ENOBUFS) {
send_senddone_event(sock, &dev, ISC_R_NORESOURCES);
return (DOIO_HARD);
}
/*
* The other error types depend on whether or not the
* socket is UDP or TCP. If it is UDP, some errors
* that we expect to be fatal under TCP are merely
* annoying, and are really soft errors.
*
* However, these soft errors are still returned as
* a status.
*/
UNEXPECTED_ERROR(__FILE__, __LINE__,
"internal_send: %s",
strerror(errno));
sock->send_result = ISC_R_UNEXPECTED;
send_senddone_event(sock, &dev, ISC_R_UNEXPECTED);
return (DOIO_HARD);
}
if (cc == 0)
UNEXPECTED_ERROR(__FILE__, __LINE__,
"internal_send: send() returned 0");
/*
* if we write less than we expected, update counters,
* poke.
*/
dev->n += cc;
if ((size_t)cc != write_count)
return (DOIO_SOFT);
/*
* Exactly what we wanted to write. We're done with this
* entry. Post its completion event.
*/
send_senddone_event(sock, &dev, ISC_R_SUCCESS);
return (DOIO_SUCCESS); return (DOIO_SUCCESS);
} }
@@ -1047,18 +1120,24 @@ send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev,
* Caller must have the socket locked. * Caller must have the socket locked.
*/ */
static void static void
send_senddone_event(isc_socket_t *sock, isc_task_t **taskp, send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev,
isc_socketevent_t **dev, isc_result_t resultcode, isc_result_t resultcode)
int detach)
{ {
isc_task_t *task;
task = (*dev)->sender;
(*dev)->result = resultcode; (*dev)->result = resultcode;
(*dev)->sender = sock; (*dev)->sender = sock;
if (ISC_LINK_LINKED(*dev, link)) if (ISC_LINK_LINKED(*dev, link))
ISC_LIST_DEQUEUE(sock->send_list, *dev, link); ISC_LIST_DEQUEUE(sock->send_list, *dev, link);
if (detach)
ISC_TASK_SENDANDDETACH(taskp, (isc_event_t **)dev); if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
== ISC_SOCKEVENTATTR_ATTACHED)
ISC_TASK_SENDANDDETACH(&task, (isc_event_t **)dev);
else else
ISC_TASK_SEND(*taskp, (isc_event_t **)dev); ISC_TASK_SEND(task, (isc_event_t **)dev);
} }
/* /*
@@ -1255,9 +1334,13 @@ internal_recv(isc_task_t *me, isc_event_t *ev)
goto next; goto next;
} }
if (sock->recv_result != ISC_R_SUCCESS) {
send_recvdone_event(sock, &dev, sock->recv_result);
goto next;
}
switch (doio_recv(sock, dev)) { switch (doio_recv(sock, dev)) {
case DOIO_SOFT: case DOIO_SOFT:
case DOIO_HARD:
goto poke; goto poke;
break; break;
@@ -1278,6 +1361,7 @@ internal_recv(isc_task_t *me, isc_event_t *ev)
case DOIO_UNEXPECTED: case DOIO_UNEXPECTED:
case DOIO_SUCCESS: case DOIO_SUCCESS:
case DOIO_HARD:
break; break;
} }
@@ -1298,10 +1382,6 @@ internal_send(isc_task_t *me, isc_event_t *ev)
isc_socketevent_t *dev; isc_socketevent_t *dev;
isc_socket_t *sock; isc_socket_t *sock;
isc_task_t *task; isc_task_t *task;
int cc;
size_t write_count;
struct msghdr msghdr;
struct iovec iov[ISC_SOCKET_MAXSCATTERGATHER];
(void)me; (void)me;
@@ -1344,91 +1424,24 @@ internal_send(isc_task_t *me, isc_event_t *ev)
* continue the loop. * continue the loop.
*/ */
if (dev->type == ISC_SOCKEVENT_SENDMARK) { if (dev->type == ISC_SOCKEVENT_SENDMARK) {
send_senddone_event(sock, &task, &dev, send_senddone_event(sock, &dev, sock->send_result);
sock->send_result, 1);
goto next; goto next;
} }
/* if (sock->send_result != ISC_R_SUCCESS) {
* It must be a write request. Try to satisfy it as best send_senddone_event(sock, &dev, sock->send_result);
* we can.
*/
build_msghdr_send(sock, dev, &msghdr, iov,
ISC_SOCKET_MAXSCATTERGATHER, &write_count);
cc = sendmsg(sock->fd, &msghdr, 0);
/*
* check for error or block condition
*/
if (cc < 0) {
if (SOFT_ERROR(errno))
goto poke;
#define SOFT_OR_HARD(_system, _isc) \
if (errno == _system) { \
if (sock->connected) { \
if (sock->type == isc_sockettype_tcp) \
sock->send_result = _isc; \
send_senddone_event(sock, &task, &dev, _isc, 1); \
} \
goto next; \
}
SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED);
SOFT_OR_HARD(ENETUNREACH, ISC_R_NETUNREACH);
SOFT_OR_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH);
#undef SOFT_OR_HARD
/*
* This might not be a permanent error.
*/
if (errno == ENOBUFS) {
send_senddone_event(sock, &task, &dev,
ISC_R_NORESOURCES, 1);
goto next;
}
/*
* The other error types depend on whether or not the
* socket is UDP or TCP. If it is UDP, some errors
* that we expect to be fatal under TCP are merely
* annoying, and are really soft errors.
*
* However, these soft errors are still returned as
* a status.
*/
UNEXPECTED_ERROR(__FILE__, __LINE__,
"internal_send: %s",
strerror(errno));
sock->send_result = ISC_R_UNEXPECTED;
send_senddone_event(sock, &task, &dev,
ISC_R_UNEXPECTED, 1);
goto next; goto next;
} }
if (cc == 0) switch (doio_send(sock, dev)) {
UNEXPECTED_ERROR(__FILE__, __LINE__, case DOIO_SOFT:
"internal_send: send() returned 0");
/*
* if we write less than we expected, update counters,
* poke.
*/
if ((size_t)cc < write_count) {
dev->n += cc;
goto poke; goto poke;
} break;
/* case DOIO_HARD:
* Exactly what we wanted to write. We're done with this case DOIO_UNEXPECTED:
* entry. Post its completion event. case DOIO_SUCCESS:
*/ break;
if ((size_t)cc == write_count) {
dev->n += write_count;
send_senddone_event(sock, &task, &dev,
ISC_R_SUCCESS, 1);
goto next;
} }
next: next:
@@ -1890,21 +1903,24 @@ isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum,
if (!was_empty) if (!was_empty)
goto queue; goto queue;
if (sock->recv_result != ISC_R_SUCCESS) {
send_recvdone_event(sock, &dev, sock->recv_result);
UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
}
switch (doio_recv(sock, dev)) { switch (doio_recv(sock, dev)) {
case DOIO_SOFT: case DOIO_SOFT:
goto queue; goto queue;
break; break;
case DOIO_HARD:
goto out;
break;
case DOIO_EOF: case DOIO_EOF:
send_recvdone_event(sock, &dev, ISC_R_EOF); send_recvdone_event(sock, &dev, ISC_R_EOF);
UNLOCK(&sock->lock); UNLOCK(&sock->lock);
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
break; break;
case DOIO_HARD:
case DOIO_UNEXPECTED: case DOIO_UNEXPECTED:
case DOIO_SUCCESS: case DOIO_SUCCESS:
UNLOCK(&sock->lock); UNLOCK(&sock->lock);
@@ -1920,7 +1936,6 @@ isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum,
* Attach to socket and to task * Attach to socket and to task
*/ */
isc_task_attach(task, &ntask); isc_task_attach(task, &ntask);
dev->sender = ntask;
dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED; dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
/* /*
@@ -1934,7 +1949,6 @@ isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum,
XTRACE(TRACE_RECV, XTRACE(TRACE_RECV,
("isc_socket_recv: queued event %p, task %p\n", dev, ntask)); ("isc_socket_recv: queued event %p, task %p\n", dev, ntask));
out:
UNLOCK(&sock->lock); UNLOCK(&sock->lock);
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
} }
@@ -1957,11 +1971,7 @@ isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
isc_socketevent_t *dev; isc_socketevent_t *dev;
isc_socketmgr_t *manager; isc_socketmgr_t *manager;
isc_task_t *ntask = NULL; isc_task_t *ntask = NULL;
int cc;
isc_boolean_t was_empty; isc_boolean_t was_empty;
struct msghdr msghdr;
struct iovec iov[ISC_SOCKET_MAXSCATTERGATHER];
size_t write_count;
REQUIRE(VALID_SOCKET(sock)); REQUIRE(VALID_SOCKET(sock));
REQUIRE(region != NULL); REQUIRE(region != NULL);
@@ -1982,6 +1992,7 @@ isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
} }
dev->region = *region; dev->region = *region;
dev->sender = task;
set_dev_address(address, sock, dev); set_dev_address(address, sock, dev);
@@ -1992,73 +2003,24 @@ isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
if (!was_empty) if (!was_empty)
goto queue; goto queue;
build_msghdr_send(sock, dev, &msghdr, iov, if (sock->send_result != ISC_R_SUCCESS) {
ISC_SOCKET_MAXSCATTERGATHER, &write_count); send_senddone_event(sock, &dev, sock->send_result);
cc = sendmsg(sock->fd, &msghdr, 0);
if (cc < 0) {
if (SOFT_ERROR(errno))
goto queue;
#define SOFT_OR_HARD(_system, _isc) \
if (errno == _system) { \
if (sock->connected) { \
if (sock->type == isc_sockettype_tcp) \
sock->send_result = _isc; \
send_senddone_event(sock, &task, &dev, _isc, 0); \
} \
select_poke(sock->manager, sock->fd); \
goto out; \
}
SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED);
SOFT_OR_HARD(ENETUNREACH, ISC_R_NETUNREACH);
SOFT_OR_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH);
#undef SOFT_OR_HARD
/*
* This might not be a permanent error.
*/
switch (errno) {
case ENOBUFS:
send_senddone_event(sock, &task, &dev,
ISC_R_NORESOURCES, 0);
goto out;
break;
case EINVAL:
FATAL_ERROR(__FILE__, __LINE__,
"isc_socket_sendto: EINVAL");
break;
default:
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_socket_sendto: errno: %s",
strerror(errno));
sock->send_result = ISC_R_UNEXPECTED;
send_senddone_event(sock, &task, &dev,
ISC_R_UNEXPECTED, 0);
}
UNLOCK(&sock->lock); UNLOCK(&sock->lock);
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
} }
dev->n = cc; switch (doio_send(sock, dev)) {
case DOIO_SOFT:
/*
* Partial writes need to be queued
*/
if ((size_t)cc != write_count)
goto queue; goto queue;
break;
/* case DOIO_HARD:
* full writes are posted. case DOIO_UNEXPECTED:
*/ case DOIO_SUCCESS:
send_senddone_event(sock, &task, &dev, ISC_R_SUCCESS, 0); UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
UNLOCK(&sock->lock); break;
return (ISC_R_SUCCESS); }
queue: queue:
/* /*
@@ -2066,7 +2028,7 @@ isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
* it. * it.
*/ */
isc_task_attach(task, &ntask); isc_task_attach(task, &ntask);
dev->sender = ntask; dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
/* /*
* Enqueue the request. If the socket was previously not being * Enqueue the request. If the socket was previously not being
@@ -2079,7 +2041,6 @@ isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
XTRACE(TRACE_SEND, XTRACE(TRACE_SEND,
("isc_socket_send: queued event %p, task %p\n", dev, ntask)); ("isc_socket_send: queued event %p, task %p\n", dev, ntask));
out:
UNLOCK(&sock->lock); UNLOCK(&sock->lock);
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
} }
@@ -2543,8 +2504,8 @@ isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how)
next = ISC_LIST_NEXT(dev, link); next = ISC_LIST_NEXT(dev, link);
if ((task == NULL) || (task == current_task)) if ((task == NULL) || (task == current_task))
send_senddone_event(sock, &current_task, &dev, send_senddone_event(sock, &dev,
ISC_R_CANCELED, 1); ISC_R_CANCELED);
dev = next; dev = next;
} }
} }