]> arthur.barton.de Git - netdata.git/commitdiff
prevent packet fragmentation using TCP_CORK when available
authorCosta Tsaousis <costa@tsaousis.gr>
Tue, 31 May 2016 17:42:03 +0000 (20:42 +0300)
committerCosta Tsaousis <costa@tsaousis.gr>
Tue, 31 May 2016 17:42:03 +0000 (20:42 +0300)
src/web_client.c
src/web_client.h

index dc3bbea2b5a37c0e0e4b43eadd154469cad2652d..423555513883c7249204d1f02a90ac320e102cca 100644 (file)
@@ -30,7 +30,6 @@
 #include "registry.h"
 
 #include "web_client.h"
-#include "../config.h"
 
 #define INITIAL_WEB_DATA_LENGTH 16384
 #define WEB_REQUEST_LENGTH 16384
@@ -44,6 +43,36 @@ extern int netdata_exit;
 struct web_client *web_clients = NULL;
 unsigned long long web_clients_count = 0;
 
+inline int web_client_crock_socket(struct web_client *w) {
+#ifdef TCP_CORK
+       if(likely(!w->tcp_cork && w->ofd != -1)) {
+               w->tcp_cork = 1;
+               if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
+                       error("%llu: failed to enable TCP_CORK on socket.", w->id);
+                       w->tcp_cork = 0;
+                       return -1;
+               }
+       }
+#endif /* TCP_CORK */
+
+       return 0;
+}
+
+inline int web_client_uncrock_socket(struct web_client *w) {
+#ifdef TCP_CORK
+       if(likely(w->tcp_cork && w->ofd != -1)) {
+               w->tcp_cork = 0;
+               if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
+                       error("%llu: failed to disable TCP_CORK on socket.", w->id);
+                       w->tcp_cork = 1;
+                       return -1;
+               }
+       }
+#endif /* TCP_CORK */
+
+       return 0;
+}
+
 struct web_client *web_client_create(int listener)
 {
        struct web_client *w;
@@ -81,7 +110,6 @@ struct web_client *web_client_create(int listener)
                w->client_port[NI_MAXSERV] = '\0';
 
                switch(sadr->sa_family) {
-
                case AF_INET:
                        debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv4 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
                        break;
@@ -101,8 +129,14 @@ struct web_client *web_client_create(int listener)
                }
 
                int flag = 1;
+               if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0)
+                       error("%llu: failed to enable TCP_NODELAY on socket.", w->id);
+
+               flag = 1;
                if(setsockopt(w->ifd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)) != 0)
                        error("%llu: Cannot set SO_KEEPALIVE on socket.", w->id);
+
+
        }
 
        w->response.data = buffer_create(INITIAL_WEB_DATA_LENGTH);
@@ -146,6 +180,8 @@ struct web_client *web_client_create(int listener)
 
 void web_client_reset(struct web_client *w)
 {
+       web_client_uncrock_socket(w);
+
        struct timeval tv;
        gettimeofday(&tv, NULL);
 
@@ -234,15 +270,16 @@ void web_client_reset(struct web_client *w)
 }
 
 struct web_client *web_client_free(struct web_client *w) {
+       web_client_uncrock_socket(w);
+
        struct web_client *n = w->next;
        if(w == web_clients) web_clients = n;
 
        debug(D_WEB_CLIENT_ACCESS, "%llu: Closing web client from %s port %s.", w->id, w->client_ip, w->client_port);
 
 #ifdef NETDATA_WITH_ZLIB
-       if(w->response.zinitialized) {
+       if(w->response.zinitialized)
                deflateEnd(&w->response.zstream);
-       }
 #endif // NETDATA_WITH_ZLIB
 
        if(w->prev)     w->prev->next = w->next;
@@ -1726,11 +1763,6 @@ void web_client_process(struct web_client *w) {
 
        buffer_strcat(w->response.header_output, "\r\n");
 
-       // disable TCP_NODELAY, to buffer the header
-       int flag = 0;
-       if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0)
-               error("%llu: failed to disable TCP_NODELAY on socket.", w->id);
-
        // sent the HTTP header
        debug(D_WEB_DATA, "%llu: Sending response HTTP header of size %d: '%s'"
                        , w->id
@@ -1738,6 +1770,8 @@ void web_client_process(struct web_client *w) {
                        , buffer_tostring(w->response.header_output)
                        );
 
+       web_client_crock_socket(w);
+
        bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0);
        if(bytes != (ssize_t) buffer_strlen(w->response.header_output)) {
                if(bytes > 0)
@@ -1752,11 +1786,6 @@ void web_client_process(struct web_client *w) {
        else 
                w->stats_sent_bytes += bytes;
 
-       // enable TCP_NODELAY, to send all data immediately at the next send()
-       flag = 1;
-       if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0)
-               error("%llu: failed to enable TCP_NODELAY on socket.", w->id);
-
        // enable sending immediately if we have data
        if(w->response.data->len) w->wait_send = 1;
        else w->wait_send = 0;
index f2dc554a3ecf72ab6e928f6490248e4c97a69b94..c5a448e0b850b828c85f97e00a2bac18a0c5f565 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <sys/time.h>
 #include <string.h>
+#include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -68,6 +69,10 @@ struct web_client {
        uint8_t wait_receive:1;                         // 1 = we are waiting more input data
        uint8_t wait_send:1;                            // 1 = we have data to send to the client
 
+#ifdef TCP_CORK
+       int tcp_cork;                                           // 1 = we have a cork on the socket
+#endif /* TCP_CORK */
+
        int ifd;
        int ofd;