@cryptotaxi247 / netdata-1 / commits / 82769cefc

prevent packet fragmentation using TCP_CORK when available

Costa Tsaousis committed May 31, 2016 at 20:42 UTC 82769cefc7afa6b65b34e41397d3dcb4e66ee424
2 files changed +48 -14
src/web_client.c
+43 -14
@@ -30,7 +30,6 @@
30 #include "registry.h"
31
32 #include "web_client.h"
33 -#include "../config.h"
33
34 #define INITIAL_WEB_DATA_LENGTH 16384
35 #define WEB_REQUEST_LENGTH 16384
@@ -44,6 +43,36 @@ extern int netdata_exit;
43 struct web_client *web_clients = NULL;
44 unsigned long long web_clients_count = 0;
45
46 +inline int web_client_crock_socket(struct web_client *w) {
47 +#ifdef TCP_CORK
48 + if(likely(!w->tcp_cork && w->ofd != -1)) {
49 + w->tcp_cork = 1;
50 + if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
51 + error("%llu: failed to enable TCP_CORK on socket.", w->id);
52 + w->tcp_cork = 0;
53 + return -1;
54 + }
55 + }
56 +#endif /* TCP_CORK */
57 +
58 + return 0;
59 +}
60 +
61 +inline int web_client_uncrock_socket(struct web_client *w) {
62 +#ifdef TCP_CORK
63 + if(likely(w->tcp_cork && w->ofd != -1)) {
64 + w->tcp_cork = 0;
65 + if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
66 + error("%llu: failed to disable TCP_CORK on socket.", w->id);
67 + w->tcp_cork = 1;
68 + return -1;
69 + }
70 + }
71 +#endif /* TCP_CORK */
72 +
73 + return 0;
74 +}
75 +
76 struct web_client *web_client_create(int listener)
77 {
78 struct web_client *w;
@@ -81,7 +110,6 @@ struct web_client *web_client_create(int listener)
110 w->client_port[NI_MAXSERV] = '\0';
111
112 switch(sadr->sa_family) {
84 -
113 case AF_INET:
114 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);
115 break;
@@ -101,8 +129,14 @@ struct web_client *web_client_create(int listener)
129 }
130
131 int flag = 1;
132 + if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0)
133 + error("%llu: failed to enable TCP_NODELAY on socket.", w->id);
134 +
135 + flag = 1;
136 if(setsockopt(w->ifd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)) != 0)
137 error("%llu: Cannot set SO_KEEPALIVE on socket.", w->id);
138 +
139 +
140 }
141
142 w->response.data = buffer_create(INITIAL_WEB_DATA_LENGTH);
@@ -146,6 +180,8 @@ struct web_client *web_client_create(int listener)
180
181 void web_client_reset(struct web_client *w)
182 {
183 + web_client_uncrock_socket(w);
184 +
185 struct timeval tv;
186 gettimeofday(&tv, NULL);
187
@@ -234,15 +270,16 @@ void web_client_reset(struct web_client *w)
270 }
271
272 struct web_client *web_client_free(struct web_client *w) {
273 + web_client_uncrock_socket(w);
274 +
275 struct web_client *n = w->next;
276 if(w == web_clients) web_clients = n;
277
278 debug(D_WEB_CLIENT_ACCESS, "%llu: Closing web client from %s port %s.", w->id, w->client_ip, w->client_port);
279
280 #ifdef NETDATA_WITH_ZLIB
243 - if(w->response.zinitialized) {
281 + if(w->response.zinitialized)
282 deflateEnd(&w->response.zstream);
245 - }
283 #endif // NETDATA_WITH_ZLIB
284
285 if(w->prev) w->prev->next = w->next;
@@ -1726,11 +1763,6 @@ void web_client_process(struct web_client *w) {
1763
1764 buffer_strcat(w->response.header_output, "\r\n");
1765
1729 - // disable TCP_NODELAY, to buffer the header
1730 - int flag = 0;
1731 - if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0)
1732 - error("%llu: failed to disable TCP_NODELAY on socket.", w->id);
1733 -
1766 // sent the HTTP header
1767 debug(D_WEB_DATA, "%llu: Sending response HTTP header of size %d: '%s'"
1768 , w->id
@@ -1738,6 +1770,8 @@ void web_client_process(struct web_client *w) {
1770 , buffer_tostring(w->response.header_output)
1771 );
1772
1773 + web_client_crock_socket(w);
1774 +
1775 bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0);
1776 if(bytes != (ssize_t) buffer_strlen(w->response.header_output)) {
1777 if(bytes > 0)
@@ -1752,11 +1786,6 @@ void web_client_process(struct web_client *w) {
1786 else
1787 w->stats_sent_bytes += bytes;
1788
1755 - // enable TCP_NODELAY, to send all data immediately at the next send()
1756 - flag = 1;
1757 - if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0)
1758 - error("%llu: failed to enable TCP_NODELAY on socket.", w->id);
1759 -
1789 // enable sending immediately if we have data
1790 if(w->response.data->len) w->wait_send = 1;
1791 else w->wait_send = 0;
src/web_client.h
+5
@@ -5,6 +5,7 @@
5
6 #include <sys/time.h>
7 #include <string.h>
8 +#include <sys/types.h>
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
@@ -68,6 +69,10 @@ struct web_client {
69 uint8_t wait_receive:1; // 1 = we are waiting more input data
70 uint8_t wait_send:1; // 1 = we have data to send to the client
71
72 +#ifdef TCP_CORK
73 + int tcp_cork; // 1 = we have a cork on the socket
74 +#endif /* TCP_CORK */
75 +
76 int ifd;
77 int ofd;
78