2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-03 08:05:21 +00:00

Add isc__nm_senddns()

The new internal function works in the same way as isc_nm_send()
except that it sends a DNS message size ahead of the DNS message
data (the format used in DNS over TCP).

The intention is to provide a fast path for sending DNS messages over
streams protocols - that is, without allocating any intermediate
memory buffers.
This commit is contained in:
Artem Boldariev
2022-12-07 13:33:52 +02:00
parent 56732ac2a0
commit ad876a65af
3 changed files with 92 additions and 15 deletions

View File

@@ -1337,6 +1337,14 @@ isc__nm_async_tcpstop(isc__networker_t *worker, isc__netievent_t *ev0);
* stoplisten, send, read, pause, close).
*/
void
isc__nm_tcp_senddns(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
/*%<
* The same as 'isc__nm_tcp_send()', but with data length sent
* ahead of data (two bytes (16 bit) in big-endian format).
*/
void
isc__nm_async_tlsclose(isc__networker_t *worker, isc__netievent_t *ev0);
@@ -1993,3 +2001,11 @@ isc__nmhandle_get_selected_alpn(isc_nmhandle_t *handle,
* not negotiated of the underlying protocol of the connection
* represented via the given handle does not support ALPN.
*/
void
isc__nm_senddns(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
void *cbarg);
/*%<
* The same as 'isc_nm_send()', but with data length sent
* ahead of data (two bytes (16 bit) in big-endian format).
*/

View File

@@ -1873,6 +1873,20 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
}
}
void
isc__nm_senddns(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
void *cbarg) {
REQUIRE(VALID_NMHANDLE(handle));
switch (handle->sock->type) {
case isc_nm_tcpsocket:
isc__nm_tcp_senddns(handle, region, cb, cbarg);
break;
default:
UNREACHABLE();
}
}
void
isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
REQUIRE(VALID_NMHANDLE(handle));

View File

@@ -996,9 +996,9 @@ failure:
return (result);
}
void
isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg) {
static void
tcp_send(isc_nmhandle_t *handle, const isc_region_t *region, isc_nm_cb_t cb,
void *cbarg, const bool dnsmsg) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
@@ -1011,6 +1011,9 @@ isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
REQUIRE(sock->tid == isc_tid());
uvreq = isc__nm_uvreq_get(sock->worker, sock);
if (dnsmsg) {
*(uint16_t *)uvreq->tcplen = htons(region->length);
}
uvreq->uvbuf.base = (char *)region->base;
uvreq->uvbuf.len = region->length;
@@ -1034,6 +1037,18 @@ isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
return;
}
void
isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg) {
tcp_send(handle, region, cb, cbarg, false);
}
void
isc__nm_tcp_senddns(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg) {
tcp_send(handle, region, cb, cbarg, true);
}
static void
tcp_send_cb(uv_write_t *req, int status) {
isc__nm_uvreq_t *uvreq = (isc__nm_uvreq_t *)req->data;
@@ -1065,27 +1080,59 @@ tcp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
REQUIRE(sock->type == isc_nm_tcpsocket);
int r;
uv_buf_t bufs[2] = { { 0 }, { 0 } }; /* ugly, but required for old GCC
versions */
size_t nbufs = 1;
if (isc__nmsocket_closing(sock)) {
return (ISC_R_CANCELED);
}
uv_buf_t uvbuf = { .base = req->uvbuf.base, .len = req->uvbuf.len };
/* Check if we are not trying to send a DNS message */
if (*(uint16_t *)req->tcplen == 0) {
bufs[0].base = req->uvbuf.base;
bufs[0].len = req->uvbuf.len;
r = uv_try_write(&sock->uv_handle.stream, &uvbuf, 1);
r = uv_try_write(&sock->uv_handle.stream, bufs, nbufs);
if (r == (int)(uvbuf.len)) {
if (r == (int)(bufs[0].len)) {
/* Wrote everything */
isc__nm_sendcb(sock, req, ISC_R_SUCCESS, true);
return (ISC_R_SUCCESS);
} else if (r > 0) {
uvbuf.base += (size_t)r;
uvbuf.len -= (size_t)r;
bufs[0].base += (size_t)r;
bufs[0].len -= (size_t)r;
} else if (!(r == UV_ENOSYS || r == UV_EAGAIN)) {
return (isc_uverr2result(r));
}
} else {
nbufs = 2;
bufs[0].base = req->tcplen;
bufs[0].len = 2;
bufs[1].base = req->uvbuf.base;
bufs[1].len = req->uvbuf.len;
r = uv_write(&req->uv_req.write, &sock->uv_handle.stream, &uvbuf, 1,
r = uv_try_write(&sock->uv_handle.stream, bufs, nbufs);
if (r == (int)(bufs[0].len + bufs[1].len)) {
/* Wrote everything */
isc__nm_sendcb(sock, req, ISC_R_SUCCESS, true);
return (ISC_R_SUCCESS);
} else if (r == 1) {
/* Partial write of DNSMSG length */
bufs[0].base = req->tcplen + 1;
bufs[0].len = 1;
} else if (r > 0) {
/* Partial write of DNSMSG */
nbufs = 1;
bufs[0].base = req->uvbuf.base + (r - 2);
bufs[0].len = req->uvbuf.len - (r - 2);
} else if (!(r == UV_ENOSYS || r == UV_EAGAIN)) {
return (isc_uverr2result(r));
}
}
r = uv_write(&req->uv_req.write, &sock->uv_handle.stream, bufs, nbufs,
tcp_send_cb);
if (r < 0) {
return (isc_uverr2result(r));