Dave Taht's anti-congestion patch.
authorWayne Davison <wayned@samba.org>
Sun, 26 Jan 2014 19:39:36 +0000 (11:39 -0800)
committerWayne Davison <wayned@samba.org>
Sun, 26 Jan 2014 19:59:22 +0000 (11:59 -0800)
congestion.diff [new file with mode: 0644]

diff --git a/congestion.diff b/congestion.diff
new file mode 100644 (file)
index 0000000..f830816
--- /dev/null
@@ -0,0 +1,193 @@
+From: Dave Taht <d@taht.net>
+
+In the bufferbloat age, anything that can make for a kinder, gentler bulk
+transfer protocol seems desirable.
+
+This add support for user and server selectable congestion control algorithms.
+As examples:
+
+--congestion-alg=lp # For the tcp-lp algorithm on the command line
+
+Or in a subsection:
+
+[mystuff]
+congestion alg = westwood # for a wireless connection
+
+And diffserv support: --diffserv=8 for setting the CS1 bit
+
+This could be improved by being able to specify a list of congestion algorithms
+to try, symbolic names for diffserv (CS1), a better name than 'congestion-alg',
+and some error checking.
+
+To use this patch, run these commands for a successful build:
+
+    patch -p1 <patches/congestion.diff
+    ./configure                         (optional if already run)
+    make
+
+based-on: 8946cfc6f8018e30740ee1db4cc2e2008e4f7e7e
+diff --git a/loadparm.c b/loadparm.c
+--- a/loadparm.c
++++ b/loadparm.c
+@@ -109,6 +109,7 @@ typedef struct {
+       char *auth_users;
+       char *charset;
+       char *comment;
++      char *congestion_alg;
+       char *dont_compress;
+       char *exclude;
+       char *exclude_from;
+@@ -138,6 +139,7 @@ typedef struct {
+       int max_verbosity;
+       int syslog_facility;
+       int timeout;
++      int diffserv;
+       BOOL fake_super;
+       BOOL forward_lookup;
+@@ -185,6 +187,7 @@ static const all_vars Defaults = {
+  /* auth_users; */            NULL,
+  /* charset; */               NULL,
+  /* comment; */               NULL,
++ /* congestion_alg; */                NULL,
+  /* dont_compress; */         DEFAULT_DONT_COMPRESS,
+  /* exclude; */                       NULL,
+  /* exclude_from; */          NULL,
+@@ -212,6 +215,7 @@ static const all_vars Defaults = {
+  /* max_verbosity; */         1,
+  /* syslog_facility; */               LOG_DAEMON,
+  /* timeout; */                       0,
++ /* diffserv; */              8,
+  /* fake_super; */            False,
+  /* forward_lookup; */                True,
+@@ -322,6 +326,8 @@ static struct parm_struct parm_table[] =
+  {"auth users",        P_STRING, P_LOCAL, &Vars.l.auth_users,          NULL,0},
+  {"charset",           P_STRING, P_LOCAL, &Vars.l.charset,             NULL,0},
+  {"comment",           P_STRING, P_LOCAL, &Vars.l.comment,             NULL,0},
++ {"congestion alg",    P_STRING, P_LOCAL, &Vars.l.congestion_alg,      NULL,0},
++ {"diffserv",         P_INTEGER,P_LOCAL, &Vars.l.diffserv,            NULL,0},
+  {"dont compress",     P_STRING, P_LOCAL, &Vars.l.dont_compress,       NULL,0},
+  {"exclude from",      P_STRING, P_LOCAL, &Vars.l.exclude_from,        NULL,0},
+  {"exclude",           P_STRING, P_LOCAL, &Vars.l.exclude,             NULL,0},
+@@ -454,6 +460,7 @@ FN_GLOBAL_INTEGER(lp_rsync_port, &Vars.g.rsync_port)
+ FN_LOCAL_STRING(lp_auth_users, auth_users)
+ FN_LOCAL_STRING(lp_charset, charset)
+ FN_LOCAL_STRING(lp_comment, comment)
++FN_LOCAL_STRING(lp_congestion_alg, congestion_alg)
+ FN_LOCAL_STRING(lp_dont_compress, dont_compress)
+ FN_LOCAL_STRING(lp_exclude, exclude)
+ FN_LOCAL_STRING(lp_exclude_from, exclude_from)
+@@ -481,6 +488,7 @@ FN_LOCAL_INTEGER(lp_max_connections, max_connections)
+ FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
+ FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility)
+ FN_LOCAL_INTEGER(lp_timeout, timeout)
++FN_LOCAL_INTEGER(lp_diffserv, diffserv)
+ FN_LOCAL_BOOL(lp_fake_super, fake_super)
+ FN_LOCAL_BOOL(lp_forward_lookup, forward_lookup)
+diff --git a/options.c b/options.c
+--- a/options.c
++++ b/options.c
+@@ -69,6 +69,8 @@ int delete_during = 0;
+ int delete_before = 0;
+ int delete_after = 0;
+ int delete_excluded = 0;
++int diffserv = 8;
++char *congestion_alg = NULL;
+ int remove_source_files = 0;
+ int one_file_system = 0;
+ int protocol_version = PROTOCOL_VERSION;
+@@ -778,6 +780,8 @@ void usage(enum logcode F)
+   rprintf(F,"     --address=ADDRESS       bind address for outgoing socket to daemon\n");
+   rprintf(F,"     --port=PORT             specify double-colon alternate port number\n");
+   rprintf(F,"     --sockopts=OPTIONS      specify custom TCP options\n");
++  rprintf(F,"     --diffserv=[0-63]       specify diffserv setting \n");
++  rprintf(F,"     --congestion-alg=STRING choose a congestion algo\n");
+   rprintf(F,"     --blocking-io           use blocking I/O for the remote shell\n");
+   rprintf(F,"     --stats                 give some file-transfer stats\n");
+   rprintf(F," -8, --8-bit-output          leave high-bit chars unescaped in output\n");
+@@ -1036,6 +1040,8 @@ static struct poptOption long_options[] = {
+ #endif
+   {"remote-option",   'M', POPT_ARG_STRING, 0, 'M', 0, 0 },
+   {"protocol",         0,  POPT_ARG_INT,    &protocol_version, 0, 0, 0 },
++  {"congestion-alg",   0,  POPT_ARG_STRING, &congestion_alg, 0, 0, 0 },
++  {"diffserv",         0,  POPT_ARG_INT,    &diffserv, 0, 0, 0 },
+   {"checksum-seed",    0,  POPT_ARG_INT,    &checksum_seed, 0, 0, 0 },
+   {"server",           0,  POPT_ARG_NONE,   0, OPT_SERVER, 0, 0 },
+   {"sender",           0,  POPT_ARG_NONE,   0, OPT_SENDER, 0, 0 },
+@@ -1063,6 +1069,8 @@ static void daemon_usage(enum logcode F)
+   rprintf(F,"     --log-file=FILE         override the \"log file\" setting\n");
+   rprintf(F,"     --log-file-format=FMT   override the \"log format\" setting\n");
+   rprintf(F,"     --sockopts=OPTIONS      specify custom TCP options\n");
++  rprintf(F,"     --diffserv=[0-63]       specify diffserv setting \n");
++  rprintf(F,"     --congestion-alg=STRING choose a congestion algo\n");
+   rprintf(F," -v, --verbose               increase verbosity\n");
+   rprintf(F," -4, --ipv4                  prefer IPv4\n");
+   rprintf(F," -6, --ipv6                  prefer IPv6\n");
+diff --git a/socket.c b/socket.c
+--- a/socket.c
++++ b/socket.c
+@@ -38,6 +38,8 @@ extern char *bind_address;
+ extern char *sockopts;
+ extern int default_af_hint;
+ extern int connect_timeout;
++extern int diffserv;
++extern char *congestion_alg;
+ #ifdef HAVE_SIGACTION
+ static struct sigaction sigact;
+@@ -166,6 +168,37 @@ static RETSIGTYPE contimeout_handler(UNUSED(int val))
+       connect_timeout = -1;
+ }
++/* Set special socket options
++ *
++ * Diffserv is a value in the range of 0-63, and needs to be shifted left
++ *          2 places AND treated differently for ipv4 and ipv6.
++ * Setting TCP congestion control is rather Linux specific (at the moment)
++ * and sends a varying length string to setsockopt rather than an integer
++ * or character.
++*/
++
++void set_special_sockopts(int s)
++{
++#if defined(TCP_CONGESTION)
++      if (congestion_alg) {
++              if (setsockopt(s, SOL_TCP, TCP_CONGESTION, congestion_alg, strlen(congestion_alg)) == -1)
++                      rprintf(FINFO, "Couldn't set %s congestion algorithm\n", congestion_alg);
++      }
++#endif
++
++/* setting the diffserv/tos bits is different on ipv6 and
++ *  ipv4, so we just hammer down on both and ignore the result
++ *  And ipv6 demands an int for v. I didn't write the spec.
++ */
++      if (diffserv) {
++              int v = (diffserv & 63) <<2;
++              setsockopt(s,IPPROTO_IP, IP_TOS, &v, sizeof(v));
++#if defined(IPV6_TCLASS)
++              setsockopt(s,IPPROTO_IPV6, IPV6_TCLASS, &v, sizeof(v));
++#endif
++      }
++}
++
+ /* Open a socket to a tcp remote host with the specified port.
+  *
+  * Based on code from Warren.  Proxy support by Stephen Rothwell.
+@@ -275,6 +308,7 @@ int open_socket_out(char *host, int port, const char *bind_addr,
+                       alarm(connect_timeout);
+               }
++              set_special_sockopts(s);
+               set_socket_options(s, sockopts);
+               while (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+                       if (connect_timeout < 0)
+@@ -449,6 +483,7 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
+                       continue;
+               }
++              set_special_sockopts(s);
+               setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+                          (char *)&one, sizeof one);
+               if (sockopts)