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

[master] allow shared TCP sockets when connecting

4041.	[func]		TCP sockets can now be shared while connecting.
			(This will be used to enable client-side support
			of pipelined queries.) [RT #38231]
This commit is contained in:
Evan Hunt
2015-01-20 17:22:31 -08:00
parent d9184858dd
commit ff62d4458a
16 changed files with 314 additions and 195 deletions

View File

@@ -347,7 +347,7 @@ struct isc__socket {
ISC_LIST(isc_socketevent_t) send_list;
ISC_LIST(isc_socketevent_t) recv_list;
ISC_LIST(isc_socket_newconnev_t) accept_list;
isc_socket_connev_t *connect_ev;
ISC_LIST(isc_socket_connev_t) connect_list;
/*
* Internal events. Posted when a descriptor is readable or
@@ -471,6 +471,7 @@ static isc_result_t socket_create(isc_socketmgr_t *manager0, int pf,
isc_socket_t *dup_socket);
static void send_recvdone_event(isc__socket_t *, isc_socketevent_t **);
static void send_senddone_event(isc__socket_t *, isc_socketevent_t **);
static void send_connectdone_event(isc__socket_t *, isc_socket_connev_t **);
static void free_socket(isc__socket_t **);
static isc_result_t allocate_socket(isc__socketmgr_t *, isc_sockettype_t,
isc__socket_t **);
@@ -2216,10 +2217,10 @@ destroy(isc__socket_t **sockp) {
socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
ISC_MSG_DESTROYING, "destroying");
INSIST(ISC_LIST_EMPTY(sock->connect_list));
INSIST(ISC_LIST_EMPTY(sock->accept_list));
INSIST(ISC_LIST_EMPTY(sock->recv_list));
INSIST(ISC_LIST_EMPTY(sock->send_list));
INSIST(sock->connect_ev == NULL);
REQUIRE(sock->fd == -1 || sock->fd < (int)manager->maxsocks);
if (sock->fd >= 0) {
@@ -2326,7 +2327,7 @@ allocate_socket(isc__socketmgr_t *manager, isc_sockettype_t type,
ISC_LIST_INIT(sock->recv_list);
ISC_LIST_INIT(sock->send_list);
ISC_LIST_INIT(sock->accept_list);
sock->connect_ev = NULL;
ISC_LIST_INIT(sock->connect_list);
sock->pending_recv = 0;
sock->pending_send = 0;
sock->pending_accept = 0;
@@ -2394,6 +2395,7 @@ free_socket(isc__socket_t **socketp) {
INSIST(ISC_LIST_EMPTY(sock->recv_list));
INSIST(ISC_LIST_EMPTY(sock->send_list));
INSIST(ISC_LIST_EMPTY(sock->accept_list));
INSIST(ISC_LIST_EMPTY(sock->connect_list));
INSIST(!ISC_LINK_LINKED(sock, link));
if (sock->recvcmsgbuf != NULL)
@@ -3223,7 +3225,7 @@ isc__socket_close(isc_socket_t *sock0) {
INSIST(ISC_LIST_EMPTY(sock->recv_list));
INSIST(ISC_LIST_EMPTY(sock->send_list));
INSIST(ISC_LIST_EMPTY(sock->accept_list));
INSIST(sock->connect_ev == NULL);
INSIST(ISC_LIST_EMPTY(sock->connect_list));
manager = sock->manager;
fd = sock->fd;
@@ -3356,7 +3358,7 @@ dispatch_connect(isc__socket_t *sock) {
iev = &sock->writable_ev;
ev = sock->connect_ev;
ev = ISC_LIST_HEAD(sock->connect_list);
INSIST(ev != NULL); /* XXX */
INSIST(sock->connecting);
@@ -3421,6 +3423,26 @@ send_senddone_event(isc__socket_t *sock, isc_socketevent_t **dev) {
isc_task_send(task, (isc_event_t **)dev);
}
/*
* See comments for send_recvdone_event() above.
*
* Caller must have the socket locked if the event is attached to the socket.
*/
static void
send_connectdone_event(isc__socket_t *sock, isc_socket_connev_t **dev) {
isc_task_t *task;
INSIST(dev != NULL && *dev != NULL);
task = (*dev)->ev_sender;
(*dev)->ev_sender = sock;
if (ISC_LINK_LINKED(*dev, ev_link))
ISC_LIST_DEQUEUE(sock->connect_list, *dev, ev_link);
isc_task_sendanddetach(&task, (isc_event_t **)dev);
}
/*
* Call accept() on a socket, to get the new file descriptor. The listen
* socket is used as a prototype to create a new isc_socket_t. The new
@@ -5682,8 +5704,6 @@ isc__socket_connect(isc_socket_t *sock0, isc_sockaddr_t *addr,
LOCK(&sock->lock);
REQUIRE(!sock->connecting);
dev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock,
ISC_SOCKEVENT_CONNECT,
action, arg,
@@ -5694,6 +5714,11 @@ isc__socket_connect(isc_socket_t *sock0, isc_sockaddr_t *addr,
}
ISC_LINK_INIT(dev, ev_link);
if (sock->connecting) {
INSIST(isc_sockaddr_equal(&sock->peer_address, addr));
goto queue;
}
/*
* Try to do the connect right away, as there can be only one
* outstanding, and it might happen to complete.
@@ -5780,8 +5805,6 @@ isc__socket_connect(isc_socket_t *sock0, isc_sockaddr_t *addr,
*/
isc_task_attach(task, &ntask);
sock->connecting = 1;
dev->ev_sender = ntask;
/*
@@ -5789,10 +5812,12 @@ isc__socket_connect(isc_socket_t *sock0, isc_sockaddr_t *addr,
* is no race condition. We will keep the lock for such a short
* bit of time waking it up now or later won't matter all that much.
*/
if (sock->connect_ev == NULL)
if (ISC_LIST_EMPTY(sock->connect_list) && !sock->connecting)
select_poke(manager, sock->fd, SELECT_POKE_CONNECT);
sock->connect_ev = dev;
sock->connecting = 1;
ISC_LIST_ENQUEUE(sock->connect_list, dev, ev_link);
UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
@@ -5805,8 +5830,8 @@ static void
internal_connect(isc_task_t *me, isc_event_t *ev) {
isc__socket_t *sock;
isc_socket_connev_t *dev;
isc_task_t *task;
int cc;
isc_result_t result;
ISC_SOCKADDR_LEN_T optlen;
char strbuf[ISC_STRERRORSIZE];
char peerbuf[ISC_SOCKADDR_FORMATSIZE];
@@ -5832,9 +5857,10 @@ internal_connect(isc_task_t *me, isc_event_t *ev) {
}
/*
* Has this event been canceled?
* Get the first item off the connect list.
* If it is empty, unlock the socket and return.
*/
dev = sock->connect_ev;
dev = ISC_LIST_HEAD(sock->connect_list);
if (dev == NULL) {
INSIST(!sock->connecting);
UNLOCK(&sock->lock);
@@ -5875,7 +5901,7 @@ internal_connect(isc_task_t *me, isc_event_t *ev) {
* Translate other errors into ISC_R_* flavors.
*/
switch (errno) {
#define ERROR_MATCH(a, b) case a: dev->result = b; break;
#define ERROR_MATCH(a, b) case a: result = b; break;
ERROR_MATCH(EACCES, ISC_R_NOPERM);
ERROR_MATCH(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
ERROR_MATCH(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
@@ -5892,7 +5918,7 @@ internal_connect(isc_task_t *me, isc_event_t *ev) {
ERROR_MATCH(ECONNRESET, ISC_R_CONNECTIONRESET);
#undef ERROR_MATCH
default:
dev->result = ISC_R_UNEXPECTED;
result = ISC_R_UNEXPECTED;
isc_sockaddr_format(&sock->peer_address, peerbuf,
sizeof(peerbuf));
isc__strerror(errno, strbuf, sizeof(strbuf));
@@ -5903,18 +5929,18 @@ internal_connect(isc_task_t *me, isc_event_t *ev) {
} else {
inc_stats(sock->manager->stats,
sock->statsindex[STATID_CONNECT]);
dev->result = ISC_R_SUCCESS;
result = ISC_R_SUCCESS;
sock->connected = 1;
sock->bound = 1;
}
sock->connect_ev = NULL;
do {
dev->result = result;
send_connectdone_event(sock, &dev);
dev = ISC_LIST_HEAD(sock->connect_list);
} while (dev != NULL);
UNLOCK(&sock->lock);
task = dev->ev_sender;
dev->ev_sender = sock;
isc_task_sendanddetach(&task, ISC_EVENT_PTR(&dev));
}
isc_result_t
@@ -6072,27 +6098,26 @@ isc__socket_cancel(isc_socket_t *sock0, isc_task_t *task, unsigned int how) {
}
}
/*
* Connecting is not a list.
*/
if (((how & ISC_SOCKCANCEL_CONNECT) == ISC_SOCKCANCEL_CONNECT)
&& sock->connect_ev != NULL) {
&& !ISC_LIST_EMPTY(sock->connect_list)) {
isc_socket_connev_t *dev;
isc_socket_connev_t *next;
isc_task_t *current_task;
INSIST(sock->connecting);
sock->connecting = 0;
dev = sock->connect_ev;
current_task = dev->ev_sender;
dev = ISC_LIST_HEAD(sock->connect_list);
if ((task == NULL) || (task == current_task)) {
sock->connect_ev = NULL;
while (dev != NULL) {
current_task = dev->ev_sender;
next = ISC_LIST_NEXT(dev, ev_link);
dev->result = ISC_R_CANCELED;
dev->ev_sender = sock;
isc_task_sendanddetach(&current_task,
ISC_EVENT_PTR(&dev));
if ((task == NULL) || (task == current_task)) {
dev->result = ISC_R_CANCELED;
send_connectdone_event(sock, &dev);
}
dev = next;
}
}