Compare commits
52
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
600364259a | ||
|
|
128acf9fac | ||
|
|
7e334da824 | ||
|
|
d84533af69 | ||
|
|
0d9a516323 | ||
|
|
6cee82ba3a | ||
|
|
673c476037 | ||
|
|
c421039402 | ||
|
|
f89a9957b3 | ||
|
|
7627cdefe9 | ||
|
|
f9cc0b3639 | ||
|
|
b3c77ade26 | ||
|
|
f5b70924e3 | ||
|
|
670560a223 | ||
|
|
2899eb1e8c | ||
|
|
4dde1b4558 | ||
|
|
725d973ab9 | ||
|
|
06d6627457 | ||
|
|
0c41c19cbf | ||
|
|
bc3747f56b | ||
|
|
213376b8fa | ||
|
|
9784baad54 | ||
|
|
7c01178369 | ||
|
|
3b8e287994 | ||
|
|
dbe5d42ff3 | ||
|
|
469b7a5ecb | ||
|
|
ca3a5d1e52 | ||
|
|
2779c44e27 | ||
|
|
3a09529d78 | ||
|
|
de0c3c3019 | ||
|
|
f8ef33db6d | ||
|
|
f43af328b6 | ||
|
|
090161e1fc | ||
|
|
1d32b9799e | ||
|
|
d7b441a1d5 | ||
|
|
dc6811101a | ||
|
|
5c52feb442 | ||
|
|
7aa9bbb8ac | ||
|
|
4c8f28f087 | ||
|
|
1817dadf5d | ||
|
|
34b0bb84ca | ||
|
|
eea946e741 | ||
|
|
d0f3d3f421 | ||
|
|
9cefc63b4c | ||
|
|
1cea2ede55 | ||
|
|
5316b99628 | ||
|
|
77bedef71e | ||
|
|
db354895e7 | ||
|
|
03009e7159 | ||
|
|
c2adc2ac27 | ||
|
|
cac6b52672 | ||
|
|
9748d9f4d0 |
@@ -1,3 +1,7 @@
|
||||
5495. [func] Add a netmgr TLS layer, enabling server-side DoT
|
||||
support (not yet available), and client-side DoT
|
||||
support in dig with "dig +tls". [GL #1840]
|
||||
|
||||
5494. [bug] Silence the EPROTO syslog message on older systems.
|
||||
[GL #1928]
|
||||
|
||||
|
||||
@@ -367,3 +367,25 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
|
||||
+35
-16
@@ -68,6 +68,9 @@ struct controlkey {
|
||||
|
||||
struct controlconnection {
|
||||
isc_nmhandle_t *handle;
|
||||
isc_nmhandle_t *readhandle;
|
||||
isc_nmhandle_t *sendhandle;
|
||||
isc_nmhandle_t *cmdhandle;
|
||||
isccc_ccmsg_t ccmsg;
|
||||
bool ccmsg_valid;
|
||||
bool sending;
|
||||
@@ -221,10 +224,8 @@ control_senddone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
|
||||
conn->sending = false;
|
||||
|
||||
isc_nmhandle_unref(handle);
|
||||
|
||||
if (result == ISC_R_CANCELED) {
|
||||
return;
|
||||
goto cleanup;
|
||||
} else if (result != ISC_R_SUCCESS) {
|
||||
char socktext[ISC_SOCKADDR_FORMATSIZE];
|
||||
|
||||
@@ -233,16 +234,23 @@ control_senddone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING,
|
||||
"error sending command response to %s: %s",
|
||||
socktext, isc_result_totext(result));
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (conn->readhandle == NULL) {
|
||||
isc_nmhandle_attach(handle, &conn->readhandle);
|
||||
}
|
||||
result = isccc_ccmsg_readmessage(&conn->ccmsg, control_recvmessage,
|
||||
conn);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_nmhandle_detach(&conn->readhandle);
|
||||
maybe_free_listener(listener);
|
||||
}
|
||||
|
||||
listener->listening = true;
|
||||
|
||||
cleanup:
|
||||
isc_nmhandle_detach(&conn->sendhandle);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -324,11 +332,11 @@ control_respond(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
r.base = conn->buffer->base;
|
||||
r.length = conn->buffer->used;
|
||||
|
||||
isc_nmhandle_ref(handle);
|
||||
isc_nmhandle_attach(handle, &conn->sendhandle);
|
||||
conn->sending = true;
|
||||
result = isc_nm_send(handle, &r, control_senddone, conn);
|
||||
result = isc_nm_send(conn->sendhandle, &r, control_senddone, conn);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_nmhandle_detach(&conn->sendhandle);
|
||||
conn->sending = false;
|
||||
}
|
||||
|
||||
@@ -356,17 +364,12 @@ control_command(isc_task_t *task, isc_event_t *event) {
|
||||
|
||||
UNUSED(task);
|
||||
|
||||
/*
|
||||
* An extra ref and two unrefs are needed here to
|
||||
* ensure the handle isn't cleaned up if we're running
|
||||
* an "rndc stop" command.
|
||||
*/
|
||||
isc_nmhandle_ref(conn->handle);
|
||||
conn->result = named_control_docommand(conn->request,
|
||||
listener->readonly, &conn->text);
|
||||
control_respond(conn->handle, conn->result, conn);
|
||||
isc_nmhandle_unref(conn->handle);
|
||||
isc_nmhandle_unref(conn->handle);
|
||||
|
||||
isc_nmhandle_detach(&conn->cmdhandle);
|
||||
|
||||
isc_event_free(&event);
|
||||
}
|
||||
|
||||
@@ -399,6 +402,10 @@ control_recvmessage(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
log_invalid(&conn->ccmsg, result);
|
||||
}
|
||||
|
||||
if (conn->readhandle != NULL) {
|
||||
isc_nmhandle_detach(&conn->readhandle);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -424,6 +431,9 @@ control_recvmessage(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
REGION_SIZE(conn->secret));
|
||||
if (result != ISCCC_R_BADAUTH) {
|
||||
log_invalid(&conn->ccmsg, result);
|
||||
if (conn->readhandle != NULL) {
|
||||
isc_nmhandle_detach(&conn->readhandle);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -513,10 +523,11 @@ control_recvmessage(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
/*
|
||||
* Trigger the command.
|
||||
*/
|
||||
isc_nmhandle_ref(handle);
|
||||
isc_nmhandle_attach(handle, &conn->cmdhandle);
|
||||
event = isc_event_allocate(listener->mctx, conn, NAMED_EVENT_COMMAND,
|
||||
control_command, conn, sizeof(isc_event_t));
|
||||
isc_task_send(named_g_server->task, &event);
|
||||
isc_nmhandle_detach(&conn->readhandle);
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
@@ -534,6 +545,10 @@ cleanup:
|
||||
if (conn->text != NULL) {
|
||||
isc_buffer_free(&conn->text);
|
||||
}
|
||||
|
||||
if (conn->readhandle != NULL) {
|
||||
isc_nmhandle_detach(&conn->readhandle);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -604,9 +619,13 @@ newconnection(controllistener_t *listener, isc_nmhandle_t *handle) {
|
||||
|
||||
ISC_LINK_INIT(conn, link);
|
||||
|
||||
if (conn->readhandle == NULL) {
|
||||
isc_nmhandle_attach(handle, &conn->readhandle);
|
||||
}
|
||||
result = isccc_ccmsg_readmessage(&conn->ccmsg, control_recvmessage,
|
||||
conn);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_nmhandle_detach(&conn->readhandle);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -14856,14 +14856,15 @@ named_server_zonestatus(named_server_t *server, isc_lex_t *lex,
|
||||
|
||||
/* Serial number */
|
||||
result = dns_zone_getserial(mayberaw, &serial);
|
||||
/* XXXWPK TODO this is to mirror old behavior with dns_zone_getserial */
|
||||
|
||||
/* This is to mirror old behavior with dns_zone_getserial */
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
serial = 0;
|
||||
}
|
||||
|
||||
snprintf(serbuf, sizeof(serbuf), "%u", serial);
|
||||
if (hasraw) {
|
||||
result = dns_zone_getserial(zone, &signed_serial);
|
||||
/* XXXWPK TODO ut supra */
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
serial = 0;
|
||||
}
|
||||
|
||||
+22
-7
@@ -24,6 +24,7 @@
|
||||
#include <isc/log.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/net.h>
|
||||
#include <isc/netmgr.h>
|
||||
#include <isc/print.h>
|
||||
#include <isc/random.h>
|
||||
#include <isc/refcount.h>
|
||||
@@ -89,6 +90,7 @@ static uint32_t serial;
|
||||
static bool quiet = false;
|
||||
static bool showresult = false;
|
||||
static bool shuttingdown = false;
|
||||
isc_nmhandle_t *readhandle = NULL, *sendhandle = NULL;
|
||||
|
||||
static void
|
||||
rndc_startconnect(isc_sockaddr_t *addr);
|
||||
@@ -288,19 +290,21 @@ get_addresses(const char *host, in_port_t port) {
|
||||
|
||||
static void
|
||||
rndc_senddone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
REQUIRE(handle == sendhandle);
|
||||
|
||||
UNUSED(arg);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fatal("send failed: %s", isc_result_totext(result));
|
||||
}
|
||||
|
||||
isc_nmhandle_detach(&sendhandle);
|
||||
if (atomic_fetch_sub_release(&sends, 1) == 1 &&
|
||||
atomic_load_acquire(&recvs) == 0)
|
||||
{
|
||||
shuttingdown = true;
|
||||
isc_task_shutdown(rndc_task);
|
||||
isc_app_shutdown();
|
||||
isc_nmhandle_unref(handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,7 +322,10 @@ rndc_recvdone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
atomic_fetch_sub_release(&recvs, 1);
|
||||
|
||||
if (shuttingdown && (result == ISC_R_EOF || result == ISC_R_CANCELED)) {
|
||||
isc_nmhandle_unref(handle);
|
||||
if (readhandle != NULL) {
|
||||
INSIST(handle == readhandle);
|
||||
isc_nmhandle_detach(&readhandle);
|
||||
}
|
||||
return;
|
||||
} else if (result == ISC_R_EOF) {
|
||||
fatal("connection to remote host closed.\n"
|
||||
@@ -378,8 +385,8 @@ rndc_recvdone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
|
||||
if (atomic_load_acquire(&sends) == 0 &&
|
||||
atomic_load_acquire(&recvs) == 0) {
|
||||
isc_nmhandle_detach(&readhandle);
|
||||
shuttingdown = true;
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_task_shutdown(rndc_task);
|
||||
isc_app_shutdown();
|
||||
}
|
||||
@@ -398,12 +405,13 @@ rndc_recvnonce(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
isccc_sexpr_t *data;
|
||||
isc_buffer_t b;
|
||||
|
||||
REQUIRE(handle == readhandle);
|
||||
REQUIRE(ccmsg != NULL);
|
||||
|
||||
atomic_fetch_sub_release(&recvs, 1);
|
||||
|
||||
if (shuttingdown && result == ISC_R_EOF) {
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_nmhandle_detach(&readhandle);
|
||||
return;
|
||||
} else if (result == ISC_R_EOF) {
|
||||
fatal("connection to remote host closed.\n"
|
||||
@@ -471,6 +479,9 @@ rndc_recvnonce(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
isccc_ccmsg_readmessage(ccmsg, rndc_recvdone, ccmsg));
|
||||
atomic_fetch_add_relaxed(&recvs, 1);
|
||||
|
||||
if (sendhandle == NULL) {
|
||||
isc_nmhandle_attach(handle, &sendhandle);
|
||||
}
|
||||
DO("send message", isc_nm_send(handle, &r, rndc_senddone, NULL));
|
||||
atomic_fetch_add_relaxed(&sends, 1);
|
||||
|
||||
@@ -534,12 +545,16 @@ rndc_connected(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
isccc_ccmsg_init(rndc_mctx, handle, ccmsg);
|
||||
isccc_ccmsg_setmaxsize(ccmsg, 1024 * 1024);
|
||||
|
||||
isc_nmhandle_ref(handle);
|
||||
|
||||
if (readhandle == NULL) {
|
||||
isc_nmhandle_attach(handle, &readhandle);
|
||||
}
|
||||
DO("schedule recv",
|
||||
isccc_ccmsg_readmessage(ccmsg, rndc_recvnonce, ccmsg));
|
||||
atomic_fetch_add_relaxed(&recvs, 1);
|
||||
|
||||
if (sendhandle == NULL) {
|
||||
isc_nmhandle_attach(handle, &sendhandle);
|
||||
}
|
||||
DO("send message", isc_nm_send(handle, &r, rndc_senddone, NULL));
|
||||
atomic_fetch_add_relaxed(&sends, 1);
|
||||
|
||||
@@ -1009,7 +1024,7 @@ main(int argc, char **argv) {
|
||||
isc_mem_create(&rndc_mctx);
|
||||
netmgr = isc_nm_start(rndc_mctx, 1);
|
||||
DO("create task manager",
|
||||
isc_taskmgr_create(rndc_mctx, 1, 0, NULL, &taskmgr));
|
||||
isc_taskmgr_create(rndc_mctx, 1, 0, netmgr, &taskmgr));
|
||||
DO("create task", isc_task_create(taskmgr, 0, &rndc_task));
|
||||
isc_log_create(rndc_mctx, &log, &logconfig);
|
||||
isc_log_setcontext(log);
|
||||
|
||||
@@ -103,15 +103,20 @@ status=`expr $status + $ret`
|
||||
n=`expr $n + 1`
|
||||
echo_i "checking drop edns server setup ($n)"
|
||||
ret=0
|
||||
echo x
|
||||
$DIG $DIGOPTS +edns @10.53.0.2 dropedns soa > dig.out.1.test$n && ret=1
|
||||
echo x
|
||||
grep "connection timed out; no servers could be reached" dig.out.1.test$n > /dev/null || ret=1
|
||||
$DIG $DIGOPTS +noedns @10.53.0.2 dropedns soa > dig.out.2.test$n || ret=1
|
||||
echo x
|
||||
grep "status: NOERROR" dig.out.2.test$n > /dev/null || ret=1
|
||||
grep "EDNS: version:" dig.out.2.test$n > /dev/null && ret=1
|
||||
$DIG $DIGOPTS +noedns +tcp @10.53.0.2 dropedns soa > dig.out.3.test$n || ret=1
|
||||
echo x
|
||||
grep "status: NOERROR" dig.out.3.test$n > /dev/null || ret=1
|
||||
grep "EDNS: version:" dig.out.3.test$n > /dev/null && ret=1
|
||||
$DIG $DIGOPTS +edns +tcp @10.53.0.2 dropedns soa > dig.out.4.test$n && ret=1
|
||||
echo x
|
||||
grep "connection timed out; no servers could be reached" dig.out.4.test$n > /dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
|
||||
@@ -26,12 +26,10 @@ $DIFF ref output > /dev/null && { ret=1 ; echo_i "diff out of order failed"; }
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
|
||||
# flush resolver so queries will be from others again
|
||||
$RNDCCMD 10.53.0.4 flush
|
||||
sleep 1
|
||||
|
||||
echo_i "check pipelined TCP queries using mdig"
|
||||
ret=0
|
||||
$RNDCCMD 10.53.0.4 flush
|
||||
sleep 1
|
||||
$MDIG $MDIGOPTS +noall +answer +vc -f input -b 10.53.0.4 @10.53.0.4 > raw.mdig
|
||||
awk '{ print $1 " " $5 }' < raw.mdig > output.mdig
|
||||
sort < output.mdig > output-sorted.mdig
|
||||
@@ -42,6 +40,8 @@ status=`expr $status + $ret`
|
||||
|
||||
echo_i "check keep-response-order"
|
||||
ret=0
|
||||
$RNDCCMD 10.53.0.4 flush
|
||||
sleep 1
|
||||
$PIPEQUERIES -p ${PORT} ++ < inputb > rawb || ret=1
|
||||
awk '{ print $1 " " $5 }' < rawb > outputb
|
||||
$DIFF refb outputb || ret=1
|
||||
@@ -50,6 +50,8 @@ status=`expr $status + $ret`
|
||||
|
||||
echo_i "check keep-response-order using mdig"
|
||||
ret=0
|
||||
$RNDCCMD 10.53.0.4 flush
|
||||
sleep 1
|
||||
$MDIG $MDIGOPTS +noall +answer +vc -f inputb -b 10.53.0.7 @10.53.0.4 > rawb.mdig
|
||||
awk '{ print $1 " " $5 }' < rawb.mdig > outputb.mdig
|
||||
$DIFF refb outputb.mdig || ret=1
|
||||
@@ -58,6 +60,8 @@ status=`expr $status + $ret`
|
||||
|
||||
echo_i "check mdig -4 -6"
|
||||
ret=0
|
||||
$RNDCCMD 10.53.0.4 flush
|
||||
sleep 1
|
||||
$MDIG $MDIGOPTS -4 -6 -f input @10.53.0.4 > output46.mdig 2>&1 && ret=1
|
||||
grep "only one of -4 and -6 allowed" output46.mdig > /dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
|
||||
@@ -15,6 +15,7 @@ options {
|
||||
listen-on { 10.53.0.4; };
|
||||
listen-on-v6 { none; };
|
||||
recursion yes;
|
||||
dnssec-validation yes;
|
||||
};
|
||||
|
||||
view normal {
|
||||
|
||||
@@ -8,11 +8,10 @@
|
||||
# information regarding copyright ownership.
|
||||
|
||||
rm -f ns*/*.jnl
|
||||
rm -f ns*/named.conf
|
||||
rm -f ns*/named.lock
|
||||
rm -f ns*/named.memstats
|
||||
rm -f ns*/named.run
|
||||
rm -f ns*/rpz*.txt
|
||||
rm -f resolver/named.conf
|
||||
rm -f */named.conf
|
||||
rm -f */named.run
|
||||
rm -rf __pycache__
|
||||
rm -f *.status
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
logging {
|
||||
channel basic {
|
||||
file "named.run";
|
||||
severity debug 999;
|
||||
print-time yes;
|
||||
};
|
||||
category default { basic; };
|
||||
};
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm hmac-sha256;
|
||||
|
||||
+11
-2
@@ -131,7 +131,7 @@ AC_CONFIG_FILES([libltdl/Makefile])
|
||||
#
|
||||
# Set the default CFLAGS and CPPFLAGS
|
||||
#
|
||||
STD_CFLAGS="-Wall -Wextra -Wwrite-strings -Wcast-qual -Wpointer-arith -Wno-missing-field-initializers -Wformat -Wshadow"
|
||||
STD_CFLAGS="-Wall -Wextra -Wwrite-strings -Wpointer-arith -Wno-missing-field-initializers -Wformat -Wshadow"
|
||||
|
||||
# These should be always errors
|
||||
STD_CFLAGS="$STD_CFLAGS -Werror=implicit-function-declaration -Werror=missing-prototypes -Werror=format-security -Werror=parentheses -Werror=implicit -Werror=strict-prototypes"
|
||||
@@ -563,6 +563,15 @@ LIBS="$LIBS $LIBUV_LIBS"
|
||||
AC_CHECK_FUNCS([uv_handle_get_data uv_handle_set_data uv_import])
|
||||
AX_RESTORE_FLAGS([libuv])
|
||||
|
||||
# libnghttp2
|
||||
AC_MSG_CHECKING([for libnghttp2])
|
||||
PKG_CHECK_MODULES([LIBNGHTTP2], [libnghttp2 >= 1.40.0], [],
|
||||
[AC_MSG_ERROR([libnghttp2 not found])])
|
||||
AX_SAVE_FLAGS([libnghttp2])
|
||||
|
||||
CFLAGS="$CFLAGS $LIBNGHTTP2_CFLAGS"
|
||||
LIBS="$LIBS $LIBNGHTTP2_LIBS"
|
||||
|
||||
#
|
||||
# flockfile is usually provided by pthreads
|
||||
#
|
||||
@@ -592,7 +601,7 @@ CRYPTO=OpenSSL
|
||||
#
|
||||
# OpenSSL/LibreSSL is mandatory
|
||||
#
|
||||
PKG_CHECK_MODULES([OPENSSL], [libcrypto], [],
|
||||
PKG_CHECK_MODULES([OPENSSL], [libssl libcrypto], [],
|
||||
[AX_CHECK_OPENSSL([:],[AC_MSG_FAILURE([OpenSSL/LibreSSL not found])])])
|
||||
|
||||
AX_SAVE_FLAGS([openssl])
|
||||
|
||||
@@ -123,10 +123,12 @@ libisc_la_SOURCES = \
|
||||
$(libisc_la_HEADERS) \
|
||||
$(pk11_HEADERS) \
|
||||
$(pkcs11_HEADERS) \
|
||||
netmgr/http.c \
|
||||
netmgr/netmgr-int.h \
|
||||
netmgr/netmgr.c \
|
||||
netmgr/tcp.c \
|
||||
netmgr/tcpdns.c \
|
||||
netmgr/tls.c \
|
||||
netmgr/udp.c \
|
||||
netmgr/uv-compat.c \
|
||||
netmgr/uv-compat.h \
|
||||
@@ -147,6 +149,7 @@ libisc_la_SOURCES = \
|
||||
unix/stdtime.c \
|
||||
unix/syslog.c \
|
||||
unix/time.c \
|
||||
url.c \
|
||||
pk11.c \
|
||||
pk11_result.c \
|
||||
aes.c \
|
||||
|
||||
+13
-9
@@ -75,7 +75,10 @@ struct isc_httpd {
|
||||
isc_httpdmgr_t *mgr; /*%< our parent */
|
||||
ISC_LINK(isc_httpd_t) link;
|
||||
|
||||
isc_nmhandle_t *handle;
|
||||
isc_nmhandle_t *handle; /* Permanent pointer to handle */
|
||||
isc_nmhandle_t *readhandle; /* Waiting for a read callback */
|
||||
isc_nmhandle_t *sendhandle; /* Waiting for a send callback */
|
||||
|
||||
state_t state;
|
||||
int flags;
|
||||
|
||||
@@ -636,6 +639,7 @@ new_httpd(isc_httpdmgr_t *httpdmgr, isc_nmhandle_t *handle) {
|
||||
|
||||
if (httpd->handle == NULL) {
|
||||
isc_nmhandle_setdata(handle, httpd, httpd_reset, httpd_put);
|
||||
httpd->handle = handle;
|
||||
} else {
|
||||
INSIST(httpd->handle == handle);
|
||||
}
|
||||
@@ -663,10 +667,10 @@ new_httpd(isc_httpdmgr_t *httpdmgr, isc_nmhandle_t *handle) {
|
||||
ISC_LIST_APPEND(httpdmgr->running, httpd, link);
|
||||
UNLOCK(&httpdmgr->lock);
|
||||
|
||||
isc_nmhandle_ref(handle);
|
||||
isc_nmhandle_attach(handle, &httpd->readhandle);
|
||||
result = isc_nm_read(handle, httpd_request, httpdmgr);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_nmhandle_detach(&httpd->readhandle);
|
||||
}
|
||||
|
||||
return (result);
|
||||
@@ -958,18 +962,18 @@ httpd_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
isc_nm_pauseread(handle);
|
||||
httpd->state = SEND;
|
||||
|
||||
isc_nmhandle_ref(handle);
|
||||
isc_nmhandle_attach(handle, &httpd->sendhandle);
|
||||
result = isc_nm_send(handle, &r, httpd_senddone, httpd);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_nm_resumeread(handle);
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_nmhandle_detach(&httpd->sendhandle);
|
||||
|
||||
httpd->state = RECV;
|
||||
}
|
||||
|
||||
return;
|
||||
done:
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_nmhandle_detach(&httpd->readhandle);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -990,7 +994,7 @@ isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp) {
|
||||
|
||||
httpd = ISC_LIST_HEAD(httpdmgr->running);
|
||||
while (httpd != NULL) {
|
||||
isc_nmhandle_unref(httpd->handle);
|
||||
isc_nmhandle_detach(&httpd->readhandle);
|
||||
httpd = ISC_LIST_NEXT(httpd, link);
|
||||
}
|
||||
UNLOCK(&httpdmgr->lock);
|
||||
@@ -1139,7 +1143,7 @@ httpd_senddone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
|
||||
httpd->state = RECV;
|
||||
isc_nm_resumeread(handle);
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_nmhandle_detach(&httpd->sendhandle);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
@@ -1176,7 +1180,7 @@ void
|
||||
isc_httpd_setfinishhook(void (*fn)(void)) {
|
||||
#if ENABLE_AFL
|
||||
finishhook = fn;
|
||||
#else /* ENABLE_AFL */
|
||||
#else /* ENABLE_AFL */
|
||||
UNUSED(fn);
|
||||
#endif /* ENABLE_AFL */
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include <isc/result.h>
|
||||
#include <isc/types.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
/*
|
||||
* Replacement for isc_sockettype_t provided by socket.h.
|
||||
*/
|
||||
@@ -110,9 +112,9 @@ isc_nmsocket_close(isc_nmsocket_t **sockp);
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nmhandle_ref(isc_nmhandle_t *handle);
|
||||
isc_nmhandle_attach(isc_nmhandle_t *handle, isc_nmhandle_t **dest);
|
||||
void
|
||||
isc_nmhandle_unref(isc_nmhandle_t *handle);
|
||||
isc_nmhandle_detach(isc_nmhandle_t **handlep);
|
||||
/*%<
|
||||
* Increment/decrement the reference counter in a netmgr handle,
|
||||
* but (unlike the attach/detach functions) do not change the pointer
|
||||
@@ -176,8 +178,21 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
|
||||
* as its argument.
|
||||
*
|
||||
* When handles are allocated for the socket, 'extrasize' additional bytes
|
||||
* will be allocated along with the handle for an associated object
|
||||
* (typically ns_client).
|
||||
* can be allocated along with the handle for an associated object, which
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
void
|
||||
@@ -196,12 +211,17 @@ isc_nm_pause(isc_nm_t *mgr);
|
||||
void
|
||||
isc_nm_resume(isc_nm_t *mgr);
|
||||
/*%<
|
||||
* Resume paused processing. It will return immediately
|
||||
* after signalling workers to resume.
|
||||
* Resume paused processing. It will return immediately after signalling
|
||||
* workers to resume.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
|
||||
/*
|
||||
* Begin (or continue) reading on the socket associated with 'handle', and
|
||||
* update its recv callback to 'cb', which will be called as soon as there
|
||||
* is data to process.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_nm_pauseread(isc_nmhandle_t *handle);
|
||||
@@ -212,11 +232,12 @@ isc_nm_pauseread(isc_nmhandle_t *handle);
|
||||
* \li 'handle' is a valid netmgr handle.
|
||||
*/
|
||||
|
||||
void
|
||||
bool
|
||||
isc_nm_cancelread(isc_nmhandle_t *handle);
|
||||
/*%<
|
||||
* Cancel reading on a connected socket. Calls the read/recv callback on
|
||||
* active handles with a result code of ISC_R_CANCELED.
|
||||
* active handles with a result code of ISC_R_CANCELED. Returns true if
|
||||
* the callback was called
|
||||
*
|
||||
* Requires:
|
||||
* \li 'sock' is a valid netmgr socket
|
||||
@@ -289,7 +310,8 @@ isc_result_t
|
||||
isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
|
||||
void *cbarg, isc_nm_accept_cb_t accept_cb,
|
||||
void *accept_cbarg, size_t extrahandlesize, int backlog,
|
||||
isc_quota_t *quota, isc_nmsocket_t **sockp);
|
||||
isc_quota_t *quota, SSL_CTX *sslctx,
|
||||
isc_nmsocket_t **sockp);
|
||||
/*%<
|
||||
* Start listening for DNS messages over the TCP interface 'iface', using
|
||||
* net manager 'mgr'.
|
||||
@@ -367,6 +389,17 @@ isc_nm_tcp_gettimeouts(isc_nm_t *mgr, uint32_t *initial, uint32_t *idle,
|
||||
* \li 'mgr' is a valid netmgr.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface,
|
||||
isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
|
||||
size_t extrahandlesize, int backlog, isc_quota_t *quota,
|
||||
SSL_CTX *sslctx, isc_nmsocket_t **sockp);
|
||||
|
||||
isc_result_t
|
||||
isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
|
||||
isc_nm_cb_t cb, void *cbarg, SSL_CTX *ctx,
|
||||
size_t extrahandlesize);
|
||||
|
||||
void
|
||||
isc_nm_maxudp(isc_nm_t *mgr, uint32_t maxudp);
|
||||
/*%<
|
||||
@@ -385,3 +418,24 @@ 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, size_t extrahandlesize);
|
||||
|
||||
isc_result_t
|
||||
isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
|
||||
isc_nm_cb_t cb, void *cbarg, size_t extrahandlesize);
|
||||
/*%<
|
||||
* Establish a DNS client connection over either a TCP or a TLS socket.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
|
||||
isc_nm_doh_request(isc_nm_t *mgr, const char *uri, isc_region_t *message,
|
||||
isc_nm_recv_cb_t cb, void *cbarg, SSL_CTX *ctx);
|
||||
/*%<
|
||||
* Perform a DoH request on the uri provided. message is the DNS message
|
||||
* that will be POSTed to URI, cb is called with a NULL handle,
|
||||
* ctx can be NULL (it will be created).
|
||||
*/
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
#define ISC_R_DISCFULL 67 /*%< disc full */
|
||||
#define ISC_R_DEFAULT 68 /*%< default */
|
||||
#define ISC_R_IPV4PREFIX 69 /*%< IPv4 prefix */
|
||||
#define ISC_R_TLSERROR 70 /*%< TLS error */
|
||||
|
||||
/*% Not a result code: the number of results. */
|
||||
#define ISC_R_NRESULTS 70
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
|
||||
* faster
|
||||
*/
|
||||
#ifndef HTTP_PARSER_STRICT
|
||||
#define HTTP_PARSER_STRICT 1
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ISC_UF_SCHEMA = 0,
|
||||
ISC_UF_HOST = 1,
|
||||
ISC_UF_PORT = 2,
|
||||
ISC_UF_PATH = 3,
|
||||
ISC_UF_QUERY = 4,
|
||||
ISC_UF_FRAGMENT = 5,
|
||||
ISC_UF_USERINFO = 6,
|
||||
ISC_UF_MAX = 7
|
||||
} isc_url_field_t;
|
||||
|
||||
/* Result structure for isc_url_parse().
|
||||
*
|
||||
* Callers should index into field_data[] with UF_* values iff field_set
|
||||
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
|
||||
* because we probably have padding left over), we convert any port to
|
||||
* a uint16_t.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
|
||||
uint16_t port; /* Converted UF_PORT string */
|
||||
|
||||
struct {
|
||||
uint16_t off; /* Offset into buffer in which field starts */
|
||||
uint16_t len; /* Length of run in buffer */
|
||||
} field_data[ISC_UF_MAX];
|
||||
} isc_url_parser_t;
|
||||
|
||||
int
|
||||
isc_url_parse(const char *buf, size_t buflen, bool is_connect,
|
||||
isc_url_parser_t *up);
|
||||
/*%<
|
||||
* Parse a URL; return nonzero on failure
|
||||
*/
|
||||
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <isc/base64.h>
|
||||
#include <isc/netmgr.h>
|
||||
#include <isc/url.h>
|
||||
|
||||
#include "netmgr-int.h"
|
||||
|
||||
#define AUTHEXTRA 7
|
||||
|
||||
typedef struct {
|
||||
char *uri;
|
||||
isc_url_parser_t up;
|
||||
|
||||
char *authority;
|
||||
size_t authoritylen;
|
||||
char *path;
|
||||
|
||||
size_t pathlen;
|
||||
int32_t stream_id;
|
||||
isc_region_t *postdata;
|
||||
size_t postdata_pos;
|
||||
} http2_stream_t;
|
||||
|
||||
typedef struct {
|
||||
isc_mem_t *mctx;
|
||||
nghttp2_session *ngsession;
|
||||
http2_stream_t *stream;
|
||||
isc_nmhandle_t *handle;
|
||||
|
||||
isc_region_t r;
|
||||
|
||||
uint8_t buf[65535];
|
||||
size_t bufsize;
|
||||
uint8_t rbuf[65535];
|
||||
size_t rbufsize;
|
||||
|
||||
isc_nm_recv_cb_t cb;
|
||||
void *cbarg;
|
||||
|
||||
SSL_CTX *ctx;
|
||||
bool reading;
|
||||
} http2_session_t;
|
||||
|
||||
static bool
|
||||
http2_do_bio(http2_session_t *session);
|
||||
|
||||
static void
|
||||
writecb(isc_nmhandle_t *handle, isc_result_t result, void *ptr);
|
||||
|
||||
static isc_result_t
|
||||
get_http2_stream(isc_mem_t *mctx, http2_stream_t **streamp, const char *uri,
|
||||
uint16_t *port) {
|
||||
http2_stream_t *stream = NULL;
|
||||
int rv;
|
||||
|
||||
REQUIRE(streamp != NULL && *streamp == NULL);
|
||||
REQUIRE(uri != NULL);
|
||||
REQUIRE(port != NULL);
|
||||
|
||||
stream = isc_mem_get(mctx, sizeof(http2_stream_t));
|
||||
stream->uri = isc_mem_strdup(mctx, uri);
|
||||
rv = isc_url_parse(stream->uri, strlen(stream->uri), 0, &stream->up);
|
||||
if (rv != 0) {
|
||||
isc_mem_put(mctx, stream, sizeof(http2_stream_t));
|
||||
isc_mem_free(mctx, stream->uri);
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
stream->stream_id = -1;
|
||||
|
||||
stream->authoritylen = stream->up.field_data[ISC_UF_HOST].len;
|
||||
stream->authority = isc_mem_get(mctx, stream->authoritylen + AUTHEXTRA);
|
||||
memcpy(stream->authority, &uri[stream->up.field_data[ISC_UF_HOST].off],
|
||||
stream->up.field_data[ISC_UF_HOST].len);
|
||||
if (stream->up.field_set & (1 << ISC_UF_PORT)) {
|
||||
stream->authoritylen += (size_t)snprintf(
|
||||
stream->authority +
|
||||
stream->up.field_data[ISC_UF_HOST].len,
|
||||
AUTHEXTRA, ":%u", stream->up.port);
|
||||
}
|
||||
|
||||
/* If we don't have path in URI, we use "/" as path. */
|
||||
stream->pathlen = 1;
|
||||
if (stream->up.field_set & (1 << ISC_UF_PATH)) {
|
||||
stream->pathlen = stream->up.field_data[ISC_UF_PATH].len;
|
||||
}
|
||||
if (stream->up.field_set & (1 << ISC_UF_QUERY)) {
|
||||
/* +1 for '?' character */
|
||||
stream->pathlen +=
|
||||
(size_t)(stream->up.field_data[ISC_UF_QUERY].len + 1);
|
||||
}
|
||||
|
||||
stream->path = isc_mem_get(mctx, stream->pathlen);
|
||||
if (stream->up.field_set & (1 << ISC_UF_PATH)) {
|
||||
memcpy(stream->path,
|
||||
&uri[stream->up.field_data[ISC_UF_PATH].off],
|
||||
stream->up.field_data[ISC_UF_PATH].len);
|
||||
} else {
|
||||
stream->path[0] = '/';
|
||||
}
|
||||
|
||||
if (stream->up.field_set & (1 << ISC_UF_QUERY)) {
|
||||
stream->path[stream->pathlen -
|
||||
stream->up.field_data[ISC_UF_QUERY].len - 1] = '?';
|
||||
memcpy(stream->path + stream->pathlen -
|
||||
stream->up.field_data[ISC_UF_QUERY].len,
|
||||
&uri[stream->up.field_data[ISC_UF_QUERY].off],
|
||||
stream->up.field_data[ISC_UF_QUERY].len);
|
||||
}
|
||||
|
||||
*port = 443;
|
||||
if ((stream->up.field_set & (1 << ISC_UF_PORT)) != 0) {
|
||||
*port = stream->up.port;
|
||||
}
|
||||
|
||||
*streamp = stream;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
put_http2_stream(isc_mem_t *mctx, http2_stream_t *stream) {
|
||||
isc_mem_put(mctx, stream->path, stream->pathlen);
|
||||
isc_mem_put(mctx, stream->authority, stream->authoritylen + AUTHEXTRA);
|
||||
isc_mem_put(mctx, stream, sizeof(http2_stream_t));
|
||||
}
|
||||
|
||||
static void
|
||||
delete_http2_session(http2_session_t *session) {
|
||||
if (session->handle != NULL) {
|
||||
isc_nmhandle_detach(&session->handle);
|
||||
}
|
||||
if (session->ngsession != NULL) {
|
||||
nghttp2_session_del(session->ngsession);
|
||||
session->ngsession = NULL;
|
||||
}
|
||||
if (session->stream != NULL) {
|
||||
put_http2_stream(session->mctx, session->stream);
|
||||
session->stream = NULL;
|
||||
}
|
||||
|
||||
isc_mem_putanddetach(&session->mctx, session, sizeof(http2_session_t));
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* XXXWPK do we need these callback? We might want to verify headers */
|
||||
on_header_callback(nghttp2_session *ngsession, const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen, const uint8_t *value,
|
||||
size_t valuelen, uint8_t flags, void *user_data) {
|
||||
http2_session_t *session = (http2_session_t *)user_data;
|
||||
|
||||
UNUSED(ngsession);
|
||||
UNUSED(flags);
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session->stream->stream_id == frame->hd.stream_id)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
on_begin_headers_callback(nghttp2_session *ngsession,
|
||||
const nghttp2_frame *frame, void *user_data) {
|
||||
http2_session_t *session = (http2_session_t *)user_data;
|
||||
|
||||
UNUSED(ngsession);
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session->stream->stream_id == frame->hd.stream_id)
|
||||
{
|
||||
/* XXX */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
on_frame_recv_callback(nghttp2_session *ngsession, const nghttp2_frame *frame,
|
||||
void *user_data) {
|
||||
http2_session_t *session = (http2_session_t *)user_data;
|
||||
|
||||
UNUSED(ngsession);
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session->stream->stream_id == frame->hd.stream_id)
|
||||
{
|
||||
/* XXX */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
on_data_chunk_recv_callback(nghttp2_session *ngsession, uint8_t flags,
|
||||
int32_t stream_id, const uint8_t *data, size_t len,
|
||||
void *user_data) {
|
||||
http2_session_t *session = (http2_session_t *)user_data;
|
||||
|
||||
UNUSED(ngsession);
|
||||
UNUSED(flags);
|
||||
|
||||
if (session->stream->stream_id == stream_id) {
|
||||
/* TODO buffer overrun! */
|
||||
memmove(session->rbuf + session->rbufsize, data, len);
|
||||
session->rbufsize += len;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
on_stream_close_callback(nghttp2_session *ngsession, int32_t stream_id,
|
||||
uint32_t error_code, void *user_data) {
|
||||
http2_session_t *session = NULL;
|
||||
|
||||
UNUSED(error_code);
|
||||
|
||||
session = (http2_session_t *)user_data;
|
||||
if (session->stream->stream_id == stream_id) {
|
||||
int rv = nghttp2_session_terminate_session(ngsession,
|
||||
NGHTTP2_NO_ERROR);
|
||||
if (rv != 0) {
|
||||
return (NGHTTP2_ERR_CALLBACK_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
session->cb(NULL, ISC_R_SUCCESS,
|
||||
&(isc_region_t){ session->rbuf, session->rbufsize },
|
||||
session->cbarg);
|
||||
/* XXXWPK TODO we need to close the session */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
/*
|
||||
* NPN TLS extension client callback. We check that server advertised
|
||||
* the HTTP/2 protocol the nghttp2 library supports. If not, exit the
|
||||
* program.
|
||||
*/
|
||||
static int
|
||||
select_next_proto_cb(SSL *ssl, unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen, void *arg) {
|
||||
UNUSED(ssl);
|
||||
UNUSED(arg);
|
||||
|
||||
if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
|
||||
/* TODO */
|
||||
}
|
||||
return (SSL_TLSEXT_ERR_OK);
|
||||
}
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
/* Create SSL_CTX. */
|
||||
static SSL_CTX *
|
||||
create_ssl_ctx(void) {
|
||||
SSL_CTX *ssl_ctx = NULL;
|
||||
|
||||
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
RUNTIME_CHECK(ssl_ctx != NULL);
|
||||
|
||||
SSL_CTX_set_options(
|
||||
ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
|
||||
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
|
||||
|
||||
return (ssl_ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
initialize_nghttp2_session(http2_session_t *session) {
|
||||
nghttp2_session_callbacks *callbacks = NULL;
|
||||
|
||||
nghttp2_session_callbacks_new(&callbacks);
|
||||
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
callbacks, on_data_chunk_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
callbacks, on_stream_close_callback);
|
||||
|
||||
#if 0
|
||||
/* Do we need it ? */
|
||||
nghttp2_session_callbacks_set_on_header_callback(callbacks,
|
||||
on_header_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
callbacks, on_begin_headers_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback(
|
||||
callbacks, on_frame_recv_callback);
|
||||
|
||||
#endif
|
||||
|
||||
nghttp2_session_client_new(&session->ngsession, callbacks, session);
|
||||
|
||||
nghttp2_session_callbacks_del(callbacks);
|
||||
}
|
||||
|
||||
static void
|
||||
send_client_connection_header(http2_session_t *session) {
|
||||
nghttp2_settings_entry iv[1] = {
|
||||
{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }
|
||||
};
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_submit_settings(session->ngsession, NGHTTP2_FLAG_NONE, iv,
|
||||
1);
|
||||
if (rv != 0) {
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
http2_do_bio(session);
|
||||
}
|
||||
|
||||
#define MAKE_NV(NAME, VALUE, VALUELEN) \
|
||||
{ \
|
||||
(uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, VALUELEN, \
|
||||
NGHTTP2_NV_FLAG_NONE \
|
||||
}
|
||||
|
||||
#define MAKE_NV2(NAME, VALUE) \
|
||||
{ \
|
||||
(uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, \
|
||||
sizeof(VALUE) - 1, NGHTTP2_NV_FLAG_NONE \
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
post_read_callback(nghttp2_session *ngsession, int32_t stream_id, uint8_t *buf,
|
||||
size_t length, uint32_t *data_flags,
|
||||
nghttp2_data_source *source, void *user_data) {
|
||||
http2_session_t *session = (http2_session_t *)user_data;
|
||||
|
||||
UNUSED(ngsession);
|
||||
UNUSED(source);
|
||||
|
||||
if (session->stream->stream_id == stream_id) {
|
||||
size_t len = session->stream->postdata->length -
|
||||
session->stream->postdata_pos;
|
||||
|
||||
if (len > length) {
|
||||
len = length;
|
||||
}
|
||||
|
||||
memcpy(buf,
|
||||
session->stream->postdata->base +
|
||||
session->stream->postdata_pos,
|
||||
len);
|
||||
session->stream->postdata_pos += len;
|
||||
|
||||
if (session->stream->postdata_pos ==
|
||||
session->stream->postdata->length) {
|
||||
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
||||
}
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Send HTTP request to the remote peer */
|
||||
static isc_result_t
|
||||
submit_request(http2_session_t *session) {
|
||||
int32_t stream_id;
|
||||
http2_stream_t *stream = session->stream;
|
||||
char *uri = stream->uri;
|
||||
isc_url_parser_t *up = &stream->up;
|
||||
char p[64];
|
||||
|
||||
snprintf(p, 64, "%u", stream->postdata->length);
|
||||
|
||||
nghttp2_nv hdrs[] = {
|
||||
MAKE_NV2(":method", "POST"),
|
||||
MAKE_NV(":scheme", &uri[up->field_data[ISC_UF_SCHEMA].off],
|
||||
up->field_data[ISC_UF_SCHEMA].len),
|
||||
MAKE_NV(":authority", stream->authority, stream->authoritylen),
|
||||
MAKE_NV(":path", stream->path, stream->pathlen),
|
||||
MAKE_NV2("content-type", "application/dns-message"),
|
||||
MAKE_NV2("accept", "application/dns-message"),
|
||||
MAKE_NV("content-length", p, strlen(p))
|
||||
};
|
||||
|
||||
nghttp2_data_provider dp = { .read_callback = post_read_callback };
|
||||
stream_id = nghttp2_submit_request(session->ngsession, NULL, hdrs, 7,
|
||||
&dp, stream);
|
||||
if (stream_id < 0) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
|
||||
stream->stream_id = stream_id;
|
||||
http2_do_bio(session);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* read callback from TLS socket.
|
||||
*/
|
||||
static void
|
||||
readcb(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region,
|
||||
void *data) {
|
||||
http2_session_t *session = NULL;
|
||||
ssize_t readlen;
|
||||
|
||||
UNUSED(handle);
|
||||
UNUSED(result);
|
||||
|
||||
session = (http2_session_t *)data;
|
||||
|
||||
readlen = nghttp2_session_mem_recv(session->ngsession, region->base,
|
||||
region->length);
|
||||
if (readlen < 0) {
|
||||
delete_http2_session(session);
|
||||
/* TODO callback! */
|
||||
return;
|
||||
}
|
||||
if (readlen < region->length) {
|
||||
INSIST(session->bufsize == 0);
|
||||
INSIST(region->length - readlen < 65535);
|
||||
memmove(session->buf, region->base, region->length - readlen);
|
||||
session->bufsize = region->length - readlen;
|
||||
isc_nm_pauseread(session->handle);
|
||||
}
|
||||
|
||||
/* We might have something to receive or send, do IO */
|
||||
http2_do_bio(session);
|
||||
}
|
||||
|
||||
static bool
|
||||
http2_do_bio(http2_session_t *session) {
|
||||
if (nghttp2_session_want_read(session->ngsession) == 0 &&
|
||||
nghttp2_session_want_write(session->ngsession) == 0)
|
||||
{
|
||||
delete_http2_session(session);
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (nghttp2_session_want_read(session->ngsession) != 0) {
|
||||
if (!session->reading) {
|
||||
/* We have not yet started reading from this handle */
|
||||
isc_nm_read(session->handle, readcb, session);
|
||||
session->reading = true;
|
||||
} else if (session->bufsize > 0) {
|
||||
/* Leftover data in the buffer, use it */
|
||||
size_t readlen = nghttp2_session_mem_recv(
|
||||
session->ngsession, session->buf,
|
||||
session->bufsize);
|
||||
|
||||
if (readlen == session->bufsize) {
|
||||
session->bufsize = 0;
|
||||
} else {
|
||||
memmove(session->buf, session->buf + readlen,
|
||||
session->bufsize - readlen);
|
||||
session->bufsize -= readlen;
|
||||
}
|
||||
|
||||
http2_do_bio(session);
|
||||
return (false);
|
||||
} else {
|
||||
/* Resume reading, it's idempotent, wait for more */
|
||||
isc_nm_resumeread(session->handle);
|
||||
}
|
||||
} else {
|
||||
/* We don't want more data, stop reading for now */
|
||||
isc_nm_pauseread(session->handle);
|
||||
}
|
||||
|
||||
if (nghttp2_session_want_write(session->ngsession) != 0) {
|
||||
isc_result_t result;
|
||||
const uint8_t *data;
|
||||
size_t sz;
|
||||
|
||||
/*
|
||||
* XXXWPK TODO
|
||||
* This function may produce very small byte string. If that
|
||||
* is the case, and application disables Nagle algorithm
|
||||
* (``TCP_NODELAY``), then writing this small chunk leads to
|
||||
* very small packet, and it is very inefficient. An
|
||||
* application should be responsible to buffer up small chunks
|
||||
* of data as necessary to avoid this situation.
|
||||
*/
|
||||
sz = nghttp2_session_mem_send(session->ngsession, &data);
|
||||
session->r.base = isc_mem_get(session->mctx, sz);
|
||||
session->r.length = sz;
|
||||
memcpy(session->r.base, data, sz);
|
||||
result = isc_nm_send(session->handle, &session->r, writecb,
|
||||
session);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
static void
|
||||
writecb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
http2_session_t *session = (http2_session_t *)arg;
|
||||
|
||||
UNUSED(handle);
|
||||
UNUSED(result);
|
||||
|
||||
http2_do_bio(session);
|
||||
isc_mem_put(session->mctx, session->r.base, session->r.length);
|
||||
}
|
||||
|
||||
static void
|
||||
connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
http2_session_t *session = (http2_session_t *)arg;
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
delete_http2_session(session);
|
||||
return;
|
||||
}
|
||||
isc_nmhandle_attach(handle, &session->handle);
|
||||
|
||||
#if 0
|
||||
/* TODO H2 */
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
if (alpn == NULL) {
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (alpn == NULL || alpnlen != 2 ||
|
||||
memcmp("h2", alpn, 2) != 0)
|
||||
{
|
||||
fprintf(stderr, "h2 is not negotiated\n");
|
||||
delete_http2_session(session);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
initialize_nghttp2_session(session);
|
||||
send_client_connection_header(session);
|
||||
submit_request(session);
|
||||
http2_do_bio(session);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_doh_request(isc_nm_t *mgr, const char *uri, isc_region_t *message,
|
||||
isc_nm_recv_cb_t cb, void *cbarg, SSL_CTX *ctx) {
|
||||
uint16_t port;
|
||||
char *host = NULL;
|
||||
http2_session_t *session = NULL;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *res = NULL;
|
||||
isc_sockaddr_t local, peer;
|
||||
isc_result_t result;
|
||||
int s;
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = create_ssl_ctx();
|
||||
}
|
||||
|
||||
session = isc_mem_get(mgr->mctx, sizeof(http2_session_t));
|
||||
*session = (http2_session_t){ .cb = cb, .cbarg = cbarg, .ctx = ctx };
|
||||
isc_mem_attach(mgr->mctx, &session->mctx);
|
||||
|
||||
result = get_http2_stream(mgr->mctx, &session->stream, uri, &port);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
delete_http2_session(session);
|
||||
return (result);
|
||||
}
|
||||
session->stream->postdata = message;
|
||||
session->stream->postdata_pos = 0;
|
||||
|
||||
/* TODO do this properly!!! */
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags |= AI_CANONNAME;
|
||||
host = strndup(
|
||||
&session->stream
|
||||
->uri[session->stream->up.field_data[ISC_UF_HOST].off],
|
||||
session->stream->up.field_data[ISC_UF_HOST].len);
|
||||
|
||||
s = getaddrinfo(host, NULL, &hints, &res);
|
||||
free(host);
|
||||
|
||||
if (s != 0) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
|
||||
isc_sockaddr_fromsockaddr(&peer, res->ai_addr);
|
||||
isc_sockaddr_setport(&peer, port);
|
||||
isc_sockaddr_anyofpf(&local, res->ai_family);
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
result = isc_nm_tlsconnect(mgr, (isc_nmiface_t *)&local,
|
||||
(isc_nmiface_t *)&peer, connect_cb, session,
|
||||
ctx, 0);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
+164
-18
@@ -14,6 +14,9 @@
|
||||
#include <unistd.h>
|
||||
#include <uv.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <isc/astack.h>
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/buffer.h>
|
||||
@@ -49,6 +52,16 @@
|
||||
#define ISC_NETMGR_RECVBUF_SIZE (65536)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define NETMGR_TRACE to activate tracing of handles and sockets.
|
||||
* This will impair performance but enables us to quickly determine,
|
||||
* if netmgr resources haven't been cleaned up on shutdown, which ones
|
||||
* are still in use.
|
||||
*/
|
||||
#ifdef NETMGR_TRACE
|
||||
#define TRACE_SIZE 8
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Single network event loop worker.
|
||||
*/
|
||||
@@ -104,6 +117,11 @@ struct isc_nmhandle {
|
||||
isc_sockaddr_t local;
|
||||
isc_nm_opaquecb_t doreset; /* reset extra callback, external */
|
||||
isc_nm_opaquecb_t dofree; /* free extra callback, external */
|
||||
#ifdef NETMGR_TRACE
|
||||
void *backtrace[TRACE_SIZE];
|
||||
int backtrace_size;
|
||||
LINK(isc_nmhandle_t) active_link;
|
||||
#endif
|
||||
void *opaque;
|
||||
char extra[];
|
||||
};
|
||||
@@ -116,13 +134,14 @@ struct isc_nmiface {
|
||||
};
|
||||
|
||||
typedef enum isc__netievent_type {
|
||||
netievent_udpconnect,
|
||||
netievent_udpsend,
|
||||
netievent_udprecv,
|
||||
netievent_udpread,
|
||||
netievent_udpstop,
|
||||
netievent_udpclose,
|
||||
|
||||
netievent_tcpconnect,
|
||||
netievent_tcpsend,
|
||||
netievent_tcprecv,
|
||||
netievent_tcpstartread,
|
||||
netievent_tcppauseread,
|
||||
netievent_tcpchildaccept,
|
||||
@@ -130,8 +149,14 @@ typedef enum isc__netievent_type {
|
||||
netievent_tcpstop,
|
||||
netievent_tcpclose,
|
||||
|
||||
netievent_tcpdnsclose,
|
||||
netievent_tcpdnssend,
|
||||
netievent_tcpdnsread,
|
||||
netievent_tcpdnsclose,
|
||||
|
||||
netievent_tlsclose,
|
||||
netievent_tlssend,
|
||||
netievent_tlsstartread,
|
||||
netievent_tlsconnect,
|
||||
|
||||
netievent_closecb,
|
||||
netievent_shutdown,
|
||||
@@ -146,20 +171,12 @@ typedef enum isc__netievent_type {
|
||||
netievent_tcplisten,
|
||||
} isc__netievent_type;
|
||||
|
||||
/*
|
||||
* We have to split it because we can read and write on a socket
|
||||
* simultaneously.
|
||||
*/
|
||||
typedef union {
|
||||
isc_nm_recv_cb_t recv;
|
||||
isc_nm_cb_t connect;
|
||||
isc_nm_accept_cb_t accept;
|
||||
} isc__nm_readcb_t;
|
||||
|
||||
typedef union {
|
||||
isc_nm_cb_t send;
|
||||
isc_nm_cb_t connect;
|
||||
} isc__nm_writecb_t;
|
||||
|
||||
typedef union {
|
||||
isc_nm_recv_cb_t recv;
|
||||
isc_nm_accept_cb_t accept;
|
||||
@@ -206,13 +223,18 @@ 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_tlsclose_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_tcpdnsclose_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;
|
||||
@@ -256,6 +278,20 @@ 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_tlsconnect {
|
||||
isc__netievent_type type;
|
||||
isc_nmsocket_t *sock;
|
||||
SSL_CTX *ctx;
|
||||
isc_sockaddr_t local; /* local address */
|
||||
isc_sockaddr_t peer; /* peer address */
|
||||
} isc__netievent_tlsconnect_t;
|
||||
|
||||
typedef struct isc__netievent {
|
||||
isc__netievent_type type;
|
||||
} isc__netievent_t;
|
||||
@@ -325,6 +361,10 @@ struct isc_nm {
|
||||
uint32_t idle;
|
||||
uint32_t keepalive;
|
||||
uint32_t advertised;
|
||||
|
||||
#ifdef NETMGR_TRACE
|
||||
ISC_LIST(isc_nmsocket_t) active_sockets;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef enum isc_nmsocket_type {
|
||||
@@ -333,7 +373,9 @@ typedef enum isc_nmsocket_type {
|
||||
isc_nm_tcpsocket,
|
||||
isc_nm_tcplistener,
|
||||
isc_nm_tcpdnslistener,
|
||||
isc_nm_tcpdnssocket
|
||||
isc_nm_tcpdnssocket,
|
||||
isc_nm_tlslistener,
|
||||
isc_nm_tlssocket
|
||||
} isc_nmsocket_type;
|
||||
|
||||
/*%
|
||||
@@ -371,6 +413,16 @@ struct isc_nmsocket {
|
||||
/*% Self, for self-contained unreferenced sockets (tcpdns) */
|
||||
isc_nmsocket_t *self;
|
||||
|
||||
/*% TLS stuff */
|
||||
struct tls {
|
||||
bool server;
|
||||
BIO *app_bio;
|
||||
SSL *ssl;
|
||||
SSL_CTX *ctx;
|
||||
BIO *ssl_bio;
|
||||
enum { INIT, HANDSHAKE, IO, CLOSING } state;
|
||||
} tls;
|
||||
|
||||
/*%
|
||||
* quota is the TCP client, attached when a TCP connection
|
||||
* is established. pquota is a non-attached pointer to the
|
||||
@@ -403,7 +455,7 @@ struct isc_nmsocket {
|
||||
isc_nmsocket_t *children;
|
||||
int nchildren;
|
||||
isc_nmiface_t *iface;
|
||||
isc_nmhandle_t *tcphandle;
|
||||
isc_nmhandle_t *statichandle;
|
||||
isc_nmhandle_t *outerhandle;
|
||||
|
||||
/*% Extra data allocated at the end of each isc_nmhandle_t */
|
||||
@@ -445,7 +497,12 @@ struct isc_nmsocket {
|
||||
isc_refcount_t references;
|
||||
|
||||
/*%
|
||||
* TCPDNS socket has been set not to pipeliine.
|
||||
* Established an outgoing connection, as client not server.
|
||||
*/
|
||||
atomic_bool client;
|
||||
|
||||
/*%
|
||||
* TCPDNS socket has been set not to pipeline.
|
||||
*/
|
||||
atomic_bool sequential;
|
||||
|
||||
@@ -536,6 +593,12 @@ struct isc_nmsocket {
|
||||
|
||||
isc__nm_cb_t accept_cb;
|
||||
void *accept_cbarg;
|
||||
#ifdef NETMGR_TRACE
|
||||
void *backtrace[TRACE_SIZE];
|
||||
int backtrace_size;
|
||||
LINK(isc_nmsocket_t) active_link;
|
||||
ISC_LIST(isc_nmhandle_t) active_handles;
|
||||
#endif
|
||||
};
|
||||
|
||||
bool
|
||||
@@ -663,16 +726,40 @@ 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_stoplistening(isc_nmsocket_t *sock);
|
||||
|
||||
bool
|
||||
isc__nm_udp_cancelread(isc_nmhandle_t *handle);
|
||||
/*%<
|
||||
* Stop reading on a pending UDP handle.
|
||||
*/
|
||||
|
||||
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_udpclose(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
/*%<
|
||||
* Callback handlers for asynchronous UDP events (listen, stoplisten, send).
|
||||
*/
|
||||
@@ -686,6 +773,9 @@ isc__nm_tcp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
|
||||
isc_result_t
|
||||
isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
|
||||
/*
|
||||
* Back-end implementation of isc_nm_read() for TCP handles.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_tcp_close(isc_nmsocket_t *sock);
|
||||
@@ -712,10 +802,10 @@ isc__nm_tcp_shutdown(isc_nmsocket_t *sock);
|
||||
* sockets.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_tcp_cancelread(isc_nmsocket_t *sock);
|
||||
bool
|
||||
isc__nm_tcp_cancelread(isc_nmhandle_t *handle);
|
||||
/*%<
|
||||
* Stop reading on a connected socket.
|
||||
* Stop reading on a connected TCP handle.
|
||||
*/
|
||||
|
||||
void
|
||||
@@ -748,6 +838,22 @@ isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
* stoplisten, send, read, pause, close).
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_async_tlsclose(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
void
|
||||
isc__nm_async_tlssend(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
void
|
||||
isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
void
|
||||
isc__nm_async_tls_startread(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
/*%<
|
||||
* Callback handlers for asynchronouse TLS events.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region,
|
||||
isc_nm_cb_t cb, void *cbarg);
|
||||
@@ -770,6 +876,46 @@ 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);
|
||||
|
||||
bool
|
||||
isc__nm_tcpdns_cancelread(isc_nmhandle_t *handle);
|
||||
/*%<
|
||||
* Stop reading on a connected TCPDNS handle.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc__nm_tls_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
void *cbarg);
|
||||
|
||||
isc_result_t
|
||||
isc__nm_tls_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
|
||||
|
||||
void
|
||||
isc__nm_tls_close(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Close a TLS socket.
|
||||
*/
|
||||
isc_result_t
|
||||
isc__nm_tls_pauseread(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Pause reading on this socket, while still remembering the callback.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc__nm_tls_resumeread(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Resume reading from socket.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_tls_stoplistening(isc_nmsocket_t *sock);
|
||||
|
||||
#define isc__nm_uverr2result(x) \
|
||||
isc___nm_uverr2result(x, true, __FILE__, __LINE__)
|
||||
isc_result_t
|
||||
|
||||
+129
-17
@@ -33,6 +33,10 @@
|
||||
#include "netmgr-int.h"
|
||||
#include "uv-compat.h"
|
||||
|
||||
#ifdef NETMGR_TRACE
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
/*%
|
||||
* How many isc_nmhandles and isc_nm_uvreqs will we be
|
||||
* caching for reuse in a socket.
|
||||
@@ -157,6 +161,10 @@ isc_nm_start(isc_mem_t *mctx, uint32_t workers) {
|
||||
atomic_init(&mgr->paused, false);
|
||||
atomic_init(&mgr->interlocked, false);
|
||||
|
||||
#ifdef NETMGR_TRACE
|
||||
ISC_LIST_INIT(mgr->active_sockets);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Default TCP timeout values.
|
||||
* May be updated by isc_nm_tcptimeouts().
|
||||
@@ -393,6 +401,7 @@ isc_nm_closedown(isc_nm_t *mgr) {
|
||||
void
|
||||
isc_nm_destroy(isc_nm_t **mgr0) {
|
||||
isc_nm_t *mgr = NULL;
|
||||
int counter = 0;
|
||||
|
||||
REQUIRE(mgr0 != NULL);
|
||||
REQUIRE(VALID_NM(*mgr0));
|
||||
@@ -407,7 +416,7 @@ isc_nm_destroy(isc_nm_t **mgr0) {
|
||||
/*
|
||||
* Wait for the manager to be dereferenced elsewhere.
|
||||
*/
|
||||
while (isc_refcount_current(&mgr->references) > 1) {
|
||||
while (isc_refcount_current(&mgr->references) > 1 && counter++ < 1000) {
|
||||
/*
|
||||
* Sometimes libuv gets stuck, pausing and unpausing
|
||||
* netmgr goes over all events in async queue for all
|
||||
@@ -418,10 +427,14 @@ isc_nm_destroy(isc_nm_t **mgr0) {
|
||||
isc_nm_resume(mgr);
|
||||
#ifdef WIN32
|
||||
_sleep(10);
|
||||
#else /* ifdef WIN32 */
|
||||
#else /* ifdef WIN32 */
|
||||
usleep(10000);
|
||||
#endif /* ifdef WIN32 */
|
||||
}
|
||||
#ifdef NETMGR_TRACE
|
||||
INSIST(ISC_LIST_EMPTY(mgr->active_sockets));
|
||||
#endif
|
||||
INSIST(counter <= 1000);
|
||||
|
||||
/*
|
||||
* Detach final reference.
|
||||
@@ -546,7 +559,7 @@ nm_thread(isc_threadarg_t worker0) {
|
||||
*/
|
||||
#ifdef WIN32
|
||||
_sleep(100);
|
||||
#else /* ifdef WIN32 */
|
||||
#else /* ifdef WIN32 */
|
||||
usleep(100000);
|
||||
#endif /* ifdef WIN32 */
|
||||
}
|
||||
@@ -591,6 +604,10 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) {
|
||||
uv_stop(&worker->loop);
|
||||
isc_mempool_put(worker->mgr->evpool, ievent);
|
||||
return;
|
||||
case netievent_udpconnect:
|
||||
isc__nm_async_udpconnect(worker, ievent);
|
||||
break;
|
||||
|
||||
case netievent_udplisten:
|
||||
isc__nm_async_udplisten(worker, ievent);
|
||||
break;
|
||||
@@ -600,6 +617,14 @@ 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_udpclose:
|
||||
isc__nm_async_udpclose(worker, ievent);
|
||||
break;
|
||||
|
||||
case netievent_tcpconnect:
|
||||
isc__nm_async_tcpconnect(worker, ievent);
|
||||
break;
|
||||
@@ -630,9 +655,27 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) {
|
||||
case netievent_tcpclose:
|
||||
isc__nm_async_tcpclose(worker, ievent);
|
||||
break;
|
||||
|
||||
case netievent_tlsstartread:
|
||||
isc__nm_async_tls_startread(worker, ievent);
|
||||
break;
|
||||
case netievent_tlssend:
|
||||
isc__nm_async_tlssend(worker, ievent);
|
||||
break;
|
||||
case netievent_tlsclose:
|
||||
isc__nm_async_tlsclose(worker, ievent);
|
||||
break;
|
||||
case netievent_tlsconnect:
|
||||
isc__nm_async_tlsconnect(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);
|
||||
break;
|
||||
@@ -739,11 +782,10 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree) {
|
||||
isc__nm_decstats(sock->mgr, sock->statsindex[STATID_ACTIVE]);
|
||||
}
|
||||
|
||||
sock->tcphandle = NULL;
|
||||
sock->statichandle = NULL;
|
||||
|
||||
if (sock->outerhandle != NULL) {
|
||||
isc_nmhandle_unref(sock->outerhandle);
|
||||
sock->outerhandle = NULL;
|
||||
isc_nmhandle_detach(&sock->outerhandle);
|
||||
}
|
||||
|
||||
if (sock->outer != NULL) {
|
||||
@@ -786,7 +828,11 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree) {
|
||||
isc_mem_free(sock->mgr->mctx, sock->ah_handles);
|
||||
isc_mutex_destroy(&sock->lock);
|
||||
isc_condition_destroy(&sock->cond);
|
||||
|
||||
#ifdef NETMGR_TRACE
|
||||
LOCK(&sock->mgr->lock);
|
||||
ISC_LIST_UNLINK(sock->mgr->active_sockets, sock, active_link);
|
||||
UNLOCK(&sock->mgr->lock);
|
||||
#endif
|
||||
if (dofree) {
|
||||
isc_nm_t *mgr = sock->mgr;
|
||||
isc_mem_put(mgr->mctx, sock, sizeof(*sock));
|
||||
@@ -833,7 +879,7 @@ nmsocket_maybe_destroy(isc_nmsocket_t *sock) {
|
||||
}
|
||||
}
|
||||
|
||||
if (active_handles == 0 || sock->tcphandle != NULL) {
|
||||
if (active_handles == 0 || sock->statichandle != NULL) {
|
||||
destroy = true;
|
||||
}
|
||||
|
||||
@@ -875,12 +921,18 @@ 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;
|
||||
case isc_nm_tcpdnssocket:
|
||||
isc__nm_tcpdns_close(sock);
|
||||
return;
|
||||
case isc_nm_tlssocket:
|
||||
isc__nm_tls_close(sock);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -944,6 +996,15 @@ isc__nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
|
||||
.inactivereqs = isc_astack_new(
|
||||
mgr->mctx, ISC_NM_REQS_STACK_SIZE) };
|
||||
|
||||
#ifdef NETMGR_TRACE
|
||||
sock->backtrace_size = backtrace(sock->backtrace, TRACE_SIZE);
|
||||
ISC_LINK_INIT(sock, active_link);
|
||||
ISC_LIST_INIT(sock->active_handles);
|
||||
LOCK(&mgr->lock);
|
||||
ISC_LIST_APPEND(mgr->active_sockets, sock, active_link);
|
||||
UNLOCK(&mgr->lock);
|
||||
#endif
|
||||
|
||||
isc_nm_attach(mgr, &sock->mgr);
|
||||
sock->uv_handle.handle.data = sock;
|
||||
|
||||
@@ -1032,6 +1093,9 @@ alloc_handle(isc_nmsocket_t *sock) {
|
||||
sizeof(isc_nmhandle_t) + sock->extrahandlesize);
|
||||
|
||||
*handle = (isc_nmhandle_t){ .magic = NMHANDLE_MAGIC };
|
||||
#ifdef NETMGR_TRACE
|
||||
ISC_LINK_INIT(handle, active_link);
|
||||
#endif
|
||||
isc_refcount_init(&handle->references, 1);
|
||||
|
||||
return (handle);
|
||||
@@ -1057,6 +1121,10 @@ isc__nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer,
|
||||
|
||||
isc__nmsocket_attach(sock, &handle->sock);
|
||||
|
||||
#ifdef NETMGR_TRACE
|
||||
handle->backtrace_size = backtrace(handle->backtrace, TRACE_SIZE);
|
||||
#endif
|
||||
|
||||
if (peer != NULL) {
|
||||
memcpy(&handle->peer, peer, sizeof(isc_sockaddr_t));
|
||||
} else {
|
||||
@@ -1097,21 +1165,29 @@ isc__nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer,
|
||||
INSIST(sock->ah_handles[pos] == NULL);
|
||||
sock->ah_handles[pos] = handle;
|
||||
handle->ah_pos = pos;
|
||||
#ifdef NETMGR_TRACE
|
||||
ISC_LIST_APPEND(sock->active_handles, handle, active_link);
|
||||
#endif
|
||||
UNLOCK(&sock->lock);
|
||||
|
||||
if (sock->type == isc_nm_tcpsocket) {
|
||||
INSIST(sock->tcphandle == NULL);
|
||||
sock->tcphandle = handle;
|
||||
if (sock->type == isc_nm_tcpsocket || sock->type == isc_nm_tlssocket ||
|
||||
(sock->type == isc_nm_udpsocket && sock->client))
|
||||
{
|
||||
INSIST(sock->statichandle == NULL);
|
||||
/* Note: statichandle is assigned, not attached. */
|
||||
sock->statichandle = handle;
|
||||
}
|
||||
|
||||
return (handle);
|
||||
}
|
||||
|
||||
void
|
||||
isc_nmhandle_ref(isc_nmhandle_t *handle) {
|
||||
isc_nmhandle_attach(isc_nmhandle_t *handle, isc_nmhandle_t **handlep) {
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
REQUIRE(handlep != NULL && *handlep == NULL);
|
||||
|
||||
isc_refcount_increment(&handle->references);
|
||||
*handlep = handle;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -1153,6 +1229,10 @@ nmhandle_deactivate(isc_nmsocket_t *sock, isc_nmhandle_t *handle) {
|
||||
INSIST(sock->ah_size > handle->ah_pos);
|
||||
INSIST(atomic_load(&sock->ah) > 0);
|
||||
|
||||
#ifdef NETMGR_TRACE
|
||||
ISC_LIST_UNLINK(sock->active_handles, handle, active_link);
|
||||
#endif
|
||||
|
||||
sock->ah_handles[handle->ah_pos] = NULL;
|
||||
handlenum = atomic_fetch_sub(&sock->ah, 1) - 1;
|
||||
sock->ah_frees[handlenum] = handle->ah_pos;
|
||||
@@ -1167,14 +1247,20 @@ nmhandle_deactivate(isc_nmsocket_t *sock, isc_nmhandle_t *handle) {
|
||||
}
|
||||
|
||||
void
|
||||
isc_nmhandle_unref(isc_nmhandle_t *handle) {
|
||||
isc_nmhandle_detach(isc_nmhandle_t **handlep) {
|
||||
isc_nmsocket_t *sock = NULL;
|
||||
isc_nmhandle_t *handle = NULL;
|
||||
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
REQUIRE(handlep != NULL);
|
||||
REQUIRE(VALID_NMHANDLE(*handlep));
|
||||
|
||||
handle = *handlep;
|
||||
*handlep = NULL;
|
||||
|
||||
if (isc_refcount_decrement(&handle->references) > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* We need an acquire memory barrier here */
|
||||
(void)isc_refcount_current(&handle->references);
|
||||
|
||||
@@ -1208,6 +1294,11 @@ isc_nmhandle_unref(isc_nmhandle_t *handle) {
|
||||
}
|
||||
}
|
||||
|
||||
if (handle == sock->statichandle) {
|
||||
/* statichandle is assigned, not attached. */
|
||||
sock->statichandle = NULL;
|
||||
}
|
||||
|
||||
isc__nmsocket_detach(&sock);
|
||||
}
|
||||
|
||||
@@ -1309,7 +1400,7 @@ isc__nm_uvreq_put(isc__nm_uvreq_t **req0, isc_nmsocket_t *sock) {
|
||||
}
|
||||
|
||||
if (handle != NULL) {
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_nmhandle_detach(&handle);
|
||||
}
|
||||
|
||||
isc__nmsocket_detach(&sock);
|
||||
@@ -1328,6 +1419,8 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
return (isc__nm_tcp_send(handle, region, cb, cbarg));
|
||||
case isc_nm_tcpdnssocket:
|
||||
return (isc__nm_tcpdns_send(handle, region, cb, cbarg));
|
||||
case isc_nm_tlssocket:
|
||||
return (isc__nm_tls_send(handle, region, cb, cbarg));
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
@@ -1339,21 +1432,33 @@ 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));
|
||||
case isc_nm_tlssocket:
|
||||
return (isc__nm_tls_read(handle, cb, cbarg));
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
isc_nm_cancelread(isc_nmhandle_t *handle) {
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
|
||||
switch (handle->sock->type) {
|
||||
case isc_nm_udpsocket:
|
||||
return (isc__nm_udp_cancelread(handle));
|
||||
break;
|
||||
case isc_nm_tcpsocket:
|
||||
isc__nm_tcp_cancelread(handle->sock);
|
||||
return (isc__nm_tcp_cancelread(handle));
|
||||
break;
|
||||
case isc_nm_tcpdnssocket:
|
||||
return (isc__nm_tcpdns_cancelread(handle));
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
@@ -1370,6 +1475,8 @@ isc_nm_pauseread(isc_nmhandle_t *handle) {
|
||||
switch (sock->type) {
|
||||
case isc_nm_tcpsocket:
|
||||
return (isc__nm_tcp_pauseread(sock));
|
||||
case isc_nm_tlssocket:
|
||||
return (isc__nm_tls_pauseread(sock));
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
@@ -1385,6 +1492,8 @@ isc_nm_resumeread(isc_nmhandle_t *handle) {
|
||||
switch (sock->type) {
|
||||
case isc_nm_tcpsocket:
|
||||
return (isc__nm_tcp_resumeread(sock));
|
||||
case isc_nm_tlssocket:
|
||||
return (isc__nm_tls_resumeread(sock));
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
@@ -1405,6 +1514,9 @@ isc_nm_stoplistening(isc_nmsocket_t *sock) {
|
||||
case isc_nm_tcplistener:
|
||||
isc__nm_tcp_stoplistening(sock);
|
||||
break;
|
||||
case isc_nm_tlslistener:
|
||||
isc__nm_tls_stoplistening(sock);
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
|
||||
+55
-53
@@ -147,49 +147,46 @@ done:
|
||||
|
||||
static void
|
||||
tcp_connect_cb(uv_connect_t *uvreq, int status) {
|
||||
isc_result_t result;
|
||||
isc__nm_uvreq_t *req = (isc__nm_uvreq_t *)uvreq->data;
|
||||
isc_nmsocket_t *sock = NULL;
|
||||
struct sockaddr_storage ss;
|
||||
isc_nmhandle_t *handle = NULL;
|
||||
|
||||
sock = uv_handle_get_data((uv_handle_t *)uvreq->handle);
|
||||
|
||||
REQUIRE(VALID_UVREQ(req));
|
||||
|
||||
if (status == 0) {
|
||||
isc_result_t result;
|
||||
struct sockaddr_storage ss;
|
||||
isc_nmhandle_t *handle = NULL;
|
||||
|
||||
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,
|
||||
&(int){ sizeof(ss) });
|
||||
result = isc_sockaddr_fromsockaddr(&sock->peer,
|
||||
(struct sockaddr *)&ss);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
||||
handle = isc__nmhandle_get(sock, NULL, NULL);
|
||||
req->cb.connect(handle, ISC_R_SUCCESS, req->cbarg);
|
||||
|
||||
isc__nm_uvreq_put(&req, sock);
|
||||
|
||||
/*
|
||||
* The sock is now attached to the handle.
|
||||
*/
|
||||
isc__nmsocket_detach(&sock);
|
||||
|
||||
/*
|
||||
* If the connect callback wants to hold on to the handle,
|
||||
* it needs to attach to it.
|
||||
*/
|
||||
isc_nmhandle_unref(handle);
|
||||
} else {
|
||||
/*
|
||||
* TODO:
|
||||
* Handle the connect error properly and free the socket.
|
||||
*/
|
||||
if (status != 0) {
|
||||
req->cb.connect(NULL, isc__nm_uverr2result(status), req->cbarg);
|
||||
isc__nm_uvreq_put(&req, sock);
|
||||
return;
|
||||
}
|
||||
|
||||
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,
|
||||
&(int){ sizeof(ss) });
|
||||
result = isc_sockaddr_fromsockaddr(&sock->peer, (struct sockaddr *)&ss);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
||||
handle = isc__nmhandle_get(sock, NULL, NULL);
|
||||
req->cb.connect(handle, ISC_R_SUCCESS, req->cbarg);
|
||||
|
||||
isc__nm_uvreq_put(&req, sock);
|
||||
|
||||
sock->client = true;
|
||||
|
||||
/*
|
||||
* The sock is now attached to the handle.
|
||||
*/
|
||||
isc__nmsocket_detach(&sock);
|
||||
|
||||
/*
|
||||
* If the connect callback wants to hold on to the handle,
|
||||
* it needs to attach to it.
|
||||
*/
|
||||
isc_nmhandle_detach(&handle);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
@@ -201,6 +198,8 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
|
||||
REQUIRE(VALID_NM(mgr));
|
||||
REQUIRE(local != NULL);
|
||||
REQUIRE(peer != NULL);
|
||||
|
||||
nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
|
||||
isc__nmsocket_init(nsock, mgr, isc_nm_tcpsocket, local);
|
||||
@@ -211,6 +210,7 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
|
||||
req->cb.connect = cb;
|
||||
req->cbarg = cbarg;
|
||||
req->peer = peer->addr;
|
||||
req->local = local->addr;
|
||||
|
||||
ievent = isc__nm_get_ievent(mgr, netievent_tcpconnect);
|
||||
ievent->sock = nsock;
|
||||
@@ -501,7 +501,7 @@ isc__nm_async_tcpchildaccept(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
* If the accept callback wants to hold on to the handle,
|
||||
* it needs to attach to it.
|
||||
*/
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_nmhandle_detach(&handle);
|
||||
return;
|
||||
|
||||
error:
|
||||
@@ -604,7 +604,7 @@ readtimeout_cb(uv_timer_t *handle) {
|
||||
isc_quota_detach(&sock->quota);
|
||||
}
|
||||
if (sock->rcb.recv != NULL) {
|
||||
sock->rcb.recv(sock->tcphandle, ISC_R_TIMEDOUT, NULL,
|
||||
sock->rcb.recv(sock->statichandle, ISC_R_TIMEDOUT, NULL,
|
||||
sock->rcbarg);
|
||||
isc__nmsocket_clearcb(sock);
|
||||
}
|
||||
@@ -766,8 +766,8 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
|
||||
.length = nread };
|
||||
|
||||
if (sock->rcb.recv != NULL) {
|
||||
sock->rcb.recv(sock->tcphandle, ISC_R_SUCCESS, ®ion,
|
||||
sock->rcbarg);
|
||||
sock->rcb.recv(sock->statichandle, ISC_R_SUCCESS,
|
||||
®ion, sock->rcbarg);
|
||||
}
|
||||
|
||||
sock->read_timeout = (atomic_load(&sock->keepalive)
|
||||
@@ -792,7 +792,8 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
|
||||
*/
|
||||
if (sock->rcb.recv != NULL) {
|
||||
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_RECVFAIL]);
|
||||
sock->rcb.recv(sock->tcphandle, ISC_R_EOF, NULL, sock->rcbarg);
|
||||
sock->rcb.recv(sock->statichandle, ISC_R_EOF, NULL,
|
||||
sock->rcbarg);
|
||||
isc__nmsocket_clearcb(sock);
|
||||
}
|
||||
|
||||
@@ -958,8 +959,7 @@ isc__nm_tcp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
uvreq = isc__nm_uvreq_get(sock->mgr, sock);
|
||||
uvreq->uvbuf.base = (char *)region->base;
|
||||
uvreq->uvbuf.len = region->length;
|
||||
uvreq->handle = handle;
|
||||
isc_nmhandle_ref(uvreq->handle);
|
||||
isc_nmhandle_attach(handle, &uvreq->handle);
|
||||
uvreq->cb.send = cb;
|
||||
uvreq->cbarg = cbarg;
|
||||
|
||||
@@ -1002,7 +1002,6 @@ tcp_send_cb(uv_write_t *req, int status) {
|
||||
uvreq->cb.send(uvreq->handle, result, uvreq->cbarg);
|
||||
|
||||
sock = uvreq->handle->sock;
|
||||
isc_nmhandle_unref(uvreq->handle);
|
||||
isc__nm_uvreq_put(&uvreq, sock);
|
||||
}
|
||||
|
||||
@@ -1034,8 +1033,6 @@ tcp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
|
||||
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
REQUIRE(sock->type == isc_nm_tcpsocket);
|
||||
|
||||
isc_nmhandle_ref(req->handle);
|
||||
r = uv_write(&req->uv_req.write, &sock->uv_handle.stream, &req->uvbuf,
|
||||
1, tcp_send_cb);
|
||||
if (r < 0) {
|
||||
@@ -1125,24 +1122,29 @@ void
|
||||
isc__nm_tcp_shutdown(isc_nmsocket_t *sock) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
|
||||
if (sock->type == isc_nm_tcpsocket && sock->tcphandle != NULL &&
|
||||
if (sock->type == isc_nm_tcpsocket && sock->statichandle != NULL &&
|
||||
sock->rcb.recv != NULL)
|
||||
{
|
||||
sock->rcb.recv(sock->tcphandle, ISC_R_CANCELED, NULL,
|
||||
sock->rcb.recv(sock->statichandle, ISC_R_CANCELED, NULL,
|
||||
sock->rcbarg);
|
||||
isc__nmsocket_clearcb(sock);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_tcp_cancelread(isc_nmsocket_t *sock) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
bool
|
||||
isc__nm_tcp_cancelread(isc_nmhandle_t *handle) {
|
||||
isc_nmsocket_t *sock = NULL;
|
||||
|
||||
if (sock->type == isc_nm_tcpsocket && sock->tcphandle != NULL &&
|
||||
sock->rcb.recv != NULL)
|
||||
{
|
||||
sock->rcb.recv(sock->tcphandle, ISC_R_CANCELED, NULL,
|
||||
sock->rcbarg);
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
|
||||
sock = handle->sock;
|
||||
|
||||
REQUIRE(sock->type == isc_nm_tcpsocket);
|
||||
|
||||
if (sock->client && sock->rcb.recv != NULL) {
|
||||
sock->rcb.recv(handle, ISC_R_EOF, NULL, sock->rcbarg);
|
||||
isc__nmsocket_clearcb(sock);
|
||||
return (true);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
+252
-38
@@ -82,7 +82,9 @@ alloc_dnsbuf(isc_nmsocket_t *sock, size_t len) {
|
||||
static void
|
||||
timer_close_cb(uv_handle_t *handle) {
|
||||
isc_nmsocket_t *sock = (isc_nmsocket_t *)uv_handle_get_data(handle);
|
||||
INSIST(VALID_NMSOCK(sock));
|
||||
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
|
||||
atomic_store(&sock->closed, true);
|
||||
tcpdns_close_direct(sock);
|
||||
}
|
||||
@@ -94,9 +96,9 @@ dnstcp_readtimeout(uv_timer_t *timer) {
|
||||
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
/* Close the TCP connection, it's closing should fire 'our' closing */
|
||||
isc_nmhandle_unref(sock->outerhandle);
|
||||
sock->outerhandle = NULL;
|
||||
|
||||
/* Close the TCP connection; its closure should fire ours. */
|
||||
isc_nmhandle_detach(&sock->outerhandle);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -106,6 +108,7 @@ static isc_result_t
|
||||
dnslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
||||
isc_nmsocket_t *dnslistensock = (isc_nmsocket_t *)cbarg;
|
||||
isc_nmsocket_t *dnssock = NULL;
|
||||
isc_nmhandle_t *readhandle = NULL;
|
||||
|
||||
REQUIRE(VALID_NMSOCK(dnslistensock));
|
||||
REQUIRE(dnslistensock->type == isc_nm_tcpdnslistener);
|
||||
@@ -132,8 +135,7 @@ dnslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
||||
|
||||
isc__nmsocket_attach(dnssock, &dnssock->self);
|
||||
|
||||
dnssock->outerhandle = handle;
|
||||
isc_nmhandle_ref(dnssock->outerhandle);
|
||||
isc_nmhandle_attach(handle, &dnssock->outerhandle);
|
||||
|
||||
dnssock->peer = handle->sock->peer;
|
||||
dnssock->read_timeout = handle->sock->mgr->init;
|
||||
@@ -147,10 +149,14 @@ dnslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
||||
uv_timer_start(&dnssock->timer, dnstcp_readtimeout,
|
||||
dnssock->read_timeout, 0);
|
||||
|
||||
isc_nmhandle_ref(handle);
|
||||
result = isc_nm_read(handle, dnslisten_readcb, dnssock);
|
||||
/*
|
||||
* Add a reference to handle to keep it from being freed by
|
||||
* the caller; it will be detached in dnslisten_readcb().
|
||||
*/
|
||||
isc_nmhandle_attach(handle, &readhandle);
|
||||
result = isc_nm_read(readhandle, dnslisten_readcb, dnssock);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_nmhandle_detach(&readhandle);
|
||||
}
|
||||
isc__nmsocket_detach(&dnssock);
|
||||
|
||||
@@ -187,8 +193,13 @@ processbuffer(isc_nmsocket_t *dnssock, isc_nmhandle_t **handlep) {
|
||||
*/
|
||||
len = dnslen(dnssock->buf);
|
||||
if (len <= dnssock->buf_len - 2) {
|
||||
isc_nmhandle_t *dnshandle = isc__nmhandle_get(dnssock, NULL,
|
||||
NULL);
|
||||
isc_nmhandle_t *dnshandle = NULL;
|
||||
if (dnssock->client && dnssock->statichandle != NULL) {
|
||||
isc_nmhandle_attach(dnssock->statichandle, &dnshandle);
|
||||
} else {
|
||||
dnshandle = isc__nmhandle_get(dnssock, NULL, NULL);
|
||||
}
|
||||
|
||||
isc_nmsocket_t *listener = dnssock->listener;
|
||||
|
||||
if (listener != NULL && listener->rcb.recv != NULL) {
|
||||
@@ -197,6 +208,20 @@ processbuffer(isc_nmsocket_t *dnssock, isc_nmhandle_t **handlep) {
|
||||
&(isc_region_t){ .base = dnssock->buf + 2,
|
||||
.length = len },
|
||||
listener->rcbarg);
|
||||
} else if (dnssock->rcb.recv != NULL) {
|
||||
isc_nm_recv_cb_t cb = dnssock->rcb.recv;
|
||||
void *cbarg = dnssock->rcbarg;
|
||||
|
||||
/*
|
||||
* We need to clear the read callback *before*
|
||||
* calling it, because it might make another
|
||||
* call to isc_nm_read() and set up a new callback.
|
||||
*/
|
||||
isc__nmsocket_clearcb(dnssock);
|
||||
cb(dnshandle, ISC_R_SUCCESS,
|
||||
&(isc_region_t){ .base = dnssock->buf + 2,
|
||||
.length = len },
|
||||
cbarg);
|
||||
}
|
||||
|
||||
len += 2;
|
||||
@@ -227,20 +252,18 @@ dnslisten_readcb(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
|
||||
REQUIRE(VALID_NMSOCK(dnssock));
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
REQUIRE(dnssock->tid == isc_nm_tid());
|
||||
|
||||
if (region == NULL || eresult != ISC_R_SUCCESS) {
|
||||
/* Connection closed */
|
||||
isc_nmhandle_unref(handle);
|
||||
dnssock->result = eresult;
|
||||
if (dnssock->self != NULL) {
|
||||
isc__nmsocket_detach(&dnssock->self);
|
||||
}
|
||||
isc__nmsocket_clearcb(dnssock);
|
||||
if (dnssock->outerhandle != NULL) {
|
||||
isc_nmhandle_unref(dnssock->outerhandle);
|
||||
dnssock->outerhandle = NULL;
|
||||
isc_nmhandle_detach(&dnssock->outerhandle);
|
||||
}
|
||||
isc_nmhandle_detach(&handle);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -277,11 +300,14 @@ dnslisten_readcb(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
uv_timer_stop(&dnssock->timer);
|
||||
}
|
||||
|
||||
if (atomic_load(&dnssock->sequential)) {
|
||||
if (atomic_load(&dnssock->sequential) ||
|
||||
dnssock->rcb.recv == NULL) {
|
||||
/*
|
||||
* We're in sequential mode and we processed
|
||||
* one packet, so we're done until the next read
|
||||
* completes.
|
||||
* There are two reasons we might want to pause here:
|
||||
* - We're in sequential mode and we've received
|
||||
* a whole packet, so we're done until it's been
|
||||
* processed; or
|
||||
* - We no longer have a read callback.
|
||||
*/
|
||||
isc_nm_pauseread(dnssock->outerhandle);
|
||||
done = true;
|
||||
@@ -300,7 +326,7 @@ dnslisten_readcb(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
}
|
||||
}
|
||||
|
||||
isc_nmhandle_unref(dnshandle);
|
||||
isc_nmhandle_detach(&dnshandle);
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
@@ -313,8 +339,8 @@ isc_result_t
|
||||
isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
|
||||
void *cbarg, isc_nm_accept_cb_t accept_cb,
|
||||
void *accept_cbarg, size_t extrahandlesize, int backlog,
|
||||
isc_quota_t *quota, isc_nmsocket_t **sockp) {
|
||||
/* A 'wrapper' socket object with outer set to true TCP socket */
|
||||
isc_quota_t *quota, SSL_CTX *sslctx,
|
||||
isc_nmsocket_t **sockp) {
|
||||
isc_nmsocket_t *dnslistensock = isc_mem_get(mgr->mctx,
|
||||
sizeof(*dnslistensock));
|
||||
isc_result_t result;
|
||||
@@ -328,10 +354,21 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
|
||||
dnslistensock->accept_cbarg = accept_cbarg;
|
||||
dnslistensock->extrahandlesize = extrahandlesize;
|
||||
|
||||
/* We set dnslistensock->outer to a true listening socket */
|
||||
result = isc_nm_listentcp(mgr, iface, dnslisten_acceptcb, dnslistensock,
|
||||
extrahandlesize, backlog, quota,
|
||||
&dnslistensock->outer);
|
||||
/*
|
||||
* dnslistensock will be a DNS 'wrapper' around a connected
|
||||
* stream. We set dnslistensock->outer to a socket listening
|
||||
* for a TCP or TLS connection.
|
||||
*/
|
||||
if (sslctx != NULL) {
|
||||
result = isc_nm_listentls(mgr, iface, dnslisten_acceptcb,
|
||||
dnslistensock, extrahandlesize,
|
||||
backlog, quota, sslctx,
|
||||
&dnslistensock->outer);
|
||||
} else {
|
||||
result = isc_nm_listentcp(
|
||||
mgr, iface, dnslisten_acceptcb, dnslistensock,
|
||||
extrahandlesize, backlog, quota, &dnslistensock->outer);
|
||||
}
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
atomic_store(&dnslistensock->listening, true);
|
||||
*sockp = dnslistensock;
|
||||
@@ -429,12 +466,11 @@ resume_processing(void *arg) {
|
||||
if (sock->timer_initialized) {
|
||||
uv_timer_stop(&sock->timer);
|
||||
}
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_nmhandle_detach(&handle);
|
||||
} else if (sock->outerhandle != NULL) {
|
||||
result = isc_nm_resumeread(sock->outerhandle);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_nmhandle_unref(sock->outerhandle);
|
||||
sock->outerhandle = NULL;
|
||||
isc_nmhandle_detach(&sock->outerhandle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,7 +500,7 @@ resume_processing(void *arg) {
|
||||
uv_timer_stop(&sock->timer);
|
||||
}
|
||||
atomic_store(&sock->outerhandle->sock->processing, true);
|
||||
isc_nmhandle_unref(dnshandle);
|
||||
isc_nmhandle_detach(&dnshandle);
|
||||
} while (atomic_load(&sock->ah) < TCPDNS_CLIENTS_PER_CONN);
|
||||
}
|
||||
|
||||
@@ -495,8 +531,7 @@ isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
|
||||
r.base = (unsigned char *)req->uvbuf.base;
|
||||
r.length = req->uvbuf.len;
|
||||
result = isc__nm_tcp_send(sock->outerhandle, &r, tcpdnssend_cb,
|
||||
req);
|
||||
result = isc_nm_send(sock->outerhandle, &r, tcpdnssend_cb, req);
|
||||
}
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
@@ -522,8 +557,7 @@ isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region,
|
||||
REQUIRE(sock->type == isc_nm_tcpdnssocket);
|
||||
|
||||
uvreq = isc__nm_uvreq_get(sock->mgr, sock);
|
||||
uvreq->handle = handle;
|
||||
isc_nmhandle_ref(uvreq->handle);
|
||||
isc_nmhandle_attach(handle, &uvreq->handle);
|
||||
uvreq->cb.send = cb;
|
||||
uvreq->cbarg = cbarg;
|
||||
|
||||
@@ -538,8 +572,8 @@ isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region,
|
||||
r.base = (unsigned char *)uvreq->uvbuf.base;
|
||||
r.length = uvreq->uvbuf.len;
|
||||
|
||||
return (isc__nm_tcp_send(sock->outerhandle, &r, tcpdnssend_cb,
|
||||
uvreq));
|
||||
return (isc_nm_send(sock->outerhandle, &r, tcpdnssend_cb,
|
||||
uvreq));
|
||||
} else {
|
||||
isc__netievent_tcpdnssend_t *ievent = NULL;
|
||||
|
||||
@@ -579,8 +613,7 @@ tcpdns_close_direct(isc_nmsocket_t *sock) {
|
||||
*/
|
||||
if (sock->outerhandle != NULL) {
|
||||
isc__nmsocket_clearcb(sock->outerhandle->sock);
|
||||
isc_nmhandle_unref(sock->outerhandle);
|
||||
sock->outerhandle = NULL;
|
||||
isc_nmhandle_detach(&sock->outerhandle);
|
||||
}
|
||||
if (sock->listener != NULL) {
|
||||
isc__nmsocket_detach(&sock->listener);
|
||||
@@ -616,3 +649,184 @@ 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;
|
||||
|
||||
isc_mem_putanddetach(&conn->mctx, conn, sizeof(*conn));
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
cb(NULL, result, cbarg);
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
|
||||
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();
|
||||
|
||||
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_nmhandle_detach(&handle);
|
||||
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, 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, 0));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
|
||||
isc_nm_cb_t cb, void *cbarg, size_t extrahandlesize) {
|
||||
tcpconnect_t *conn = isc_mem_get(mgr->mctx, sizeof(tcpconnect_t));
|
||||
SSL_CTX *ctx = NULL;
|
||||
|
||||
*conn = (tcpconnect_t){ .cb = cb,
|
||||
.cbarg = cbarg,
|
||||
.extrahandlesize = extrahandlesize };
|
||||
isc_mem_attach(mgr->mctx, &conn->mctx);
|
||||
|
||||
ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
return (isc_nm_tlsconnect(mgr, local, peer, tcpdnsconnect_cb, conn, ctx,
|
||||
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->rcb.recv == NULL);
|
||||
REQUIRE(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->rcb.recv = cb;
|
||||
sock->rcbarg = 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);
|
||||
|
||||
handle = sock->statichandle;
|
||||
|
||||
if (sock->type != isc_nm_tcpdnssocket || sock->outerhandle == NULL) {
|
||||
sock->rcb.recv(handle, ISC_R_NOTCONNECTED, NULL, sock->rcbarg);
|
||||
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->rcb.recv;
|
||||
void *cbarg = sock->rcbarg;
|
||||
|
||||
isc__nmsocket_clearcb(sock);
|
||||
cb(handle, ISC_R_NOTCONNECTED, NULL, cbarg);
|
||||
}
|
||||
|
||||
isc_nmhandle_detach(&handle);
|
||||
}
|
||||
|
||||
bool
|
||||
isc__nm_tcpdns_cancelread(isc_nmhandle_t *handle) {
|
||||
isc_nmsocket_t *sock = NULL;
|
||||
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
|
||||
sock = handle->sock;
|
||||
|
||||
REQUIRE(sock->type == isc_nm_tcpdnssocket);
|
||||
|
||||
if (sock->client && sock->rcb.recv != NULL) {
|
||||
sock->rcb.recv(handle, ISC_R_CANCELED, NULL, sock->rcbarg);
|
||||
isc__nmsocket_clearcb(sock);
|
||||
isc__nm_tcp_cancelread(sock->outerhandle);
|
||||
return (true);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,580 @@
|
||||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <uv.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/condition.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/netmgr.h>
|
||||
#include <isc/quota.h>
|
||||
#include <isc/random.h>
|
||||
#include <isc/refcount.h>
|
||||
#include <isc/region.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/sockaddr.h>
|
||||
#include <isc/stdtime.h>
|
||||
#include <isc/thread.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include "netmgr-int.h"
|
||||
#include "uv-compat.h"
|
||||
|
||||
#define TLS_CHECK_RV INT_MAX
|
||||
|
||||
static isc_result_t
|
||||
tls_error_to_result(int tls_err) {
|
||||
switch (tls_err) {
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return (ISC_R_EOF);
|
||||
default:
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tls_do_bio(isc_nmsocket_t *sock, int rv);
|
||||
|
||||
static void
|
||||
tls_close_direct(isc_nmsocket_t *sock);
|
||||
|
||||
static isc_result_t
|
||||
tls_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req);
|
||||
|
||||
static void
|
||||
tls_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
|
||||
isc_nmsocket_t *sock = (isc_nmsocket_t *)cbarg;
|
||||
|
||||
UNUSED(handle);
|
||||
UNUSED(eresult);
|
||||
|
||||
tls_do_bio(sock, TLS_CHECK_RV);
|
||||
}
|
||||
|
||||
static void
|
||||
tls_do_bio(isc_nmsocket_t *sock, int rv) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
int pending, tls_err = 0;
|
||||
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
|
||||
if (rv == TLS_CHECK_RV) {
|
||||
char buf[1];
|
||||
rv = SSL_peek(sock->tls.ssl, buf, 1);
|
||||
if (rv == 1) {
|
||||
if (sock->rcb.recv != NULL &&
|
||||
!atomic_load(&sock->readpaused)) {
|
||||
isc_region_t region = {
|
||||
isc_mem_get(sock->mgr->mctx, 4096), 4096
|
||||
};
|
||||
isc_region_t dregion;
|
||||
|
||||
memset(region.base, 0, region.length);
|
||||
rv = SSL_read(sock->tls.ssl, region.base,
|
||||
region.length);
|
||||
|
||||
dregion = (isc_region_t){ region.base, rv };
|
||||
sock->rcb.recv(sock->statichandle,
|
||||
ISC_R_SUCCESS, &dregion,
|
||||
sock->rcbarg);
|
||||
isc_mem_put(sock->mgr->mctx, region.base, 4096);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pending = BIO_pending(sock->tls.app_bio);
|
||||
if (pending > 0) {
|
||||
char *p = malloc(pending);
|
||||
|
||||
rv = BIO_read(sock->tls.app_bio, p, pending);
|
||||
result = isc_nm_send(sock->outerhandle,
|
||||
&(isc_region_t){ (unsigned char *)p, rv },
|
||||
tls_senddone, sock);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
tls_err = SSL_get_error(sock->tls.ssl, rv);
|
||||
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR,
|
||||
ISC_LOG_DEBUG(30), "SSL error code in BIO: %d", tls_err);
|
||||
if (tls_err == 0) {
|
||||
return;
|
||||
} else if (tls_err == SSL_ERROR_WANT_WRITE) {
|
||||
isc_nm_pauseread(sock->outerhandle);
|
||||
pending = BIO_pending(sock->tls.app_bio);
|
||||
if (pending > 0) {
|
||||
char *p = malloc(pending);
|
||||
rv = BIO_read(sock->tls.app_bio, p, pending);
|
||||
result = isc_nm_send(
|
||||
sock->outerhandle,
|
||||
&(isc_region_t){ (unsigned char *)p, rv },
|
||||
tls_senddone, sock);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
} else if (tls_err == SSL_ERROR_WANT_READ) {
|
||||
isc_nm_resumeread(sock->outerhandle);
|
||||
} else {
|
||||
result = tls_error_to_result(tls_err);
|
||||
goto error;
|
||||
}
|
||||
return;
|
||||
|
||||
error:
|
||||
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR,
|
||||
ISC_LOG_ERROR, "SSL error in BIO: %d", tls_err);
|
||||
if (sock->rcb.recv != NULL) {
|
||||
sock->rcb.recv(sock->statichandle, result, NULL, sock->rcbarg);
|
||||
} else {
|
||||
tls_close_direct(sock);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tls_readcb(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region,
|
||||
void *cbarg) {
|
||||
isc_nmsocket_t *tlssock = (isc_nmsocket_t *)cbarg;
|
||||
int rv;
|
||||
|
||||
REQUIRE(VALID_NMSOCK(tlssock));
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
REQUIRE(tlssock->tid == isc_nm_tid());
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
/* Connection closed */
|
||||
/*
|
||||
* TODO accept_cb should be called if we're not
|
||||
* initialized yet!
|
||||
*/
|
||||
if (tlssock->rcb.recv != NULL) {
|
||||
tlssock->rcb.recv(tlssock->statichandle, result, region,
|
||||
tlssock->rcbarg);
|
||||
}
|
||||
isc__nm_tls_close(tlssock);
|
||||
return;
|
||||
}
|
||||
|
||||
rv = BIO_write(tlssock->tls.app_bio, region->base, region->length);
|
||||
INSIST(rv > 0 && (unsigned int)rv == region->length);
|
||||
tls_do_bio(tlssock, TLS_CHECK_RV);
|
||||
if (tlssock->tls.state != IO) {
|
||||
if (SSL_is_init_finished(tlssock->tls.ssl) == 1) {
|
||||
if (tlssock->server) {
|
||||
tlssock->listener->accept_cb.accept(
|
||||
tlssock->statichandle, ISC_R_SUCCESS,
|
||||
tlssock->listener->accept_cbarg);
|
||||
} else {
|
||||
isc_nmhandle_t *tlshandle =
|
||||
isc__nmhandle_get(tlssock, NULL, NULL);
|
||||
tlssock->accept_cb.connect(
|
||||
tlshandle, ISC_R_SUCCESS,
|
||||
tlssock->accept_cbarg);
|
||||
}
|
||||
tlssock->tls.state = IO;
|
||||
|
||||
/* We need to do it again - to flush incoming buffer */
|
||||
tls_do_bio(tlssock, TLS_CHECK_RV);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
initialize_tls(isc_nmsocket_t *sock, bool server) {
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
|
||||
sock->tls.ssl = SSL_new(sock->tls.ctx);
|
||||
if (sock->tls.ssl == NULL) {
|
||||
return (ISC_R_TLSERROR);
|
||||
}
|
||||
|
||||
if (BIO_new_bio_pair(&(sock->tls.ssl_bio), 0, &(sock->tls.app_bio),
|
||||
0) != 1) {
|
||||
SSL_free(sock->tls.ssl);
|
||||
return (ISC_R_TLSERROR);
|
||||
}
|
||||
|
||||
SSL_set_bio(sock->tls.ssl, sock->tls.ssl_bio, sock->tls.ssl_bio);
|
||||
if (server) {
|
||||
SSL_set_accept_state(sock->tls.ssl);
|
||||
} else {
|
||||
SSL_set_connect_state(sock->tls.ssl);
|
||||
}
|
||||
|
||||
isc_nm_read(sock->outerhandle, tls_readcb, sock);
|
||||
tls_do_bio(sock, TLS_CHECK_RV);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
tlslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
||||
isc_nmsocket_t *tlslistensock = (isc_nmsocket_t *)cbarg;
|
||||
isc_nmsocket_t *tlssock = NULL;
|
||||
|
||||
REQUIRE(VALID_NMSOCK(tlslistensock));
|
||||
REQUIRE(tlslistensock->type == isc_nm_tlslistener);
|
||||
|
||||
/* If accept() was unsuccessful we can't do anything */
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to create a 'wrapper' tlssocket for this connection.
|
||||
*/
|
||||
tlssock = isc_mem_get(handle->sock->mgr->mctx, sizeof(*tlssock));
|
||||
isc__nmsocket_init(tlssock, handle->sock->mgr, isc_nm_tlssocket,
|
||||
handle->sock->iface);
|
||||
|
||||
tlssock->extrahandlesize = tlslistensock->extrahandlesize;
|
||||
isc__nmsocket_attach(tlslistensock, &tlssock->listener);
|
||||
isc_nmhandle_attach(handle, &tlssock->outerhandle);
|
||||
tlssock->peer = handle->sock->peer;
|
||||
tlssock->read_timeout = handle->sock->mgr->init;
|
||||
tlssock->tid = isc_nm_tid();
|
||||
tlssock->tls.server = true;
|
||||
isc__nmhandle_get(tlssock, NULL, NULL);
|
||||
|
||||
uv_timer_init(&tlssock->mgr->workers[isc_nm_tid()].loop,
|
||||
&tlssock->timer);
|
||||
tlssock->timer.data = tlssock;
|
||||
tlssock->timer_initialized = true;
|
||||
tlssock->tls.ctx = tlslistensock->tls.ctx;
|
||||
|
||||
result = initialize_tls(tlssock, true);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
/* TODO: catch failure code, detach tlssock, and log the error */
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface,
|
||||
isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
|
||||
size_t extrahandlesize, int backlog, isc_quota_t *quota,
|
||||
SSL_CTX *sslctx, isc_nmsocket_t **sockp) {
|
||||
isc_result_t result;
|
||||
isc_nmsocket_t *tlssock = isc_mem_get(mgr->mctx, sizeof(*tlssock));
|
||||
|
||||
isc__nmsocket_init(tlssock, mgr, isc_nm_tlslistener, iface);
|
||||
tlssock->accept_cb.accept = accept_cb;
|
||||
tlssock->accept_cbarg = accept_cbarg;
|
||||
tlssock->extrahandlesize = extrahandlesize;
|
||||
tlssock->tls.ctx = sslctx;
|
||||
|
||||
/*
|
||||
* tlssock will be a TLS 'wrapper' around an unencrypted stream.
|
||||
* We set tlssock->outer to a socket listening for a TCP connection.
|
||||
*/
|
||||
result = isc_nm_listentcp(mgr, iface, tlslisten_acceptcb, tlssock,
|
||||
extrahandlesize, backlog, quota,
|
||||
&tlssock->outer);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
atomic_store(&tlssock->listening, true);
|
||||
*sockp = tlssock;
|
||||
return (ISC_R_SUCCESS);
|
||||
} else {
|
||||
atomic_store(&tlssock->closed, true);
|
||||
isc__nmsocket_detach(&tlssock);
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_async_tlssend(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc_result_t result;
|
||||
isc__netievent_tcpsend_t *ievent = (isc__netievent_tcpsend_t *)ev0;
|
||||
|
||||
REQUIRE(worker->id == ievent->sock->tid);
|
||||
|
||||
if (!atomic_load(&ievent->sock->active)) {
|
||||
return;
|
||||
}
|
||||
|
||||
result = tls_send_direct(ievent->sock, ievent->req);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
ievent->req->cb.send(ievent->req->handle, result,
|
||||
ievent->req->cbarg);
|
||||
isc__nm_uvreq_put(&ievent->req, ievent->req->handle->sock);
|
||||
}
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
tls_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
|
||||
int rv;
|
||||
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
REQUIRE(sock->type == isc_nm_tlssocket);
|
||||
|
||||
rv = SSL_write(sock->tls.ssl, req->uvbuf.base, req->uvbuf.len);
|
||||
if (rv < 0) {
|
||||
isc__nm_uvreq_put(&req, sock);
|
||||
return (isc__nm_uverr2result(rv));
|
||||
}
|
||||
INSIST((unsigned)rv == req->uvbuf.len);
|
||||
|
||||
tls_do_bio(sock, TLS_CHECK_RV);
|
||||
req->cb.send(sock->statichandle, ISC_R_SUCCESS, req->cbarg);
|
||||
isc__nm_uvreq_put(&req, sock);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_tls_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
void *cbarg) {
|
||||
isc_nmsocket_t *sock = handle->sock;
|
||||
isc__netievent_tcpsend_t *ievent = NULL;
|
||||
isc__nm_uvreq_t *uvreq = NULL;
|
||||
|
||||
REQUIRE(sock->type == isc_nm_tlssocket);
|
||||
|
||||
uvreq = isc__nm_uvreq_get(sock->mgr, sock);
|
||||
uvreq->uvbuf.base = (char *)region->base;
|
||||
uvreq->uvbuf.len = region->length;
|
||||
isc_nmhandle_attach(handle, &uvreq->handle);
|
||||
uvreq->cb.send = cb;
|
||||
uvreq->cbarg = cbarg;
|
||||
|
||||
/*
|
||||
* We need to create an event and pass it using async channel
|
||||
*/
|
||||
ievent = isc__nm_get_ievent(sock->mgr, netievent_tlssend);
|
||||
ievent->sock = sock;
|
||||
ievent->req = uvreq;
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_async_tls_startread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__netievent_startread_t *ievent = (isc__netievent_startread_t *)ev0;
|
||||
isc_nmsocket_t *sock = ievent->sock;
|
||||
|
||||
REQUIRE(worker->id == isc_nm_tid());
|
||||
|
||||
tls_do_bio(sock, TLS_CHECK_RV);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_tls_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));
|
||||
|
||||
sock = handle->sock;
|
||||
sock->rcb.recv = cb;
|
||||
sock->rcbarg = cbarg;
|
||||
|
||||
ievent = isc__nm_get_ievent(sock->mgr, netievent_tlsstartread);
|
||||
ievent->sock = sock;
|
||||
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_tls_pauseread(isc_nmsocket_t *sock) {
|
||||
atomic_store(&sock->readpaused, true);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_tls_resumeread(isc_nmsocket_t *sock) {
|
||||
atomic_store(&sock->readpaused, false);
|
||||
tls_do_bio(sock, TLS_CHECK_RV);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
timer_close_cb(uv_handle_t *handle) {
|
||||
isc_nmsocket_t *sock = (isc_nmsocket_t *)uv_handle_get_data(handle);
|
||||
INSIST(VALID_NMSOCK(sock));
|
||||
isc__nmsocket_detach(&sock);
|
||||
}
|
||||
|
||||
static void
|
||||
tls_close_direct(isc_nmsocket_t *sock) {
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
|
||||
/* We don't need atomics here, it's all in single network thread */
|
||||
if (sock->timer_initialized) {
|
||||
/*
|
||||
* We need to fire the timer callback to clean it up,
|
||||
* it will then call us again (via detach) so that we
|
||||
* can finally close the socket.
|
||||
*/
|
||||
sock->timer_initialized = false;
|
||||
uv_timer_stop(&sock->timer);
|
||||
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
|
||||
} else {
|
||||
/*
|
||||
* At this point we're certain that there are no external
|
||||
* references, we can close everything.
|
||||
*/
|
||||
if (sock->outerhandle != NULL) {
|
||||
isc_nm_pauseread(sock->outerhandle);
|
||||
isc_nmhandle_detach(&sock->outerhandle);
|
||||
}
|
||||
if (sock->listener != NULL) {
|
||||
isc__nmsocket_detach(&sock->listener);
|
||||
}
|
||||
atomic_store(&sock->closed, true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_tls_close(isc_nmsocket_t *sock) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
REQUIRE(sock->type == isc_nm_tlssocket);
|
||||
|
||||
if (sock->tid == isc_nm_tid()) {
|
||||
tls_close_direct(sock);
|
||||
} else {
|
||||
isc__netievent_tlsclose_t *ievent =
|
||||
isc__nm_get_ievent(sock->mgr, netievent_tlsclose);
|
||||
|
||||
ievent->sock = sock;
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_async_tlsclose(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__netievent_tlsclose_t *ievent = (isc__netievent_tlsclose_t *)ev0;
|
||||
|
||||
REQUIRE(worker->id == ievent->sock->tid);
|
||||
|
||||
tls_close_direct(ievent->sock);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_tls_stoplistening(isc_nmsocket_t *sock) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
REQUIRE(sock->type == isc_nm_tlslistener);
|
||||
|
||||
atomic_store(&sock->listening, false);
|
||||
atomic_store(&sock->closed, true);
|
||||
sock->rcb.recv = NULL;
|
||||
sock->rcbarg = NULL;
|
||||
|
||||
if (sock->outer != NULL) {
|
||||
isc_nm_stoplistening(sock->outer);
|
||||
isc__nmsocket_detach(&sock->outer);
|
||||
}
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
|
||||
isc_nm_cb_t cb, void *cbarg, SSL_CTX *ctx,
|
||||
size_t extrahandlesize) {
|
||||
isc_nmsocket_t *nsock = NULL, *tmp = NULL;
|
||||
isc__netievent_tlsconnect_t *ievent = NULL;
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
|
||||
REQUIRE(VALID_NM(mgr));
|
||||
|
||||
nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
|
||||
isc__nmsocket_init(nsock, mgr, isc_nm_tlssocket, local);
|
||||
nsock->extrahandlesize = extrahandlesize;
|
||||
nsock->result = ISC_R_SUCCESS;
|
||||
nsock->accept_cb.connect = cb;
|
||||
nsock->accept_cbarg = cbarg;
|
||||
nsock->tls.ctx = ctx;
|
||||
|
||||
ievent = isc__nm_get_ievent(mgr, netievent_tlsconnect);
|
||||
ievent->sock = nsock;
|
||||
ievent->local = local->addr;
|
||||
ievent->peer = peer->addr;
|
||||
ievent->ctx = ctx;
|
||||
|
||||
/*
|
||||
* Async callbacks can dereference the socket in the meantime,
|
||||
* we need to hold an additional reference to it.
|
||||
*/
|
||||
isc__nmsocket_attach(nsock, &tmp);
|
||||
|
||||
if (isc__nm_in_netthread()) {
|
||||
nsock->tid = isc_nm_tid();
|
||||
isc__nm_async_tlsconnect(&mgr->workers[nsock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
isc__nm_put_ievent(mgr, ievent);
|
||||
} else {
|
||||
nsock->tid = isc_random_uniform(mgr->nworkers);
|
||||
isc__nm_enqueue_ievent(&mgr->workers[nsock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
}
|
||||
|
||||
isc__nmsocket_detach(&tmp);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
tls_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
||||
isc_nmsocket_t *tlssock = (isc_nmsocket_t *)cbarg;
|
||||
|
||||
REQUIRE(VALID_NMSOCK(tlssock));
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
tlssock->accept_cb.connect(NULL, result, tlssock->accept_cbarg);
|
||||
return;
|
||||
}
|
||||
|
||||
INSIST(VALID_NMHANDLE(handle));
|
||||
|
||||
isc_nmhandle_attach(handle, &tlssock->outerhandle);
|
||||
result = initialize_tls(tlssock, false);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
tlssock->accept_cb.connect(NULL, result, tlssock->accept_cbarg);
|
||||
/* TODO CLOSE! */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__netievent_tlsconnect_t *ievent =
|
||||
(isc__netievent_tlsconnect_t *)ev0;
|
||||
isc_nmsocket_t *tlssock = ievent->sock;
|
||||
isc_result_t result;
|
||||
|
||||
UNUSED(worker);
|
||||
|
||||
tlssock->tid = isc_nm_tid();
|
||||
uv_timer_init(&tlssock->mgr->workers[isc_nm_tid()].loop,
|
||||
&tlssock->timer);
|
||||
tlssock->timer.data = tlssock;
|
||||
tlssock->timer_initialized = true;
|
||||
|
||||
result = isc_nm_tcpconnect(worker->mgr, (isc_nmiface_t *)&ievent->local,
|
||||
(isc_nmiface_t *)&ievent->peer,
|
||||
tls_connect_cb, tlssock, 0);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
tlssock->accept_cb.connect(NULL, result, tlssock->accept_cbarg);
|
||||
/* TODO CLOSE! */
|
||||
return;
|
||||
}
|
||||
}
|
||||
+310
-29
@@ -40,6 +40,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) {
|
||||
@@ -80,7 +83,7 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
|
||||
csock->rcb.recv = cb;
|
||||
csock->rcbarg = cbarg;
|
||||
csock->fd = socket(family, SOCK_DGRAM, 0);
|
||||
INSIST(csock->fd >= 0);
|
||||
RUNTIME_CHECK(csock->fd >= 0);
|
||||
|
||||
/*
|
||||
* This is SO_REUSE**** hell:
|
||||
@@ -159,7 +162,7 @@ udp_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
|
||||
}
|
||||
|
||||
/*
|
||||
* handle 'udplisten' async call - start listening on a socket.
|
||||
* Asynchrnous 'udplisten' call handler: start listening on a UDP socket.
|
||||
*/
|
||||
void
|
||||
isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
@@ -223,7 +226,7 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
}
|
||||
|
||||
static void
|
||||
udp_close_cb(uv_handle_t *handle) {
|
||||
udp_stop_cb(uv_handle_t *handle) {
|
||||
isc_nmsocket_t *sock = uv_handle_get_data(handle);
|
||||
atomic_store(&sock->closed, true);
|
||||
|
||||
@@ -236,7 +239,7 @@ stop_udp_child(isc_nmsocket_t *sock) {
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
|
||||
uv_udp_recv_stop(&sock->uv_handle.udp);
|
||||
uv_close((uv_handle_t *)&sock->uv_handle.udp, udp_close_cb);
|
||||
uv_close((uv_handle_t *)&sock->uv_handle.udp, udp_stop_cb);
|
||||
|
||||
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CLOSE]);
|
||||
|
||||
@@ -311,7 +314,7 @@ isc__nm_udp_stoplistening(isc_nmsocket_t *sock) {
|
||||
}
|
||||
|
||||
/*
|
||||
* handle 'udpstop' async call - stop listening on a socket.
|
||||
* Asynchrnous 'udpstop' call handler: stop listening on a UDP socket.
|
||||
*/
|
||||
void
|
||||
isc__nm_async_udpstop(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
@@ -375,9 +378,9 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Three reasons to return now without processing:
|
||||
* - If addr == NULL that's the end of stream - we can
|
||||
* free the buffer and bail.
|
||||
* Three possible reasons to return now without processing:
|
||||
* - If addr == NULL, in which case it's the end of stream;
|
||||
* we can free the buffer and bail.
|
||||
* - If we're simulating a firewall blocking UDP packets
|
||||
* bigger than 'maxudp' bytes for testing purposes.
|
||||
* - If the socket is no longer active.
|
||||
@@ -395,7 +398,11 @@ 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 (!sock->connected) {
|
||||
nmhandle = isc__nmhandle_get(sock, &sockaddr, NULL);
|
||||
} else {
|
||||
nmhandle = sock->statichandle;
|
||||
}
|
||||
region.base = (unsigned char *)buf->base;
|
||||
region.length = nrecv;
|
||||
|
||||
@@ -414,24 +421,24 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
|
||||
* If the recv callback wants to hold on to the handle,
|
||||
* it needs to attach to it.
|
||||
*/
|
||||
isc_nmhandle_unref(nmhandle);
|
||||
isc_nmhandle_detach(&nmhandle);
|
||||
}
|
||||
|
||||
/*
|
||||
* isc__nm_udp_send sends buf to a peer on a socket.
|
||||
* It tries to find a proper sibling/child socket so that we won't have
|
||||
* to jump to another thread.
|
||||
* Send the data in 'region' to a peer via a UDP socket. We try to find
|
||||
* a proper sibling/child socket so that we won't have to jump to another
|
||||
* thread.
|
||||
*/
|
||||
isc_result_t
|
||||
isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
void *cbarg) {
|
||||
isc_nmsocket_t *psock = NULL, *rsock = NULL;
|
||||
isc_nmsocket_t *sock = handle->sock;
|
||||
isc_nmsocket_t *psock = NULL, *rsock = sock;
|
||||
isc_sockaddr_t *peer = &handle->peer;
|
||||
isc__netievent_udpsend_t *ievent = NULL;
|
||||
isc__nm_uvreq_t *uvreq = NULL;
|
||||
int ntid;
|
||||
uint32_t maxudp = atomic_load(&sock->mgr->maxudp);
|
||||
int ntid;
|
||||
|
||||
/*
|
||||
* We're simulating a firewall blocking UDP packets bigger than
|
||||
@@ -442,16 +449,16 @@ isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
* we need to do so here.
|
||||
*/
|
||||
if (maxudp != 0 && region->length > maxudp) {
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_nmhandle_detach(&handle);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
if (sock->type == isc_nm_udpsocket) {
|
||||
if (sock->type == isc_nm_udpsocket && !sock->client) {
|
||||
INSIST(sock->parent != NULL);
|
||||
psock = sock->parent;
|
||||
} else if (sock->type == isc_nm_udplistener) {
|
||||
psock = sock;
|
||||
} else {
|
||||
} else if (!sock->client) {
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
}
|
||||
@@ -467,20 +474,21 @@ isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
*/
|
||||
if (isc__nm_in_netthread()) {
|
||||
ntid = isc_nm_tid();
|
||||
} else if (sock->type == isc_nm_udpsocket) {
|
||||
} else if (sock->type == isc_nm_udpsocket && !sock->client) {
|
||||
ntid = sock->tid;
|
||||
} else {
|
||||
ntid = (int)isc_random_uniform(sock->nchildren);
|
||||
}
|
||||
|
||||
rsock = &psock->children[ntid];
|
||||
if (psock != NULL) {
|
||||
rsock = &psock->children[ntid];
|
||||
}
|
||||
|
||||
uvreq = isc__nm_uvreq_get(sock->mgr, sock);
|
||||
uvreq->uvbuf.base = (char *)region->base;
|
||||
uvreq->uvbuf.len = region->length;
|
||||
|
||||
uvreq->handle = handle;
|
||||
isc_nmhandle_ref(uvreq->handle);
|
||||
isc_nmhandle_attach(handle, &uvreq->handle);
|
||||
|
||||
uvreq->cb.send = cb;
|
||||
uvreq->cbarg = cbarg;
|
||||
@@ -507,7 +515,7 @@ isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
}
|
||||
|
||||
/*
|
||||
* handle 'udpsend' async event - send a packet on the socket
|
||||
* Asynchronous 'udpsend' event handler: send a packet on a UDP socket.
|
||||
*/
|
||||
void
|
||||
isc__nm_async_udpsend(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
@@ -524,9 +532,6 @@ isc__nm_async_udpsend(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* udp_send_cb - callback
|
||||
*/
|
||||
static void
|
||||
udp_send_cb(uv_udp_send_t *req, int status) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
@@ -542,7 +547,6 @@ udp_send_cb(uv_udp_send_t *req, int status) {
|
||||
}
|
||||
|
||||
uvreq->cb.send(uvreq->handle, result, uvreq->cbarg);
|
||||
isc_nmhandle_unref(uvreq->handle);
|
||||
isc__nm_uvreq_put(&uvreq, uvreq->sock);
|
||||
}
|
||||
|
||||
@@ -553,6 +557,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;
|
||||
int rv;
|
||||
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
@@ -561,9 +566,10 @@ udp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
|
||||
if (!isc__nmsocket_active(sock)) {
|
||||
return (ISC_R_CANCELED);
|
||||
}
|
||||
isc_nmhandle_ref(req->handle);
|
||||
|
||||
sa = sock->connected ? NULL : &peer->type.sa;
|
||||
rv = uv_udp_send(&req->uv_req.udp_send, &sock->uv_handle.udp,
|
||||
&req->uvbuf, 1, &peer->type.sa, udp_send_cb);
|
||||
&req->uvbuf, 1, sa, udp_send_cb);
|
||||
if (rv < 0) {
|
||||
isc__nm_incstats(req->sock->mgr,
|
||||
req->sock->statsindex[STATID_SENDFAIL]);
|
||||
@@ -572,3 +578,278 @@ 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;
|
||||
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);
|
||||
handle = isc__nmhandle_get(sock, &ievent->peer, &sock->iface->addr);
|
||||
|
||||
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);
|
||||
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);
|
||||
sock->result = isc__nm_uverr2result(r);
|
||||
goto done;
|
||||
}
|
||||
|
||||
r = 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);
|
||||
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);
|
||||
sock->result = ISC_R_SUCCESS;
|
||||
|
||||
done:
|
||||
sock->rcb.connect(handle, sock->result, sock->rcbarg);
|
||||
|
||||
LOCK(&sock->lock);
|
||||
SIGNAL(&sock->cond);
|
||||
UNLOCK(&sock->lock);
|
||||
|
||||
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, 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->rcb.recv == NULL && sock->rcbarg == NULL);
|
||||
sock->rcb.connect = cb;
|
||||
sock->rcbarg = cbarg;
|
||||
sock->extrahandlesize = extrahandlesize;
|
||||
sock->peer = peer->addr;
|
||||
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);
|
||||
}
|
||||
|
||||
if (sock->result != ISC_R_SUCCESS) {
|
||||
result = sock->result;
|
||||
isc__nmsocket_detach(&sock);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
UNUSED(worker);
|
||||
|
||||
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;
|
||||
sock->rcb.recv = cb;
|
||||
sock->rcbarg = 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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
isc__nm_udp_cancelread(isc_nmhandle_t *handle) {
|
||||
isc_nmsocket_t *sock = NULL;
|
||||
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
|
||||
sock = handle->sock;
|
||||
|
||||
REQUIRE(sock->type == isc_nm_udpsocket);
|
||||
|
||||
if (sock->client && sock->rcb.recv != NULL) {
|
||||
sock->rcb.recv(handle, ISC_R_CANCELED, NULL, sock->rcbarg);
|
||||
isc__nmsocket_clearcb(sock);
|
||||
return (true);
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
+672
@@ -0,0 +1,672 @@
|
||||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <isc/url.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#ifndef BIT_AT
|
||||
#define BIT_AT(a, i) \
|
||||
(!!((unsigned int)(a)[(unsigned int)(i) >> 3] & \
|
||||
(1 << ((unsigned int)(i)&7))))
|
||||
#endif
|
||||
|
||||
#if HTTP_PARSER_STRICT
|
||||
#define T(v) 0
|
||||
#else
|
||||
#define T(v) v
|
||||
#endif
|
||||
|
||||
static const uint8_t normal_url_char[32] = {
|
||||
/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
|
||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
|
||||
/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
|
||||
0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0,
|
||||
/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
|
||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
|
||||
/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
|
||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
|
||||
/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
|
||||
0 | 2 | 4 | 0 | 16 | 32 | 64 | 128,
|
||||
/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
|
||||
/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
|
||||
};
|
||||
|
||||
#undef T
|
||||
|
||||
typedef enum {
|
||||
s_dead = 1, /* important that this is > 0 */
|
||||
|
||||
s_start_req_or_res,
|
||||
s_res_or_resp_H,
|
||||
s_start_res,
|
||||
s_res_H,
|
||||
s_res_HT,
|
||||
s_res_HTT,
|
||||
s_res_HTTP,
|
||||
s_res_http_major,
|
||||
s_res_http_dot,
|
||||
s_res_http_minor,
|
||||
s_res_http_end,
|
||||
s_res_first_status_code,
|
||||
s_res_status_code,
|
||||
s_res_status_start,
|
||||
s_res_status,
|
||||
s_res_line_almost_done,
|
||||
|
||||
s_start_req,
|
||||
|
||||
s_req_method,
|
||||
s_req_spaces_before_url,
|
||||
s_req_schema,
|
||||
s_req_schema_slash,
|
||||
s_req_schema_slash_slash,
|
||||
s_req_server_start,
|
||||
s_req_server,
|
||||
s_req_server_with_at,
|
||||
s_req_path,
|
||||
s_req_query_string_start,
|
||||
s_req_query_string,
|
||||
s_req_fragment_start,
|
||||
s_req_fragment,
|
||||
s_req_http_start,
|
||||
s_req_http_H,
|
||||
s_req_http_HT,
|
||||
s_req_http_HTT,
|
||||
s_req_http_HTTP,
|
||||
s_req_http_I,
|
||||
s_req_http_IC,
|
||||
s_req_http_major,
|
||||
s_req_http_dot,
|
||||
s_req_http_minor,
|
||||
s_req_http_end,
|
||||
s_req_line_almost_done,
|
||||
|
||||
s_header_field_start,
|
||||
s_header_field,
|
||||
s_header_value_discard_ws,
|
||||
s_header_value_discard_ws_almost_done,
|
||||
s_header_value_discard_lws,
|
||||
s_header_value_start,
|
||||
s_header_value,
|
||||
s_header_value_lws,
|
||||
|
||||
s_header_almost_done,
|
||||
|
||||
s_chunk_size_start,
|
||||
s_chunk_size,
|
||||
s_chunk_parameters,
|
||||
s_chunk_size_almost_done,
|
||||
|
||||
s_headers_almost_done,
|
||||
s_headers_done,
|
||||
|
||||
/*
|
||||
* Important: 's_headers_done' must be the last 'header' state. All
|
||||
* states beyond this must be 'body' states. It is used for overflow
|
||||
* checking. See the PARSING_HEADER() macro.
|
||||
*/
|
||||
|
||||
s_chunk_data,
|
||||
s_chunk_data_almost_done,
|
||||
s_chunk_data_done,
|
||||
|
||||
s_body_identity,
|
||||
s_body_identity_eof,
|
||||
|
||||
s_message_done
|
||||
} state_t;
|
||||
|
||||
typedef enum {
|
||||
s_http_host_dead = 1,
|
||||
s_http_userinfo_start,
|
||||
s_http_userinfo,
|
||||
s_http_host_start,
|
||||
s_http_host_v6_start,
|
||||
s_http_host,
|
||||
s_http_host_v6,
|
||||
s_http_host_v6_end,
|
||||
s_http_host_v6_zone_start,
|
||||
s_http_host_v6_zone,
|
||||
s_http_host_port_start,
|
||||
s_http_host_port
|
||||
} host_state_t;
|
||||
|
||||
/* Macros for character classes; depends on strict-mode */
|
||||
#define LOWER(c) (unsigned char)(c | 0x20)
|
||||
#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
|
||||
#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
|
||||
#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
|
||||
#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
|
||||
#define IS_MARK(c) \
|
||||
((c) == '-' || (c) == '_' || (c) == '.' || (c) == '!' || (c) == '~' || \
|
||||
(c) == '*' || (c) == '\'' || (c) == '(' || (c) == ')')
|
||||
#define IS_USERINFO_CHAR(c) \
|
||||
(IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || (c) == ';' || \
|
||||
(c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || (c) == '$' || \
|
||||
(c) == ',')
|
||||
|
||||
#if HTTP_PARSER_STRICT
|
||||
#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
|
||||
#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
|
||||
#else
|
||||
#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c) || ((c)&0x80))
|
||||
#define IS_HOST_CHAR(c) \
|
||||
(IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Our URL parser.
|
||||
*
|
||||
* This is designed to be shared by http_parser_execute() for URL validation,
|
||||
* hence it has a state transition + byte-for-byte interface. In addition, it
|
||||
* is meant to be embedded in http_parser_parse_url(), which does the dirty
|
||||
* work of turning state transitions URL components for its API.
|
||||
*
|
||||
* This function should only be invoked with non-space characters. It is
|
||||
* assumed that the caller cares about (and can detect) the transition between
|
||||
* URL and non-URL states by looking for these.
|
||||
*/
|
||||
static state_t
|
||||
parse_url_char(state_t s, const char ch) {
|
||||
if (ch == ' ' || ch == '\r' || ch == '\n') {
|
||||
return (s_dead);
|
||||
}
|
||||
|
||||
#if HTTP_PARSER_STRICT
|
||||
if (ch == '\t' || ch == '\f') {
|
||||
return (s_dead);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (s) {
|
||||
case s_req_spaces_before_url:
|
||||
/* Proxied requests are followed by scheme of an absolute URI
|
||||
* (alpha). All methods except CONNECT are followed by '/' or
|
||||
* '*'.
|
||||
*/
|
||||
|
||||
if (ch == '/' || ch == '*') {
|
||||
return (s_req_path);
|
||||
}
|
||||
|
||||
if (IS_ALPHA(ch)) {
|
||||
return (s_req_schema);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_schema:
|
||||
if (IS_ALPHA(ch)) {
|
||||
return (s);
|
||||
}
|
||||
|
||||
if (ch == ':') {
|
||||
return (s_req_schema_slash);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_schema_slash:
|
||||
if (ch == '/') {
|
||||
return (s_req_schema_slash_slash);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_schema_slash_slash:
|
||||
if (ch == '/') {
|
||||
return (s_req_server_start);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_server_with_at:
|
||||
if (ch == '@') {
|
||||
return (s_dead);
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case s_req_server_start:
|
||||
case s_req_server:
|
||||
if (ch == '/') {
|
||||
return (s_req_path);
|
||||
}
|
||||
|
||||
if (ch == '?') {
|
||||
return (s_req_query_string_start);
|
||||
}
|
||||
|
||||
if (ch == '@') {
|
||||
return (s_req_server_with_at);
|
||||
}
|
||||
|
||||
if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
|
||||
return (s_req_server);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_path:
|
||||
if (IS_URL_CHAR(ch)) {
|
||||
return (s);
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case '?':
|
||||
return (s_req_query_string_start);
|
||||
|
||||
case '#':
|
||||
return (s_req_fragment_start);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_query_string_start:
|
||||
case s_req_query_string:
|
||||
if (IS_URL_CHAR(ch)) {
|
||||
return (s_req_query_string);
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case '?':
|
||||
/* allow extra '?' in query string */
|
||||
return (s_req_query_string);
|
||||
|
||||
case '#':
|
||||
return (s_req_fragment_start);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_fragment_start:
|
||||
if (IS_URL_CHAR(ch)) {
|
||||
return (s_req_fragment);
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case '?':
|
||||
return (s_req_fragment);
|
||||
|
||||
case '#':
|
||||
return (s);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_fragment:
|
||||
if (IS_URL_CHAR(ch)) {
|
||||
return (s);
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case '?':
|
||||
case '#':
|
||||
return (s);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We should never fall out of the switch above unless there's an
|
||||
* error.
|
||||
*/
|
||||
return (s_dead);
|
||||
}
|
||||
|
||||
static host_state_t
|
||||
http_parse_host_char(host_state_t s, const char ch) {
|
||||
switch (s) {
|
||||
case s_http_userinfo:
|
||||
case s_http_userinfo_start:
|
||||
if (ch == '@') {
|
||||
return (s_http_host_start);
|
||||
}
|
||||
|
||||
if (IS_USERINFO_CHAR(ch)) {
|
||||
return (s_http_userinfo);
|
||||
}
|
||||
break;
|
||||
|
||||
case s_http_host_start:
|
||||
if (ch == '[') {
|
||||
return (s_http_host_v6_start);
|
||||
}
|
||||
|
||||
if (IS_HOST_CHAR(ch)) {
|
||||
return (s_http_host);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_http_host:
|
||||
if (IS_HOST_CHAR(ch)) {
|
||||
return (s_http_host);
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case s_http_host_v6_end:
|
||||
if (ch == ':') {
|
||||
return (s_http_host_port_start);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_http_host_v6:
|
||||
if (ch == ']') {
|
||||
return (s_http_host_v6_end);
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case s_http_host_v6_start:
|
||||
if (IS_HEX(ch) || ch == ':' || ch == '.') {
|
||||
return (s_http_host_v6);
|
||||
}
|
||||
|
||||
if (s == s_http_host_v6 && ch == '%') {
|
||||
return (s_http_host_v6_zone_start);
|
||||
}
|
||||
break;
|
||||
|
||||
case s_http_host_v6_zone:
|
||||
if (ch == ']') {
|
||||
return (s_http_host_v6_end);
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case s_http_host_v6_zone_start:
|
||||
/* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */
|
||||
if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' ||
|
||||
ch == '_' || ch == '~')
|
||||
{
|
||||
return (s_http_host_v6_zone);
|
||||
}
|
||||
break;
|
||||
|
||||
case s_http_host_port:
|
||||
case s_http_host_port_start:
|
||||
if (IS_NUM(ch)) {
|
||||
return (s_http_host_port);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (s_http_host_dead);
|
||||
}
|
||||
|
||||
static int
|
||||
http_parse_host(const char *buf, isc_url_parser_t *up, int found_at) {
|
||||
host_state_t s;
|
||||
const char *p = NULL;
|
||||
size_t buflen = up->field_data[ISC_UF_HOST].off +
|
||||
up->field_data[ISC_UF_HOST].len;
|
||||
|
||||
REQUIRE((up->field_set & (1 << ISC_UF_HOST)) != 0);
|
||||
|
||||
up->field_data[ISC_UF_HOST].len = 0;
|
||||
|
||||
s = found_at ? s_http_userinfo_start : s_http_host_start;
|
||||
|
||||
for (p = buf + up->field_data[ISC_UF_HOST].off; p < buf + buflen; p++) {
|
||||
host_state_t new_s = http_parse_host_char(s, *p);
|
||||
|
||||
if (new_s == s_http_host_dead) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
switch (new_s) {
|
||||
case s_http_host:
|
||||
if (s != s_http_host) {
|
||||
up->field_data[ISC_UF_HOST].off =
|
||||
(uint16_t)(p - buf);
|
||||
}
|
||||
up->field_data[ISC_UF_HOST].len++;
|
||||
break;
|
||||
|
||||
case s_http_host_v6:
|
||||
if (s != s_http_host_v6) {
|
||||
up->field_data[ISC_UF_HOST].off =
|
||||
(uint16_t)(p - buf);
|
||||
}
|
||||
up->field_data[ISC_UF_HOST].len++;
|
||||
break;
|
||||
|
||||
case s_http_host_v6_zone_start:
|
||||
case s_http_host_v6_zone:
|
||||
up->field_data[ISC_UF_HOST].len++;
|
||||
break;
|
||||
|
||||
case s_http_host_port:
|
||||
if (s != s_http_host_port) {
|
||||
up->field_data[ISC_UF_PORT].off =
|
||||
(uint16_t)(p - buf);
|
||||
up->field_data[ISC_UF_PORT].len = 0;
|
||||
up->field_set |= (1 << ISC_UF_PORT);
|
||||
}
|
||||
up->field_data[ISC_UF_PORT].len++;
|
||||
break;
|
||||
|
||||
case s_http_userinfo:
|
||||
if (s != s_http_userinfo) {
|
||||
up->field_data[ISC_UF_USERINFO].off =
|
||||
(uint16_t)(p - buf);
|
||||
up->field_data[ISC_UF_USERINFO].len = 0;
|
||||
up->field_set |= (1 << ISC_UF_USERINFO);
|
||||
}
|
||||
up->field_data[ISC_UF_USERINFO].len++;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
s = new_s;
|
||||
}
|
||||
|
||||
/* Make sure we don't end somewhere unexpected */
|
||||
switch (s) {
|
||||
case s_http_host_start:
|
||||
case s_http_host_v6_start:
|
||||
case s_http_host_v6:
|
||||
case s_http_host_v6_zone_start:
|
||||
case s_http_host_v6_zone:
|
||||
case s_http_host_port_start:
|
||||
case s_http_userinfo:
|
||||
case s_http_userinfo_start:
|
||||
return (1);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
isc_url_parse(const char *buf, size_t buflen, bool is_connect,
|
||||
isc_url_parser_t *up) {
|
||||
state_t s;
|
||||
isc_url_field_t uf, old_uf;
|
||||
int found_at = 0;
|
||||
const char *p = NULL;
|
||||
|
||||
if (buflen == 0) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
up->port = up->field_set = 0;
|
||||
s = is_connect ? s_req_server_start : s_req_spaces_before_url;
|
||||
old_uf = ISC_UF_MAX;
|
||||
|
||||
for (p = buf; p < buf + buflen; p++) {
|
||||
s = parse_url_char(s, *p);
|
||||
|
||||
/* Figure out the next field that we're operating on */
|
||||
switch (s) {
|
||||
case s_dead:
|
||||
return (1);
|
||||
|
||||
/* Skip delimeters */
|
||||
case s_req_schema_slash:
|
||||
case s_req_schema_slash_slash:
|
||||
case s_req_server_start:
|
||||
case s_req_query_string_start:
|
||||
case s_req_fragment_start:
|
||||
continue;
|
||||
|
||||
case s_req_schema:
|
||||
uf = ISC_UF_SCHEMA;
|
||||
break;
|
||||
|
||||
case s_req_server_with_at:
|
||||
found_at = 1;
|
||||
|
||||
/* FALLTHROUGH*/
|
||||
case s_req_server:
|
||||
uf = ISC_UF_HOST;
|
||||
break;
|
||||
|
||||
case s_req_path:
|
||||
uf = ISC_UF_PATH;
|
||||
break;
|
||||
|
||||
case s_req_query_string:
|
||||
uf = ISC_UF_QUERY;
|
||||
break;
|
||||
|
||||
case s_req_fragment:
|
||||
uf = ISC_UF_FRAGMENT;
|
||||
break;
|
||||
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
}
|
||||
|
||||
/* Nothing's changed; soldier on */
|
||||
if (uf == old_uf) {
|
||||
up->field_data[uf].len++;
|
||||
continue;
|
||||
}
|
||||
|
||||
up->field_data[uf].off = (uint16_t)(p - buf);
|
||||
up->field_data[uf].len = 1;
|
||||
|
||||
up->field_set |= (1 << uf);
|
||||
old_uf = uf;
|
||||
}
|
||||
|
||||
/* host must be present if there is a schema */
|
||||
/* parsing http:///toto will fail */
|
||||
if ((up->field_set & (1 << ISC_UF_SCHEMA)) &&
|
||||
(up->field_set & (1 << ISC_UF_HOST)) == 0)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (up->field_set & (1 << ISC_UF_HOST)) {
|
||||
if (http_parse_host(buf, up, found_at) != 0) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* CONNECT requests can only contain "hostname:port" */
|
||||
if (is_connect &&
|
||||
up->field_set != ((1 << ISC_UF_HOST) | (1 << ISC_UF_PORT))) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (up->field_set & (1 << ISC_UF_PORT)) {
|
||||
uint16_t off;
|
||||
uint16_t len;
|
||||
const char *pp = NULL;
|
||||
const char *end = NULL;
|
||||
unsigned long v;
|
||||
|
||||
off = up->field_data[ISC_UF_PORT].off;
|
||||
len = up->field_data[ISC_UF_PORT].len;
|
||||
end = buf + off + len;
|
||||
|
||||
/*
|
||||
* NOTE: The characters are already validated and are in the
|
||||
* [0-9] range
|
||||
*/
|
||||
INSIST(off + len <= buflen);
|
||||
|
||||
v = 0;
|
||||
for (pp = buf + off; pp < end; p++) {
|
||||
v *= 10;
|
||||
v += *pp - '0';
|
||||
|
||||
/* Ports have a max value of 2^16 */
|
||||
if (v > 0xffff) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
up->port = (uint16_t)v;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -436,15 +436,15 @@ isc_netaddr_setzone
|
||||
isc_netaddr_totext
|
||||
isc_netaddr_unspec
|
||||
isc_netscope_pton
|
||||
isc_nmhandle_attach
|
||||
isc_nmhandle_detach
|
||||
isc_nmhandle_getdata
|
||||
isc_nmhandle_getextra
|
||||
isc_nmhandle_is_stream
|
||||
isc_nmhandle_netmgr
|
||||
isc_nmhandle_localaddr
|
||||
isc_nmhandle_peeraddr
|
||||
isc_nmhandle_ref
|
||||
isc_nmhandle_setdata
|
||||
isc_nmhandle_unref
|
||||
isc_nm_cancelread
|
||||
isc_nm_closedown
|
||||
isc_nm_destroy
|
||||
@@ -461,11 +461,14 @@ 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_tlsconnect
|
||||
isc_nm_tlsdnsconnect
|
||||
isc_nmsocket_close
|
||||
isc__nm_acquire_interlocked
|
||||
isc__nm_drop_interlocked
|
||||
@@ -694,6 +697,7 @@ isc_timermgr_destroy
|
||||
isc_timermgr_poke
|
||||
isc_tm_timegm
|
||||
isc_tm_strptime
|
||||
isc_url_parse
|
||||
isc_utf8_bom
|
||||
isc_utf8_valid
|
||||
isc_win32os_versioncheck
|
||||
|
||||
@@ -260,6 +260,9 @@
|
||||
<ClInclude Include="..\include\isc\types.h">
|
||||
<Filter>Library Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\include\isc\url.h">
|
||||
<Filter>Library Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\include\isc\utf8.h">
|
||||
<Filter>Library Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -614,6 +617,9 @@
|
||||
<ClCompile Include="..\tm.c">
|
||||
<Filter>Library Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\url.c">
|
||||
<Filter>Library Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\utf8.c">
|
||||
<Filter>Library Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -321,6 +321,7 @@ copy InstallFiles ..\Build\Release\
|
||||
<ClInclude Include="..\include\isc\timer.h" />
|
||||
<ClInclude Include="..\include\isc\tm.h" />
|
||||
<ClInclude Include="..\include\isc\types.h" />
|
||||
<ClInclude Include="..\include\isc\url.h" />
|
||||
<ClInclude Include="..\include\isc\utf8.h" />
|
||||
<ClInclude Include="..\include\isc\util.h" />
|
||||
@IF PKCS11
|
||||
@@ -425,6 +426,7 @@ copy InstallFiles ..\Build\Release\
|
||||
<ClCompile Include="..\taskpool.c" />
|
||||
<ClCompile Include="..\timer.c" />
|
||||
<ClCompile Include="..\tm.c" />
|
||||
<ClCompile Include="..\url.c" />
|
||||
<ClCompile Include="..\utf8.c" />
|
||||
@IF PKCS11
|
||||
<ClCompile Include="..\pk11.c" />
|
||||
|
||||
+2
-6
@@ -108,7 +108,6 @@ recv_data(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
||||
done:
|
||||
isc_nm_pauseread(handle);
|
||||
ccmsg->cb(handle, ccmsg->result, ccmsg->cbarg);
|
||||
isc_nmhandle_unref(handle);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -149,18 +148,14 @@ isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg, isc_nm_cb_t cb, void *cbarg) {
|
||||
ccmsg->result = ISC_R_UNEXPECTED; /* unknown right now */
|
||||
ccmsg->length_received = false;
|
||||
|
||||
isc_nmhandle_ref(ccmsg->handle);
|
||||
if (ccmsg->reading) {
|
||||
result = isc_nm_resumeread(ccmsg->handle);
|
||||
} else {
|
||||
result = isc_nm_read(ccmsg->handle, recv_data, ccmsg);
|
||||
ccmsg->reading = true;
|
||||
}
|
||||
if (result == ISC_R_CANCELED) {
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
ccmsg->reading = false;
|
||||
} else if (result != ISC_R_SUCCESS) {
|
||||
ccmsg->reading = false;
|
||||
isc_nmhandle_unref(ccmsg->handle);
|
||||
}
|
||||
|
||||
return (result);
|
||||
@@ -172,6 +167,7 @@ isccc_ccmsg_cancelread(isccc_ccmsg_t *ccmsg) {
|
||||
|
||||
if (ccmsg->reading) {
|
||||
isc_nm_cancelread(ccmsg->handle);
|
||||
ccmsg->reading = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,9 @@ void
|
||||
isccc_ccmsg_init(isc_mem_t *mctx, isc_nmhandle_t *handle, isccc_ccmsg_t *ccmsg);
|
||||
/*%
|
||||
* Associate a cc message state with a given memory context and
|
||||
* netmgr handle.
|
||||
* netmgr handle. (Note that the caller must hold a reference to
|
||||
* the handle during asynchronous ccmsg operations; the ccmsg code
|
||||
* does not hold the reference itself.)
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
|
||||
+20
-31
@@ -129,7 +129,7 @@
|
||||
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
LIBNS_EXTERNAL_DATA atomic_uint_fast32_t ns_client_requests;
|
||||
#else /* if defined(_WIN32) && !defined(_WIN64) */
|
||||
#else /* if defined(_WIN32) && !defined(_WIN64) */
|
||||
LIBNS_EXTERNAL_DATA atomic_uint_fast64_t ns_client_requests;
|
||||
#endif /* if defined(_WIN32) && !defined(_WIN64) */
|
||||
|
||||
@@ -275,7 +275,7 @@ static void
|
||||
client_senddone(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
||||
ns_client_t *client = cbarg;
|
||||
|
||||
REQUIRE(client->handle == handle);
|
||||
REQUIRE(client->sendhandle == handle);
|
||||
|
||||
CTRACE("senddone");
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
@@ -284,7 +284,7 @@ client_senddone(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
||||
"send failed: %s", isc_result_totext(result));
|
||||
}
|
||||
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_nmhandle_detach(&client->sendhandle);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -325,13 +325,18 @@ client_allocsendbuf(ns_client_t *client, isc_buffer_t *buffer,
|
||||
|
||||
static isc_result_t
|
||||
client_sendpkg(ns_client_t *client, isc_buffer_t *buffer) {
|
||||
isc_result_t result;
|
||||
isc_region_t r;
|
||||
|
||||
REQUIRE(client->sendhandle == NULL);
|
||||
|
||||
isc_buffer_usedregion(buffer, &r);
|
||||
|
||||
INSIST(client->handle != NULL);
|
||||
|
||||
return (isc_nm_send(client->handle, &r, client_senddone, client));
|
||||
isc_nmhandle_attach(client->handle, &client->sendhandle);
|
||||
result = isc_nm_send(client->handle, &r, client_senddone, client);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_nmhandle_detach(&client->sendhandle);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -383,7 +388,6 @@ done:
|
||||
}
|
||||
|
||||
ns_client_drop(client, result);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -405,17 +409,13 @@ ns_client_send(ns_client_t *client) {
|
||||
isc_region_t zr;
|
||||
#endif /* HAVE_DNSTAP */
|
||||
|
||||
REQUIRE(NS_CLIENT_VALID(client));
|
||||
|
||||
/*
|
||||
* XXXWPK TODO
|
||||
* Delay the response according to the -T delay option
|
||||
*/
|
||||
|
||||
REQUIRE(NS_CLIENT_VALID(client));
|
||||
/*
|
||||
* We need to do it to make sure the client and handle
|
||||
* won't disappear from under us with client_senddone.
|
||||
*/
|
||||
|
||||
env = ns_interfacemgr_getaclenv(client->manager->interface->mgr);
|
||||
|
||||
CTRACE("send");
|
||||
@@ -591,12 +591,7 @@ renderend:
|
||||
|
||||
respsize = isc_buffer_usedlength(&buffer);
|
||||
|
||||
isc_nmhandle_ref(client->handle);
|
||||
result = client_sendpkg(client, &buffer);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
/* We won't get a callback to clean it up */
|
||||
isc_nmhandle_unref(client->handle);
|
||||
}
|
||||
|
||||
switch (isc_sockaddr_pf(&client->peeraddr)) {
|
||||
case AF_INET:
|
||||
@@ -626,12 +621,7 @@ renderend:
|
||||
|
||||
respsize = isc_buffer_usedlength(&buffer);
|
||||
|
||||
isc_nmhandle_ref(client->handle);
|
||||
result = client_sendpkg(client, &buffer);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
/* We won't get a callback to clean it up */
|
||||
isc_nmhandle_unref(client->handle);
|
||||
}
|
||||
|
||||
switch (isc_sockaddr_pf(&client->peeraddr)) {
|
||||
case AF_INET:
|
||||
@@ -1683,6 +1673,7 @@ ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
ns__client_put_cb);
|
||||
client->handle = handle;
|
||||
}
|
||||
|
||||
if (isc_nmhandle_is_stream(handle)) {
|
||||
client->attributes |= NS_CLIENTATTR_TCP;
|
||||
}
|
||||
@@ -1697,8 +1688,7 @@ ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
isc_buffer_add(&tbuffer, region->length);
|
||||
buffer = &tbuffer;
|
||||
|
||||
client->peeraddr = isc_nmhandle_peeraddr(client->handle);
|
||||
|
||||
client->peeraddr = isc_nmhandle_peeraddr(handle);
|
||||
client->peeraddr_valid = true;
|
||||
|
||||
reqsize = isc_buffer_usedlength(buffer);
|
||||
@@ -1968,8 +1958,7 @@ ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
isc_netaddr_fromsockaddr(&client->destaddr,
|
||||
&client->manager->interface->addr);
|
||||
} else {
|
||||
isc_sockaddr_t sockaddr =
|
||||
isc_nmhandle_localaddr(client->handle);
|
||||
isc_sockaddr_t sockaddr = isc_nmhandle_localaddr(handle);
|
||||
isc_netaddr_fromsockaddr(&client->destaddr, &sockaddr);
|
||||
}
|
||||
|
||||
@@ -2174,7 +2163,7 @@ ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
&client->requesttime, NULL, buffer);
|
||||
#endif /* HAVE_DNSTAP */
|
||||
|
||||
isc_nmhandle_ref(client->handle);
|
||||
isc_nmhandle_attach(handle, &client->reqhandle);
|
||||
ns_query_start(client);
|
||||
break;
|
||||
case dns_opcode_update:
|
||||
@@ -2185,13 +2174,13 @@ ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
&client->requesttime, NULL, buffer);
|
||||
#endif /* HAVE_DNSTAP */
|
||||
ns_client_settimeout(client, 60);
|
||||
isc_nmhandle_ref(client->handle);
|
||||
isc_nmhandle_attach(handle, &client->reqhandle);
|
||||
ns_update_start(client, sigresult);
|
||||
break;
|
||||
case dns_opcode_notify:
|
||||
CTRACE("notify");
|
||||
ns_client_settimeout(client, 60);
|
||||
isc_nmhandle_ref(client->handle);
|
||||
isc_nmhandle_attach(handle, &client->reqhandle);
|
||||
ns_notify_start(client);
|
||||
break;
|
||||
case dns_opcode_iquery:
|
||||
|
||||
@@ -183,7 +183,12 @@ struct ns_client {
|
||||
isc_task_t * task;
|
||||
dns_view_t * view;
|
||||
dns_dispatch_t * dispatch;
|
||||
isc_nmhandle_t * handle;
|
||||
isc_nmhandle_t * handle; /* Permanent pointer to handle */
|
||||
isc_nmhandle_t * sendhandle; /* Waiting for send callback */
|
||||
isc_nmhandle_t * reqhandle; /* Waiting for request callback
|
||||
(query, update, notify) */
|
||||
isc_nmhandle_t * fetchhandle; /* Waiting for recursive fetch */
|
||||
isc_nmhandle_t * updatehandle; /* Waiting for update callback */
|
||||
unsigned char * tcpbuf;
|
||||
dns_message_t * message;
|
||||
unsigned char * sendbuf;
|
||||
@@ -274,7 +279,7 @@ struct ns_client {
|
||||
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
LIBNS_EXTERNAL_DATA extern atomic_uint_fast32_t ns_client_requests;
|
||||
#else /* if defined(_WIN32) && !defined(_WIN64) */
|
||||
#else /* if defined(_WIN32) && !defined(_WIN64) */
|
||||
LIBNS_EXTERNAL_DATA extern atomic_uint_fast64_t ns_client_requests;
|
||||
#endif /* if defined(_WIN32) && !defined(_WIN64) */
|
||||
|
||||
|
||||
@@ -468,7 +468,7 @@ ns_interface_listentcp(ns_interface_t *ifp) {
|
||||
result = isc_nm_listentcpdns(
|
||||
ifp->mgr->nm, (isc_nmiface_t *)&ifp->addr, ns__client_request,
|
||||
ifp, ns__client_tcpconn, ifp, sizeof(ns_client_t),
|
||||
ifp->mgr->backlog, &ifp->mgr->sctx->tcpquota,
|
||||
ifp->mgr->backlog, &ifp->mgr->sctx->tcpquota, NULL,
|
||||
&ifp->tcplistensocket);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
|
||||
|
||||
+2
-2
@@ -54,7 +54,7 @@ respond(ns_client_t *client, isc_result_t result) {
|
||||
}
|
||||
if (msg_result != ISC_R_SUCCESS) {
|
||||
ns_client_drop(client, msg_result);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->reqhandle);
|
||||
return;
|
||||
}
|
||||
message->rcode = rcode;
|
||||
@@ -65,7 +65,7 @@ respond(ns_client_t *client, isc_result_t result) {
|
||||
}
|
||||
|
||||
ns_client_send(client);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->reqhandle);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+22
-15
@@ -550,7 +550,7 @@ query_send(ns_client_t *client) {
|
||||
|
||||
inc_stats(client, counter);
|
||||
ns_client_send(client);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->reqhandle);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -577,7 +577,7 @@ query_error(ns_client_t *client, isc_result_t result, int line) {
|
||||
log_queryerror(client, result, line, loglevel);
|
||||
|
||||
ns_client_error(client, result);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->reqhandle);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -590,7 +590,7 @@ query_next(ns_client_t *client, isc_result_t result) {
|
||||
inc_stats(client, ns_statscounter_failure);
|
||||
}
|
||||
ns_client_drop(client, result);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->reqhandle);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -2475,7 +2475,7 @@ prefetch_done(isc_task_t *task, isc_event_t *event) {
|
||||
}
|
||||
|
||||
free_devent(client, &event, &devent);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->fetchhandle);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2518,7 +2518,7 @@ query_prefetch(ns_client_t *client, dns_name_t *qname,
|
||||
peeraddr = NULL;
|
||||
}
|
||||
|
||||
isc_nmhandle_ref(client->handle);
|
||||
isc_nmhandle_attach(client->handle, &client->fetchhandle);
|
||||
options = client->query.fetchoptions | DNS_FETCHOPT_PREFETCH;
|
||||
result = dns_resolver_createfetch(
|
||||
client->view->resolver, qname, rdataset->type, NULL, NULL, NULL,
|
||||
@@ -2527,7 +2527,7 @@ query_prefetch(ns_client_t *client, dns_name_t *qname,
|
||||
&client->query.prefetch);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
ns_client_putrdataset(client, &tmprdataset);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->fetchhandle);
|
||||
}
|
||||
|
||||
dns_rdataset_clearprefetch(rdataset);
|
||||
@@ -2732,7 +2732,7 @@ query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) {
|
||||
}
|
||||
|
||||
options = client->query.fetchoptions;
|
||||
isc_nmhandle_ref(client->handle);
|
||||
isc_nmhandle_attach(client->handle, &client->fetchhandle);
|
||||
result = dns_resolver_createfetch(
|
||||
client->view->resolver, qname, type, NULL, NULL, NULL, peeraddr,
|
||||
client->message->id, options, 0, NULL, client->task,
|
||||
@@ -2740,7 +2740,7 @@ query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) {
|
||||
&client->query.prefetch);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
ns_client_putrdataset(client, &tmprdataset);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->fetchhandle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5178,7 +5178,7 @@ query_trace(query_ctx_t *qctx) {
|
||||
(int)qctx->client->query.authdbset,
|
||||
(int)qctx->client->query.isreferral);
|
||||
CCTRACE(ISC_LOG_DEBUG(3), mbuf);
|
||||
#else /* ifdef WANT_QUERYTRACE */
|
||||
#else /* ifdef WANT_QUERYTRACE */
|
||||
UNUSED(qctx);
|
||||
#endif /* ifdef WANT_QUERYTRACE */
|
||||
}
|
||||
@@ -5703,6 +5703,12 @@ fetch_callback(isc_task_t *task, isc_event_t *event) {
|
||||
}
|
||||
UNLOCK(&client->manager->reclock);
|
||||
|
||||
if (client->reqhandle == NULL) {
|
||||
isc_nmhandle_attach(client->handle, &client->reqhandle);
|
||||
}
|
||||
|
||||
isc_nmhandle_detach(&client->fetchhandle);
|
||||
|
||||
client->query.attributes &= ~NS_QUERYATTR_RECURSING;
|
||||
client->state = NS_CLIENTSTATE_WORKING;
|
||||
|
||||
@@ -5748,7 +5754,6 @@ fetch_callback(isc_task_t *task, isc_event_t *event) {
|
||||
}
|
||||
|
||||
dns_resolver_destroyfetch(&fetch);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
}
|
||||
|
||||
/*%
|
||||
@@ -5940,14 +5945,14 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
|
||||
peeraddr = &client->peeraddr;
|
||||
}
|
||||
|
||||
isc_nmhandle_ref(client->handle);
|
||||
isc_nmhandle_attach(client->handle, &client->fetchhandle);
|
||||
result = dns_resolver_createfetch(
|
||||
client->view->resolver, qname, qtype, qdomain, nameservers,
|
||||
NULL, peeraddr, client->message->id, client->query.fetchoptions,
|
||||
0, NULL, client->task, fetch_callback, client, rdataset,
|
||||
sigrdataset, &client->query.fetch);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->fetchhandle);
|
||||
ns_client_putrdataset(client, &rdataset);
|
||||
if (sigrdataset != NULL) {
|
||||
ns_client_putrdataset(client, &sigrdataset);
|
||||
@@ -6194,7 +6199,7 @@ ns__query_sfcache(query_ctx_t *qctx) {
|
||||
qctx->view->failcache, qctx->client->query.qname,
|
||||
qctx->qtype, &flags, &qctx->client->tnow);
|
||||
}
|
||||
#else /* ifdef ENABLE_AFL */
|
||||
#else /* ifdef ENABLE_AFL */
|
||||
failcache = dns_badcache_find(qctx->view->failcache,
|
||||
qctx->client->query.qname, qctx->qtype,
|
||||
&flags, &qctx->client->tnow);
|
||||
@@ -8344,7 +8349,7 @@ query_nodata(query_ctx_t *qctx, isc_result_t res) {
|
||||
|
||||
#ifdef dns64_bis_return_excluded_addresses
|
||||
if (qctx->dns64)
|
||||
#else /* ifdef dns64_bis_return_excluded_addresses */
|
||||
#else /* ifdef dns64_bis_return_excluded_addresses */
|
||||
if (qctx->dns64 && !qctx->dns64_exclude)
|
||||
#endif /* ifdef dns64_bis_return_excluded_addresses */
|
||||
{
|
||||
@@ -11060,7 +11065,9 @@ log_query(ns_client_t *client, unsigned int flags, unsigned int extflags) {
|
||||
TCP(client) ? "T" : "",
|
||||
((extflags & DNS_MESSAGEEXTFLAG_DO) != 0) ? "D" : "",
|
||||
((flags & DNS_MESSAGEFLAG_CD) != 0) ? "C" : "",
|
||||
HAVECOOKIE(client) ? "V" : WANTCOOKIE(client) ? "K" : "",
|
||||
HAVECOOKIE(client) ? "V"
|
||||
: WANTCOOKIE(client) ? "K"
|
||||
: "",
|
||||
onbuf, ecsbuf);
|
||||
}
|
||||
|
||||
|
||||
+31
-10
@@ -1567,7 +1567,9 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) {
|
||||
client->nupdates++;
|
||||
event->ev_arg = client;
|
||||
|
||||
isc_nmhandle_ref(client->handle);
|
||||
if (client->updatehandle == NULL) {
|
||||
isc_nmhandle_attach(client->handle, &client->updatehandle);
|
||||
}
|
||||
dns_zone_gettask(zone, &zonetask);
|
||||
isc_task_send(zonetask, ISC_EVENT_PTR(&event));
|
||||
|
||||
@@ -1585,7 +1587,6 @@ respond(ns_client_t *client, isc_result_t result) {
|
||||
client->message->rcode = dns_result_torcode(result);
|
||||
|
||||
ns_client_send(client);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
return;
|
||||
|
||||
msg_failure:
|
||||
@@ -1594,7 +1595,7 @@ msg_failure:
|
||||
"could not create update response message: %s",
|
||||
isc_result_totext(msg_result));
|
||||
ns_client_drop(client, msg_result);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->reqhandle);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1673,6 +1674,8 @@ ns_update_start(ns_client_t *client, isc_result_t sigresult) {
|
||||
default:
|
||||
FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
|
||||
}
|
||||
|
||||
isc_nmhandle_detach(&client->reqhandle);
|
||||
return;
|
||||
|
||||
failure:
|
||||
@@ -1690,6 +1693,7 @@ failure:
|
||||
if (zone != NULL) {
|
||||
dns_zone_detach(&zone);
|
||||
}
|
||||
isc_nmhandle_detach(&client->reqhandle);
|
||||
}
|
||||
|
||||
/*%
|
||||
@@ -3497,6 +3501,10 @@ common:
|
||||
}
|
||||
uev->ev_type = DNS_EVENT_UPDATEDONE;
|
||||
uev->ev_action = updatedone_action;
|
||||
|
||||
if (client->updatehandle == NULL) {
|
||||
isc_nmhandle_attach(client->handle, &client->updatehandle);
|
||||
}
|
||||
isc_task_send(client->task, &event);
|
||||
|
||||
INSIST(ver == NULL);
|
||||
@@ -3510,8 +3518,9 @@ updatedone_action(isc_task_t *task, isc_event_t *event) {
|
||||
|
||||
UNUSED(task);
|
||||
|
||||
INSIST(event->ev_type == DNS_EVENT_UPDATEDONE);
|
||||
INSIST(task == client->task);
|
||||
REQUIRE(event->ev_type == DNS_EVENT_UPDATEDONE);
|
||||
REQUIRE(task == client->task);
|
||||
REQUIRE(client->updatehandle == client->handle);
|
||||
|
||||
INSIST(client->nupdates > 0);
|
||||
switch (uev->result) {
|
||||
@@ -3528,16 +3537,18 @@ updatedone_action(isc_task_t *task, isc_event_t *event) {
|
||||
if (uev->zone != NULL) {
|
||||
dns_zone_detach(&uev->zone);
|
||||
}
|
||||
|
||||
client->nupdates--;
|
||||
|
||||
respond(client, uev->result);
|
||||
|
||||
isc_event_free(&event);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->updatehandle);
|
||||
}
|
||||
|
||||
/*%
|
||||
* Update forwarding support.
|
||||
*/
|
||||
|
||||
static void
|
||||
forward_fail(isc_task_t *task, isc_event_t *event) {
|
||||
ns_client_t *client = (ns_client_t *)event->ev_arg;
|
||||
@@ -3548,7 +3559,7 @@ forward_fail(isc_task_t *task, isc_event_t *event) {
|
||||
client->nupdates--;
|
||||
respond(client, DNS_R_SERVFAIL);
|
||||
isc_event_free(&event);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->updatehandle);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3568,6 +3579,10 @@ forward_callback(void *arg, isc_result_t result, dns_message_t *answer) {
|
||||
uev->answer = answer;
|
||||
inc_stats(client, zone, ns_statscounter_updaterespfwd);
|
||||
}
|
||||
|
||||
if (client->updatehandle == NULL) {
|
||||
isc_nmhandle_attach(client->handle, &client->updatehandle);
|
||||
}
|
||||
isc_task_send(client->task, ISC_EVENT_PTR(&uev));
|
||||
dns_zone_detach(&zone);
|
||||
}
|
||||
@@ -3584,7 +3599,7 @@ forward_done(isc_task_t *task, isc_event_t *event) {
|
||||
ns_client_sendraw(client, uev->answer);
|
||||
dns_message_destroy(&uev->answer);
|
||||
isc_event_free(&event);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->updatehandle);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3594,6 +3609,10 @@ forward_action(isc_task_t *task, isc_event_t *event) {
|
||||
ns_client_t *client = (ns_client_t *)event->ev_arg;
|
||||
isc_result_t result;
|
||||
|
||||
if (client->updatehandle == NULL) {
|
||||
isc_nmhandle_attach(client->handle, &client->updatehandle);
|
||||
}
|
||||
|
||||
result = dns_zone_forwardupdate(zone, client->message, forward_callback,
|
||||
event);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
@@ -3636,7 +3655,9 @@ send_forward_event(ns_client_t *client, dns_zone_t *zone) {
|
||||
namebuf, classbuf);
|
||||
|
||||
dns_zone_gettask(zone, &zonetask);
|
||||
isc_nmhandle_ref(client->handle);
|
||||
if (client->updatehandle == NULL) {
|
||||
isc_nmhandle_attach(client->handle, &client->updatehandle);
|
||||
}
|
||||
isc_task_send(zonetask, ISC_EVENT_PTR(&event));
|
||||
|
||||
if (event != NULL) {
|
||||
|
||||
+4
-4
@@ -1192,7 +1192,7 @@ failure:
|
||||
NS_LOGMODULE_XFER_OUT, ISC_LOG_DEBUG(3),
|
||||
"zone transfer setup failed");
|
||||
ns_client_error(client, result);
|
||||
isc_nmhandle_unref(client->handle);
|
||||
isc_nmhandle_detach(&client->handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1580,7 +1580,7 @@ sendstream(xfrout_ctx_t *xfr) {
|
||||
xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response");
|
||||
ns_client_send(xfr->client);
|
||||
xfr->stream->methods->pause(xfr->stream);
|
||||
isc_nmhandle_unref(xfr->client->handle);
|
||||
isc_nmhandle_detach(&xfr->client->handle);
|
||||
xfrout_ctx_destroy(&xfr);
|
||||
return;
|
||||
}
|
||||
@@ -1718,7 +1718,7 @@ xfrout_senddone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
|
||||
xfrout_ctx_destroy(&xfr);
|
||||
/* We're done, unreference the handle */
|
||||
isc_nmhandle_unref(handle);
|
||||
isc_nmhandle_detach(&handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1744,7 +1744,7 @@ xfrout_maybe_destroy(xfrout_ctx_t *xfr) {
|
||||
} else {
|
||||
#endif /* if 0 */
|
||||
ns_client_drop(xfr->client, ISC_R_CANCELED);
|
||||
isc_nmhandle_unref(xfr->client->handle);
|
||||
isc_nmhandle_detach(&xfr->client->handle);
|
||||
xfrout_ctx_destroy(&xfr);
|
||||
#if 0
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ AC_DEFUN([AX_CHECK_OPENSSL], [
|
||||
AS_IF([test -f "$ssldir/include/openssl/ssl.h"],
|
||||
[
|
||||
OPENSSL_CFLAGS="-I$ssldir/include"
|
||||
OPENSSL_LIBS="-L$ssldir/lib -lcrypto"
|
||||
OPENSSL_LIBS="-L$ssldir/lib -lcrypto -lssl"
|
||||
found=true
|
||||
AC_MSG_RESULT([yes])
|
||||
break
|
||||
|
||||
@@ -1861,6 +1861,7 @@
|
||||
./lib/isc/include/isc/timer.h C 1998,1999,2000,2001,2002,2004,2005,2006,2007,2008,2009,2012,2013,2014,2016,2018,2019,2020
|
||||
./lib/isc/include/isc/tm.h C 2014,2016,2018,2019,2020
|
||||
./lib/isc/include/isc/types.h C 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2012,2013,2014,2016,2017,2018,2019,2020
|
||||
./lib/isc/include/isc/url.h C 2020
|
||||
./lib/isc/include/isc/utf8.h C 2020
|
||||
./lib/isc/include/isc/util.h C 1998,1999,2000,2001,2004,2005,2006,2007,2010,2011,2012,2015,2016,2017,2018,2019,2020
|
||||
./lib/isc/include/pk11/constants.h C 2014,2016,2017,2018,2019,2020
|
||||
@@ -1878,10 +1879,12 @@
|
||||
./lib/isc/mem_p.h C 2018,2019,2020
|
||||
./lib/isc/mutexblock.c C 1999,2000,2001,2004,2005,2007,2011,2012,2016,2018,2019,2020
|
||||
./lib/isc/netaddr.c C 1999,2000,2001,2002,2004,2005,2007,2010,2011,2012,2014,2015,2016,2017,2018,2019,2020
|
||||
./lib/isc/netmgr/http.c C 2020
|
||||
./lib/isc/netmgr/netmgr-int.h C 2019,2020
|
||||
./lib/isc/netmgr/netmgr.c C 2019,2020
|
||||
./lib/isc/netmgr/tcp.c C 2019,2020
|
||||
./lib/isc/netmgr/tcpdns.c C 2019,2020
|
||||
./lib/isc/netmgr/tls.c C 2020
|
||||
./lib/isc/netmgr/udp.c C 2019,2020
|
||||
./lib/isc/netmgr/uv-compat.c C 2020
|
||||
./lib/isc/netmgr/uv-compat.h C 2019,2020
|
||||
@@ -1985,6 +1988,7 @@
|
||||
./lib/isc/unix/stdtime.c C 1999,2000,2001,2004,2005,2007,2016,2018,2019,2020
|
||||
./lib/isc/unix/syslog.c C 2001,2004,2005,2007,2016,2018,2019,2020
|
||||
./lib/isc/unix/time.c C 1998,1999,2000,2001,2003,2004,2005,2006,2007,2008,2011,2012,2014,2015,2016,2017,2018,2019,2020
|
||||
./lib/isc/url.c C 2020
|
||||
./lib/isc/utf8.c C 2020
|
||||
./lib/isc/win32/DLLMain.c C 2001,2004,2007,2016,2018,2019,2020
|
||||
./lib/isc/win32/condition.c C 1998,1999,2000,2001,2004,2006,2007,2016,2018,2019,2020
|
||||
|
||||
Reference in New Issue
Block a user