Compare commits

...
Author SHA1 Message Date
Evan Hunt b10dccf4ea fixup! checkpoint: xfrin using netmgr 2020-10-06 23:50:02 -07:00
Evan Hunt 64b5662914 fixup! checkpoint: xfrin using netmgr 2020-10-06 23:50:02 -07:00
Evan Hunt 16f3479571 checkpoint: xfrin using netmgr
use isc_nm_tcpdnsconnect() in xfrin.c for zone transfers
2020-10-06 23:50:02 -07:00
Evan Hunt 4e68fb68f6 fixup! retry isc_nm_udpconnect() if it fails 2020-10-06 21:56:37 -07:00
Evan Hunt 05719575af fixup! experiment: make sock->result atomic 2020-10-06 21:53:25 -07:00
Evan Hunt 265bf814db fixup! WIP: add udp_cancelread() and udp_recv timeout support 2020-10-06 15:42:08 -07:00
Evan Hunt 90b1095635 fixup! WIP: add udp_cancelread() and udp_recv timeout support 2020-10-06 15:42:06 -07:00
Ondřej SurýandEvan Hunt 6bbadaabd8 WIP: add udp_cancelread() and udp_recv timeout support 2020-10-06 15:41:44 -07:00
Evan Hunt 81c4021178 make isc_nm_cancelread() run asynchronously
reading can be canceled in non-network threads (e.g., by a timeout),
and this was causing an assertion failure.
2020-10-06 12:03:38 -07:00
Evan Hunt c1c040084a experiment: make sock->result atomic 2020-10-06 12:03:38 -07:00
Evan Hunt f432ee863a don't detach handle on timeout unless we're still reading
there's a window in which the connect timeout can still run
after a recv completion, in which case we do want to clear the
query but we don't want to perform the extra handle detach.
2020-10-06 12:03:38 -07:00
Evan Hunt cdf3e5b04e retry isc_nm_udpconnect() if it fails
On FreeBSD, we sometimes see spurious transient EADDRINUSE errors
when connecting to a UDP socket. We now try a few times to ensure
the error is real before giving up.

This commit also fixes a memory leak that occurred if an error was
encountered in isc__nm_async_udpconnect().
2020-10-06 12:03:38 -07:00
Evan Hunt 0efb8864bf reduce timing dependency in resolver test
one of the tests in the resolver system test depends on dig
getting no response to its first two query attempts, and SERVFAIL
on the third after resolution times out.

using a 5-second retry timer in dig means the SERVFAIL response
could occur while dig is discarding the second query and preparing
to send the third. in this case the server's response could be
missed.  shortening the retry interval to 4 seconds ensures that
dig has already sent the third query when the SERVFAIL response
arrives.
2020-10-06 12:03:38 -07:00
Evan Hunt f38779c1db replace query context with a new one when resending UDP queries
resending UDP queries using the same query object could result
in a recv completion event for a previous query arriving before
the send completion event for the current one, leading to
inconsistencies that could cause crashes or hangs on shutdown.
creating a new query context for each send fixes the problem.
2020-10-06 12:03:38 -07:00
Evan Hunt cc5d0e9ade experiment: extend dig timeout 2020-10-06 12:03:38 -07:00
Evan Hunt 3cebd43f09 ensure errors are caught when UDP send() fails 2020-10-06 12:03:38 -07:00
Evan Hunt e4853efb9d fixup! Add isc_uv_udp_connect() shim 2020-10-06 12:03:38 -07:00
Evan Hunt 545cd3934e fixup! dig: remove "+unexpected" option 2020-10-06 12:03:38 -07:00
Evan Hunt 230085c176 fixup! Add isc_uv_udp_connect() shim 2020-10-06 12:03:38 -07:00
Evan Hunt a68a93a1ce handle TCP read timeout in connect_timeout()
when the code to handle TCP connect timeouts was moved out of
connect_timeout(), it caused hangs when dig connected via TCP to a
server and the connection succeded but the server never sent a
response. we should add a read timeout mechanism for client TCP
connections as well as a connect timeout mechanism. in the meantime,
however, I've restored the TCP functionality in connect_timeout()
so it can handle the case of read timeouts.
2020-10-06 12:03:38 -07:00
Evan Hunt 43c4891758 fixup! kluge: prevent crash on interrupt when TCP connect is pending 2020-10-06 12:03:38 -07:00
Evan Hunt 378afa9979 kluge: prevent crash on interrupt when TCP connect is pending
- stop and clean up resources from the TCP connect timer in
  isc__nm_tcp_shutdown(), and call the connect callback with
  ISC_R_CANCELED
- don't clear TCP queries that are waiting for connect in
  clear_query(); they'll be taken care of by tcp_connected() now.
2020-10-06 12:03:38 -07:00
Ondřej SurýandEvan Hunt 9243e6d935 fixup! Clone the csock in accept_connection(), not in callback 2020-10-06 12:03:38 -07:00
Ondřej SurýandEvan Hunt f02c68f884 fixup! Clone the csock in accept_connection(), not in callback 2020-10-06 12:03:38 -07:00
Ondřej SurýandEvan Hunt d3c0a04ad7 Clone the csock in accept_connection(), not in callback
If we clone the csock (children socket) in TCP accept_connection() instead of
passing the ssock (server socket) to the call back and cloning it there we
unbreak the assumption that every socket is handled inside it's own worker
thread and therefore we can get rid of (at least) callback locking.
2020-10-06 12:03:33 -07:00
Evan Hunt 6521a3b69c fixup! Add isc_uv_udp_connect() shim 2020-10-06 12:03:05 -07:00
Ondřej SurýandEvan Hunt 44a431cee6 Add isc_uv_udp_connect() shim
The uv_udp_connect() function is available from libuv 1.27+, move the code to
connect to udp socket to a (limited) shim function called isc_uv_udp_connect().
2020-10-06 12:03:05 -07:00
Evan Hunt 5aee9f642b implement a TCP connect timeout
Attempting to connect dig to the wrong address via TCP caused a hang on
shutdown due to a dangling socket reference; tcp_connect_cb() was never
reached and so the TCP socket was never detached.

This commit adds a connection timeout mechanism to isc_nm_tcpconnect()
and isc_nm_tcpdnsconnect().

NOTE: Currently this only works correctly with "dig +tries=1". If the
connection is retried, we get a segfault on shutdown in uv_walk(); I
haven't yet worked out why.
2020-10-06 12:03:05 -07:00
Evan Hunt e70823f14a fixup! fixup! WIP: Convert the sendcount/recvcount to isc_refcount_t 2020-10-06 12:03:05 -07:00
Evan Hunt 255b180964 fixup! WIP: Convert the sendcount/recvcount to isc_refcount_t 2020-10-06 12:03:05 -07:00
Evan Hunt 91d143999e fixup! WIP: Convert the sendcount/recvcount to isc_refcount_t 2020-10-06 12:03:05 -07:00
Ondřej SurýandEvan Hunt 6bc352ea56 WIP: Convert the sendcount/recvcount to isc_refcount_t 2020-10-06 12:03:05 -07:00
Evan Hunt 795085ffc2 kluge: extra handle detach when canceling
when dig is interrupted with SIGINT while a UDP connection is still
pending, it hangs due to recv_done() never being called. adding
an extra handle detach in cancel_all() corrects this, but is probably
not the correct way to fix it.
2020-10-06 12:03:05 -07:00
Evan Hunt e4282ad606 CHANGES and release note 2020-10-06 12:03:03 -07:00
Evan Hunt 7cd82f419f dig: setup IDN whenever printing a message
because dig now uses the netmgr, printing of response messages
happens in a different thread than setup. the IDN output filtering
procedure, which set using dns_name_settotextfilter(), is stored as
thread-local data, and so if it's set during setup, it won't be
accessible when printing. we now set it immediately before printing,
in the same thread, and clear it immedately afterward.
2020-10-06 12:02:47 -07:00
Evan Hunt d9542cf35d dig: remove "+unexpected" option
The network manager does not support returning UDP datagrams to
clients from unexpected sources; it is therefore not possible for
dig to accept them.  The "+[no]unexpected" option has therefore
been removed from the dig command and its documentation.
2020-10-06 12:02:47 -07:00
Evan Hunt 1fa4db11d6 fixup! convert dig/host/nslookup to use the netmgr 2020-10-06 12:02:47 -07:00
Evan Hunt 569cf55243 convert dig/host/nslookup to use the netmgr
use netmgr functions instead of isc_socket for dig, host, and
nslookup. note that `dig +unexpected` is not working.
2020-10-06 12:02:47 -07:00
Evan Hunt 6831adf3df shim code for UDP connect in older libuv versions
uv_udp_connect() was added in libuv 1.27; we need a method of
connecting UDP sockets for older versions.
2020-10-06 12:02:47 -07:00
Evan Hunt 68c2ddb63a add netmgr functions to support outgoing DNS queries
- isc_nm_tcpdnsconnect() sets up up an outgoing TCP DNS connection
- isc_nm_udpconnect() sets up a connected UDP socket
- isc_nm_read() now supports UDP; it reads a single datagram and then
  stops until the next time it's called.

