]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Disable Nagle's algorithm for HTTP/2 connections
authorArtem Boldariev <artem@boldariev.com>
Sun, 28 Feb 2021 17:33:16 +0000 (19:33 +0200)
committerArtem Boldariev <artem@boldariev.com>
Fri, 5 Mar 2021 16:09:42 +0000 (18:09 +0200)
It is advisable to disable Nagle's algorithm for HTTP/2 connections
because multiple HTTP/2 streams could be multiplexed over one
transport connection. Thus, delays when delivering small packets could
bring down performance for the whole session. HTTP/2 is meant to be
used this way.

lib/isc/netmgr/http.c
lib/isc/netmgr/netmgr-int.h
lib/isc/netmgr/netmgr.c
lib/isc/netmgr/tlsstream.c

index 0ce8881b71dcd00ce00067c29c82faa0a3414fff..6de06a55cf9e72716bafc6a35d86d71ece9b0282 100644 (file)
@@ -170,6 +170,9 @@ client_send(isc_nmhandle_t *handle, const isc_region_t *region);
 static void
 finish_http_session(isc_nm_http_session_t *session);
 
+static void
+http_transpost_tcp_nodelay(isc_nmhandle_t *transphandle);
+
 static bool
 http_session_active(isc_nm_http_session_t *session) {
        REQUIRE(VALID_HTTP2_SESSION(session));
@@ -867,7 +870,7 @@ http_writecb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
                INSIST(session->handle == handle);
        }
 
-       if (req->cb) {
+       if (req->cb != NULL) {
                req->cb(req->httphandle, result, req->cbarg);
                isc_nmhandle_detach(&req->httphandle);
        }
@@ -1094,6 +1097,7 @@ transport_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
                goto error;
        }
 
+       http_transpost_tcp_nodelay(handle);
        http_call_connect_cb(http_sock, result);
        http_do_bio(session, NULL, NULL, NULL);
        isc__nmsocket_detach(&http_sock);
@@ -1678,7 +1682,7 @@ server_on_request_recv(nghttp2_session *ngsession,
                goto error;
        }
 
-       if (!socket->h2.request_path || !socket->h2.cb) {
+       if (socket->h2.request_path == NULL || socket->h2.cb == NULL) {
                code = ISC_HTTP_ERROR_NOT_FOUND;
        } else if (socket->h2.request_type == ISC_HTTP_REQ_POST &&
                   socket->h2.bufsize > socket->h2.content_length)
@@ -1975,6 +1979,31 @@ server_send_connection_header(isc_nm_http_session_t *session) {
        return (0);
 }
 
+/*
+ * It is advisable to disable Nagle's algorithm for HTTP/2
+ * connections because multiple HTTP/2 streams could be multiplexed
+ * over one transport connection. Thus, delays when delivering small
+ * packets could bring down performance for the whole session.
+ * HTTP/2 is meant to be used this way.
+ */
+static void
+http_transpost_tcp_nodelay(isc_nmhandle_t *transphandle) {
+#ifndef _WIN32
+       isc_nmsocket_t *tcpsock = NULL;
+       uv_os_fd_t tcp_fd = (uv_os_fd_t)-1;
+
+       if (transphandle->sock->type == isc_nm_tlssocket) {
+               tcpsock = transphandle->sock->outerhandle->sock;
+       } else {
+               tcpsock = transphandle->sock;
+       }
+
+       (void)uv_fileno((uv_handle_t *)&tcpsock->uv_handle.tcp, &tcp_fd);
+       RUNTIME_CHECK(tcp_fd != (uv_os_fd_t)-1);
+       (void)isc__nm_socket_tcp_nodelay((uv_os_sock_t)tcp_fd);
+#endif
+}
+
 static isc_result_t
 httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
        isc_nmsocket_t *httplistensock = (isc_nmsocket_t *)cbarg;
@@ -1983,6 +2012,7 @@ httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
 
        REQUIRE(VALID_NMHANDLE(handle));
        REQUIRE(VALID_NMSOCK(handle->sock));
+
        if (handle->sock->type == isc_nm_tlssocket) {
                REQUIRE(VALID_NMSOCK(handle->sock->listener));
                listener = handle->sock->listener;
@@ -2016,6 +2046,8 @@ httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
                return (ISC_R_CANCELED);
        }
 
+       http_transpost_tcp_nodelay(handle);
+
        new_session(httplistensock->mgr->mctx, NULL, &session);
        initialize_nghttp2_server_session(session);
        handle->sock->h2.session = session;
@@ -2249,7 +2281,7 @@ failed_httpstream_read_cb(isc_nmsocket_t *sock, isc_result_t result,
        REQUIRE(VALID_NMSOCK(sock));
        INSIST(sock->type == isc_nm_httpsocket);
 
-       if (!sock->h2.request_path) {
+       if (sock->h2.request_path == NULL) {
                return;
        }
 
@@ -2378,7 +2410,7 @@ isc__nm_base64url_to_base64(isc_mem_t *mem, const char *base64url,
 
        INSIST(i == len);
 
-       if (res_len) {
+       if (res_len != NULL) {
                *res_len = len;
        }
 
index e74eba82a000a034b068ad83700b14e528306425..5514355520e4ce2d83f9003af055cee289e4026d 100644 (file)
@@ -1687,6 +1687,12 @@ isc__nm_socket_connectiontimeout(uv_os_sock_t fd, int timeout_ms);
  * the minimum value must be at least 1000 (1 second).
  */
 
+isc_result_t
+isc__nm_socket_tcp_nodelay(uv_os_sock_t fd);
+/*%<
+ * Disables Nagle's algorithm on a TCP socket (sets TCP_NODELAY).
+ */
+
 /*
  * typedef all the netievent types
  */
index a29ec728a3d38e868bc5d402c8c7f5de7957db88..eb6ef11961c8b7b40e2c2c9c75e644b9267e9248 100644 (file)
@@ -2407,6 +2407,20 @@ isc__nm_socket_connectiontimeout(uv_os_sock_t fd, int timeout_ms) {
 #endif
 }
 
+isc_result_t
+isc__nm_socket_tcp_nodelay(uv_os_sock_t fd) {
+#ifdef TCP_NODELAY
+       if (setsockopt_on(fd, IPPROTO_TCP, TCP_NODELAY) == -1) {
+               return (ISC_R_FAILURE);
+       } else {
+               return (ISC_R_SUCCESS);
+       }
+#else
+       UNUSED(fd);
+       return (ISC_R_SUCCESS);
+#endif
+}
+
 #ifdef NETMGR_TRACE
 /*
  * Dump all active sockets in netmgr. We output to stderr
index 5505f3e2b46d17b1a51da65aeaf43d878cf99dfd..976970cba039a450af7a4a33f95c1ca86bdb21b3 100644 (file)
@@ -410,6 +410,7 @@ tls_readcb(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region,
        REQUIRE(VALID_NMSOCK(tlssock));
        REQUIRE(VALID_NMHANDLE(handle));
        REQUIRE(tlssock->tid == isc_nm_tid());
+
        if (result != ISC_R_SUCCESS) {
                tls_failed_read_cb(tlssock, tlssock->statichandle, result);
                return;