diff --git a/CHANGES b/CHANGES index 7c64bdfe50..a85652202f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +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 diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in index d8e4c4acdd..968114ad9f 100644 --- a/bin/tests/system/conf.sh.in +++ b/bin/tests/system/conf.sh.in @@ -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 diff --git a/bin/tests/system/pipelined/clean.sh b/bin/tests/system/pipelined/clean.sh index 1cca633dd1..7c2f213209 100644 --- a/bin/tests/system/pipelined/clean.sh +++ b/bin/tests/system/pipelined/clean.sh @@ -17,3 +17,4 @@ rm -f */named.memstats rm -f */named.run rm -f raw* output* +rm -f ns*/named.lock diff --git a/bin/tests/system/pipelined/ns3/named.args b/bin/tests/system/pipelined/ns3/named.args index a6b0f54e56..51b9cc34dd 100644 --- a/bin/tests/system/pipelined/ns3/named.args +++ b/bin/tests/system/pipelined/ns3/named.args @@ -1 +1 @@ --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 diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c index 41794ec84a..0b40f8cf57 100644 --- a/bin/tests/system/pipelined/pipequeries.c +++ b/bin/tests/system/pipelined/pipequeries.c @@ -1,5 +1,5 @@ /* - * 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 #include #include +#include #include #include #include @@ -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[]) -{ - isc_taskmgr_t *taskmgr; - 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; - 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; +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; + dns_dispatchmgr_t *dispatchmgr; + unsigned int attrs, attrmask; + dns_dispatch_t *dispatchv4; + dns_view_t *view; 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); diff --git a/config.h.win32 b/config.h.win32 index 73a64ca45f..bcd7fdd8d2 100644 --- a/config.h.win32 +++ b/config.h.win32 @@ -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@ diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 1e31209f16..325dc718bc 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -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); } diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 25622ed201..14ebf61daa 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -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()). */ diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h index b19e91164d..767eea0356 100644 --- a/lib/dns/include/dns/request.h +++ b/lib/dns/include/dns/request.h @@ -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. * diff --git a/lib/dns/request.c b/lib/dns/request.c index 4827bbd674..e31239ab74 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -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; diff --git a/lib/dns/win32/libdns.def.in b/lib/dns/win32/libdns.def.in index fe65fc81b3..4b9a602105 100644 --- a/lib/dns/win32/libdns.def.in +++ b/lib/dns/win32/libdns.def.in @@ -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 diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index 2aae76f118..fea8e87e59 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -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; } } diff --git a/lib/isc/win32/libisc.def.in b/lib/isc/win32/libisc.def.in index ade7a6e6a2..b56d4d6441 100644 --- a/lib/isc/win32/libisc.def.in +++ b/lib/isc/win32/libisc.def.in @@ -483,9 +483,6 @@ isc_portset_isset 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 @@ -583,42 +580,8 @@ isc_sockaddr_pf 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 diff --git a/lib/isc/win32/socket.c b/lib/isc/win32/socket.c index 1e078fb67a..276b13b0fe 100644 --- a/lib/isc/win32/socket.c +++ b/lib/isc/win32/socket.c @@ -266,7 +266,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; isc_sockaddr_t address; /* remote address */ @@ -375,6 +375,7 @@ static void send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev); 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); @@ -388,6 +389,7 @@ void 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; @@ -436,6 +438,13 @@ sock_dump(isc_socket_t *sock) { 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 @@ -1486,7 +1495,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_accept = 0; sock->pending_recv = 0; sock->pending_send = 0; @@ -1565,7 +1574,7 @@ consistent(isc_socket_t *sock) { } if (count > sock->pending_accept) { crash = ISC_TRUE; - crash_reason = "send_list > sock->pending_send"; + crash_reason = "accept_list > sock->pending_accept"; } if (crash) { @@ -1609,6 +1618,7 @@ maybe_free_socket(isc_socket_t **socketp, int lineno) { || !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; @@ -2030,7 +2040,8 @@ send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev) { 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); @@ -2148,6 +2159,7 @@ done: 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)); @@ -2160,7 +2172,7 @@ internal_connect(isc_socket_t *sock, IoCompletionInfo *lpo, int connect_errno) { 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)) { @@ -2195,7 +2207,7 @@ internal_connect(isc_socket_t *sock, IoCompletionInfo *lpo, int connect_errno) { * 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); @@ -2210,7 +2222,7 @@ internal_connect(isc_socket_t *sock, IoCompletionInfo *lpo, int connect_errno) { 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", @@ -2219,14 +2231,18 @@ internal_connect(isc_socket_t *sock, IoCompletionInfo *lpo, int connect_errno) { } 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); } @@ -2245,6 +2261,20 @@ send_recvdone_abort(isc_socket_t *sock, isc_result_t result) { } } +/* + * 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. @@ -2361,9 +2391,8 @@ internal_send(isc_socket_t *sock, isc_socketevent_t *dev, } /* - * 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) @@ -2392,7 +2421,13 @@ acceptdone_is_active(isc_socket_t *sock, isc_socket_newconnev_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); } // @@ -2592,10 +2627,9 @@ SocketIoThread(LPVOID ThreadContext) { 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; } @@ -3535,8 +3569,6 @@ isc__socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, sock->bound = 1; } - REQUIRE(!sock->pending_connect); - cdev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock, ISC_SOCKEVENT_CONNECT, action, arg, @@ -3547,7 +3579,7 @@ isc__socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, } 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(). */ @@ -3573,9 +3605,17 @@ isc__socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, /* * 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); @@ -3761,28 +3801,28 @@ isc__socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) { } 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; diff --git a/lib/isccfg/win32/libisccfg.def b/lib/isccfg/win32/libisccfg.def index a0d464eb45..bbd6c43182 100644 --- a/lib/isccfg/win32/libisccfg.def +++ b/lib/isccfg/win32/libisccfg.def @@ -93,7 +93,6 @@ cfg_print_boolean cfg_print_bracketed_list cfg_print_chars cfg_print_cstr -cfg_print_fixedpoint cfg_print_grammar cfg_print_map cfg_print_mapbody diff --git a/util/copyrights b/util/copyrights index e62dd1da1f..c66cd14e10 100644 --- a/util/copyrights +++ b/util/copyrights @@ -1588,7 +1588,7 @@ ./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