cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: TCP_NODELAY

From: Joe Halpin <j.p.h_at_comcast.net>
Date: Wed, 24 Mar 2004 19:05:08 -0600

Daniel Stenberg wrote:
> On Sun, 21 Mar 2004, Joe Halpin wrote:

> I approve of the idea and the concept. I have only a few minor nits on the
> patch:
>
> 1. I'd rather see a new command line option than an environment variable for
> the command line tool (perhaps called --tcp-nodelay).
>
> 2. Instead of duplicating 5 lines of code, I'd prefer to have the actual code
> that do the setsockopt() call put into a separate function, and call
> that function from two places (the ipv4 code and the ipv6 code).
>
> 3. errno is not set on windows for network related stuff as one would think,
> use Curl_ourerrno() to get a portable errno. (used if the setsockopt() call
> returns failure)
>
> Should we include some further details on what TCP_NODELAY actually does in
> the curl_easy_setopt man page?
>

Sorry I haven't sent this before now, but I'm buried at work and my
alergies are kicking my butt :-(

Joe

Index: docs/curl.1
===================================================================
RCS file: /repository/curl/docs/curl.1,v
retrieving revision 1.118
diff -u -r1.118 curl.1
--- docs/curl.1 5 Mar 2004 07:55:02 -0000 1.118
+++ docs/curl.1 25 Mar 2004 01:00:25 -0000
@@ -707,6 +707,9 @@
 you're using a shell with decent redirecting capabilities.
 
 If this option is used several times, the last one will be used.
+.IP "--tcp-nodelay"
+Turn on the TCP_NODELAY option. See the curl_easy_setopt man page for
+details about this option.
 .IP "-t/--telnet-option <OPT=val>"
 Pass options to the telnet protocol. Supported options are:
 
Index: docs/libcurl/curl_easy_setopt.3
===================================================================
RCS file: /repository/curl/docs/libcurl/curl_easy_setopt.3,v
retrieving revision 1.82
diff -u -r1.82 curl_easy_setopt.3
--- docs/libcurl/curl_easy_setopt.3 12 Mar 2004 09:14:45 -0000 1.82
+++ docs/libcurl/curl_easy_setopt.3 25 Mar 2004 01:00:30 -0000
@@ -295,6 +295,22 @@
 .IP CURLOPT_PORT
 Pass a long specifying what remote port number to connect to, instead of the
 one specified in the URL or the default port for the used protocol.
+.IP CURLOPT_TCP_NODELAY
+Pass a long specifying whether the TCP_NODELAY option should be set or
+cleared (1 = set, 0 = clear). The option is cleared by default. This
+will have no effect after the connection has been established.
+
+Setting this option will disable TCP's Nagle algorithm. The purpose of
+this algorithm is to try to minimize the number of small packets on
+the network (where "small packets" means TCP segments less than the
+Maximum Segment Size (MSS) for the network).
+
+Maximizing the amount of data sent per TCP segment is good because it
+amortizes the overhead of the send. However, in some cases (most
+notably telnet or rlogin) small segments may need to be sent
+without delay. This is less efficient than sending larger amounts of
+data at a time, and can contribute to congestion on the network if
+overdone.
 .SH NAMES and PASSWORDS OPTIONS (Authentication)
 .IP CURLOPT_NETRC
 This parameter controls the preference of libcurl between using user names and
Index: include/curl/curl.h
===================================================================
RCS file: /repository/curl/include/curl/curl.h,v
retrieving revision 1.243
diff -u -r1.243 curl.h
--- include/curl/curl.h 12 Mar 2004 08:55:50 -0000 1.243
+++ include/curl/curl.h 25 Mar 2004 01:00:31 -0000
@@ -786,6 +786,9 @@
   /* The _LARGE version of the standard POSTFIELDSIZE option */
   CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120),
 
+ /* Enable/disable the TCP Nagle algorithm */
+ CINIT(TCP_NODELAY, LONG, 121),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
Index: lib/connect.c
===================================================================
RCS file: /repository/curl/lib/connect.c,v
retrieving revision 1.82
diff -u -r1.82 connect.c
--- lib/connect.c 17 Mar 2004 12:46:45 -0000 1.82
+++ lib/connect.c 25 Mar 2004 01:00:32 -0000
@@ -31,6 +31,7 @@
 #endif
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
+#include <netinet/tcp.h> /* for TCP_NODELAY */
 #endif
 #include <sys/ioctl.h>
 #ifdef HAVE_UNISTD_H
@@ -504,6 +505,15 @@
 }
 
 
+void Curl_setNoDelay(struct SessionHandle *data,int sockfd,const char *ip)
+{
+ socklen_t onoff = (socklen_t) data->tcp_nodelay;
+ infof(data,"Setting TCP_NODELAY for %s\n", ip);
+ if(setsockopt(sockfd,IPPROTO_TCP,TCP_NODELAY,&onoff,sizeof onoff) < 0)
+ infof(data, "Could not set TCP_NODELAY: %s\n", strerror(errno));
+}
+
+
 /*
  * TCP connect to the given host with timeout, proxy or remote doesn't matter.
  * There might be more than one IP address to try out. Fill in the passed
@@ -581,6 +591,9 @@
     sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
     if (sockfd == CURL_SOCKET_BAD)
       continue;
+
+ else if(1 == conn->tcp_nodelay)
+ Curl_setNoDelay(data,sockfd,"IPv6");
 #else
   /*
    * Connecting with old style IPv4-only support
@@ -600,6 +613,9 @@
       return CURLE_COULDNT_CONNECT; /* big time error */
     }
 
