4041. [func] TCP sockets can now be shared while connecting.
(This will be used to enable client-side support
of pipelined queries.) [RT #38231]
+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
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
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
#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>
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
}
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;
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);
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));
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;
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,
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();
dns_requestmgr_detach(&requestmgr);
dns_dispatch_detach(&dispatchv4);
- dns_dispatch_detach(&tcpdispatch);
dns_dispatchmgr_destroy(&dispatchmgr);
isc_socketmgr_destroy(&socketmgr);
/* 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@
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,
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);
}
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()).
*/
#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);
* 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
* 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.
*
* 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.
*
}
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)
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) {
}
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,
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);
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;
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;
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;
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;
dns_adb_plainresponse
dns_adb_probesize
dns_adb_probesize2
-dns_adb_probesize512
dns_adb_setadbsize
dns_adb_setudpsize
dns_adb_setsit
dns_dispatch_getlocaladdress
dns_dispatch_getsocket
dns_dispatch_gettcp
+dns_dispatch_gettcp2
dns_dispatch_getudp
dns_dispatch_getudp_dup
dns_dispatch_importrecv
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
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 **);
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) {
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;
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)
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;
iev = &sock->writable_ev;
- ev = sock->connect_ev;
+ ev = ISC_LIST_HEAD(sock->connect_list);
INSIST(ev != NULL); /* XXX */
INSIST(sock->connecting);
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
LOCK(&sock->lock);
- REQUIRE(!sock->connecting);
-
dev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock,
ISC_SOCKEVENT_CONNECT,
action, arg,
}
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.
*/
isc_task_attach(task, &ntask);
- sock->connecting = 1;
-
dev->ev_sender = ntask;
/*
* 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);
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];
}
/*
- * 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);
* 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);
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));
} 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
}
}
- /*
- * 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;
}
}
isc_portset_nports
isc_portset_remove
isc_portset_removerange
-isc_print_snprintf
-isc_print_sprintf
-isc_print_vsnprintf
isc_quota_attach
isc_quota_destroy
isc_quota_detach
isc_sockaddr_setport
isc_sockaddr_totext
isc_sockaddr_v6fromin
-isc_socket_accept
-isc_socket_attach
-isc_socket_bind
-isc_socket_cancel
-isc_socket_cleanunix
-isc_socket_close
-isc_socket_connect
-isc_socket_create
-isc_socket_detach
-isc_socket_dscp
-isc_socket_dup
-isc_socket_fdwatchcreate
-isc_socket_fdwatchpoke
-isc_socket_filter
-isc_socket_getpeername
-isc_socket_getsockname
-isc_socket_gettype
-isc_socket_ipv6only
-isc_socket_listen
-isc_socket_open
-isc_socket_permunix
-isc_socket_register
-isc_socket_recv
-isc_socket_recv2
-isc_socket_recvv
-isc_socket_send
-isc_socket_sendto
-isc_socket_sendto2
-isc_socket_sendtov
-isc_socket_sendtov2
-isc_socket_sendv
isc_socket_socketevent
-isc_socketmgr_create
-isc_socketmgr_create2
isc_socketmgr_createinctx
-isc_socketmgr_destroy
@IF LIBXML2
isc_socketmgr_renderxml
@END LIBXML2
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;
isc_sockaddr_t address; /* remote address */
static void send_acceptdone_event(isc_socket_t *sock, isc_socket_newconnev_t **adev);
static void send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev);
static void send_recvdone_abort(isc_socket_t *sock, isc_result_t result);
+static void send_connectdone_abort(isc_socket_t *sock, isc_result_t result);
static void queue_receive_event(isc_socket_t *sock, isc_task_t *task, isc_socketevent_t *dev);
static void queue_receive_request(isc_socket_t *sock);
sock_dump(isc_socket_t *sock) {
isc_socketevent_t *ldev;
isc_socket_newconnev_t *ndev;
+ isc_socket_connev_t *cdev;
#if 0
isc_sockaddr_t addr;
printf("\t\tdev: %p\n", ldev);
ndev = ISC_LIST_NEXT(ndev, ev_link);
}
+
+ printf("\n\t\tSock Connect List\n");
+ cdev = ISC_LIST_HEAD(sock->connect_list);
+ while (cdev != NULL) {
+ printf("\t\tdev: %p\n", cdev);
+ cdev = ISC_LIST_NEXT(cdev, ev_link);
+ }
}
static void
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_accept = 0;
sock->pending_recv = 0;
sock->pending_send = 0;
}
if (count > sock->pending_accept) {
crash = ISC_TRUE;
- crash_reason = "send_list > sock->pending_send";
+ crash_reason = "accept_list > sock->pending_accept";
}
if (crash) {
|| !ISC_LIST_EMPTY(sock->recv_list)
|| !ISC_LIST_EMPTY(sock->send_list)
|| !ISC_LIST_EMPTY(sock->accept_list)
+ || !ISC_LIST_EMPTY(sock->connect_list)
|| sock->fd != INVALID_SOCKET) {
UNLOCK(&sock->lock);
return;
task = (*cdev)->ev_sender;
(*cdev)->ev_sender = sock;
- sock->connect_ev = NULL;
+ if (ISC_LINK_LINKED(*cdev, ev_link))
+ ISC_LIST_DEQUEUE(sock->connect_list, *cdev, ev_link);
isc_task_sendanddetach(&task, (isc_event_t **)cdev);
static void
internal_connect(isc_socket_t *sock, IoCompletionInfo *lpo, int connect_errno) {
isc_socket_connev_t *cdev;
+ isc_result_t result;
char strbuf[ISC_STRERRORSIZE];
INSIST(VALID_SOCKET(sock));
sock->pending_connect = 0;
/*
- * Has this event been canceled?
+ * If the event is no longer in the list we can just close and return.
*/
cdev = lpo->cdev;
if (!connectdone_is_active(sock, cdev)) {
* Translate other errors into ISC_R_* flavors.
*/
switch (connect_errno) {
-#define ERROR_MATCH(a, b) case a: cdev->result = b; break;
+#define ERROR_MATCH(a, b) case a: result = b; break;
ERROR_MATCH(WSAEACCES, ISC_R_NOPERM);
ERROR_MATCH(WSAEADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
ERROR_MATCH(WSAEAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
ERROR_MATCH(WSAETIMEDOUT, ISC_R_TIMEDOUT);
#undef ERROR_MATCH
default:
- cdev->result = ISC_R_UNEXPECTED;
+ result = ISC_R_UNEXPECTED;
isc__strerror(connect_errno, strbuf, sizeof(strbuf));
UNEXPECTED_ERROR(__FILE__, __LINE__,
"internal_connect: connect() %s",
} else {
INSIST(setsockopt(sock->fd, SOL_SOCKET,
SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == 0);
- cdev->result = ISC_R_SUCCESS;
+ result = ISC_R_SUCCESS;
sock->connected = 1;
socket_log(__LINE__, sock, &sock->address, IOEVENT,
isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
"internal_connect: success");
}
- send_connectdone_event(sock, &cdev);
+ do {
+ cdev->result = result;
+ send_connectdone_event(sock, &cdev);
+ cdev = ISC_LIST_HEAD(sock->connect_list);
+ } while (cdev != NULL);
UNLOCK(&sock->lock);
}
}
}
+/*
+ * Loop through the socket, returning result for each done event pending.
+ */
+static void
+send_connectdone_abort(isc_socket_t *sock, isc_result_t result) {
+ isc_socket_connev_t *dev;
+
+ while (!ISC_LIST_EMPTY(sock->connect_list)) {
+ dev = ISC_LIST_HEAD(sock->connect_list);
+ dev->result = result;
+ send_connectdone_event(sock, &dev);
+ }
+}
+
/*
* Take the data we received in our private buffer, and if any recv() calls on
* our list are satisfied, send the corresponding done event.
}
/*
- * These return if the done event passed in is on the list (or for connect, is
- * the one we're waiting for. Using these ensures we will not double-send an
- * event.
+ * These return if the done event passed in is on the list.
+ * Using these ensures we will not double-send an event.
*/
static isc_boolean_t
senddone_is_active(isc_socket_t *sock, isc_socketevent_t *dev)
static isc_boolean_t
connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev)
{
- return (sock->connect_ev == dev ? ISC_TRUE : ISC_FALSE);
+ isc_socket_connev_t *cdev;
+
+ cdev = ISC_LIST_HEAD(sock->connect_list);
+ while (cdev != NULL && cdev != dev)
+ cdev = ISC_LIST_NEXT(cdev, ev_link);
+
+ return (cdev == NULL ? ISC_FALSE : ISC_TRUE);
}
//
INSIST(sock->pending_connect == 1);
sock->pending_connect = 0;
if (connectdone_is_active(sock, lpo->cdev)) {
- lpo->cdev->result = isc_result;
socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
"canceled_connect");
- send_connectdone_event(sock, &lpo->cdev);
+ send_connectdone_abort(sock, isc_result);
}
break;
}
sock->bound = 1;
}
- REQUIRE(!sock->pending_connect);
-
cdev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock,
ISC_SOCKEVENT_CONNECT,
action, arg,
}
ISC_LINK_INIT(cdev, ev_link);
- if (sock->type == isc_sockettype_tcp) {
+ if ((sock->type == isc_sockettype_tcp) && !sock->pending_connect) {
/*
* Queue io completion for an accept().
*/
/*
* Enqueue the request.
*/
- sock->connect_ev = cdev;
+ INSIST(!ISC_LINK_LINKED(cdev, ev_link));
+ ISC_LIST_ENQUEUE(sock->connect_list, cdev, ev_link);
sock->pending_iocp++;
+ } else if (sock->type == isc_sockettype_tcp) {
+ INSIST(isc_sockaddr_equal(&sock->address, addr));
+ isc_task_attach(task, &ntask);
+ cdev->ev_sender = ntask;
+ INSIST(!ISC_LINK_LINKED(cdev, ev_link));
+ ISC_LIST_ENQUEUE(sock->connect_list, cdev, ev_link);
} else {
+ REQUIRE(!sock->pending_connect);
WSAConnect(sock->fd, &addr->type.sa, addr->length, NULL, NULL, NULL, NULL);
cdev->result = ISC_R_SUCCESS;
isc_task_send(task, (isc_event_t **)&cdev);
}
how &= ~ISC_SOCKCANCEL_ACCEPT;
- /*
- * 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->pending_connect);
- dev = sock->connect_ev;
- current_task = dev->ev_sender;
+ dev = ISC_LIST_HEAD(sock->connect_list);
- if ((task == NULL) || (task == current_task)) {
- closesocket(sock->fd);
- sock->fd = INVALID_SOCKET;
- _set_state(sock, SOCK_CLOSED);
-
- sock->connect_ev = NULL;
- dev->result = ISC_R_CANCELED;
- send_connectdone_event(sock, &dev);
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+ if ((task == NULL) || (task == current_task)) {
+ dev->result = ISC_R_CANCELED;
+ send_connectdone_event(sock, &dev);
+ }
+ dev = next;
}
+ closesocket(sock->fd);
+ sock->fd = INVALID_SOCKET;
+ _set_state(sock, SOCK_CLOSED);
}
how &= ~ISC_SOCKCANCEL_CONNECT;
cfg_print_bracketed_list
cfg_print_chars
cfg_print_cstr
-cfg_print_fixedpoint
cfg_print_grammar
cfg_print_map
cfg_print_mapbody
./bin/tests/system/pipelined/ns3/named.args X 2014
./bin/tests/system/pipelined/ns3/named.conf CONF-C 2014
./bin/tests/system/pipelined/ns4/named.conf CONF-C 2014
-./bin/tests/system/pipelined/pipequeries.c C 2014
+./bin/tests/system/pipelined/pipequeries.c C 2014,2015
./bin/tests/system/pipelined/ref X 2014
./bin/tests/system/pipelined/refb X 2014
./bin/tests/system/pipelined/setup.sh SH 2014