Updated for the latest source.
[rsync-patches.git] / congestion.diff
1 From: Dave Taht <d@taht.net>
2
3 In the bufferbloat age, anything that can make for a kinder, gentler bulk
4 transfer protocol seems desirable.
5
6 This add support for user and server selectable congestion control algorithms.
7
8 For example:
9     --congestion-alg=lp # For the tcp-lp algorithm on the command line
10
11 And diffserv support:
12     --diffserv=8 for setting the CS1 bit
13
14 Also available in rsync daemon modules:
15
16 [mystuff]
17     congestion alg = westwood # for a wireless connection
18     diffserv = 8
19
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.
23
24 To use this patch, run these commands for a successful build:
25
26     patch -p1 <patches/congestion.diff
27     ./configure                         (optional if already run)
28     make
29
30 based-on: 3b36bde9536614737bb73eaac5aa1e9c039472a3
31 diff --git a/loadparm.c b/loadparm.c
32 --- a/loadparm.c
33 +++ b/loadparm.c
34 @@ -121,6 +121,7 @@ typedef struct {
35         char *auth_users;
36         char *charset;
37         char *comment;
38 +       char *congestion_alg;
39         char *dont_compress;
40         char *exclude;
41         char *exclude_from;
42 @@ -149,6 +150,7 @@ typedef struct {
43         BOOL auth_users_EXP;
44         BOOL charset_EXP;
45         BOOL comment_EXP;
46 +       BOOL congestion_alg_EXP;
47         BOOL dont_compress_EXP;
48         BOOL exclude_EXP;
49         BOOL exclude_from_EXP;
50 @@ -173,6 +175,7 @@ typedef struct {
51         BOOL temp_dir_EXP;
52         BOOL uid_EXP;
53  
54 +       int diffserv;
55         int max_connections;
56         int max_verbosity;
57         int syslog_facility;
58 @@ -235,6 +238,7 @@ static const all_vars Defaults = {
59   /* auth_users; */             NULL,
60   /* charset; */                NULL,
61   /* comment; */                NULL,
62 + /* congestion_alg; */                 NULL,
63   /* dont_compress; */          DEFAULT_DONT_COMPRESS,
64   /* exclude; */                        NULL,
65   /* exclude_from; */           NULL,
66 @@ -262,6 +266,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 @@ -286,6 +291,7 @@ static const all_vars Defaults = {
75   /* temp_dir_EXP; */           False,
76   /* uid_EXP; */                        False,
77  
78 + /* diffserv; */               8,
79   /* max_connections; */                0,
80   /* max_verbosity; */          1,
81   /* syslog_facility; */                LOG_DAEMON,
82 @@ -403,6 +409,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 @@ -542,6 +550,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 @@ -566,6 +575,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)
102  
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
108 --- a/options.c
109 +++ b/options.c
110 @@ -75,6 +75,8 @@ int delete_during = 0;
111  int delete_before = 0;
112  int delete_after = 0;
113  int delete_excluded = 0;
114 +int diffserv = 8;
115 +char *congestion_alg = NULL;
116  int remove_source_files = 0;
117  int one_file_system = 0;
118  int protocol_version = PROTOCOL_VERSION;
119 @@ -789,6 +791,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 @@ -1058,6 +1062,8 @@ static struct poptOption long_options[] = {
129  #endif
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 @@ -1085,6 +1091,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
147 --- a/socket.c
148 +++ 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;
155  
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;
160  }
161  
162 +/* Set special socket options
163 + *
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
168 + * or character.
169 +*/
170 +
171 +void set_special_sockopts(int s)
172 +{
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);
177 +       }
178 +#endif
179 +
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.
183 + */
184 +       if (diffserv) {
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));
189 +#endif
190 +       }
191 +}
192 +
193  /* Open a socket to a tcp remote host with the specified port.
194   *
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);
198                 }
199  
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,
205                         continue;
206                 }
207  
208 +               set_special_sockopts(s);
209                 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
210                            (char *)&one, sizeof one);
211                 if (sockopts)