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