Tweaked some whitespace to match the latest version from autoconf.
[rsync/rsync.git] / socket.c
CommitLineData
7c1b4daa 1/* -*- c-file-style: "linux" -*-
9c07d253 2
d54765c4 3 rsync -- fast file replication program
9c07d253 4
eecd22ff 5 Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
362099a5 6 Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
9c07d253 7
bc2e93eb
AT
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
9c07d253 12
bc2e93eb
AT
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
9c07d253 17
bc2e93eb
AT
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
d5d4b282
MP
23/**
24 * @file socket.c
9c07d253 25 *
d5d4b282 26 * Socket functions used in rsync.
362099a5
MP
27 *
28 * This file is now converted to use the new-style getaddrinfo()
29 * interface, which supports IPv6 but is also supported on recent
30 * IPv4-only machines. On systems that don't have that interface, we
31 * emulate it using the KAME implementation.
d5d4b282 32 **/
bc2e93eb 33
f0fca04e 34#include "rsync.h"
5899b8cf
WD
35#include <netinet/in_systm.h>
36#include <netinet/ip.h>
f0fca04e 37
2c7d63c7
WD
38extern char *bind_address;
39extern int default_af_hint;
9a5a8673 40
44e604f4 41#ifdef HAVE_SIGACTION
2b28968d
WD
42static struct sigaction sigact;
43#endif
44
a7dc44d2
MP
45/**
46 * Establish a proxy connection on an open socket to a web proxy by
a3a84107
WD
47 * using the CONNECT method. If proxy_user and proxy_pass are not NULL,
48 * they are used to authenticate to the proxy using the "Basic"
49 * proxy-authorization protocol
a7dc44d2 50 **/
a3a84107
WD
51static int establish_proxy_connection(int fd, char *host, int port,
52 char *proxy_user, char *proxy_pass)
4c3b4b25 53{
a3a84107
WD
54 char *cp, buffer[1024];
55 char *authhdr, authbuf[1024];
56 int len;
57
58 if (proxy_user && proxy_pass) {
893c4cc0
WD
59 stringjoin(buffer, sizeof buffer,
60 proxy_user, ":", proxy_pass, NULL);
a3a84107 61 len = strlen(buffer);
4c3b4b25 62
8030b28f 63 if ((len*8 + 5) / 6 >= (int)sizeof authbuf - 3) {
a3a84107
WD
64 rprintf(FERROR,
65 "authentication information is too long\n");
66 return -1;
67 }
68
6854bf69 69 base64_encode(buffer, len, authbuf, 1);
a3a84107
WD
70 authhdr = "\r\nProxy-Authorization: Basic ";
71 } else {
72 *authbuf = '\0';
73 authhdr = "";
74 }
75
76 snprintf(buffer, sizeof buffer, "CONNECT %s:%d HTTP/1.0%s%s\r\n\r\n",
77 host, port, authhdr, authbuf);
78 len = strlen(buffer);
79 if (write(fd, buffer, len) != len) {
d62bcc17 80 rsyserr(FERROR, errno, "failed to write to proxy");
4c3b4b25
AT
81 return -1;
82 }
83
a3a84107 84 for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) {
4c3b4b25 85 if (read(fd, cp, 1) != 1) {
d62bcc17 86 rsyserr(FERROR, errno, "failed to read from proxy");
4c3b4b25
AT
87 return -1;
88 }
89 if (*cp == '\n')
90 break;
91 }
92
93 if (*cp != '\n')
94 cp++;
95 *cp-- = '\0';
96 if (*cp == '\r')
97 *cp = '\0';
98 if (strncmp(buffer, "HTTP/", 5) != 0) {
4ccfd96c 99 rprintf(FERROR, "bad response from proxy -- %s\n",
4c3b4b25
AT
100 buffer);
101 return -1;
102 }
9c07d253 103 for (cp = &buffer[5]; isdigit(*(uchar*)cp) || *cp == '.'; cp++) {}
4c3b4b25
AT
104 while (*cp == ' ')
105 cp++;
106 if (*cp != '2') {
4ccfd96c 107 rprintf(FERROR, "bad response from proxy -- %s\n",
4c3b4b25
AT
108 buffer);
109 return -1;
110 }
111 /* throw away the rest of the HTTP header */
112 while (1) {
a3a84107 113 for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) {
4c3b4b25 114 if (read(fd, cp, 1) != 1) {
d62bcc17
WD
115 rsyserr(FERROR, errno,
116 "failed to read from proxy");
4c3b4b25
AT
117 return -1;
118 }
119 if (*cp == '\n')
120 break;
121 }
9c07d253 122 if (cp > buffer && *cp == '\n')
4c3b4b25 123 cp--;
9c07d253 124 if (cp == buffer && (*cp == '\n' || *cp == '\r'))
4c3b4b25
AT
125 break;
126 }
127 return 0;
128}
129
130
f8be7d42
MP
131/**
132 * Try to set the local address for a newly-created socket. Return -1
133 * if this fails.
134 **/
e028b9ff 135int try_bind_local(int s, int ai_family, int ai_socktype,
4313d6f9 136 const char *bind_addr)
f8be7d42
MP
137{
138 int error;
139 struct addrinfo bhints, *bres_all, *r;
140
a3a84107 141 memset(&bhints, 0, sizeof bhints);
f8be7d42
MP
142 bhints.ai_family = ai_family;
143 bhints.ai_socktype = ai_socktype;
144 bhints.ai_flags = AI_PASSIVE;
4313d6f9 145 if ((error = getaddrinfo(bind_addr, NULL, &bhints, &bres_all))) {
f8be7d42 146 rprintf(FERROR, RSYNC_NAME ": getaddrinfo %s: %s\n",
4313d6f9 147 bind_addr, gai_strerror(error));
f8be7d42
MP
148 return -1;
149 }
150
151 for (r = bres_all; r; r = r->ai_next) {
9ec75284 152 if (bind(s, r->ai_addr, r->ai_addrlen) == -1)
f8be7d42 153 continue;
6b2d24de 154 freeaddrinfo(bres_all);
f8be7d42
MP
155 return s;
156 }
157
158 /* no error message; there might be some problem that allows
159 * creation of the socket but not binding, perhaps if the
160 * machine has no ipv6 address of this name. */
6b2d24de 161 freeaddrinfo(bres_all);
f8be7d42
MP
162 return -1;
163}
164
eecd22ff 165
d5d4b282
MP
166/**
167 * Open a socket to a tcp remote host with the specified port .
06963d0f 168 *
d5d4b282
MP
169 * Based on code from Warren. Proxy support by Stephen Rothwell.
170 * getaddrinfo() rewrite contributed by KAME.net.
06963d0f 171 *
d5d4b282
MP
172 * Now that we support IPv6 we need to look up the remote machine's
173 * address first, using @p af_hint to set a preference for the type
174 * of address. Then depending on whether it has v4 or v6 addresses we
175 * try to open a connection.
06963d0f 176 *
d5d4b282
MP
177 * The loop allows for machines with some addresses which may not be
178 * reachable, perhaps because we can't e.g. route ipv6 to that network
179 * but we can get ip4 packets through.
180 *
4313d6f9 181 * @param bind_addr Local address to use. Normally NULL to bind
d5d4b282
MP
182 * the wildcard address.
183 *
184 * @param af_hint Address family, e.g. AF_INET or AF_INET6.
06963d0f 185 **/
4313d6f9 186int open_socket_out(char *host, int port, const char *bind_addr,
d5d4b282 187 int af_hint)
bc2e93eb 188{
f0fca04e 189 int type = SOCK_STREAM;
a3a84107 190 int error, s;
06963d0f
MP
191 struct addrinfo hints, *res0, *res;
192 char portbuf[10];
a3a84107 193 char *h, *cp;
4c3b4b25
AT
194 int proxied = 0;
195 char buffer[1024];
a3a84107 196 char *proxy_user = NULL, *proxy_pass = NULL;
4c3b4b25 197
660c6fbd 198 /* if we have a RSYNC_PROXY env variable then redirect our
a3a84107 199 * connetcion via a web proxy at the given address. */
4c3b4b25 200 h = getenv("RSYNC_PROXY");
9c07d253 201 proxied = h != NULL && *h != '\0';
4c3b4b25
AT
202
203 if (proxied) {
a3a84107
WD
204 strlcpy(buffer, h, sizeof buffer);
205
206 /* Is the USER:PASS@ prefix present? */
b31c92ed 207 if ((cp = strrchr(buffer, '@')) != NULL) {
a3a84107
WD
208 *cp++ = '\0';
209 /* The remainder is the HOST:PORT part. */
210 h = cp;
211
212 if ((cp = strchr(buffer, ':')) == NULL) {
213 rprintf(FERROR,
214 "invalid proxy specification: should be USER:PASS@HOST:PORT\n");
215 return -1;
216 }
217 *cp++ = '\0';
218
219 proxy_user = buffer;
220 proxy_pass = cp;
221 } else {
222 /* The whole buffer is the HOST:PORT part. */
223 h = buffer;
224 }
225
226 if ((cp = strchr(h, ':')) == NULL) {
660c6fbd
MP
227 rprintf(FERROR,
228 "invalid proxy specification: should be HOST:PORT\n");
4c3b4b25
AT
229 return -1;
230 }
231 *cp++ = '\0';
a3a84107 232 strlcpy(portbuf, cp, sizeof portbuf);
7bea78ce
MP
233 if (verbose >= 2) {
234 rprintf(FINFO, "connection via http proxy %s port %s\n",
235 h, portbuf);
236 }
4c3b4b25 237 } else {
a3a84107 238 snprintf(portbuf, sizeof portbuf, "%d", port);
4c3b4b25 239 h = host;
4c3b4b25 240 }
f0fca04e 241
a3a84107 242 memset(&hints, 0, sizeof hints);
d5d4b282 243 hints.ai_family = af_hint;
06963d0f
MP
244 hints.ai_socktype = type;
245 error = getaddrinfo(h, portbuf, &hints, &res0);
246 if (error) {
d5d4b282
MP
247 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: %s %s: %s\n",
248 h, portbuf, gai_strerror(error));
f0fca04e
AT
249 return -1;
250 }
251
06963d0f 252 s = -1;
2d6dbe29
MP
253 /* Try to connect to all addresses for this machine until we get
254 * through. It might e.g. be multi-homed, or have both IPv4 and IPv6
255 * addresses. We need to create a socket for each record, since the
256 * address record tells us what protocol to use to try to connect. */
06963d0f
MP
257 for (res = res0; res; res = res->ai_next) {
258 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
259 if (s < 0)
260 continue;
f0fca04e 261
4313d6f9 262 if (bind_addr
a3a84107 263 && try_bind_local(s, res->ai_family, type,
4313d6f9 264 bind_addr) == -1) {
a3a84107
WD
265 close(s);
266 s = -1;
267 continue;
268 }
06963d0f
MP
269 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
270 close(s);
271 s = -1;
272 continue;
273 }
a3a84107
WD
274 if (proxied
275 && establish_proxy_connection(s, host, port,
276 proxy_user, proxy_pass) != 0) {
06963d0f
MP
277 close(s);
278 s = -1;
279 continue;
a3a84107
WD
280 }
281 break;
4c3b4b25 282 }
06963d0f
MP
283 freeaddrinfo(res0);
284 if (s < 0) {
d62bcc17 285 rsyserr(FERROR, errno, "failed to connect to %s", h);
f0fca04e
AT
286 return -1;
287 }
06963d0f 288 return s;
f0fca04e
AT
289}
290
291
eecd22ff
MP
292/**
293 * Open an outgoing socket, but allow for it to be intercepted by
294 * $RSYNC_CONNECT_PROG, which will execute a program across a TCP
295 * socketpair rather than really opening a socket.
296 *
297 * We use this primarily in testing to detect TCP flow bugs, but not
298 * cause security problems by really opening remote connections.
299 *
300 * This is based on the Samba LIBSMB_PROG feature.
06963d0f 301 *
4313d6f9 302 * @param bind_addr Local address to use. Normally NULL to get the stack default.
eecd22ff 303 **/
4313d6f9 304int open_socket_out_wrapped(char *host, int port, const char *bind_addr,
9c07d253 305 int af_hint)
eecd22ff 306{
df5cd107 307 char *prog = getenv("RSYNC_CONNECT_PROG");
eecd22ff 308
df5cd107
WD
309 if (verbose >= 2) {
310 rprintf(FINFO, "%sopening tcp connection to %s port %d\n",
311 prog ? "Using RSYNC_CONNECT_PROG instead of " : "",
312 host, port);
313 }
314 if (prog)
9c07d253 315 return sock_exec(prog);
4313d6f9 316 return open_socket_out(host, port, bind_addr, af_hint);
eecd22ff
MP
317}
318
319
320
06963d0f 321/**
2c7d63c7
WD
322 * Open one or more sockets for incoming data using the specified type,
323 * port, and address.
06963d0f 324 *
2c7d63c7
WD
325 * The getaddrinfo() call may return several address results, e.g. for
326 * the machine's IPv4 and IPv6 name.
9c07d253 327 *
2c7d63c7
WD
328 * We return an array of file-descriptors to the sockets, with a trailing
329 * -1 value to indicate the end of the list.
9c07d253 330 *
4313d6f9 331 * @param bind_addr Local address to bind, or NULL to allow it to
06963d0f
MP
332 * default.
333 **/
4313d6f9 334static int *open_socket_in(int type, int port, const char *bind_addr,
b0fd253a 335 int af_hint)
f0fca04e 336{
2c7d63c7 337 int one = 1;
5c6d4632 338 int s, *socks, maxs, i, ecnt;
13e29995 339 struct addrinfo hints, *all_ai, *resp;
5c6d4632 340 char portbuf[10], **errmsgs;
06963d0f
MP
341 int error;
342
a3a84107 343 memset(&hints, 0, sizeof hints);
d5d4b282 344 hints.ai_family = af_hint;
06963d0f
MP
345 hints.ai_socktype = type;
346 hints.ai_flags = AI_PASSIVE;
a3a84107 347 snprintf(portbuf, sizeof portbuf, "%d", port);
4313d6f9 348 error = getaddrinfo(bind_addr, portbuf, &hints, &all_ai);
06963d0f 349 if (error) {
7ef6aa64 350 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
4313d6f9 351 bind_addr, gai_strerror(error));
b0fd253a
WD
352 return NULL;
353 }
354
355 /* Count max number of sockets we might open. */
356 for (maxs = 0, resp = all_ai; resp; resp = resp->ai_next, maxs++) {}
2c7d63c7 357
5c6d4632
WD
358 socks = new_array(int, maxs + 1);
359 errmsgs = new_array(char *, maxs);
360 if (!socks || !errmsgs)
2c7d63c7 361 out_of_memory("open_socket_in");
06963d0f 362
13e29995
MP
363 /* We may not be able to create the socket, if for example the
364 * machine knows about IPv6 in the C library, but not in the
365 * kernel. */
5c6d4632 366 for (resp = all_ai, i = ecnt = 0; resp; resp = resp->ai_next) {
13e29995
MP
367 s = socket(resp->ai_family, resp->ai_socktype,
368 resp->ai_protocol);
369
b0fd253a 370 if (s == -1) {
5c6d4632
WD
371 int r = asprintf(&errmsgs[ecnt++],
372 "socket(%d,%d,%d) failed: %s\n",
373 (int)resp->ai_family, (int)resp->ai_socktype,
374 (int)resp->ai_protocol, strerror(errno));
375 if (r < 0)
376 out_of_memory("open_socket_in");
13e29995
MP
377 /* See if there's another address that will work... */
378 continue;
b0fd253a 379 }
9c07d253 380
13e29995
MP
381 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
382 (char *)&one, sizeof one);
9c07d253 383
b0fd253a
WD
384#ifdef IPV6_V6ONLY
385 if (resp->ai_family == AF_INET6) {
dcd08dc5
WD
386 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
387 (char *)&one, sizeof one) < 0
388 && default_af_hint != AF_INET6) {
389 close(s);
390 continue;
391 }
b0fd253a
WD
392 }
393#endif
394
e028b9ff
WD
395 /* Now we've got a socket - we need to bind it. */
396 if (bind(s, resp->ai_addr, resp->ai_addrlen) < 0) {
13e29995 397 /* Nope, try another */
5c6d4632 398 int r = asprintf(&errmsgs[ecnt++],
e2d774cd
WD
399 "bind() failed: %s (address-family %d)\n",
400 strerror(errno), (int)resp->ai_family);
5c6d4632
WD
401 if (r < 0)
402 out_of_memory("open_socket_in");
13e29995
MP
403 close(s);
404 continue;
b8771f96 405 }
e23d790f 406
2c7d63c7 407 socks[i++] = s;
f0fca04e 408 }
2c7d63c7 409 socks[i] = -1;
f0fca04e 410
b0fd253a
WD
411 if (all_ai)
412 freeaddrinfo(all_ai);
b8771f96 413
5c6d4632
WD
414 /* Only output the socket()/bind() messages if we were totally
415 * unsuccessful, or if the daemon is being run with -vv. */
416 for (s = 0; s < ecnt; s++) {
417 if (!i || verbose > 1)
418 rwrite(FLOG, errmsgs[s], strlen(errmsgs[s]));
419 free(errmsgs[s]);
420 }
421 free(errmsgs);
422
2c7d63c7 423 if (!i) {
b0fd253a 424 rprintf(FERROR,
2c7d63c7
WD
425 "unable to bind any inbound sockets on port %d\n",
426 port);
b0fd253a
WD
427 free(socks);
428 return NULL;
429 }
430 return socks;
f0fca04e
AT
431}
432
433
7c1b4daa
MP
434/*
435 * Determine if a file descriptor is in fact a socket
436 */
f0fca04e
AT
437int is_a_socket(int fd)
438{
ac2a1a44 439 int v;
a3a84107
WD
440 socklen_t l = sizeof (int);
441
442 /* Parameters to getsockopt, setsockopt etc are very
443 * unstandardized across platforms, so don't be surprised if
444 * there are compiler warnings on e.g. SCO OpenSwerver or AIX.
445 * It seems they all eventually get the right idea.
446 *
447 * Debian says: ``The fifth argument of getsockopt and
448 * setsockopt is in reality an int [*] (and this is what BSD
449 * 4.* and libc4 and libc5 have). Some POSIX confusion
450 * resulted in the present socklen_t. The draft standard has
451 * not been adopted yet, but glibc2 already follows it and
452 * also has socklen_t [*]. See also accept(2).''
453 *
454 * We now return to your regularly scheduled programming. */
9c07d253 455 return getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0;
f0fca04e
AT
456}
457
458
067669da
WD
459static RETSIGTYPE sigchld_handler(UNUSED(int val))
460{
ca20c7fd
WD
461#ifdef WNOHANG
462 while (waitpid(-1, NULL, WNOHANG) > 0) {}
463#endif
44e604f4 464#ifndef HAVE_SIGACTION
cb984e62 465 signal(SIGCHLD, sigchld_handler);
2b28968d 466#endif
ca20c7fd
WD
467}
468
469
39993af5 470void start_accept_loop(int port, int (*fn)(int, int))
f0fca04e 471{
b0fd253a 472 fd_set deffds;
d8d36af4 473 int *sp, maxfd, i;
f0fca04e 474
44e604f4 475#ifdef HAVE_SIGACTION
2b28968d
WD
476 sigact.sa_flags = SA_NOCLDSTOP;
477#endif
478
f0fca04e 479 /* open an incoming socket */
b0fd253a
WD
480 sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
481 if (sp == NULL)
65417579 482 exit_cleanup(RERR_SOCKETIO);
f0fca04e
AT
483
484 /* ready to listen */
b0fd253a 485 FD_ZERO(&deffds);
2c7d63c7
WD
486 for (i = 0, maxfd = -1; sp[i] >= 0; i++) {
487 if (listen(sp[i], 5) < 0) {
d62bcc17 488 rsyserr(FERROR, errno, "listen() on socket failed");
4f5b0756 489#ifdef INET6
2c7d63c7
WD
490 if (errno == EADDRINUSE && i > 0) {
491 rprintf(FINFO,
880570f2 492 "Try using --ipv4 or --ipv6 to avoid this listen() error.\n");
2c7d63c7
WD
493 }
494#endif
b0fd253a
WD
495 exit_cleanup(RERR_SOCKETIO);
496 }
497 FD_SET(sp[i], &deffds);
498 if (maxfd < sp[i])
499 maxfd = sp[i];
f0fca04e
AT
500 }
501
f0fca04e 502 /* now accept incoming connections - forking a new process
a3a84107 503 * for each incoming connection */
f0fca04e
AT
504 while (1) {
505 fd_set fds;
c4a5c57d 506 pid_t pid;
f0fca04e 507 int fd;
2d6dbe29 508 struct sockaddr_storage addr;
d54765c4 509 socklen_t addrlen = sizeof addr;
f0fca04e 510
15b84e14 511 /* close log file before the potentially very long select so
a3a84107
WD
512 * file can be trimmed by another process instead of growing
513 * forever */
8ee6adef 514 logfile_close();
45a83540 515
b0fd253a
WD
516#ifdef FD_COPY
517 FD_COPY(&deffds, &fds);
518#else
519 fds = deffds;
520#endif
f0fca04e 521
b0fd253a 522 if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1)
9c07d253 523 continue;
f0fca04e 524
2c7d63c7 525 for (i = 0, fd = -1; sp[i] >= 0; i++) {
b0fd253a
WD
526 if (FD_ISSET(sp[i], &fds)) {
527 fd = accept(sp[i], (struct sockaddr *)&addr,
528 &addrlen);
529 break;
530 }
531 }
f0fca04e 532
b0fd253a 533 if (fd < 0)
9c07d253 534 continue;
f0fca04e 535
2b28968d 536 SIGACTION(SIGCHLD, sigchld_handler);
31f440e6 537
c4a5c57d 538 if ((pid = fork()) == 0) {
9f639210 539 int ret;
2c7d63c7
WD
540 for (i = 0; sp[i] >= 0; i++)
541 close(sp[i]);
1da05366 542 /* Re-open log file in child before possibly giving
8ee6adef
WD
543 * up privileges (see logfile_close() above). */
544 logfile_reopen();
9f639210
DD
545 ret = fn(fd, fd);
546 close_all();
547 _exit(ret);
c4a5c57d 548 } else if (pid < 0) {
d62bcc17
WD
549 rsyserr(FERROR, errno,
550 "could not create child server process");
c4a5c57d
MP
551 close(fd);
552 /* This might have happened because we're
553 * overloaded. Sleep briefly before trying to
554 * accept again. */
555 sleep(2);
bd37c666 556 } else {
79845f28 557 /* Parent doesn't need this fd anymore. */
bd37c666 558 close(fd);
f0fca04e 559 }
f0fca04e 560 }
f0fca04e
AT
561}
562
563
564enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
565
566struct
567{
568 char *name;
569 int level;
570 int option;
571 int value;
572 int opttype;
573} socket_options[] = {
574 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
575 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
576 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
577#ifdef TCP_NODELAY
578 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
579#endif
580#ifdef IPTOS_LOWDELAY
581 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
582#endif
583#ifdef IPTOS_THROUGHPUT
584 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
585#endif
586#ifdef SO_SNDBUF
587 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
588#endif
589#ifdef SO_RCVBUF
590 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
591#endif
592#ifdef SO_SNDLOWAT
593 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
594#endif
595#ifdef SO_RCVLOWAT
596 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
597#endif
598#ifdef SO_SNDTIMEO
599 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
600#endif
601#ifdef SO_RCVTIMEO
602 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
603#endif
604 {NULL,0,0,0,0}};
605
9c07d253 606
f0fca04e 607
a7dc44d2
MP
608/**
609 * Set user socket options
610 **/
f0fca04e
AT
611void set_socket_options(int fd, char *options)
612{
613 char *tok;
9c07d253
WD
614
615 if (!options || !*options)
616 return;
a6801c39 617
f0fca04e 618 options = strdup(options);
f0fca04e 619
9c07d253
WD
620 if (!options)
621 out_of_memory("set_socket_options");
622
623 for (tok = strtok(options, " \t,"); tok; tok = strtok(NULL," \t,")) {
f0fca04e
AT
624 int ret=0,i;
625 int value = 1;
626 char *p;
627 int got_value = 0;
628
629 if ((p = strchr(tok,'='))) {
630 *p = 0;
631 value = atoi(p+1);
632 got_value = 1;
633 }
634
9c07d253 635 for (i = 0; socket_options[i].name; i++) {
f0fca04e
AT
636 if (strcmp(socket_options[i].name,tok)==0)
637 break;
9c07d253 638 }
f0fca04e
AT
639
640 if (!socket_options[i].name) {
641 rprintf(FERROR,"Unknown socket option %s\n",tok);
642 continue;
643 }
644
645 switch (socket_options[i].opttype) {
646 case OPT_BOOL:
647 case OPT_INT:
648 ret = setsockopt(fd,socket_options[i].level,
a3a84107
WD
649 socket_options[i].option,
650 (char *)&value, sizeof (int));
f0fca04e 651 break;
9c07d253 652
f0fca04e
AT
653 case OPT_ON:
654 if (got_value)
4ccfd96c 655 rprintf(FERROR,"syntax error -- %s does not take a value\n",tok);
f0fca04e
AT
656
657 {
658 int on = socket_options[i].value;
659 ret = setsockopt(fd,socket_options[i].level,
a3a84107
WD
660 socket_options[i].option,
661 (char *)&on, sizeof (int));
f0fca04e 662 }
9c07d253 663 break;
f0fca04e 664 }
9c07d253 665
d62bcc17
WD
666 if (ret != 0) {
667 rsyserr(FERROR, errno,
668 "failed to set socket option %s", tok);
669 }
f0fca04e
AT
670 }
671
672 free(options);
673}
674
a7dc44d2
MP
675/**
676 * Become a daemon, discarding the controlling terminal
677 **/
f0fca04e
AT
678void become_daemon(void)
679{
b11ed3b1
AT
680 int i;
681
c46ded46 682 if (fork()) {
f0fca04e 683 _exit(0);
c46ded46 684 }
f0fca04e
AT
685
686 /* detach from the terminal */
4f5b0756 687#ifdef HAVE_SETSID
f0fca04e 688 setsid();
4f5b0756 689#elif defined TIOCNOTTY
c46ded46
AT
690 i = open("/dev/tty", O_RDWR);
691 if (i >= 0) {
9c07d253 692 ioctl(i, (int)TIOCNOTTY, (char *)0);
c46ded46 693 close(i);
f0fca04e 694 }
f0fca04e 695#endif
b11ed3b1 696 /* make sure that stdin, stdout an stderr don't stuff things
a3a84107 697 * up (library functions, for example) */
9c07d253
WD
698 for (i = 0; i < 3; i++) {
699 close(i);
b11ed3b1
AT
700 open("/dev/null", O_RDWR);
701 }
bc2e93eb 702}
ff8b29b8 703
eecd22ff 704
a7dc44d2
MP
705/**
706 * This is like socketpair but uses tcp. It is used by the Samba
707 * regression test code.
9c07d253 708 *
a7dc44d2
MP
709 * The function guarantees that nobody else can attach to the socket,
710 * or if they do that this function fails and the socket gets closed
711 * returns 0 on success, -1 on failure the resulting file descriptors
712 * are symmetrical.
713 **/
eecd22ff
MP
714static int socketpair_tcp(int fd[2])
715{
716 int listener;
717 struct sockaddr_in sock;
718 struct sockaddr_in sock2;
a3a84107 719 socklen_t socklen = sizeof sock;
eb8ffa90 720 int connect_done = 0;
9c07d253 721
eecd22ff
MP
722 fd[0] = fd[1] = listener = -1;
723
a3a84107 724 memset(&sock, 0, sizeof sock);
9c07d253
WD
725
726 if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1)
727 goto failed;
eecd22ff 728
a3a84107 729 memset(&sock2, 0, sizeof sock2);
4f5b0756 730#ifdef HAVE_SOCKADDR_IN_LEN
a3a84107 731 sock2.sin_len = sizeof sock2;
eecd22ff 732#endif
a3a84107 733 sock2.sin_family = PF_INET;
eecd22ff 734
a3a84107 735 bind(listener, (struct sockaddr *)&sock2, sizeof sock2);
eecd22ff 736
9c07d253
WD
737 if (listen(listener, 1) != 0)
738 goto failed;
eecd22ff 739
9c07d253
WD
740 if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0)
741 goto failed;
eecd22ff 742
9c07d253
WD
743 if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1)
744 goto failed;
eecd22ff
MP
745
746 set_nonblocking(fd[1]);
747
748 sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
749
a3a84107 750 if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) == -1) {
9c07d253
WD
751 if (errno != EINPROGRESS)
752 goto failed;
753 } else
eecd22ff 754 connect_done = 1;
eecd22ff 755
9c07d253
WD
756 if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1)
757 goto failed;
eecd22ff
MP
758
759 close(listener);
ab217f7f
WD
760 listener = -1;
761
762 set_blocking(fd[1]);
763
eecd22ff 764 if (connect_done == 0) {
a3a84107 765 if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0
9c07d253
WD
766 && errno != EISCONN)
767 goto failed;
eecd22ff
MP
768 }
769
eecd22ff
MP
770 /* all OK! */
771 return 0;
772
773 failed:
9c07d253
WD
774 if (fd[0] != -1)
775 close(fd[0]);
776 if (fd[1] != -1)
777 close(fd[1]);
778 if (listener != -1)
779 close(listener);
eecd22ff
MP
780 return -1;
781}
782
783
d02984bb
MP
784
785/**
786 * Run a program on a local tcp socket, so that we can talk to it's
255810c0
MP
787 * stdin and stdout. This is used to fake a connection to a daemon
788 * for testing -- not for the normal case of running SSH.
d02984bb
MP
789 *
790 * @return a socket which is attached to a subprocess running
791 * "prog". stdin and stdout are attached. stderr is left attached to
792 * the original stderr
793 **/
eecd22ff
MP
794int sock_exec(const char *prog)
795{
796 int fd[2];
9c07d253 797
eecd22ff 798 if (socketpair_tcp(fd) != 0) {
d62bcc17 799 rsyserr(FERROR, errno, "socketpair_tcp failed");
eecd22ff
MP
800 return -1;
801 }
df5cd107
WD
802 if (verbose >= 2)
803 rprintf(FINFO, "Running socket program: \"%s\"\n", prog);
eecd22ff
MP
804 if (fork() == 0) {
805 close(fd[0]);
806 close(0);
807 close(1);
808 dup(fd[1]);
809 dup(fd[1]);
9c07d253 810 exit(system(prog));
eecd22ff 811 }
9c07d253 812 close(fd[1]);
eecd22ff
MP
813 return fd[0];
814}