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:
@@ -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).
|
||||
*/
|
||||
|
@@ -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));
|
||||
|
@@ -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));
|
||||
|
Reference in New Issue
Block a user