1 From: Dave Taht <d@taht.net>
3 In the bufferbloat age, anything that can make for a kinder, gentler bulk
4 transfer protocol seems desirable.
6 This add support for user and server selectable congestion control algorithms.
9 --congestion-alg=lp # For the tcp-lp algorithm on the command line
12 --diffserv=8 for setting the CS1 bit
14 Also available in rsync daemon modules:
17 congestion alg = westwood # for a wireless connection
20 This could be improved by being able to specify a list of congestion algorithms
21 to try, symbolic names for diffserv (CS1), a better name than 'congestion-alg',
22 and some error checking.
24 To use this patch, run these commands for a successful build:
26 patch -p1 <patches/congestion.diff
27 ./configure (optional if already run)
30 based-on: 2a87d78f693f10fe5ad13af0bb9311bd3714077d
31 diff --git a/loadparm.c b/loadparm.c
34 @@ -120,6 +120,7 @@ typedef struct {
38 + char *congestion_alg;
42 @@ -148,6 +149,7 @@ typedef struct {
46 + BOOL congestion_alg_EXP;
47 BOOL dont_compress_EXP;
49 BOOL exclude_from_EXP;
50 @@ -172,6 +174,7 @@ typedef struct {
58 @@ -234,6 +237,7 @@ static const all_vars Defaults = {
59 /* auth_users; */ NULL,
62 + /* congestion_alg; */ NULL,
63 /* dont_compress; */ DEFAULT_DONT_COMPRESS,
65 /* exclude_from; */ NULL,
66 @@ -261,6 +265,7 @@ static const all_vars Defaults = {
67 /* auth_users_EXP; */ False,
68 /* charset_EXP; */ False,
69 /* comment_EXP; */ False,
70 + /* congestion_alg_EXP; */ False,
71 /* dont_compress_EXP; */ False,
72 /* exclude_EXP; */ False,
73 /* exclude_from_EXP; */ False,
74 @@ -285,6 +290,7 @@ static const all_vars Defaults = {
75 /* temp_dir_EXP; */ False,
79 /* max_connections; */ 0,
80 /* max_verbosity; */ 1,
81 /* syslog_facility; */ LOG_DAEMON,
82 @@ -402,6 +408,8 @@ static struct parm_struct parm_table[] =
83 {"auth users", P_STRING, P_LOCAL, &Vars.l.auth_users, NULL,0},
84 {"charset", P_STRING, P_LOCAL, &Vars.l.charset, NULL,0},
85 {"comment", P_STRING, P_LOCAL, &Vars.l.comment, NULL,0},
86 + {"congestion alg", P_STRING, P_LOCAL, &Vars.l.congestion_alg, NULL,0},
87 + {"diffserv", P_INTEGER,P_LOCAL, &Vars.l.diffserv, NULL,0},
88 {"dont compress", P_STRING, P_LOCAL, &Vars.l.dont_compress, NULL,0},
89 {"exclude from", P_STRING, P_LOCAL, &Vars.l.exclude_from, NULL,0},
90 {"exclude", P_STRING, P_LOCAL, &Vars.l.exclude, NULL,0},
91 @@ -541,6 +549,7 @@ FN_GLOBAL_INTEGER(lp_rsync_port, rsync_port)
92 FN_LOCAL_STRING(lp_auth_users, auth_users)
93 FN_LOCAL_STRING(lp_charset, charset)
94 FN_LOCAL_STRING(lp_comment, comment)
95 +FN_LOCAL_STRING(lp_congestion_alg, congestion_alg)
96 FN_LOCAL_STRING(lp_dont_compress, dont_compress)
97 FN_LOCAL_STRING(lp_exclude, exclude)
98 FN_LOCAL_STRING(lp_exclude_from, exclude_from)
99 @@ -565,6 +574,7 @@ FN_LOCAL_STRING(lp_syslog_tag, syslog_tag)
100 FN_LOCAL_STRING(lp_temp_dir, temp_dir)
101 FN_LOCAL_STRING(lp_uid, uid)
103 +FN_LOCAL_INTEGER(lp_diffserv, diffserv)
104 FN_LOCAL_INTEGER(lp_max_connections, max_connections)
105 FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
106 FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility)
107 diff --git a/options.c b/options.c
110 @@ -73,6 +73,8 @@ int delete_during = 0;
111 int delete_before = 0;
112 int delete_after = 0;
113 int delete_excluded = 0;
115 +char *congestion_alg = NULL;
116 int remove_source_files = 0;
117 int one_file_system = 0;
118 int protocol_version = PROTOCOL_VERSION;
119 @@ -785,6 +787,8 @@ void usage(enum logcode F)
120 rprintf(F," --address=ADDRESS bind address for outgoing socket to daemon\n");
121 rprintf(F," --port=PORT specify double-colon alternate port number\n");
122 rprintf(F," --sockopts=OPTIONS specify custom TCP options\n");
123 + rprintf(F," --diffserv=[0-63] specify diffserv setting \n");
124 + rprintf(F," --congestion-alg=STRING choose a congestion algo\n");
125 rprintf(F," --blocking-io use blocking I/O for the remote shell\n");
126 rprintf(F," --stats give some file-transfer stats\n");
127 rprintf(F," -8, --8-bit-output leave high-bit chars unescaped in output\n");
128 @@ -1049,6 +1053,8 @@ static struct poptOption long_options[] = {
130 {"remote-option", 'M', POPT_ARG_STRING, 0, 'M', 0, 0 },
131 {"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 },
132 + {"congestion-alg", 0, POPT_ARG_STRING, &congestion_alg, 0, 0, 0 },
133 + {"diffserv", 0, POPT_ARG_INT, &diffserv, 0, 0, 0 },
134 {"checksum-seed", 0, POPT_ARG_INT, &checksum_seed, 0, 0, 0 },
135 {"server", 0, POPT_ARG_NONE, 0, OPT_SERVER, 0, 0 },
136 {"sender", 0, POPT_ARG_NONE, 0, OPT_SENDER, 0, 0 },
137 @@ -1076,6 +1082,8 @@ static void daemon_usage(enum logcode F)
138 rprintf(F," --log-file=FILE override the \"log file\" setting\n");
139 rprintf(F," --log-file-format=FMT override the \"log format\" setting\n");
140 rprintf(F," --sockopts=OPTIONS specify custom TCP options\n");
141 + rprintf(F," --diffserv=[0-63] specify diffserv setting \n");
142 + rprintf(F," --congestion-alg=STRING choose a congestion algo\n");
143 rprintf(F," -v, --verbose increase verbosity\n");
144 rprintf(F," -4, --ipv4 prefer IPv4\n");
145 rprintf(F," -6, --ipv6 prefer IPv6\n");
146 diff --git a/socket.c b/socket.c
149 @@ -38,6 +38,8 @@ extern char *bind_address;
150 extern char *sockopts;
151 extern int default_af_hint;
152 extern int connect_timeout;
153 +extern int diffserv;
154 +extern char *congestion_alg;
156 #ifdef HAVE_SIGACTION
157 static struct sigaction sigact;
158 @@ -166,6 +168,37 @@ static void contimeout_handler(UNUSED(int val))
159 connect_timeout = -1;
162 +/* Set special socket options
164 + * Diffserv is a value in the range of 0-63, and needs to be shifted left
165 + * 2 places AND treated differently for ipv4 and ipv6.
166 + * Setting TCP congestion control is rather Linux specific (at the moment)
167 + * and sends a varying length string to setsockopt rather than an integer
171 +void set_special_sockopts(int s)
173 +#if defined(TCP_CONGESTION)
174 + if (congestion_alg) {
175 + if (setsockopt(s, SOL_TCP, TCP_CONGESTION, congestion_alg, strlen(congestion_alg)) == -1)
176 + rprintf(FINFO, "Couldn't set %s congestion algorithm\n", congestion_alg);
180 +/* setting the diffserv/tos bits is different on ipv6 and
181 + * ipv4, so we just hammer down on both and ignore the result
182 + * And ipv6 demands an int for v. I didn't write the spec.
185 + int v = (diffserv & 63) <<2;
186 + setsockopt(s,IPPROTO_IP, IP_TOS, &v, sizeof(v));
187 +#if defined(IPV6_TCLASS)
188 + setsockopt(s,IPPROTO_IPV6, IPV6_TCLASS, &v, sizeof(v));
193 /* Open a socket to a tcp remote host with the specified port.
195 * Based on code from Warren. Proxy support by Stephen Rothwell.
196 @@ -275,6 +308,7 @@ int open_socket_out(char *host, int port, const char *bind_addr,
197 alarm(connect_timeout);
200 + set_special_sockopts(s);
201 set_socket_options(s, sockopts);
202 while (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
203 if (connect_timeout < 0)
204 @@ -449,6 +483,7 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
208 + set_special_sockopts(s);
209 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
210 (char *)&one, sizeof one);