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:
@@ -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(¤t_task,
|
||||
ISC_EVENT_PTR(&dev));
|
||||
if ((task == NULL) || (task == current_task)) {
|
||||
dev->result = ISC_R_CANCELED;
|
||||
send_connectdone_event(sock, &dev);
|
||||
}
|
||||
dev = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user