Blob Blame History Raw
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.

For example:
    --congestion-alg=lp # For the tcp-lp algorithm on the command line

And diffserv support:
    --diffserv=8 for setting the CS1 bit

Also available in rsync daemon modules:

[mystuff]
    congestion alg = westwood # for a wireless connection
    diffserv = 8

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: d73762eea3f15f2c56bb3fa9394ad1883c25c949
diff --git a/loadparm.c b/loadparm.c
--- a/loadparm.c
+++ b/loadparm.c
@@ -112,6 +112,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 {
 /* NOTE: update this macro if the last char* variable changes! */
 #define LOCAL_STRING_COUNT() (offsetof(local_vars, uid) / sizeof (char*) + 1)
 
+	int diffserv;
 	int max_connections;
 	int max_verbosity;
 	int syslog_facility;
@@ -192,6 +194,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,
@@ -216,6 +219,7 @@ static const all_vars Defaults = {
  /* temp_dir; */ 		NULL,
  /* uid; */			NULL,
 
+ /* diffserv; */		8,
  /* max_connections; */		0,
  /* max_verbosity; */		1,
  /* syslog_facility; */		LOG_DAEMON,
@@ -333,6 +337,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},
@@ -469,6 +475,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)
@@ -493,6 +500,7 @@ FN_LOCAL_STRING(lp_syslog_tag, syslog_tag)
 FN_LOCAL_STRING(lp_temp_dir, temp_dir)
 FN_LOCAL_STRING(lp_uid, uid)
 
+FN_LOCAL_INTEGER(lp_diffserv, diffserv)
 FN_LOCAL_INTEGER(lp_max_connections, max_connections)
 FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
 FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility)
diff --git a/options.c b/options.c
--- a/options.c
+++ b/options.c
@@ -71,6 +71,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;
@@ -780,6 +782,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");
@@ -1041,6 +1045,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 },
@@ -1068,6 +1074,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 void 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)
diff -Nurp a/proto.h b/proto.h
--- a/proto.h
+++ b/proto.h
@@ -201,6 +201,7 @@ int lp_rsync_port(void);
 char *lp_auth_users(int module_id);
 char *lp_charset(int module_id);
 char *lp_comment(int module_id);
+char *lp_congestion_alg(int module_id);
 char *lp_dont_compress(int module_id);
 char *lp_exclude(int module_id);
 char *lp_exclude_from(int module_id);
@@ -224,6 +225,7 @@ char *lp_secrets_file(int module_id);
 char *lp_syslog_tag(int module_id);
 char *lp_temp_dir(int module_id);
 char *lp_uid(int module_id);
+int lp_diffserv(int module_id);
 int lp_max_connections(int module_id);
 int lp_max_verbosity(int module_id);
 int lp_syslog_facility(int module_id);
@@ -311,6 +313,7 @@ void successful_send(int ndx);
 void send_files(int f_in, int f_out);
 int try_bind_local(int s, int ai_family, int ai_socktype,
 		   const char *bind_addr);
+void set_special_sockopts(int s);
 int open_socket_out(char *host, int port, const char *bind_addr,
 		    int af_hint);
 int open_socket_out_wrapped(char *host, int port, const char *bind_addr,