these functions will later be used to support outgoing queries in dig,
dispatch, etc.
2020-10-06 12:02:45 -07:00
31 changed files with 1652 additions and 923 deletions
+5
View File
@@ -1,3 +1,8 @@
5517. [func] Convert "dig", "host" and "nslookup" to use the
network manager. As a side effect of this change,
"dig +unexpected" no longer works, and has been
disabled. [GL #2140]
5516. [func] The default EDNS buffer size has been changed from 4096
to 1232, the EDNS buffer size probing has been removed
and ``named`` now sets the DON'T FRAGMENT flag on
+12 -11
View File
@@ -296,9 +296,6 @@ help(void) {
"in records)\n"
" +[no]ttlunits (Display TTLs in "
"human-readable units)\n"
" +[no]unexpected (Print replies from "
"unexpected sources\n"
" default=off)\n"
" +[no]unknownformat (Print RDATA in RFC 3597 "
"\"unknown\" "
"format)\n"
@@ -555,6 +552,8 @@ printmessage(dig_query_t *query, const isc_buffer_t *msgbuf, dns_message_t *msg,
UNUSED(msgbuf);
dig_idnsetup(query->lookup, true);
styleflags |= DNS_STYLEFLAG_REL_OWNER;
if (yaml) {
msg->indent.string = " ";
@@ -642,7 +641,6 @@ printmessage(dig_query_t *query, const isc_buffer_t *msgbuf, dns_message_t *msg,
if (yaml) {
enum { Q = 0x1, R = 0x2 }; /* Q:query; R:ecursive */
unsigned int tflag = 0;
isc_sockaddr_t saddr;
char sockstr[ISC_SOCKADDR_FORMATSIZE];
uint16_t sport;
char *hash;
@@ -723,10 +721,9 @@ printmessage(dig_query_t *query, const isc_buffer_t *msgbuf, dns_message_t *msg,
printf(" response_port: %u\n", sport);
}
if (query->sock != NULL &&
isc_socket_getsockname(query->sock, &saddr) ==
ISC_R_SUCCESS)
{
if (query->handle != NULL) {
isc_sockaddr_t saddr =
isc_nmhandle_localaddr(query->handle);
sport = isc_sockaddr_getport(&saddr);
isc_sockaddr_format(&saddr, sockstr, sizeof(sockstr));
hash = strchr(sockstr, '#');
@@ -917,6 +914,9 @@ repopulate_buffer:
if (style != NULL) {
dns_master_styledestroy(&style, mctx);
}
dig_idnsetup(query->lookup, false);
return (result);
}
@@ -1809,7 +1809,8 @@ plus_option(char *option, bool is_batchfile, dig_lookup_t *lookup) {
switch (cmd[2]) {
case 'e':
FULLCHECK("unexpected");
lookup->accept_reply_unexpected_src = state;
fprintf(stderr, ";; +unexpected option "
"is deprecated");
break;
case 'k':
FULLCHECK("unknownformat");
@@ -1979,10 +1980,10 @@ dash_option(char *option, char *next, dig_lookup_t **lookup,
srcport = 0;
}
if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) {
isc_sockaddr_fromin6(&bind_address, &in6, srcport);
isc_sockaddr_fromin6(&localaddr, &in6, srcport);
isc_net_disableipv4();
} else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) {
isc_sockaddr_fromin(&bind_address, &in4, srcport);
isc_sockaddr_fromin(&localaddr, &in4, srcport);
isc_net_disableipv6();
} else {
if (hash != NULL) {
-5
View File
@@ -549,11 +549,6 @@ abbreviation is unambiguous; for example, ``+cd`` is equivalent to
units of ``s``, ``m``, ``h``, ``d``, and ``w``, representing seconds, minutes,
hours, days, and weeks. This implies ``+ttlid``.
``+[no]unexpected``
This option accepts [or does not accept] answers from unexpected sources. By default, ``dig``
will not accept a reply from a source other than the one to which it sent the
query.
``+[no]unknownformat``
This option prints all RDATA in unknown RR type presentation format (:rfc:`3597`).
The default is to print RDATA for known types in the type's
+493 -566
View File
File diff suppressed because it is too large Load Diff
+22 -17
View File
@@ -26,6 +26,7 @@
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/print.h>
#include <isc/refcount.h>
#include <isc/sockaddr.h>
#include <isc/socket.h>
@@ -114,12 +115,9 @@ struct dig_lookup {
tcp_keepalive, header_only, ednsneg, mapped,
print_unknown_format, multiline, nottl, noclass, onesoa,
use_usec, nocrypto, ttlunits, idnin, idnout, expandaaaa, qr,
accept_reply_unexpected_src, /*% print replies from
* unexpected
* sources. */
setqid; /*% use a speciied query ID */
char textname[MXNAME]; /*% Name we're going to be
* looking up */
setqid; /*% use a specified query ID */
char textname[MXNAME]; /*% Name we're going to be
* looking up */
char cmdline[MXNAME];
dns_rdatatype_t rdtype;
dns_rdatatype_t qrdtype;
@@ -172,8 +170,7 @@ struct dig_query {
unsigned int magic;
dig_lookup_t *lookup;
bool waiting_connect, pending_free, waiting_senddone, first_pass,
first_soa_rcvd, second_rr_rcvd, first_repeat_rcvd, recv_made,
warn_id, timedout;
first_soa_rcvd, second_rr_rcvd, first_repeat_rcvd, warn_id;
uint32_t first_rr_serial;
uint32_t second_rr_serial;
uint32_t msg_count;
@@ -181,9 +178,11 @@ struct dig_query {
bool ixfr_axfr;
char *servname;
char *userarg;
isc_buffer_t recvbuf, lengthbuf, tmpsendbuf, sendbuf;
isc_buffer_t sendbuf;
char *recvspace, *tmpsendspace, lengthspace[4];
isc_socket_t *sock;
isc_nmhandle_t *handle;
isc_nmhandle_t *readhandle;
isc_nmhandle_t *sendhandle;
ISC_LINK(dig_query_t) link;
ISC_LINK(dig_query_t) clink;
isc_sockaddr_t sockaddr;
@@ -221,11 +220,11 @@ extern bool check_ra, have_ipv4, have_ipv6, specified_source, usesearch,
extern in_port_t port;
extern unsigned int timeout;
extern isc_mem_t *mctx;
extern int sendcount;
extern isc_refcount_t sendcount;
extern int ndots;
extern int lookup_counter;
extern int exitcode;
extern isc_sockaddr_t bind_address;
extern isc_sockaddr_t localaddr;
extern char keynametext[MXNAME];
extern char keyfile[MXNAME];
extern char keysecret[MXNAME];
@@ -390,32 +389,38 @@ setup_text_key(void);
* Routines exported from dig.c for use by dig for iOS
*/
/*%<
/*%
* Call once only to set up libraries, parse global
* parameters and initial command line query parameters
*/
void
dig_setup(int argc, char **argv);
/*%<
/*%
* Call to supply new parameters for the next lookup
*/
void
dig_query_setup(bool, bool, int argc, char **argv);
/*%<
/*%
* set the main application event cycle running
*/
void
dig_startup(void);
/*%<
/*%
* Initiates the next lookup cycle
*/
void
dig_query_start(void);
/*%<
/*%
* Activate/deactivate IDN filtering of output.
*/
void
dig_idnsetup(dig_lookup_t *lookup, bool active);
/*%
* Cleans up the application
*/
void
+2 -6
View File
@@ -915,13 +915,9 @@ flush_lookup_list(void) {
while (l != NULL) {
q = ISC_LIST_HEAD(l->q);
while (q != NULL) {
if (q->sock != NULL) {
isc_socket_cancel(q->sock, NULL,
ISC_SOCKCANCEL_ALL);
isc_socket_detach(&q->sock);
if (q->readhandle != NULL) {
isc_nmhandle_detach(&q->readhandle);
}
isc_buffer_invalidate(&q->recvbuf);
isc_buffer_invalidate(&q->lengthbuf);
qp = q;
q = ISC_LIST_NEXT(q, link);
ISC_LIST_DEQUEUE(l->q, qp, link);
+1 -1
View File
@@ -10051,7 +10051,7 @@ named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_taskmgr,
named_g_timermgr, named_g_socketmgr,
&server->zonemgr),
named_g_nm, &server->zonemgr),
"dns_zonemgr_create");
CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), "dns_zonemgr_"
"setsize");
+1 -1
View File
@@ -605,7 +605,7 @@ rndc_startconnect(isc_sockaddr_t *addr) {
DO("create connection",
isc_nm_tcpconnect(netmgr, (isc_nmiface_t *)local,
(isc_nmiface_t *)addr, rndc_connected, &rndc_ccmsg,
0));
10000, 0));
}
static void
+3 -30
View File
@@ -82,7 +82,7 @@ if [ -x "$NSLOOKUP" -a $checkupdate -eq 1 ] ; then
n=$((n+1))
echo_i "check nslookup handles UPDATE response ($n)"
ret=0
"$NSLOOKUP" -q=CNAME "-port=$PORT" foo.bar 10.53.0.7 > nslookup.out.test$n 2>&1 && ret=1
"$NSLOOKUP" -q=CNAME -timeout=1 "-port=$PORT" foo.bar 10.53.0.7 > nslookup.out.test$n 2>&1 && ret=1
grep "Opcode mismatch" nslookup.out.test$n > /dev/null || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
@@ -94,7 +94,7 @@ if [ -x "$HOST" -a $checkupdate -eq 1 ] ; then
n=$((n+1))
echo_i "check host handles UPDATE response ($n)"
ret=0
"$HOST" -t CNAME -p $PORT foo.bar 10.53.0.7 > host.out.test$n 2>&1 && ret=1
"$HOST" -W 1 -t CNAME -p $PORT foo.bar 10.53.0.7 > host.out.test$n 2>&1 && ret=1
grep "Opcode mismatch" host.out.test$n > /dev/null || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
@@ -108,7 +108,7 @@ if [ -x "$DIG" ] ; then
n=$((n+1))
echo_i "check dig handles UPDATE response ($n)"
ret=0
dig_with_opts @10.53.0.7 cname foo.bar > dig.out.test$n 2>&1 && ret=1
dig_with_opts @10.53.0.7 +tries=1 +timeout=1 cname foo.bar > dig.out.test$n 2>&1 && ret=1
grep "Opcode mismatch" dig.out.test$n > /dev/null || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
@@ -919,33 +919,6 @@ if [ -x "$DIG" ] ; then
status=$((status+ret))
fi
n=$((n+1))
echo_i "check that dig +unexpected works ($n)"
ret=0
dig_with_opts @10.53.0.6 +unexpected a a.example > dig.out.test$n || ret=1
grep 'reply from unexpected source' dig.out.test$n > /dev/null || ret=1
grep 'status: NOERROR' dig.out.test$n > /dev/null || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "check that dig +nounexpected works ($n)"
ret=0
dig_with_opts @10.53.0.6 +nounexpected +tries=1 +time=2 a a.example > dig.out.test$n && ret=1
grep 'reply from unexpected source' dig.out.test$n > /dev/null || ret=1
grep "status: NOERROR" < dig.out.test$n > /dev/null && ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "check that dig default for +[no]unexpected (+nounexpected) works ($n)"
ret=0
dig_with_opts @10.53.0.6 +tries=1 +time=2 a a.example > dig.out.test$n && ret=1
grep 'reply from unexpected source' dig.out.test$n > /dev/null || ret=1
grep "status: NOERROR" < dig.out.test$n > /dev/null && ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "check that dig +bufsize=0 just sets the buffer size to 0 ($n)"
ret=0
+2 -2
View File
@@ -806,7 +806,7 @@ status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "check that the resolver accepts a reply with empty question section with TC=1 and retries over TCP ($n)"
ret=0
$DIG $DIGOPTS @10.53.0.5 truncated.no-questions. a +tries=3 +time=5 > dig.ns5.out.${n} || ret=1
$DIG $DIGOPTS @10.53.0.5 truncated.no-questions. a +tries=3 +time=4 > dig.ns5.out.${n} || ret=1
grep "status: NOERROR" dig.ns5.out.${n} > /dev/null || ret=1
grep "ANSWER: 1," dig.ns5.out.${n} > /dev/null || ret=1
grep "1\.2\.3\.4" dig.ns5.out.${n} > /dev/null || ret=1
@@ -816,7 +816,7 @@ status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "check that the resolver rejects a reply with empty question section with TC=0 ($n)"
ret=0
$DIG $DIGOPTS @10.53.0.5 not-truncated.no-questions. a +tries=3 +time=5 > dig.ns5.out.${n} || ret=1
$DIG $DIGOPTS @10.53.0.5 not-truncated.no-questions. a +tries=3 +time=4 > dig.ns5.out.${n} || ret=1
grep "status: NOERROR" dig.ns5.out.${n} > /dev/null && ret=1
grep "ANSWER: 1," dig.ns5.out.${n} > /dev/null && ret=1
grep "1\.2\.3\.4" dig.ns5.out.${n} > /dev/null && ret=1
+4 -2
View File
@@ -13,14 +13,16 @@
RNDCCMD="$RNDC -c ../common/rndc.conf -p ${CONTROLPORT} -s"
# wait up to ten seconds to ensure that a file has been written
# wait up to 11 seconds to ensure that a file has been written
waitfile () {
for try in 0 1 2 3 4 5 6 7 8 9; do
for try in 0 1 2 3 4 5 6 7 8 9 10; do
[ -s "$1" ] && break
sleep 1
done
}
DIG="$DIG +time=11"
max_stale_ttl=$(sed -ne 's,^[[:space:]]*max-stale-ttl \([[:digit:]]*\).*,\1,p' $TOP_SRCDIR/bin/named/config.c)
status=0
+1 -1
View File
@@ -578,7 +578,7 @@ LIBS="$LIBS $LIBUV_LIBS"
# Those functions are only provided in newer versions of libuv, we'll be emulating them
# for now
AC_CHECK_FUNCS([uv_handle_get_data uv_handle_set_data uv_import])
AC_CHECK_FUNCS([uv_handle_get_data uv_handle_set_data uv_import uv_udp_connect uv_translate_sys_error])
AX_RESTORE_FLAGS([libuv])
#
-5
View File
@@ -561,11 +561,6 @@ This option displays [or does not display] the TTL in friendly human\-readable t
units of \fBs\fP, \fBm\fP, \fBh\fP, \fBd\fP, and \fBw\fP, representing seconds, minutes,
hours, days, and weeks. This implies \fB+ttlid\fP\&.
.TP
.B \fB+[no]unexpected\fP
This option accepts [or does not accept] answers from unexpected sources. By default, \fBdig\fP
will not accept a reply from a source other than the one to which it sent the
query.
.TP
.B \fB+[no]unknownformat\fP
This option prints all RDATA in unknown RR type presentation format (\fI\%RFC 3597\fP).
The default is to print RDATA for known types in the type\(aqs
+10
View File
@@ -52,6 +52,16 @@ Feature Changes
maximum payload size, so a a useful default for maximum DNS/UDP payload size
on reliable networks would be 1400. [GL #2183]
- The ``dig``, ``host``, and ``nslookup`` tools have been converted to
use the new network manager API rather than the older ISC socket API.
As a side effect of this change, the ``dig +unexpected`` option no longer
works. This could previously be used for diagnosing broken servers or
network configurations by listening for replies from servers other than
the one that was queried. With the new API such answers are filtered
before they ever reach ``dig``. Consequently, the option has been
removed. [GL #2140]
Bug Fixes
~~~~~~~~~
+2 -3
View File
@@ -49,9 +49,8 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
const isc_sockaddr_t *masteraddr,
const isc_sockaddr_t *sourceaddr, isc_dscp_t dscp,
dns_tsigkey_t *tsigkey, isc_mem_t *mctx,
isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
isc_task_t *task, dns_xfrindone_t done,
dns_xfrin_ctx_t **xfrp);
isc_timermgr_t *timermgr, isc_nm_t *netmgr, isc_task_t *task,
dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp);
/*%<
* Attempt to start an incoming zone transfer of 'zone'
* from 'masteraddr', creating a dns_xfrin_ctx_t object to
+1 -1
View File
@@ -1630,7 +1630,7 @@ dns_zone_getkeydirectory(dns_zone_t *zone);
isc_result_t
dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
dns_zonemgr_t **zmgrp);
isc_nm_t *netmgr, dns_zonemgr_t **zmgrp);
/*%<
* Create a zone manager. Note: the zone manager will not be able to
* manage any zones until dns_zonemgr_setsize() has been run.
+1 -1
View File
@@ -297,7 +297,7 @@ dns_test_setupzonemgr(void) {
isc_result_t result;
REQUIRE(zonemgr == NULL);
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr,
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL,
&zonemgr);
return (result);
}
+4 -4
View File
@@ -62,7 +62,7 @@ zonemgr_create(void **state) {
UNUSED(state);
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr,
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL,
&myzonemgr);
assert_int_equal(result, ISC_R_SUCCESS);
@@ -80,7 +80,7 @@ zonemgr_managezone(void **state) {
UNUSED(state);
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr,
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL,
&myzonemgr);
assert_int_equal(result, ISC_R_SUCCESS);
@@ -121,7 +121,7 @@ zonemgr_createzone(void **state) {
UNUSED(state);
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr,
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL,
&myzonemgr);
assert_int_equal(result, ISC_R_SUCCESS);
@@ -160,7 +160,7 @@ zonemgr_unreachable(void **state) {
TIME_NOW(&now);
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr,
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL,
&myzonemgr);
assert_int_equal(result, ISC_R_SUCCESS);
+123 -170
View File
@@ -100,7 +100,7 @@ struct dns_xfrin_ctx {
isc_task_t *task;
isc_timer_t *timer;
isc_socketmgr_t *socketmgr;
isc_nm_t *netmgr;
int connects; /*%< Connect in progress */
int sends; /*%< Send in progress */
@@ -123,16 +123,15 @@ struct dns_xfrin_ctx {
isc_sockaddr_t masteraddr;
isc_sockaddr_t sourceaddr;
isc_socket_t *socket;
isc_nmhandle_t *handle;
isc_nmhandle_t *readhandle;
isc_nmhandle_t *sendhandle;
/*% Buffer for IXFR/AXFR request message */
isc_buffer_t qbuffer;
unsigned char qbuffer_data[512];
/*% Incoming reply TCP message */
dns_tcpmsg_t tcpmsg;
bool tcpmsg_valid;
/*%
* Whether the zone originally had a database attached at the time this
* transfer context was created. Used by maybe_free() when making
@@ -190,11 +189,10 @@ struct dns_xfrin_ctx {
static isc_result_t
xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_task_t *task,
isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
dns_name_t *zonename, dns_rdataclass_t rdclass,
dns_rdatatype_t reqtype, const isc_sockaddr_t *masteraddr,
const isc_sockaddr_t *sourceaddr, isc_dscp_t dscp,
dns_tsigkey_t *tsigkey, dns_xfrin_ctx_t **xfrp);
isc_timermgr_t *timermgr, isc_nm_t *netmgr, dns_name_t *zonename,
dns_rdataclass_t rdclass, dns_rdatatype_t reqtype,
const isc_sockaddr_t *masteraddr, const isc_sockaddr_t *sourceaddr,
isc_dscp_t dscp, dns_tsigkey_t *tsigkey, dns_xfrin_ctx_t **xfrp);
static isc_result_t
axfr_init(dns_xfrin_ctx_t *xfr);
@@ -228,13 +226,14 @@ static isc_result_t
xfrin_start(dns_xfrin_ctx_t *xfr);
static void
xfrin_connect_done(isc_task_t *task, isc_event_t *event);
xfrin_connect_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg);
static isc_result_t
xfrin_send_request(dns_xfrin_ctx_t *xfr);
static void
xfrin_send_done(isc_task_t *task, isc_event_t *event);
xfrin_send_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg);
static void
xfrin_recv_done(isc_task_t *task, isc_event_t *event);
xfrin_recv_done(isc_nmhandle_t *handle, isc_result_t result,
isc_region_t *region, void *cbarg);
static void
xfrin_timeout(isc_task_t *task, isc_event_t *event);
@@ -658,9 +657,8 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
const isc_sockaddr_t *masteraddr,
const isc_sockaddr_t *sourceaddr, isc_dscp_t dscp,
dns_tsigkey_t *tsigkey, isc_mem_t *mctx,
isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
isc_task_t *task, dns_xfrindone_t done,
dns_xfrin_ctx_t **xfrp) {
isc_timermgr_t *timermgr, isc_nm_t *netmgr, isc_task_t *task,
dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp) {
dns_name_t *zonename = dns_zone_getorigin(zone);
dns_xfrin_ctx_t *xfr = NULL;
isc_result_t result;
@@ -674,7 +672,7 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
REQUIRE(db != NULL);
}
CHECK(xfrin_create(mctx, zone, db, task, timermgr, socketmgr, zonename,
CHECK(xfrin_create(mctx, zone, db, task, timermgr, netmgr, zonename,
dns_zone_getclass(zone), xfrtype, masteraddr,
sourceaddr, dscp, tsigkey, &xfr));
@@ -682,12 +680,21 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
xfr->zone_had_db = true;
}
CHECK(xfrin_start(xfr));
xfr->done = done;
if (xfr->done != NULL) {
if (done != NULL) {
xfr->done = done;
xfr->refcount++;
}
result = xfrin_start(xfr);
if (result != ISC_R_SUCCESS) {
xfr->done = NULL;
if (done != NULL) {
xfr->refcount--;
}
goto failure;
}
*xfrp = xfr;
failure:
@@ -728,14 +735,11 @@ dns_xfrin_detach(dns_xfrin_ctx_t **xfrp) {
static void
xfrin_cancelio(dns_xfrin_ctx_t *xfr) {
if (xfr->connects > 0) {
isc_socket_cancel(xfr->socket, xfr->task,
ISC_SOCKCANCEL_CONNECT);
} else if (xfr->recvs > 0) {
dns_tcpmsg_cancelread(&xfr->tcpmsg);
} else if (xfr->sends > 0) {
isc_socket_cancel(xfr->socket, xfr->task, ISC_SOCKCANCEL_SEND);
if (xfr->readhandle == NULL) {
return;
}
isc_nm_cancelread(xfr->readhandle);
isc_nmhandle_detach(&xfr->readhandle);
}
static void
@@ -746,8 +750,11 @@ xfrin_reset(dns_xfrin_ctx_t *xfr) {
xfrin_cancelio(xfr);
if (xfr->socket != NULL) {
isc_socket_detach(&xfr->socket);
if (xfr->readhandle != NULL) {
isc_nmhandle_detach(&xfr->readhandle);
}
if (xfr->sendhandle != NULL) {
isc_nmhandle_detach(&xfr->sendhandle);
}
if (xfr->lasttsig != NULL) {
@@ -765,11 +772,6 @@ xfrin_reset(dns_xfrin_ctx_t *xfr) {
(void)dns_db_endload(xfr->db, &xfr->axfr);
}
if (xfr->tcpmsg_valid) {
dns_tcpmsg_invalidate(&xfr->tcpmsg);
xfr->tcpmsg_valid = false;
}
if (xfr->ver != NULL) {
dns_db_closeversion(xfr->db, &xfr->ver, false);
}
@@ -803,82 +805,46 @@ xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg) {
static isc_result_t
xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_task_t *task,
isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
dns_name_t *zonename, dns_rdataclass_t rdclass,
dns_rdatatype_t reqtype, const isc_sockaddr_t *masteraddr,
const isc_sockaddr_t *sourceaddr, isc_dscp_t dscp,
dns_tsigkey_t *tsigkey, dns_xfrin_ctx_t **xfrp) {
isc_timermgr_t *timermgr, isc_nm_t *netmgr, dns_name_t *zonename,
dns_rdataclass_t rdclass, dns_rdatatype_t reqtype,
const isc_sockaddr_t *masteraddr, const isc_sockaddr_t *sourceaddr,
isc_dscp_t dscp, dns_tsigkey_t *tsigkey, dns_xfrin_ctx_t **xfrp) {
dns_xfrin_ctx_t *xfr = NULL;
isc_result_t result;
xfr = isc_mem_get(mctx, sizeof(*xfr));
xfr->mctx = NULL;
*xfr = (dns_xfrin_ctx_t){ .netmgr = netmgr,
.shutdown_result = ISC_R_UNSET,
.rdclass = rdclass,
.reqtype = reqtype,
.dscp = dscp,
.id = (dns_messageid_t)isc_random16(),
.maxrecords = dns_zone_getmaxrecords(zone),
.masteraddr = *masteraddr,
.sourceaddr = *sourceaddr };
isc_mem_attach(mctx, &xfr->mctx);
xfr->refcount = 0;
xfr->zone = NULL;
dns_zone_iattach(zone, &xfr->zone);
xfr->task = NULL;
isc_task_attach(task, &xfr->task);
xfr->timer = NULL;
xfr->socketmgr = socketmgr;
xfr->done = NULL;
xfr->connects = 0;
xfr->sends = 0;
xfr->recvs = 0;
xfr->shuttingdown = false;
xfr->shutdown_result = ISC_R_UNSET;
dns_name_init(&xfr->name, NULL);
xfr->rdclass = rdclass;
xfr->id = (dns_messageid_t)isc_random16();
xfr->reqtype = reqtype;
xfr->dscp = dscp;
/* sockaddr */
xfr->socket = NULL;
/* qbuffer */
/* qbuffer_data */
/* tcpmsg */
xfr->tcpmsg_valid = false;
xfr->zone_had_db = false;
xfr->db = NULL;
if (db != NULL) {
dns_db_attach(db, &xfr->db);
}
xfr->ver = NULL;
dns_diff_init(xfr->mctx, &xfr->diff);
xfr->difflen = 0;
if (reqtype == dns_rdatatype_soa) {
xfr->state = XFRST_SOAQUERY;
} else {
xfr->state = XFRST_INITIALSOA;
}
/* end_serial */
xfr->nmsg = 0;
xfr->nrecs = 0;
xfr->nbytes = 0;
xfr->maxrecords = dns_zone_getmaxrecords(zone);
isc_time_now(&xfr->start);
xfr->tsigkey = NULL;
if (tsigkey != NULL) {
dns_tsigkey_attach(tsigkey, &xfr->tsigkey);
}
xfr->lasttsig = NULL;
xfr->tsigctx = NULL;
xfr->sincetsig = 0;
xfr->is_ixfr = false;
/* ixfr.request_serial */
/* ixfr.current_serial */
xfr->ixfr.journal = NULL;
xfr->axfr.add = NULL;
xfr->axfr.add_private = NULL;
dns_name_dup(zonename, mctx, &xfr->name);
@@ -887,10 +853,7 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_task_t *task,
CHECK(dns_timer_setidle(xfr->timer, dns_zone_getmaxxfrin(xfr->zone),
dns_zone_getidlein(xfr->zone), false));
xfr->masteraddr = *masteraddr;
INSIST(isc_sockaddr_pf(masteraddr) == isc_sockaddr_pf(sourceaddr));
xfr->sourceaddr = *sourceaddr;
isc_sockaddr_setport(&xfr->sourceaddr, 0);
/*
@@ -900,6 +863,7 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_task_t *task,
sizeof(xfr->qbuffer_data) - 2);
xfr->magic = XFRIN_MAGIC;
*xfrp = xfr;
return (ISC_R_SUCCESS);
@@ -926,17 +890,15 @@ failure:
static isc_result_t
xfrin_start(dns_xfrin_ctx_t *xfr) {
isc_result_t result;
CHECK(isc_socket_create(xfr->socketmgr,
isc_sockaddr_pf(&xfr->sourceaddr),
isc_sockettype_tcp, &xfr->socket));
isc_socket_setname(xfr->socket, "xfrin", NULL);
#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
CHECK(isc_socket_bind(xfr->socket, &xfr->sourceaddr,
ISC_SOCKET_REUSEADDRESS));
#endif /* ifndef BROKEN_TCP_BIND_BEFORE_CONNECT */
isc_socket_dscp(xfr->socket, xfr->dscp);
CHECK(isc_socket_connect(xfr->socket, &xfr->masteraddr, xfr->task,
xfrin_connect_done, xfr));
/*
* XXX: timeout hard-coded to 30 seconds; this needs to be
* configurable.
*/
CHECK(isc_nm_tcpdnsconnect(
xfr->netmgr, (isc_nmiface_t *)&xfr->sourceaddr,
(isc_nmiface_t *)&xfr->masteraddr, xfrin_connect_done, xfr,
30000, 0));
/* TODO isc_socket_dscp(xfr->socket, xfr->dscp); */
xfr->connects++;
return (ISC_R_SUCCESS);
failure:
@@ -972,10 +934,8 @@ failure:
* A connection has been established.
*/
static void
xfrin_connect_done(isc_task_t *task, isc_event_t *event) {
isc_socket_connev_t *cev = (isc_socket_connev_t *)event;
dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *)event->ev_arg;
isc_result_t result = cev->result;
xfrin_connect_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *)cbarg;
char sourcetext[ISC_SOCKADDR_FORMATSIZE];
char signerbuf[DNS_NAME_FORMATSIZE];
const char *signer = "", *sep = "";
@@ -985,11 +945,6 @@ xfrin_connect_done(isc_task_t *task, isc_event_t *event) {
REQUIRE(VALID_XFRIN(xfr));
UNUSED(task);
INSIST(event->ev_type == ISC_SOCKEVENT_CONNECT);
isc_event_free(&event);
xfr->connects--;
if (xfr->shuttingdown) {
maybe_free(xfr);
@@ -1009,12 +964,9 @@ xfrin_connect_done(isc_task_t *task, isc_event_t *event) {
}
}
result = isc_socket_getsockname(xfr->socket, &sockaddr);
if (result == ISC_R_SUCCESS) {
isc_sockaddr_format(&sockaddr, sourcetext, sizeof(sourcetext));
} else {
strlcpy(sourcetext, "<UNKNOWN>", sizeof(sourcetext));
}
xfr->handle = handle;
sockaddr = isc_nmhandle_peeraddr(handle);
isc_sockaddr_format(&sockaddr, sourcetext, sizeof(sourcetext));
if (xfr->tsigkey != NULL && xfr->tsigkey->key != NULL) {
dns_name_format(dst_key_name(xfr->tsigkey->key), signerbuf,
@@ -1026,10 +978,8 @@ xfrin_connect_done(isc_task_t *task, isc_event_t *event) {
xfrin_log(xfr, ISC_LOG_INFO, "connected using %s%s%s", sourcetext, sep,
signer);
dns_tcpmsg_init(xfr->mctx, xfr->socket, &xfr->tcpmsg);
xfr->tcpmsg_valid = true;
CHECK(xfrin_send_request(xfr));
isc_nmhandle_detach(&handle);
failure:
if (result != ISC_R_SUCCESS) {
xfrin_fail(xfr, result, "failed to connect");
@@ -1167,16 +1117,13 @@ xfrin_send_request(dns_xfrin_ctx_t *xfr) {
isc_buffer_usedregion(&xfr->qbuffer, &region);
INSIST(region.length <= 65535);
/*
* Record message length and adjust region to include TCP
* length field.
*/
xfr->qbuffer_data[0] = (region.length >> 8) & 0xff;
xfr->qbuffer_data[1] = region.length & 0xff;
region.base -= 2;
region.length += 2;
CHECK(isc_socket_send(xfr->socket, &region, xfr->task, xfrin_send_done,
xfr));
isc_nmhandle_attach(xfr->handle, &xfr->sendhandle);
result = isc_nm_send(xfr->handle, &region, xfrin_send_done, xfr);
if (result != ISC_R_SUCCESS) {
isc_nmhandle_detach(&xfr->sendhandle);
goto failure;
}
xfr->sends++;
failure:
@@ -1195,62 +1142,57 @@ failure:
if (ver != NULL) {
dns_db_closeversion(xfr->db, &ver, false);
}
return (result);
}
static void
xfrin_send_done(isc_task_t *task, isc_event_t *event) {
isc_socketevent_t *sev = (isc_socketevent_t *)event;
dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *)event->ev_arg;
isc_result_t result;
xfrin_send_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *)cbarg;
REQUIRE(VALID_XFRIN(xfr));
UNUSED(task);
INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE);
UNUSED(handle);
xfr->sends--;
xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request data");
CHECK(sev->result);
CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task, xfrin_recv_done,
xfr));
xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request data");
CHECK(result);
if (xfr->readhandle == NULL) {
isc_nmhandle_attach(handle, &xfr->readhandle);
}
result = isc_nm_read(xfr->handle, xfrin_recv_done, xfr);
if (result != ISC_R_SUCCESS) {
isc_nmhandle_detach(&xfr->readhandle);
goto failure;
}
xfr->recvs++;
failure:
isc_event_free(&event);
isc_nmhandle_detach(&xfr->sendhandle);
if (result != ISC_R_SUCCESS) {
xfrin_fail(xfr, result, "failed sending request data");
}
}
static void
xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *)ev->ev_arg;
isc_result_t result;
xfrin_recv_done(isc_nmhandle_t *handle, isc_result_t result,
isc_region_t *region, void *cbarg) {
dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *)cbarg;
dns_message_t *msg = NULL;
dns_name_t *name;
dns_tcpmsg_t *tcpmsg;
const dns_name_t *tsigowner = NULL;
REQUIRE(VALID_XFRIN(xfr));
UNUSED(task);
INSIST(ev->ev_type == DNS_EVENT_TCPMSG);
tcpmsg = ev->ev_sender;
isc_event_free(&ev);
xfr->recvs--;
if (xfr->shuttingdown) {
maybe_free(xfr);
return;
}
CHECK(tcpmsg->result);
CHECK(result);
xfrin_log(xfr, ISC_LOG_DEBUG(7), "received %u bytes",
tcpmsg->buffer.used);
xfrin_log(xfr, ISC_LOG_DEBUG(7), "received %u bytes", region->length);
CHECK(isc_timer_touch(xfr->timer));
@@ -1267,13 +1209,17 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
if (xfr->nmsg > 0) {
msg->tcp_continuation = 1;
}
isc_buffer_t buffer;
isc_buffer_init(&buffer, region->base, region->length);
isc_buffer_add(&buffer, region->length);
result = dns_message_parse(msg, &tcpmsg->buffer,
result = dns_message_parse(msg, &buffer,
DNS_MESSAGEPARSE_PRESERVEORDER);
isc_sockaddr_t peer = isc_nmhandle_peeraddr(handle);
if (result == ISC_R_SUCCESS) {
dns_message_logpacket(msg, "received message from",
&tcpmsg->address, DNS_LOGCATEGORY_XFER_IN,
dns_message_logpacket(msg, "received message from", &peer,
DNS_LOGCATEGORY_XFER_IN,
DNS_LOGMODULE_XFER_IN, ISC_LOG_DEBUG(10),
xfr->mctx);
} else {
@@ -1455,7 +1401,7 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
/*
* Update the number of bytes received.
*/
xfr->nbytes += tcpmsg->buffer.used;
xfr->nbytes += buffer.used;
/*
* Take the context back.
@@ -1471,10 +1417,11 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
xfr->reqtype = dns_rdatatype_axfr;
xfr->state = XFRST_INITIALSOA;
CHECK(xfrin_send_request(xfr));
isc_nmhandle_detach(&xfr->readhandle);
break;
case XFRST_AXFR_END:
CHECK(axfr_finalize(xfr));
/* FALLTHROUGH */
/* FALLTHROUGH */
case XFRST_IXFR_END:
/*
* Close the journal.
@@ -1496,14 +1443,21 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
*/
xfr->shuttingdown = true;
xfr->shutdown_result = ISC_R_SUCCESS;
isc_nmhandle_detach(&xfr->readhandle);
maybe_free(xfr);
break;
default:
/*
* Read the next message.
*/
CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task,
xfrin_recv_done, xfr));
if (xfr->readhandle == NULL) {
isc_nmhandle_attach(handle, &xfr->readhandle);
}
result = isc_nm_read(xfr->handle, xfrin_recv_done, xfr);
if (result != ISC_R_SUCCESS) {
isc_nmhandle_detach(&xfr->readhandle);
goto failure;
}
xfr->recvs++;
}
return;
@@ -1575,8 +1529,11 @@ maybe_free(dns_xfrin_ctx_t *xfr) {
(unsigned int)(msecs / 1000), (unsigned int)(msecs % 1000),
(unsigned int)persec, xfr->end_serial);
if (xfr->socket != NULL) {
isc_socket_detach(&xfr->socket);
if (xfr->readhandle != NULL) {
isc_nmhandle_detach(&xfr->readhandle);
}
if (xfr->sendhandle != NULL) {
isc_nmhandle_detach(&xfr->sendhandle);
}
if (xfr->timer != NULL) {
@@ -1605,10 +1562,6 @@ maybe_free(dns_xfrin_ctx_t *xfr) {
(void)dns_db_endload(xfr->db, &xfr->axfr);
}
if (xfr->tcpmsg_valid) {
dns_tcpmsg_invalidate(&xfr->tcpmsg);
}
if (xfr->tsigctx != NULL) {
dst_context_destroy(&xfr->tsigctx);
}
+14 -2
View File
@@ -545,6 +545,7 @@ struct dns_zonemgr {
isc_taskmgr_t *taskmgr;
isc_timermgr_t *timermgr;
isc_socketmgr_t *socketmgr;
isc_nm_t *netmgr;
isc_taskpool_t *zonetasks;
isc_taskpool_t *loadtasks;
isc_task_t *task;
@@ -14009,6 +14010,13 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
dns_xfrin_shutdown(zone->xfr);
}
/*
* In case the shutdown didn't detach the xfr object...
*/
if (zone->xfr != NULL) {
dns_xfrin_detach(&zone->xfr);
}
/* Safe to release the zone now */
if (zone->zmgr != NULL) {
dns_zonemgr_releasezone(zone->zmgr, zone);
@@ -17099,9 +17107,12 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) {
}
UNLOCK_ZONE(zone);
INSIST(isc_sockaddr_pf(&masteraddr) == isc_sockaddr_pf(&sourceaddr));
if (zone->xfr != NULL) {
dns_xfrin_detach(&zone->xfr);
}
result = dns_xfrin_create(zone, xfrtype, &masteraddr, &sourceaddr, dscp,
zone->tsigkey, zone->mctx,
zone->zmgr->timermgr, zone->zmgr->socketmgr,
zone->zmgr->timermgr, zone->zmgr->netmgr,
zone->task, zone_xfrdone, &zone->xfr);
if (result == ISC_R_SUCCESS) {
LOCK_ZONE(zone);
@@ -17406,7 +17417,7 @@ dns_zone_first(dns_zonemgr_t *zmgr, dns_zone_t **first) {
isc_result_t
dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
dns_zonemgr_t **zmgrp) {
isc_nm_t *netmgr, dns_zonemgr_t **zmgrp) {
dns_zonemgr_t *zmgr;
isc_result_t result;
@@ -17417,6 +17428,7 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
zmgr->taskmgr = taskmgr;
zmgr->timermgr = timermgr;
zmgr->socketmgr = socketmgr;
zmgr->netmgr = netmgr;
zmgr->zonetasks = NULL;
zmgr->loadtasks = NULL;
zmgr->mctxpool = NULL;
+44 -4
View File
@@ -180,6 +180,25 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
* can then be freed automatically when the handle is destroyed.
*/
isc_result_t
isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize);
/*%<
* Open a UDP socket, bind to 'local' and connect to 'peer', and
* immediately call 'cb' with a handle so that the caller can begin
* sending packets over UDP.
*
* When handles are allocated for the socket, 'extrasize' additional bytes
* can be allocated along with the handle for an associated object, which
* can then be freed automatically when the handle is destroyed.
*
* 'timeout' specifies the timeout interval in milliseconds.
*
* The connected socket can only be accessed via the handle passed to
* 'cb'.
*/
void
isc_nm_stoplistening(isc_nmsocket_t *sock);
/*%<
@@ -277,14 +296,17 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface,
isc_result_t
isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, size_t extrahandlesize);
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize);
/*%<
* Create a socket using netmgr 'mgr', bind it to the address 'local',
* and connect it to the address 'peer'.
*
* When the connection is complete, call 'cb' with argument 'cbarg'.
* Allocate 'extrahandlesize' additional bytes along with the handle to use
* for an associated object.
* When the connection is complete or has timed out, call 'cb' with
* argument 'cbarg'. Allocate 'extrahandlesize' additional bytes along
* with the handle to use for an associated object.
*
* 'timeout' specifies the timeout interval in milliseconds.
*
* The connected socket can only be accessed via the handle passed to
* 'cb'.
@@ -390,3 +412,21 @@ isc_nm_setstats(isc_nm_t *mgr, isc_stats_t *stats);
*\li stats is a valid set of statistics counters supporting the
* full range of socket-related stats counter numbers.
*/
isc_result_t
isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize);
/*%
* Establish a DNS client connection over a TCP socket, bound to the
* address 'local', and connected to the address 'peer'.
*
* When the connection is complete or has timed out, call 'cb' with
* argument 'cbarg'. Allocate 'extrahandlesize' additional bytes along
* with the handle to use for an associated object.
*
* 'timeout' specifies the timeout interval in milliseconds.
*
* The connected socket can only be accessed via the handle passed to
* 'cb'.
*/
+72 -4
View File
@@ -135,8 +135,12 @@ struct isc_nmiface {
};
typedef enum isc__netievent_type {
netievent_udpconnect,
netievent_udpsend,
netievent_udpread,
netievent_udpstop,
netievent_udpcancel,
netievent_udpclose,
netievent_tcpconnect,
netievent_tcpsend,
@@ -145,9 +149,12 @@ typedef enum isc__netievent_type {
netievent_tcpchildaccept,
netievent_tcpaccept,
netievent_tcpstop,
netievent_tcpcancel,
netievent_tcpclose,
netievent_tcpdnssend,
netievent_tcpdnsread,
netievent_tcpdnscancel,
netievent_tcpdnsclose,
netievent_closecb,
@@ -210,13 +217,16 @@ typedef struct isc__netievent__socket {
} isc__netievent__socket_t;
typedef isc__netievent__socket_t isc__netievent_udplisten_t;
typedef isc__netievent__socket_t isc__netievent_udpread_t;
typedef isc__netievent__socket_t isc__netievent_udpstop_t;
typedef isc__netievent__socket_t isc__netievent_udpclose_t;
typedef isc__netievent__socket_t isc__netievent_tcpstop_t;
typedef isc__netievent__socket_t isc__netievent_tcpclose_t;
typedef isc__netievent__socket_t isc__netievent_startread_t;
typedef isc__netievent__socket_t isc__netievent_pauseread_t;
typedef isc__netievent__socket_t isc__netievent_closecb_t;
typedef isc__netievent__socket_t isc__netievent_tcpdnsclose_t;
typedef isc__netievent__socket_t isc__netievent_tcpdnsread_t;
typedef struct isc__netievent__socket_req {
isc__netievent_type type;
@@ -245,6 +255,10 @@ typedef struct isc__netievent__socket_handle {
isc_nmhandle_t *handle;
} isc__netievent__socket_handle_t;
typedef isc__netievent__socket_handle_t isc__netievent_udpcancel_t;
typedef isc__netievent__socket_handle_t isc__netievent_tcpcancel_t;
typedef isc__netievent__socket_handle_t isc__netievent_tcpdnscancel_t;
typedef struct isc__netievent__socket_quota {
isc__netievent_type type;
isc_nmsocket_t *sock;
@@ -260,6 +274,12 @@ typedef struct isc__netievent_udpsend {
isc__nm_uvreq_t *req;
} isc__netievent_udpsend_t;
typedef struct isc__netievent_udpconnect {
isc__netievent_type type;
isc_nmsocket_t *sock;
isc_sockaddr_t peer;
} isc__netievent_udpconnect_t;
typedef struct isc__netievent {
isc__netievent_type type;
} isc__netievent_t;
@@ -394,11 +414,14 @@ struct isc_nmsocket {
const isc_statscounter_t *statsindex;
/*%
* TCP read timeout timer.
* TCP read/connect timeout timers.
*/
uv_timer_t timer;
bool timer_initialized;
bool timer_running;
uint64_t read_timeout;
uint64_t connect_timeout;
bool timed_out;
/*% outer socket is for 'wrapped' sockets - e.g. tcpdns in tcp */
isc_nmsocket_t *outer;
@@ -447,6 +470,7 @@ struct isc_nmsocket {
atomic_bool closed;
atomic_bool listening;
atomic_bool listen_error;
atomic_bool connecting;
atomic_bool connected;
atomic_bool connect_error;
isc_refcount_t references;
@@ -501,9 +525,9 @@ struct isc_nmsocket {
isc_condition_t cond;
/*%
* Used to pass a result back from TCP listening events.
* Used to pass a result back from listen or connect events.
*/
isc_result_t result;
atomic_int_fast32_t result;
/*%
* List of active handles.
@@ -546,6 +570,9 @@ struct isc_nmsocket {
isc_nm_recv_cb_t recv_cb;
void *recv_cbarg;
isc_nm_cb_t connect_cb;
void *connect_cbarg;
isc_nm_accept_cb_t accept_cb;
void *accept_cbarg;
#ifdef NETMGR_TRACE
@@ -681,16 +708,41 @@ isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
* Back-end implementation of isc_nm_send() for UDP handles.
*/
isc_result_t
isc__nm_udp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
/*
* Back-end implementation of isc_nm_read() for UDP handles.
*/
void
isc__nm_udp_close(isc_nmsocket_t *sock);
/*%<
* Close a UDP socket.
*/
void
isc__nm_udp_cancelread(isc_nmhandle_t *handle);
/*%<
* Stop reading on a connected UDP handle.
*/
void
isc__nm_udp_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_udpconnect(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_udpstop(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_udpsend(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_udpcancel(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_udpclose(isc__networker_t *worker, isc__netievent_t *ev0);
/*%<
* Callback handlers for asynchronous UDP events (listen, stoplisten, send).
*/
@@ -763,6 +815,8 @@ isc__nm_async_tcp_startread(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcp_pauseread(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcpcancel(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ev0);
/*%<
* Callback handlers for asynchronous TCP events (connect, listen,
@@ -785,12 +839,26 @@ isc__nm_tcpdns_close(isc_nmsocket_t *sock);
void
isc__nm_tcpdns_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_async_tcpdnscancel(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcpdnsclose(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0);
isc_result_t
isc__nm_tcpdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
void
isc__nm_tcpdns_cancelread(isc_nmhandle_t *handle);
/*%<
* Stop reading on a connected TCPDNS handle.
*/
#define isc__nm_uverr2result(x) \
isc___nm_uverr2result(x, true, __FILE__, __LINE__)
isc_result_t
+35
View File
@@ -604,6 +604,9 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) {
more = false;
break;
case netievent_udpconnect:
isc__nm_async_udpconnect(worker, ievent);
break;
case netievent_udplisten:
isc__nm_async_udplisten(worker, ievent);
break;
@@ -613,6 +616,15 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) {
case netievent_udpsend:
isc__nm_async_udpsend(worker, ievent);
break;
case netievent_udpread:
isc__nm_async_udpread(worker, ievent);
break;
case netievent_udpcancel:
isc__nm_async_udpcancel(worker, ievent);
break;
case netievent_udpclose:
isc__nm_async_udpclose(worker, ievent);
break;
case netievent_tcpconnect:
isc__nm_async_tcpconnect(worker, ievent);
@@ -641,13 +653,22 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) {
case netievent_tcpstop:
isc__nm_async_tcpstop(worker, ievent);
break;
case netievent_tcpcancel:
isc__nm_async_tcpcancel(worker, ievent);
break;
case netievent_tcpclose:
isc__nm_async_tcpclose(worker, ievent);
break;
case netievent_tcpdnscancel:
isc__nm_async_tcpdnscancel(worker, ievent);
break;
case netievent_tcpdnsclose:
isc__nm_async_tcpdnsclose(worker, ievent);
break;
case netievent_tcpdnsread:
isc__nm_async_tcpdnsread(worker, ievent);
break;
case netievent_closecb:
isc__nm_async_closecb(worker, ievent);
@@ -907,6 +928,9 @@ isc__nmsocket_prep_destroy(isc_nmsocket_t *sock) {
*/
if (!atomic_load(&sock->closed)) {
switch (sock->type) {
case isc_nm_udpsocket:
isc__nm_udp_close(sock);
return;
case isc_nm_tcpsocket:
isc__nm_tcp_close(sock);
return;
@@ -1037,6 +1061,7 @@ isc__nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
void
isc__nmsocket_clearcb(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(!isc__nm_in_netthread() || sock->tid == isc_nm_tid());
sock->recv_cb = NULL;
sock->recv_cbarg = NULL;
@@ -1416,8 +1441,12 @@ isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
REQUIRE(VALID_NMHANDLE(handle));
switch (handle->sock->type) {
case isc_nm_udpsocket:
return (isc__nm_udp_read(handle, cb, cbarg));
case isc_nm_tcpsocket:
return (isc__nm_tcp_read(handle, cb, cbarg));
case isc_nm_tcpdnssocket:
return (isc__nm_tcpdns_read(handle, cb, cbarg));
default:
INSIST(0);
ISC_UNREACHABLE();
@@ -1429,9 +1458,15 @@ isc_nm_cancelread(isc_nmhandle_t *handle) {
REQUIRE(VALID_NMHANDLE(handle));
switch (handle->sock->type) {
case isc_nm_udpsocket:
isc__nm_udp_cancelread(handle);
break;
case isc_nm_tcpsocket:
isc__nm_tcp_cancelread(handle);
break;
case isc_nm_tcpdnssocket:
isc__nm_tcpdns_cancelread(handle);
break;
default:
INSIST(0);
ISC_UNREACHABLE();
+141 -63
View File
@@ -76,6 +76,22 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota);
static void
quota_accept_cb(isc_quota_t *quota, void *sock0);
static void
connecttimeout_cb(uv_timer_t *handle) {
isc__nm_uvreq_t *req = uv_handle_get_data((uv_handle_t *)handle);
isc_nmsocket_t *sock = req->sock;
if (req->cb.connect != NULL) {
req->cb.connect(NULL, ISC_R_TIMEDOUT, req->cbarg);
}
uv_timer_stop(&sock->timer);
sock->timer_running = false;
sock->timed_out = true;
isc__nm_uvreq_put(&req, sock);
isc__nmsocket_detach(&sock);
}
static int
tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
isc__networker_t *worker = NULL;
@@ -85,12 +101,24 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
worker = &sock->mgr->workers[isc_nm_tid()];
atomic_store(&sock->connecting, true);
if (!sock->timer_initialized) {
uv_timer_init(&worker->loop, &sock->timer);
uv_handle_set_data((uv_handle_t *)&sock->timer, req);
sock->timer_initialized = true;
}
uv_timer_start(&sock->timer, connecttimeout_cb, sock->connect_timeout,
0);
sock->timer_running = true;
r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
if (r != 0) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPENFAIL]);
/* Socket was never opened; no need for tcp_close_direct() */
atomic_store(&sock->closed, true);
sock->result = isc__nm_uverr2result(r);
atomic_store(&sock->result, isc__nm_uverr2result(r));
atomic_store(&sock->connect_error, true);
return (r);
}
@@ -100,7 +128,7 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
if (r != 0) {
isc__nm_incstats(sock->mgr,
sock->statsindex[STATID_BINDFAIL]);
sock->result = isc__nm_uverr2result(r);
atomic_store(&sock->result, isc__nm_uverr2result(r));
atomic_store(&sock->connect_error, true);
tcp_close_direct(sock);
return (r);
@@ -113,7 +141,7 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
if (r != 0) {
isc__nm_incstats(sock->mgr,
sock->statsindex[STATID_CONNECTFAIL]);
sock->result = isc__nm_uverr2result(r);
atomic_store(&sock->result, isc__nm_uverr2result(r));
atomic_store(&sock->connect_error, true);
tcp_close_direct(sock);
}
@@ -155,14 +183,30 @@ tcp_connect_cb(uv_connect_t *uvreq, int status) {
sock = uv_handle_get_data((uv_handle_t *)uvreq->handle);
REQUIRE(VALID_UVREQ(req));
atomic_store(&sock->connecting, false);
if (sock->timed_out) {
return;
}
uv_timer_stop(&sock->timer);
sock->timer_running = false;
if (status != 0) {
req->cb.connect(NULL, isc__nm_uverr2result(status), req->cbarg);
isc__nm_uvreq_put(&req, sock);
if (status != UV_ECANCELED) {
/*
* In this case the resources would already
* have been freed in isc__nm_tcp_shutdown().
*/
isc__nm_uvreq_put(&req, sock);
isc__nmsocket_detach(&sock);
}
return;
}
REQUIRE(VALID_UVREQ(req));
sock = uv_handle_get_data((uv_handle_t *)uvreq->handle);
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECT]);
uv_tcp_getpeername(&sock->uv_handle.tcp, (struct sockaddr *)&ss,
@@ -175,8 +219,6 @@ tcp_connect_cb(uv_connect_t *uvreq, int status) {
isc__nm_uvreq_put(&req, sock);
atomic_init(&sock->client, true);
/*
* The sock is now attached to the handle.
*/
@@ -191,7 +233,8 @@ tcp_connect_cb(uv_connect_t *uvreq, int status) {
isc_result_t
isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, size_t extrahandlesize) {
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize) {
isc_nmsocket_t *nsock = NULL, *tmp = NULL;
isc__netievent_tcpconnect_t *ievent = NULL;
isc__nm_uvreq_t *req = NULL;
@@ -204,7 +247,9 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
isc__nmsocket_init(nsock, mgr, isc_nm_tcpsocket, local);
nsock->extrahandlesize = extrahandlesize;
nsock->result = ISC_R_SUCCESS;
nsock->connect_timeout = timeout;
atomic_init(&nsock->result, ISC_R_SUCCESS);
atomic_init(&nsock->client, true);
req = isc__nm_uvreq_get(mgr, nsock);
req->cb.connect = cb;
@@ -240,8 +285,8 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
UNLOCK(&nsock->lock);
}
if (nsock->result != ISC_R_SUCCESS) {
result = nsock->result;
if (atomic_load(&nsock->result) != ISC_R_SUCCESS) {
result = atomic_load(&nsock->result);
isc__nmsocket_detach(&nsock);
}
@@ -262,11 +307,12 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface,
nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
isc__nmsocket_init(nsock, mgr, isc_nm_tcplistener, iface);
nsock->accept_cb = accept_cb;
nsock->accept_cbarg = accept_cbarg;
nsock->extrahandlesize = extrahandlesize;
nsock->backlog = backlog;
nsock->result = ISC_R_SUCCESS;
atomic_init(&nsock->result, ISC_R_SUCCESS);
if (quota != NULL) {
/*
* We don't attach to quota, just assign - to avoid
@@ -296,11 +342,11 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface,
UNLOCK(&nsock->lock);
}
if (nsock->result == ISC_R_SUCCESS) {
if (atomic_load(&nsock->result) == ISC_R_SUCCESS) {
*sockp = nsock;
return (ISC_R_SUCCESS);
} else {
isc_result_t result = nsock->result;
isc_result_t result = atomic_load(&nsock->result);
isc__nmsocket_detach(&nsock);
return (result);
}
@@ -329,7 +375,7 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPENFAIL]);
/* The socket was never opened, so no need for uv_close() */
atomic_store(&sock->closed, true);
sock->result = isc__nm_uverr2result(r);
atomic_store(&sock->result, isc__nm_uverr2result(r));
atomic_store(&sock->listen_error, true);
goto done;
}
@@ -360,7 +406,7 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
if (r != 0) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]);
uv_close(&sock->uv_handle.handle, tcp_close_cb);
sock->result = isc__nm_uverr2result(r);
atomic_store(&sock->result, isc__nm_uverr2result(r));
atomic_store(&sock->listen_error, true);
goto done;
}
@@ -375,7 +421,7 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
&snamelen);
if (r != 0) {
uv_close(&sock->uv_handle.handle, tcp_close_cb);
sock->result = isc__nm_uverr2result(r);
atomic_store(&sock->result, isc__nm_uverr2result(r));
atomic_store(&sock->listen_error, true);
goto done;
}
@@ -392,7 +438,7 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
"uv_listen failed: %s",
isc_result_totext(isc__nm_uverr2result(r)));
uv_close(&sock->uv_handle.handle, tcp_close_cb);
sock->result = isc__nm_uverr2result(r);
atomic_store(&sock->result, isc__nm_uverr2result(r));
atomic_store(&sock->listen_error, true);
goto done;
}
@@ -431,8 +477,7 @@ void
isc__nm_async_tcpchildaccept(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_tcpchildaccept_t *ievent =
(isc__netievent_tcpchildaccept_t *)ev0;
isc_nmsocket_t *ssock = ievent->sock;
isc_nmsocket_t *csock = NULL;
isc_nmsocket_t *csock = ievent->sock;
isc_nmhandle_t *handle;
isc_result_t result;
struct sockaddr_storage ss;
@@ -442,17 +487,12 @@ isc__nm_async_tcpchildaccept(isc__networker_t *worker, isc__netievent_t *ev0) {
void *accept_cbarg;
REQUIRE(isc__nm_in_netthread());
REQUIRE(ssock->type == isc_nm_tcplistener);
csock = isc_mem_get(ssock->mgr->mctx, sizeof(isc_nmsocket_t));
isc__nmsocket_init(csock, ssock->mgr, isc_nm_tcpsocket, ssock->iface);
csock->tid = isc_nm_tid();
csock->extrahandlesize = ssock->extrahandlesize;
REQUIRE(csock->tid == isc_nm_tid());
csock->quota = ievent->quota;
ievent->quota = NULL;
worker = &ssock->mgr->workers[isc_nm_tid()];
worker = &csock->mgr->workers[isc_nm_tid()];
uv_tcp_init(&worker->loop, &csock->uv_handle.tcp);
r = isc_uv_import(&csock->uv_handle.stream, &ievent->streaminfo);
@@ -490,17 +530,13 @@ isc__nm_async_tcpchildaccept(isc__networker_t *worker, isc__netievent_t *ev0) {
goto error;
}
isc__nmsocket_attach(ssock, &csock->server);
handle = isc__nmhandle_get(csock, NULL, &local);
LOCK(&ssock->lock);
INSIST(ssock->accept_cb != NULL);
accept_cb = ssock->accept_cb;
accept_cbarg = ssock->accept_cbarg;
UNLOCK(&ssock->lock);
INSIST(csock->accept_cb != NULL);
accept_cb = csock->accept_cb;
accept_cbarg = csock->accept_cbarg;
csock->read_timeout = ssock->mgr->init;
csock->read_timeout = csock->mgr->init;
accept_cb(handle, ISC_R_SUCCESS, accept_cbarg);
/*
@@ -595,7 +631,7 @@ static void
readtimeout_cb(uv_timer_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)handle);
isc_nm_recv_cb_t cb;
void *cbarg;
void *cbarg = NULL;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
@@ -617,11 +653,9 @@ readtimeout_cb(uv_timer_t *handle) {
isc_quota_detach(&sock->quota);
}
LOCK(&sock->lock);
cb = sock->recv_cb;
cbarg = sock->recv_cbarg;
isc__nmsocket_clearcb(sock);
UNLOCK(&sock->lock);
if (cb != NULL) {
cb(sock->statichandle, ISC_R_TIMEDOUT, NULL, cbarg);
@@ -638,10 +672,9 @@ isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
sock = handle->sock;
LOCK(&sock->lock);
REQUIRE(sock->tid == isc_nm_tid());
sock->recv_cb = cb;
sock->recv_cbarg = cbarg;
UNLOCK(&sock->lock);
ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpstartread);
ievent->sock = sock;
@@ -697,6 +730,7 @@ isc__nm_async_tcp_startread(isc__networker_t *worker, isc__netievent_t *ev0) {
}
uv_timer_start(&sock->timer, readtimeout_cb, sock->read_timeout,
0);
sock->timer_running = true;
}
r = uv_read_start(&sock->uv_handle.stream, tcp_alloc_cb, read_cb);
@@ -739,8 +773,9 @@ isc__nm_async_tcp_pauseread(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(worker->id == isc_nm_tid());
if (sock->timer_initialized) {
if (sock->timer_running) {
uv_timer_stop(&sock->timer);
sock->timer_running = false;
}
uv_read_stop(&sock->uv_handle.stream);
}
@@ -750,12 +785,11 @@ isc__nm_tcp_resumeread(isc_nmsocket_t *sock) {
isc__netievent_startread_t *ievent = NULL;
REQUIRE(VALID_NMSOCK(sock));
LOCK(&sock->lock);
REQUIRE(sock->tid == isc_nm_tid());
if (sock->recv_cb == NULL) {
UNLOCK(&sock->lock);
return (ISC_R_CANCELED);
}
UNLOCK(&sock->lock);
if (!atomic_load(&sock->readpaused)) {
return (ISC_R_SUCCESS);
@@ -782,15 +816,14 @@ static void
read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)stream);
isc_nm_recv_cb_t cb;
void *cbarg;
void *cbarg = NULL;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(buf != NULL);
LOCK(&sock->lock);
cb = sock->recv_cb;
cbarg = sock->recv_cbarg;
UNLOCK(&sock->lock);
if (nread >= 0) {
isc_region_t region = { .base = (unsigned char *)buf->base,
@@ -896,7 +929,6 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
int r, w;
REQUIRE(VALID_NMSOCK(ssock));
REQUIRE(ssock->tid == isc_nm_tid());
if (!atomic_load_relaxed(&ssock->active) ||
atomic_load_relaxed(&ssock->mgr->closing))
@@ -956,7 +988,18 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
/* We have an accepted TCP socket, pass it to a random worker */
w = isc_random_uniform(ssock->mgr->nworkers);
event = isc__nm_get_ievent(ssock->mgr, netievent_tcpchildaccept);
event->sock = ssock;
/* Duplicate the server socket */
isc_nmsocket_t *csock = NULL;
csock = isc_mem_get(ssock->mgr->mctx, sizeof(isc_nmsocket_t));
isc__nmsocket_init(csock, ssock->mgr, isc_nm_tcpsocket, ssock->iface);
csock->tid = w;
csock->extrahandlesize = ssock->extrahandlesize;
isc__nmsocket_attach(ssock, &csock->server);
csock->accept_cb = ssock->accept_cb;
csock->accept_cbarg = ssock->accept_cbarg;
event->sock = csock;
event->quota = quota;
r = isc_uv_export((uv_stream_t *)uvstream, &event->streaminfo);
@@ -1108,7 +1151,9 @@ tcp_close_direct(isc_nmsocket_t *sock) {
}
if (sock->timer_initialized) {
sock->timer_initialized = false;
sock->timer_running = false;
uv_timer_stop(&sock->timer);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
} else {
if (sock->server != NULL) {
@@ -1150,19 +1195,31 @@ isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ev0) {
void
isc__nm_tcp_shutdown(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
if (sock->type == isc_nm_tcpsocket && sock->statichandle != NULL) {
isc_nm_recv_cb_t cb;
void *cbarg;
if (atomic_load(&sock->connecting)) {
isc__nm_uvreq_t *req = NULL;
sock->timer_running = false;
atomic_store(&sock->connecting, false);
req = uv_handle_get_data((uv_handle_t *)&sock->timer);
uv_timer_stop(&sock->timer);
LOCK(&sock->lock);
cb = sock->recv_cb;
cbarg = sock->recv_cbarg;
isc__nmsocket_clearcb(sock);
UNLOCK(&sock->lock);
if (sock->connect_cb != NULL) {
sock->connect_cb(NULL, ISC_R_CANCELED,
sock->connect_cbarg);
}
if (cb != NULL) {
cb(sock->statichandle, ISC_R_CANCELED, NULL, cbarg);
isc__nm_uvreq_put(&req, sock);
isc__nmsocket_detach(&sock);
} else if (sock->type == isc_nm_tcpsocket && sock->statichandle != NULL)
{
if (sock->recv_cb != NULL) {
sock->recv_cb(sock->statichandle, ISC_R_CANCELED, NULL,
sock->recv_cbarg);
} else {
isc__nmsocket_detach(&sock);
}
}
}
@@ -1170,24 +1227,45 @@ isc__nm_tcp_shutdown(isc_nmsocket_t *sock) {
void
isc__nm_tcp_cancelread(isc_nmhandle_t *handle) {
isc_nmsocket_t *sock = NULL;
isc__netievent_tcpcancel_t *ievent = NULL;
REQUIRE(VALID_NMHANDLE(handle));
sock = handle->sock;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->type == isc_nm_tcpsocket);
ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpcancel);
ievent->sock = sock;
isc_nmhandle_attach(handle, &ievent->handle);
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
void
isc__nm_async_tcpcancel(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_tcpcancel_t *ievent = (isc__netievent_tcpcancel_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
isc_nmhandle_t *handle = ievent->handle;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(worker->id == sock->tid);
REQUIRE(sock->tid == isc_nm_tid());
uv_read_stop(&sock->uv_handle.stream);
if (atomic_load(&sock->client)) {
isc_nm_recv_cb_t cb;
void *cbarg;
void *cbarg = NULL;
LOCK(&sock->lock);
cb = sock->recv_cb;
cbarg = sock->recv_cbarg;
isc__nmsocket_clearcb(sock);
UNLOCK(&sock->lock);
cb(handle, ISC_R_EOF, NULL, cbarg);
if (cb != NULL) {
cb(handle, ISC_R_EOF, NULL, cbarg);
}
}
isc_nmhandle_detach(&handle);
}
+218 -13
View File
@@ -119,10 +119,8 @@ dnslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
return (result);
}
LOCK(&dnslistensock->lock);
accept_cb = dnslistensock->accept_cb;
accept_cbarg = dnslistensock->accept_cbarg;
UNLOCK(&dnslistensock->lock);
if (accept_cb != NULL) {
result = accept_cb(handle, ISC_R_SUCCESS, accept_cbarg);
@@ -184,6 +182,7 @@ processbuffer(isc_nmsocket_t *dnssock, isc_nmhandle_t **handlep) {
size_t len;
REQUIRE(VALID_NMSOCK(dnssock));
REQUIRE(dnssock->tid == isc_nm_tid());
REQUIRE(handlep != NULL && *handlep == NULL);
/*
@@ -214,12 +213,9 @@ processbuffer(isc_nmsocket_t *dnssock, isc_nmhandle_t **handlep) {
listener = dnssock->listener;
if (listener != NULL) {
LOCK(&listener->lock);
cb = listener->recv_cb;
cbarg = listener->recv_cbarg;
UNLOCK(&listener->lock);
} else if (dnssock->recv_cb != NULL) {
LOCK(&dnssock->lock);
cb = dnssock->recv_cb;
cbarg = dnssock->recv_cbarg;
/*
@@ -228,7 +224,6 @@ processbuffer(isc_nmsocket_t *dnssock, isc_nmhandle_t **handlep) {
* call to isc_nm_read() and set up a new callback.
*/
isc__nmsocket_clearcb(dnssock);
UNLOCK(&dnssock->lock);
}
if (cb != NULL) {
@@ -265,11 +260,16 @@ dnslisten_readcb(isc_nmhandle_t *handle, isc_result_t eresult,
size_t len;
REQUIRE(VALID_NMSOCK(dnssock));
REQUIRE(dnssock->tid == isc_nm_tid());
REQUIRE(VALID_NMHANDLE(handle));
if (region == NULL || eresult != ISC_R_SUCCESS) {
/* Connection closed */
dnssock->result = eresult;
atomic_store(&dnssock->result, eresult);
if (atomic_load(&dnssock->client) && dnssock->recv_cb != NULL) {
dnssock->recv_cb(dnssock->statichandle, eresult, NULL,
dnssock->recv_cbarg);
}
if (dnssock->self != NULL) {
isc__nmsocket_detach(&dnssock->self);
}
@@ -277,7 +277,15 @@ dnslisten_readcb(isc_nmhandle_t *handle, isc_result_t eresult,
if (dnssock->outerhandle != NULL) {
isc_nmhandle_detach(&dnssock->outerhandle);
}
isc_nmhandle_detach(&handle);
/*
* Server connections will hold two handle references when
* shut down, but client (tcpdnsconnect) connections have
* only one.
*/
if (!atomic_load(&dnssock->client)) {
isc_nmhandle_detach(&handle);
}
return;
}
@@ -314,10 +322,8 @@ dnslisten_readcb(isc_nmhandle_t *handle, isc_result_t eresult,
uv_timer_stop(&dnssock->timer);
}
LOCK(&dnssock->lock);
if (atomic_load(&dnssock->sequential) ||
dnssock->recv_cb == NULL) {
UNLOCK(&dnssock->lock);
/*
* There are two reasons we might want to pause here:
* - We're in sequential mode and we've received
@@ -328,7 +334,6 @@ dnslisten_readcb(isc_nmhandle_t *handle, isc_result_t eresult,
isc_nm_pauseread(dnssock->outerhandle);
done = true;
} else {
UNLOCK(&dnssock->lock);
/*
* We're pipelining, so we now resume processing
* packets until the clients-per-connection limit
@@ -364,12 +369,10 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
REQUIRE(VALID_NM(mgr));
isc__nmsocket_init(dnslistensock, mgr, isc_nm_tcpdnslistener, iface);
LOCK(&dnslistensock->lock);
dnslistensock->recv_cb = cb;
dnslistensock->recv_cbarg = cbarg;
dnslistensock->accept_cb = accept_cb;
dnslistensock->accept_cbarg = accept_cbarg;
UNLOCK(&dnslistensock->lock);
dnslistensock->extrahandlesize = extrahandlesize;
/*
@@ -536,6 +539,7 @@ isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) {
isc_nmsocket_t *sock = ievent->sock;
REQUIRE(worker->id == sock->tid);
REQUIRE(sock->tid == isc_nm_tid());
result = ISC_R_NOTCONNECTED;
if (atomic_load(&sock->active) && sock->outerhandle != NULL) {
@@ -673,3 +677,204 @@ isc__nm_async_tcpdnsclose(isc__networker_t *worker, isc__netievent_t *ev0) {
tcpdns_close_direct(ievent->sock);
}
typedef struct {
isc_mem_t *mctx;
isc_nm_cb_t cb;
void *cbarg;
size_t extrahandlesize;
} tcpconnect_t;
static void
tcpdnsconnect_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
tcpconnect_t *conn = (tcpconnect_t *)arg;
isc_nm_cb_t cb = conn->cb;
void *cbarg = conn->cbarg;
size_t extrahandlesize = conn->extrahandlesize;
isc_nmsocket_t *dnssock = NULL;
REQUIRE(result != ISC_R_SUCCESS || VALID_NMHANDLE(handle));
isc_mem_putanddetach(&conn->mctx, conn, sizeof(*conn));
if (result != ISC_R_SUCCESS) {
cb(NULL, result, cbarg);
return;
}
dnssock = isc_mem_get(handle->sock->mgr->mctx, sizeof(*dnssock));
isc__nmsocket_init(dnssock, handle->sock->mgr, isc_nm_tcpdnssocket,
handle->sock->iface);
dnssock->extrahandlesize = extrahandlesize;
isc_nmhandle_attach(handle, &dnssock->outerhandle);
dnssock->peer = handle->sock->peer;
dnssock->read_timeout = handle->sock->mgr->init;
dnssock->tid = isc_nm_tid();
atomic_init(&dnssock->client, true);
dnssock->statichandle = isc__nmhandle_get(dnssock, NULL, NULL);
uv_timer_init(&dnssock->mgr->workers[isc_nm_tid()].loop,
&dnssock->timer);
dnssock->timer.data = dnssock;
dnssock->timer_initialized = true;
uv_timer_start(&dnssock->timer, dnstcp_readtimeout,
dnssock->read_timeout, 0);
/*
* The connection is now established; we start reading immediately,
* before we've been asked to. We'll read and buffer at most one
* packet.
*/
result = isc_nm_read(handle, dnslisten_readcb, dnssock);
cb(dnssock->statichandle, result, cbarg);
isc__nmsocket_detach(&dnssock);
}
isc_result_t
isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize) {
tcpconnect_t *conn = isc_mem_get(mgr->mctx, sizeof(tcpconnect_t));
*conn = (tcpconnect_t){ .cb = cb,
.cbarg = cbarg,
.extrahandlesize = extrahandlesize };
isc_mem_attach(mgr->mctx, &conn->mctx);
return (isc_nm_tcpconnect(mgr, local, peer, tcpdnsconnect_cb, conn,
timeout, 0));
}
isc_result_t
isc__nm_tcpdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
isc_nmsocket_t *sock = handle->sock;
isc__netievent_tcpdnsread_t *ievent = NULL;
isc_nmhandle_t *eventhandle = NULL;
REQUIRE(handle == sock->statichandle);
REQUIRE(sock->recv_cb == NULL);
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->client));
/*
* This MUST be done asynchronously, no matter which thread we're
* in. The callback function for isc_nm_read() often calls
* isc_nm_read() again; if we tried to do that synchronously
* we'd clash in processbuffer() and grow the stack indefinitely.
*/
ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpdnsread);
ievent->sock = sock;
sock->recv_cb = cb;
sock->recv_cbarg = cbarg;
/*
* Add a reference to the handle to keep it from being freed by
* the caller; it will be detached in in isc__nm_async_tcpdnsread().
*/
isc_nmhandle_attach(handle, &eventhandle);
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
return (ISC_R_SUCCESS);
}
void
isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0) {
isc_result_t result;
isc__netievent_tcpdnsread_t *ievent =
(isc__netievent_tcpdnsclose_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
isc_nmhandle_t *handle = NULL, *newhandle = NULL;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(worker->id == sock->tid);
REQUIRE(sock->tid == isc_nm_tid());
handle = sock->statichandle;
if (sock->type != isc_nm_tcpdnssocket || sock->outerhandle == NULL) {
if (sock->recv_cb != NULL) {
sock->recv_cb(handle, ISC_R_NOTCONNECTED, NULL,
sock->recv_cbarg);
}
isc_nmhandle_detach(&handle);
return;
}
/*
* Maybe we have a packet already?
*/
result = processbuffer(sock, &newhandle);
if (result == ISC_R_SUCCESS) {
atomic_store(&sock->outerhandle->sock->processing, true);
if (sock->timer_initialized) {
uv_timer_stop(&sock->timer);
}
isc_nmhandle_detach(&newhandle);
} else if (sock->outerhandle != NULL) {
/* Restart reading, wait for the callback */
atomic_store(&sock->outerhandle->sock->processing, false);
if (sock->timer_initialized) {
uv_timer_start(&sock->timer, dnstcp_readtimeout,
sock->read_timeout, 0);
}
isc_nm_resumeread(sock->outerhandle);
} else {
isc_nm_recv_cb_t cb = sock->recv_cb;
void *cbarg = sock->recv_cbarg;
isc__nmsocket_clearcb(sock);
cb(handle, ISC_R_NOTCONNECTED, NULL, cbarg);
}
isc_nmhandle_detach(&handle);
}
void
isc__nm_tcpdns_cancelread(isc_nmhandle_t *handle) {
isc_nmsocket_t *sock = NULL;
isc__netievent_tcpdnscancel_t *ievent = NULL;
REQUIRE(VALID_NMHANDLE(handle));
sock = handle->sock;
REQUIRE(sock->type == isc_nm_tcpdnssocket);
ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpdnscancel);
ievent->sock = sock;
isc_nmhandle_attach(handle, &ievent->handle);
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
void
isc__nm_async_tcpdnscancel(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_tcpdnscancel_t *ievent =
(isc__netievent_tcpdnscancel_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
isc_nmhandle_t *handle = ievent->handle;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(worker->id == sock->tid);
REQUIRE(sock->tid == isc_nm_tid());
if (atomic_load(&sock->client)) {
isc_nm_recv_cb_t cb;
void *cbarg = NULL;
cb = sock->recv_cb;
cbarg = sock->recv_cbarg;
isc__nmsocket_clearcb(sock);
if (cb != NULL) {
cb(handle, ISC_R_EOF, NULL, cbarg);
}
isc__nm_tcp_cancelread(sock->outerhandle);
}
isc_nmhandle_detach(&handle);
}
+388 -10
View File
@@ -15,6 +15,7 @@
#include <isc/atomic.h>
#include <isc/buffer.h>
#include <isc/condition.h>
#include <isc/errno.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
@@ -40,6 +41,9 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
static void
udp_send_cb(uv_udp_send_t *req, int status);
static void
udp_close_cb(uv_handle_t *uvhandle);
isc_result_t
isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
void *cbarg, size_t extrahandlesize, isc_nmsocket_t **sockp) {
@@ -375,16 +379,15 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
result = isc_sockaddr_fromsockaddr(&sockaddr, addr);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
nmhandle = isc__nmhandle_get(sock, &sockaddr, NULL);
if (!atomic_load(&sock->connected)) {
nmhandle = isc__nmhandle_get(sock, &sockaddr, NULL);
} else {
nmhandle = sock->statichandle;
}
region.base = (unsigned char *)buf->base;
region.length = nrecv;
/*
* In tcp.c and tcpdns.c, this would need to be locked
* by sock->lock because callbacks may be set to NULL
* unexpectedly when the connection drops, but that isn't
* a factor in the UDP case.
*/
INSIST(sock->tid == isc_nm_tid());
INSIST(sock->recv_cb != NULL);
cb = sock->recv_cb;
cbarg = sock->recv_cbarg;
@@ -508,7 +511,15 @@ isc__nm_async_udpsend(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(worker->id == ievent->sock->tid);
if (isc__nmsocket_active(ievent->sock)) {
udp_send_direct(ievent->sock, ievent->req, &ievent->peer);
isc_result_t result;
result = udp_send_direct(ievent->sock, ievent->req,
&ievent->peer);
if (result != ISC_R_SUCCESS) {
ievent->req->cb.send(ievent->req->handle, result,
ievent->req->cbarg);
isc__nm_uvreq_put(&ievent->req, ievent->req->sock);
}
} else {
ievent->req->cb.send(ievent->req->handle, ISC_R_CANCELED,
ievent->req->cbarg);
@@ -541,7 +552,7 @@ udp_send_cb(uv_udp_send_t *req, int status) {
static isc_result_t
udp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
isc_sockaddr_t *peer) {
const struct sockaddr *sa = NULL;
const struct sockaddr *sa = &peer->type.sa;
int rv;
REQUIRE(sock->tid == isc_nm_tid());
@@ -551,7 +562,17 @@ udp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
return (ISC_R_CANCELED);
}
sa = atomic_load(&sock->connected) ? NULL : &peer->type.sa;
#ifdef HAVE_UV_UDP_CONNECT
/*
* If we used uv_udp_connect() (and not the shim version for
* older versions of libuv), then the peer address has to be
* set to NULL or else uv_udp_send() could fail or assert,
* depending on the libuv version.
*/
if (atomic_load(&sock->connected)) {
sa = NULL;
}
#endif
rv = uv_udp_send(&req->uv_req.udp_send, &sock->uv_handle.udp,
&req->uvbuf, 1, sa, udp_send_cb);
if (rv < 0) {
@@ -562,3 +583,360 @@ udp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
return (ISC_R_SUCCESS);
}
/*
* Asynchronous 'udpconnect' call handler: open a new UDP socket and call
* the 'open' callback with a handle.
*/
void
isc__nm_async_udpconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_udpconnect_t *ievent =
(isc__netievent_udpconnect_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
isc_nmhandle_t *handle = NULL;
isc_nm_cb_t cb;
void *cbarg;
int uv_bind_flags = UV_UDP_REUSEADDR;
int r;
REQUIRE(sock->type == isc_nm_udpsocket);
REQUIRE(sock->iface != NULL);
REQUIRE(sock->parent == NULL);
REQUIRE(sock->tid == isc_nm_tid());
uv_udp_init(&worker->loop, &sock->uv_handle.udp);
uv_handle_set_data(&sock->uv_handle.handle, NULL);
uv_handle_set_data(&sock->uv_handle.handle, sock);
r = uv_udp_open(&sock->uv_handle.udp, sock->fd);
if (r != 0) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPENFAIL]);
atomic_store(&sock->closed, true);
atomic_store(&sock->connect_error, true);
atomic_store(&sock->result, isc__nm_uverr2result(r));
goto done;
}
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPEN]);
if (sock->iface->addr.type.sa.sa_family == AF_INET6) {
uv_bind_flags |= UV_UDP_IPV6ONLY;
}
r = uv_udp_bind(&sock->uv_handle.udp, &sock->iface->addr.type.sa,
uv_bind_flags);
if (r != 0) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]);
atomic_store(&sock->connect_error, true);
atomic_store(&sock->result, isc__nm_uverr2result(r));
goto done;
}
r = isc_uv_udp_connect(&sock->uv_handle.udp, &ievent->peer.type.sa);
if (r < 0) {
isc__nm_incstats(sock->mgr,
sock->statsindex[STATID_CONNECTFAIL]);
atomic_store(&sock->connect_error, true);
atomic_store(&sock->result, isc__nm_uverr2result(r));
goto done;
}
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECT]);
#ifdef ISC_RECV_BUFFER_SIZE
uv_recv_buffer_size(&sock->uv_handle.handle,
&(int){ ISC_RECV_BUFFER_SIZE });
#endif
#ifdef ISC_SEND_BUFFER_SIZE
uv_send_buffer_size(&sock->uv_handle.handle,
&(int){ ISC_SEND_BUFFER_SIZE });
#endif
atomic_store(&sock->connected, true);
atomic_store(&sock->result, ISC_R_SUCCESS);
cb = sock->connect_cb;
cbarg = sock->connect_cbarg;
handle = isc__nmhandle_get(sock, &ievent->peer, &sock->iface->addr);
cb(handle, atomic_load(&sock->result), cbarg);
LOCK(&sock->lock);
SIGNAL(&sock->cond);
UNLOCK(&sock->lock);
done:
isc__nmsocket_detach(&sock);
}
isc_result_t
isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize) {
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *sock = NULL, *tmp = NULL;
isc__netievent_udpconnect_t *event = NULL;
int r = 0;
REQUIRE(VALID_NM(mgr));
REQUIRE(local != NULL);
REQUIRE(peer != NULL);
sock = isc_mem_get(mgr->mctx, sizeof(isc_nmsocket_t));
isc__nmsocket_init(sock, mgr, isc_nm_udpsocket, local);
INSIST(sock->connect_cb == NULL && sock->connect_cbarg == NULL);
sock->connect_cb = cb;
sock->connect_cbarg = cbarg;
sock->read_timeout = timeout;
sock->extrahandlesize = extrahandlesize;
sock->peer = peer->addr;
atomic_init(&sock->client, true);
sock->fd = socket(peer->addr.type.sa.sa_family, SOCK_DGRAM, 0);
RUNTIME_CHECK(sock->fd >= 0);
/*
* Set up SO_REUSE* (see comments in isc_nm_listenudp() for
* details).
*/
#if defined(SO_REUSEADDR)
r = setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 },
sizeof(int));
RUNTIME_CHECK(r == 0);
#endif
#if defined(SO_REUSEPORT_LB)
r = setsockopt(sock->fd, SOL_SOCKET, SO_REUSEPORT_LB, &(int){ 1 },
sizeof(int));
RUNTIME_CHECK(r == 0);
#elif defined(SO_REUSEPORT)
r = setsockopt(sock->fd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 },
sizeof(int));
RUNTIME_CHECK(r == 0);
#endif
#ifdef SO_INCOMING_CPU
(void)setsockopt(sock->fd, SOL_SOCKET, SO_INCOMING_CPU, &(int){ 1 },
sizeof(int));
#endif
event = isc__nm_get_ievent(mgr, netievent_udpconnect);
event->sock = sock;
event->peer = *((isc_sockaddr_t *)peer);
/*
* Hold an additional sock reference so async callbacks
* can't destroy it until we're ready.
*/
isc__nmsocket_attach(sock, &tmp);
r = isc_random_uniform(mgr->nworkers);
if (r == isc_nm_tid()) {
isc__nm_async_udpconnect(&mgr->workers[r],
(isc__netievent_t *)event);
isc__nm_put_ievent(mgr, event);
} else {
isc__nm_enqueue_ievent(&mgr->workers[r],
(isc__netievent_t *)event);
LOCK(&sock->lock);
while (!atomic_load(&sock->connected) &&
!atomic_load(&sock->connect_error)) {
WAIT(&sock->cond, &sock->lock);
}
UNLOCK(&sock->lock);
}
result = atomic_load(&sock->result);
isc__nmsocket_detach(&tmp);
return (result);
}
static void
udp_read_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
const struct sockaddr *addr, unsigned flags) {
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)handle);
udp_recv_cb(handle, nrecv, buf, addr, flags);
uv_udp_recv_stop(&sock->uv_handle.udp);
}
static void
readtimeout_cb(uv_timer_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)handle);
isc_nm_recv_cb_t cb;
void *cbarg = NULL;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
/*
* Timeout; stop reading and process whatever we have.
*/
uv_udp_recv_stop(&sock->uv_handle.udp);
cb = sock->recv_cb;
cbarg = sock->recv_cbarg;
isc__nmsocket_clearcb(sock);
if (cb != NULL) {
cb(sock->statichandle, ISC_R_TIMEDOUT, NULL, cbarg);
}
}
/*
* Asynchronous 'udpread' call handler: start or resume reading on a socket;
* pause reading and call the 'recv' callback after each datagram.
*/
void
isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_udpread_t *ievent = (isc__netievent_udpread_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
REQUIRE(worker->id == isc_nm_tid());
if (sock->read_timeout != 0) {
if (!sock->timer_initialized) {
uv_timer_init(&worker->loop, &sock->timer);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
sock->timer_initialized = true;
}
uv_timer_start(&sock->timer, readtimeout_cb, sock->read_timeout,
0);
sock->timer_running = true;
}
uv_udp_recv_start(&sock->uv_handle.udp, udp_alloc_cb, udp_read_cb);
}
isc_result_t
isc__nm_udp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
isc_nmsocket_t *sock = NULL;
isc__netievent_startread_t *ievent = NULL;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(handle->sock->type == isc_nm_udpsocket);
sock = handle->sock;
REQUIRE(sock->tid == isc_nm_tid());
sock->recv_cb = cb;
sock->recv_cbarg = cbarg;
ievent = isc__nm_get_ievent(sock->mgr, netievent_udpread);
ievent->sock = sock;
if (sock->tid == isc_nm_tid()) {
isc__nm_async_udpread(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
isc__nm_put_ievent(sock->mgr, ievent);
} else {
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
return (ISC_R_SUCCESS);
}
static void
udp_close_cb(uv_handle_t *uvhandle) {
isc_nmsocket_t *sock = uv_handle_get_data(uvhandle);
REQUIRE(VALID_NMSOCK(sock));
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CLOSE]);
atomic_store(&sock->closed, true);
isc__nmsocket_prep_destroy(sock);
}
static void
timer_close_cb(uv_handle_t *uvhandle) {
isc_nmsocket_t *sock = uv_handle_get_data(uvhandle);
REQUIRE(VALID_NMSOCK(sock));
uv_close(&sock->uv_handle.handle, udp_close_cb);
}
void
isc__nm_async_udpclose(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_udpclose_t *ievent = (isc__netievent_udpclose_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
REQUIRE(worker->id == ievent->sock->tid);
if (sock->timer_initialized) {
sock->timer_initialized = false;
sock->timer_running = false;
uv_timer_stop(&sock->timer);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
} else {
uv_close(&sock->uv_handle.handle, udp_close_cb);
}
}
void
isc__nm_udp_close(isc_nmsocket_t *sock) {
isc__netievent_udpclose_t *ievent = NULL;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->type == isc_nm_udpsocket);
ievent = isc__nm_get_ievent(sock->mgr, netievent_udpclose);
ievent->sock = sock;
if (sock->tid == isc_nm_tid()) {
isc__nm_async_udpclose(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
isc__nm_put_ievent(sock->mgr, ievent);
} else {
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
}
void
isc__nm_udp_cancelread(isc_nmhandle_t *handle) {
isc_nmsocket_t *sock = NULL;
isc__netievent_udpcancel_t *ievent = NULL;
REQUIRE(VALID_NMHANDLE(handle));
sock = handle->sock;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->type == isc_nm_udpsocket);
ievent = isc__nm_get_ievent(sock->mgr, netievent_udpcancel);
ievent->sock = sock;
isc_nmhandle_attach(handle, &ievent->handle);
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
void
isc__nm_async_udpcancel(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_udpcancel_t *ievent = (isc__netievent_udpcancel_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
isc_nmhandle_t *handle = ievent->handle;
REQUIRE(worker->id == ievent->sock->tid);
uv_udp_recv_stop(&sock->uv_handle.udp);
if (atomic_load(&sock->client)) {
isc_nm_recv_cb_t cb;
void *cbarg = NULL;
cb = sock->recv_cb;
cbarg = sock->recv_cbarg;
isc__nmsocket_clearcb(sock);
if (cb != NULL) {
cb(handle, ISC_R_EOF, NULL, cbarg);
}
}
isc_nmhandle_detach(&handle);
}
+32
View File
@@ -187,3 +187,35 @@ isc_uv_import(uv_stream_t *stream, isc_uv_stream_info_t *info) {
#endif /* ifdef WIN32 */
#endif /* ifndef HAVE_UV_IMPORT */
#ifndef HAVE_UV_UDP_CONNECT
int
isc_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) {
int err = 0;
do {
int addrlen = (addr->sa_family == AF_INET)
? sizeof(struct sockaddr_in)
: sizeof(struct sockaddr_in6);
#ifdef WIN32
err = connect(handle->socket, addr, addrlen);
#else /* WIN32 */
err = connect(handle->io_watcher.fd, addr, addrlen);
#endif /* WIN32 */
} while (err == -1 && errno == EINTR);
if (err) {
#ifdef WIN32
return (uv_translate_sys_error(err));
#else /* WIN32 */
#ifdef HAVE_UV_TRANSLATE_SYS_ERROR
return (uv_translate_sys_error(errno));
#else
return (-errno);
#endif /* HAVE_UV_TRANSLATE_SYS_ERROR */
#endif /* WIN32 */
}
return (0);
}
#endif /* ifndef HAVE_UV_UDP_CONNECT */
+16
View File
@@ -79,3 +79,19 @@ isc_uv_import(uv_stream_t *stream, isc_uv_stream_info_t *info);
*/
#endif
#ifdef HAVE_UV_UDP_CONNECT
#define isc_uv_udp_connect uv_udp_connect
#else
int
isc_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr);
/*%<
* Associate the UDP handle to a remote address and port, so every message sent
* by this handle is automatically sent to that destination.
*
* NOTE: This is just a limited shim for uv_udp_connect() as it requires the
* handle to be bound.
*/
#endif
+2
View File
@@ -79,6 +79,8 @@ isc___nm_uverr2result(int uverr, bool dolog, const char *file,
return (ISC_R_ADDRNOTAVAIL);
case UV_ECONNREFUSED:
return (ISC_R_CONNREFUSED);
case UV_ECANCELED:
return (ISC_R_CANCELED);
default:
if (dolog) {
UNEXPECTED_ERROR(file, line,
+2
View File
@@ -461,11 +461,13 @@ isc_nm_setstats
isc_nm_start
isc_nm_stoplistening
isc_nm_tcpconnect
isc_nm_tcpdnsconnect
isc_nm_tcp_gettimeouts
isc_nm_tcp_settimeouts
isc_nm_tcpdns_keepalive
isc_nm_tcpdns_sequential
isc_nm_tid
isc_nm_udpconnect
isc_nmsocket_close
isc__nm_acquire_interlocked
isc__nm_drop_interlocked
+1 -1
View File
@@ -459,7 +459,7 @@ ns_test_setupzonemgr(void) {
isc_result_t result;
REQUIRE(zonemgr == NULL);
result = dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr,
result = dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr, NULL,
&zonemgr);
return (result);
}