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