+ else if(1 == conn->tcp_nodelay)
+ Curl_setNoDelay(data,sockfd,"IPv4");
+
     /* nasty address work before connect can be made */
     memset((char *) &serv_addr, '\0', sizeof(serv_addr));
     memcpy((char *)&(serv_addr.sin_addr),
Index: lib/connect.h
===================================================================
RCS file: /repository/curl/lib/connect.h,v
retrieving revision 1.16
diff -u -r1.16 connect.h
--- lib/connect.h 9 Mar 2004 22:52:50 -0000 1.16
+++ lib/connect.h 25 Mar 2004 01:00:32 -0000
@@ -38,5 +38,7 @@
                           bool *connected /* truly connected? */
                           );
 
+void Curl_setNoDelay(struct SessionHandle *data,int sockfd,const char *ip);
+
 int Curl_ourerrno(void);
 #endif
Index: lib/url.c
===================================================================
RCS file: /repository/curl/lib/url.c,v
retrieving revision 1.350
diff -u -r1.350 url.c
--- lib/url.c 12 Mar 2004 08:55:51 -0000 1.350
+++ lib/url.c 25 Mar 2004 01:00:35 -0000
@@ -1303,6 +1303,14 @@
     data->set.max_filesize = va_arg(param, curl_off_t);
     break;
 
+ case CURLOPT_TCP_NODELAY:
+ /*
+ * Enable or disable TCP_NODELAY, which will disable/enable the Nagle
+ * algorithm
+ */
+ data->tcp_nodelay = va_arg(param, long);
+ break;
+
   default:
     /* unknown tag and its companion, just ignore: */
     return CURLE_FAILED_INIT; /* correct this */
@@ -2059,6 +2067,10 @@
   conn->bits.user_passwd = data->set.userpwd?1:0;
   conn->bits.proxy_user_passwd = data->set.proxyuserpwd?1:0;
 
+ /* Pass the nagle flag from the SessionHandle struct to the connectdata
+ * struct so it will be available for Curl_connecthost(). */
+ conn->tcp_nodelay = (data->tcp_nodelay == 0) ? 0 : 1;
+
   /* This initing continues below, see the comment "Continue connectdata
    * initialization here" */
 
Index: lib/urldata.h
===================================================================
RCS file: /repository/curl/lib/urldata.h,v
retrieving revision 1.204
diff -u -r1.204 urldata.h
--- lib/urldata.h 12 Mar 2004 13:06:01 -0000 1.204
+++ lib/urldata.h 25 Mar 2004 01:00:36 -0000
@@ -576,6 +576,9 @@
   /* data used for the asynch name resolve callback */
   struct Curl_async async;
 #endif
+
+ /* This tells Curl_connectHost whether or not to enable TCP_NODELAY */
+ int tcp_nodelay;
 };
 
 /* The end of connectdata. */
@@ -906,6 +909,9 @@
 #if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
   ENGINE* engine;
 #endif /* USE_SSLEAY */
+
+ /* This tells CreateConnection() whether to enable TCP_NODELAY or not */
+ int tcp_nodelay;
 };
 
 #define LIBCURL_NAME "libcurl"
Index: src/main.c
===================================================================
RCS file: /repository/curl/src/main.c,v
retrieving revision 1.247
diff -u -r1.247 main.c
--- src/main.c 17 Mar 2004 12:46:48 -0000 1.247
+++ src/main.c 25 Mar 2004 01:00:40 -0000
@@ -294,6 +294,8 @@
     " --disable-epsv Prevent curl from using EPSV (F)",
     " -D/--dump-header <file> Write the headers to this file",
     " --egd-file <file> EGD socket path for random data (SSL)",
+ " --tcp-nodelay Set the TCP_NODELAY option (see the curl_easy_setopt"
+ " man page for details)",
 #ifdef USE_ENVIRONMENT
     " --environment Write result codes to environment variables (RISC OS)",
 #endif
@@ -506,6 +508,8 @@
   bool ftp_ssl;
 
   char *socks5proxy;
+
+ bool tcp_nodelay;
 };
 
 /* global variable to hold info about libcurl */
@@ -1140,6 +1144,7 @@
     {"$a", "ftp-ssl", FALSE},
     {"$b", "ftp-pasv", FALSE},
     {"$c", "socks5", TRUE},
+ {"$d", "tcp-nodelay",FALSE},
     {"0", "http1.0", FALSE},
     {"1", "tlsv1", FALSE},
     {"2", "sslv2", FALSE},
@@ -1463,6 +1468,9 @@
       case 'c': /* --socks specifies a socks5 proxy to use */
         GetStr(&config->socks5proxy, nextarg);
         break;
+ case 'd': /* --tcp-nodelay option */
+ config->tcp_nodelay = 1;
+ break;
       }
       break;
     case '#': /* added 19990617 larsa */
@@ -3112,6 +3120,9 @@
         }
 #endif
 
+ if(1 == config->tcp_nodelay)
+ curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
+
         curl_easy_setopt(curl, CURLOPT_SSLENGINE, config->engine);
         curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
 
Received on 2004-03-25