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