Commit ff62d445 authored by Evan Hunt's avatar Evan Hunt

[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]
parent d9184858
4041. [func] TCP sockets can now be shared while connecting.
(This will be used to enable client-side support
of pipelined queries.) [RT #38231]
4040. [func] Added server-side support for pipelined TCP
queries. TCP connections are no longer closed after
the first query received from a client. (The new
......
......@@ -70,7 +70,7 @@ SUBDIRS="acl additional allow_query addzone autosign builtin
dns64 dnssec dsdigest dscp ecdsa ednscompliance emptyzones
filter-aaaa formerr forward geoip glue gost ixfr inline
legacy limits logfileconfig lwresd masterfile masterformat
metadata notify nslookup nsupdate pending piplined @PKCS11_TEST@
metadata notify nslookup nsupdate pending pipelined @PKCS11_TEST@
reclimit redirect resolver rndc rpz rrl rrchecker rrsetorder
rsabigexponent runtime sit sfcache smartsign sortlist spf
staticstub statistics stub tcp tkey tsig tsiggss unknown
......
......@@ -17,3 +17,4 @@
rm -f */named.memstats
rm -f */named.run
rm -f raw* output*
rm -f ns*/named.lock
-m record,size,mctx -c named.conf -d 99 -g -T delay=200
-m record,size,mctx -c named.conf -d 99 -X named.lock -g -T delay=200
/*
* Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 2014, 2015 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
......@@ -26,6 +26,7 @@
#include <isc/hash.h>
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/net.h>
#include <isc/sockaddr.h>
#include <isc/socket.h>
#include <isc/task.h>
......@@ -61,7 +62,9 @@
static isc_mem_t *mctx;
static dns_requestmgr_t *requestmgr;
isc_sockaddr_t address;
static isc_boolean_t have_src = ISC_FALSE;
static isc_sockaddr_t srcaddr;
static isc_sockaddr_t dstaddr;
static int onfly;
static void
......@@ -124,8 +127,7 @@ recvresponse(isc_task_t *task, isc_event_t *event) {
}
static isc_result_t
sendquery(isc_task_t *task)
{
sendquery(isc_task_t *task) {
dns_request_t *request;
dns_message_t *message;
dns_name_t *qname;
......@@ -175,18 +177,18 @@ sendquery(isc_task_t *task)
dns_message_addname(message, qname, DNS_SECTION_QUESTION);
request = NULL;
result = dns_request_create(requestmgr, message, &address,
DNS_REQUESTOPT_TCP, NULL,
TIMEOUT, task, recvresponse,
message, &request);
result = dns_request_createvia(requestmgr, message,
have_src ? &srcaddr : NULL, &dstaddr,
DNS_REQUESTOPT_TCP|DNS_REQUESTOPT_SHARE,
NULL, TIMEOUT, task, recvresponse,
message, &request);
CHECK("dns_request_create", result);
return ISC_R_SUCCESS;
}
static void
sendqueries(isc_task_t *task, isc_event_t *event)
{
sendqueries(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
isc_event_free(&event);
......@@ -200,42 +202,44 @@ sendqueries(isc_task_t *task, isc_event_t *event)
return;
}
static void
connecting(isc_task_t *task, isc_event_t *event)
{
isc_socket_t *sock = (isc_socket_t *)(event->ev_arg);
RUNCHECK(isc_socket_connect(sock, &address, task, sendqueries, NULL));
isc_event_free(&event);
}
int
main(int argc, char *argv[])
{
main(int argc, char *argv[]) {
isc_sockaddr_t bind_any;
struct in_addr inaddr;
isc_result_t result;
isc_log_t *lctx;
isc_logconfig_t *lcfg;
isc_entropy_t *ectx;
isc_taskmgr_t *taskmgr;
isc_task_t *task;
isc_timermgr_t *timermgr;
isc_socketmgr_t *socketmgr;
isc_socket_t *sock;
unsigned int attrs, attrmask;
isc_sockaddr_t bind_addr;
dns_dispatchmgr_t *dispatchmgr;
unsigned int attrs, attrmask;
dns_dispatch_t *dispatchv4;
dns_dispatch_t *tcpdispatch;
dns_view_t *view;
isc_entropy_t *ectx;
isc_task_t *task;
isc_log_t *lctx;
isc_logconfig_t *lcfg;
struct in_addr inaddr;
isc_result_t result;
UNUSED(argv);
if (argc > 1)
have_src = ISC_TRUE;
RUNCHECK(isc_app_start());
dns_result_register();
isc_sockaddr_any(&bind_any);
result = ISC_R_FAILURE;
if (inet_pton(AF_INET, "10.53.0.7", &inaddr) != 1)
CHECK("inet_pton", result);
isc_sockaddr_fromin(&srcaddr, &inaddr, 0);
result = ISC_R_FAILURE;
if (inet_pton(AF_INET, "10.53.0.4", &inaddr) != 1)
CHECK("inet_pton", result);
isc_sockaddr_fromin(&dstaddr, &inaddr, PORT);
mctx = NULL;
RUNCHECK(isc_mem_create(0, 0, &mctx));
......@@ -261,14 +265,7 @@ main(int argc, char *argv[])
RUNCHECK(isc_socketmgr_create(mctx, &socketmgr));
dispatchmgr = NULL;
RUNCHECK(dns_dispatchmgr_create(mctx, ectx, &dispatchmgr));
if (argc == 1) {
isc_sockaddr_any(&bind_addr);
} else {
result = ISC_R_FAILURE;
if (inet_pton(AF_INET, "10.53.0.7", &inaddr) != 1)
CHECK("inet_pton", result);
isc_sockaddr_fromin(&bind_addr, &inaddr, 0);
}
attrs = DNS_DISPATCHATTR_UDP |
DNS_DISPATCHATTR_MAKEQUERY |
DNS_DISPATCHATTR_IPV4;
......@@ -278,8 +275,9 @@ main(int argc, char *argv[])
DNS_DISPATCHATTR_IPV6;
dispatchv4 = NULL;
RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
&bind_addr, 4096, 4, 2, 3, 5,
attrs, attrmask, &dispatchv4));
have_src ? &srcaddr : &bind_any,
4096, 4, 2, 3, 5,
attrs, attrmask, &dispatchv4));
requestmgr = NULL;
RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr,
dispatchmgr, dispatchv4, NULL,
......@@ -288,31 +286,7 @@ main(int argc, char *argv[])
view = NULL;
RUNCHECK(dns_view_create(mctx, 0, "_test", &view));
sock = NULL;
RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_tcp,
&sock));
RUNCHECK(isc_socket_bind(sock, &bind_addr, 0));
result = ISC_R_FAILURE;
if (inet_pton(AF_INET, "10.53.0.4", &inaddr) != 1)
CHECK("inet_pton", result);
isc_sockaddr_fromin(&address, &inaddr, PORT);
attrs = 0;
attrs |= DNS_DISPATCHATTR_TCP;
attrs |= DNS_DISPATCHATTR_IPV4;
attrs |= DNS_DISPATCHATTR_MAKEQUERY;
attrs |= DNS_DISPATCHATTR_CONNECTED;
isc_socket_dscp(sock, -1);
tcpdispatch = NULL;
RUNCHECK(dns_dispatch_createtcp2(dispatchmgr, sock, taskmgr,
&bind_addr, &address,
4096, 20, 10, 3, 5,
attrs, &tcpdispatch));
RUNCHECK(isc_app_onrun(mctx, task, connecting, sock));
isc_socket_detach(&sock);
RUNCHECK(isc_app_onrun(mctx, task, sendqueries, NULL));
(void)isc_app_run();
......@@ -322,7 +296,6 @@ main(int argc, char *argv[])
dns_requestmgr_detach(&requestmgr);
dns_dispatch_detach(&dispatchv4);
dns_dispatch_detach(&tcpdispatch);
dns_dispatchmgr_destroy(&dispatchmgr);
isc_socketmgr_destroy(&socketmgr);
......
......@@ -314,6 +314,9 @@ typedef __int64 off_t;
/* Define to the flags type used by getnameinfo(3). */
#define IRS_GETNAMEINFO_FLAGS_T int
/* Define to the sockaddr length type used by getnameinfo(3). */
#define IRS_GETNAMEINFO_SOCKLEN_T socklen_t
/* Define to enable the "filter-aaaa-on-v4" and "filter-aaaa-on-v6" options.
*/
@ALLOW_FILTER_AAAA@
......
......@@ -2677,6 +2677,83 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, isc_sockaddr_t *destaddr,
return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND);
}
isc_result_t
dns_dispatch_gettcp2(dns_dispatchmgr_t *mgr, isc_sockaddr_t *destaddr,
isc_sockaddr_t *localaddr, isc_boolean_t *connected,
dns_dispatch_t **dispp)
{
dns_dispatch_t *disp;
isc_result_t result;
isc_sockaddr_t peeraddr;
isc_sockaddr_t sockname;
unsigned int attributes, mask;
isc_boolean_t match = ISC_FALSE;
REQUIRE(VALID_DISPATCHMGR(mgr));
REQUIRE(destaddr != NULL);
REQUIRE(dispp != NULL && *dispp == NULL);
REQUIRE(connected != NULL);
/* First pass (same than dns_dispatch_gettcp()) */
attributes = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_CONNECTED;
mask = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE |
DNS_DISPATCHATTR_EXCLUSIVE | DNS_DISPATCHATTR_CONNECTED;
LOCK(&mgr->lock);
disp = ISC_LIST_HEAD(mgr->list);
while (disp != NULL && !match) {
LOCK(&disp->lock);
if ((disp->shutting_down == 0) &&
ATTRMATCH(disp->attributes, attributes, mask) &&
(localaddr == NULL ||
isc_sockaddr_eqaddr(localaddr, &disp->local))) {
result = isc_socket_getsockname(disp->socket,
&sockname);
if (result == ISC_R_SUCCESS)
result = isc_socket_getpeername(disp->socket,
&peeraddr);
if (result == ISC_R_SUCCESS &&
isc_sockaddr_equal(destaddr, &peeraddr) &&
(localaddr == NULL ||
isc_sockaddr_eqaddr(localaddr, &sockname))) {
/* attach */
disp->refcount++;
*dispp = disp;
match = ISC_TRUE;
*connected = ISC_TRUE;
}
}
UNLOCK(&disp->lock);
disp = ISC_LIST_NEXT(disp, link);
}
if (match) {
UNLOCK(&mgr->lock);
return (ISC_R_SUCCESS);
}
/* Second pass */
attributes = DNS_DISPATCHATTR_TCP;
disp = ISC_LIST_HEAD(mgr->list);
while (disp != NULL && !match) {
LOCK(&disp->lock);
if ((disp->shutting_down == 0) &&
ATTRMATCH(disp->attributes, attributes, mask) &&
(localaddr == NULL ||
isc_sockaddr_eqaddr(localaddr, &disp->local)) &&
isc_sockaddr_equal(destaddr, &disp->peer)) {
/* attach */
disp->refcount++;
*dispp = disp;
match = ISC_TRUE;
}
UNLOCK(&disp->lock);
disp = ISC_LIST_NEXT(disp, link);
}
UNLOCK(&mgr->lock);
return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND);
}
isc_result_t
dns_dispatch_getudp_dup(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
......@@ -3332,8 +3409,10 @@ dns_dispatch_starttcp(dns_dispatch_t *disp) {
dispatch_log(disp, LVL(90), "starttcp %p", disp->task[0]);
LOCK(&disp->lock);
disp->attributes |= DNS_DISPATCHATTR_CONNECTED;
(void)startrecv(disp, NULL);
if ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) == 0) {
disp->attributes |= DNS_DISPATCHATTR_CONNECTED;
(void)startrecv(disp, NULL);
}
UNLOCK(&disp->lock);
}
......
......@@ -383,8 +383,13 @@ dns_dispatch_starttcp(dns_dispatch_t *disp);
isc_result_t
dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, isc_sockaddr_t *destaddr,
isc_sockaddr_t *localaddr, dns_dispatch_t **dispp);
isc_result_t
dns_dispatch_gettcp2(dns_dispatchmgr_t *mgr, isc_sockaddr_t *destaddr,
isc_sockaddr_t *localaddr, isc_boolean_t *connected,
dns_dispatch_t **dispp);
/*
* Attempt to connect to a existing TCP connection.
* Attempt to connect to a existing TCP connection (connection completed
* for dns_dispatch_gettcp()).
*/
......
......@@ -49,6 +49,7 @@
#define DNS_REQUESTOPT_TCP 0x00000001U
#define DNS_REQUESTOPT_CASE 0x00000002U
#define DNS_REQUESTOPT_FIXEDID 0x00000004U
#define DNS_REQUESTOPT_SHARE 0x00000008U
typedef struct dns_requestevent {
ISC_EVENT_COMMON(struct dns_requestevent);
......@@ -174,7 +175,9 @@ dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
* Notes:
*
*\li 'message' will be rendered and sent to 'address'. If the
* #DNS_REQUESTOPT_TCP option is set, TCP will be used. The request
* #DNS_REQUESTOPT_TCP option is set, TCP will be used,
* #DNS_REQUESTOPT_SHARE option is set too, connecting TCP
* (vs. connected) will be shared too. The request
* will timeout after 'timeout' seconds.
*
*\li If the #DNS_REQUESTOPT_CASE option is set, use case sensitive
......@@ -238,7 +241,9 @@ dns_request_createvia4(dns_requestmgr_t *requestmgr, dns_message_t *message,
* Notes:
*
*\li 'message' will be rendered and sent to 'address'. If the
* #DNS_REQUESTOPT_TCP option is set, TCP will be used. The request
* #DNS_REQUESTOPT_TCP option is set, TCP will be used,
* #DNS_REQUESTOPT_SHARE option is set too, connecting TCP
* (vs. connected) will be shared too. The request
* will timeout after 'timeout' seconds. UDP requests will be resent
* at 'udptimeout' intervals if non-zero or 'udpretries' is non-zero.
*
......@@ -305,7 +310,9 @@ dns_request_createraw4(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
* Notes:
*
*\li 'msgbuf' will be sent to 'destaddr' after setting the id. If the
* #DNS_REQUESTOPT_TCP option is set, TCP will be used. The request
* #DNS_REQUESTOPT_TCP option is set, TCP will be used,
* #DNS_REQUESTOPT_SHARE option is set too, connecting TCP
* (vs. connected) will be shared too. The request
* will timeout after 'timeout' seconds. UDP requests will be resent
* at 'udptimeout' intervals if non-zero or if 'udpretries' is not zero.
*
......
......@@ -525,7 +525,8 @@ isblackholed(dns_dispatchmgr_t *dispatchmgr, isc_sockaddr_t *destaddr) {
}
static isc_result_t
create_tcp_dispatch(isc_boolean_t newtcp, dns_requestmgr_t *requestmgr,
create_tcp_dispatch(isc_boolean_t newtcp, isc_boolean_t share,
dns_requestmgr_t *requestmgr,
isc_sockaddr_t *srcaddr,
isc_sockaddr_t *destaddr, isc_dscp_t dscp,
isc_boolean_t *connected, dns_dispatch_t **dispatchp)
......@@ -536,7 +537,20 @@ create_tcp_dispatch(isc_boolean_t newtcp, dns_requestmgr_t *requestmgr,
unsigned int attrs;
isc_sockaddr_t bind_any;
if (!newtcp) {
if (!newtcp && share) {
result = dns_dispatch_gettcp2(requestmgr->dispatchmgr,
destaddr, srcaddr,
connected, dispatchp);
if (result == ISC_R_SUCCESS) {
char peer[ISC_SOCKADDR_FORMATSIZE];
isc_sockaddr_format(destaddr, peer, sizeof(peer));
req_log(ISC_LOG_DEBUG(1), "attached to %s TCP "
"connection to %s",
*connected ? "existing" : "pending", peer);
return (result);
}
} else if (!newtcp) {
result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr,
srcaddr, dispatchp);
if (result == ISC_R_SUCCESS) {
......@@ -642,7 +656,7 @@ find_udp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
}
static isc_result_t
get_dispatch(isc_boolean_t tcp, isc_boolean_t newtcp,
get_dispatch(isc_boolean_t tcp, isc_boolean_t newtcp, isc_boolean_t share,
dns_requestmgr_t *requestmgr,
isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
isc_dscp_t dscp, isc_boolean_t *connected,
......@@ -651,9 +665,9 @@ get_dispatch(isc_boolean_t tcp, isc_boolean_t newtcp,
isc_result_t result;
if (tcp)
result = create_tcp_dispatch(newtcp, requestmgr, srcaddr,
destaddr, dscp, connected,
dispatchp);
result = create_tcp_dispatch(newtcp, share, requestmgr,
srcaddr, destaddr, dscp,
connected, dispatchp);
else
result = find_udp_dispatch(requestmgr, srcaddr,
destaddr, dispatchp);
......@@ -740,6 +754,7 @@ dns_request_createraw4(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
dns_messageid_t id;
isc_boolean_t tcp = ISC_FALSE;
isc_boolean_t newtcp = ISC_FALSE;
isc_boolean_t share = ISC_FALSE;
isc_region_t r;
isc_boolean_t connected = ISC_FALSE;
unsigned int dispopt = 0;
......@@ -803,9 +818,11 @@ dns_request_createraw4(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512)
tcp = ISC_TRUE;
share = ISC_TF((options & DNS_REQUESTOPT_SHARE) != 0);
again:
result = get_dispatch(tcp, newtcp, requestmgr, srcaddr, destaddr, dscp,
result = get_dispatch(tcp, newtcp, share, requestmgr,
srcaddr, destaddr, dscp,
&connected, &request->dispatch);
if (result != ISC_R_SUCCESS)
goto cleanup;
......@@ -971,6 +988,7 @@ dns_request_createvia4(dns_requestmgr_t *requestmgr, dns_message_t *message,
isc_mem_t *mctx;
dns_messageid_t id;
isc_boolean_t tcp;
isc_boolean_t share;
isc_boolean_t setkey = ISC_TRUE;
isc_boolean_t connected = ISC_FALSE;
......@@ -1031,7 +1049,9 @@ dns_request_createvia4(dns_requestmgr_t *requestmgr, dns_message_t *message,
use_tcp:
tcp = ISC_TF((options & DNS_REQUESTOPT_TCP) != 0);
result = get_dispatch(tcp, ISC_FALSE, requestmgr, srcaddr, destaddr,
share = ISC_TF((options & DNS_REQUESTOPT_SHARE) != 0);
result = get_dispatch(tcp, ISC_FALSE, share,
requestmgr, srcaddr, destaddr,
dscp, &connected, &request->dispatch);
if (result != ISC_R_SUCCESS)
goto cleanup;
......
......@@ -59,7 +59,6 @@ dns_adb_noedns
dns_adb_plainresponse
dns_adb_probesize
dns_adb_probesize2
dns_adb_probesize512
dns_adb_setadbsize
dns_adb_setudpsize
dns_adb_setsit
......@@ -257,6 +256,7 @@ dns_dispatch_getentrysocket
dns_dispatch_getlocaladdress
dns_dispatch_getsocket
dns_dispatch_gettcp
dns_dispatch_gettcp2
dns_dispatch_getudp
dns_dispatch_getudp_dup
dns_dispatch_importrecv
......
<
......@@ -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) {