]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add isc__nm_senddns()
authorArtem Boldariev <artem@boldariev.com>
Wed, 7 Dec 2022 11:33:52 +0000 (13:33 +0200)
committerArtem Boldariev <artem@boldariev.com>
Tue, 20 Dec 2022 20:13:53 +0000 (22:13 +0200)
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.

lib/isc/netmgr/netmgr-int.h
lib/isc/netmgr/netmgr.c
lib/isc/netmgr/tcp.c

index bd8d84498929b661e9a06820a477d419fe28d042..a57222c367597223b222e6306e938b4caac3bb66 100644 (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).
+ */
index eb10ce67f21671e45de3f9f0d48418fb3ff594a1..80bcca310dad86f820d1fec2f57198a8ff7a54f6 100644 (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));
index c994622d0c588df4258a36fd9d75e0a54f957392..cd49da70b40eaea379a7cf88d5ff6290dedd4edd 100644 (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)) {
-               /* 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;
-       } else if (!(r == UV_ENOSYS || r == UV_EAGAIN)) {
-               return (isc_uverr2result(r));
+               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) {
+                       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_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, &uvbuf, 1,
+       r = uv_write(&req->uv_req.write, &sock->uv_handle.stream, bufs, nbufs,
                     tcp_send_cb);
        if (r < 0) {
                return (isc_uverr2result(r));