Fixed a potential problem parsing the "!" token from a word-split string.
[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
MP
301{
302 char *prog;
303
9c07d253
WD
304 if ((prog = getenv("RSYNC_CONNECT_PROG")) != NULL)
305 return sock_exec(prog);
306 return open_socket_out(host, port, bind_address, af_hint);
eecd22ff
MP
307}
308
309
310
06963d0f
MP
311/**
312 * Open a socket of the specified type, port and address for incoming data
313 *
b8771f96
MP
314 * Try to be better about handling the results of getaddrinfo(): when
315 * opening an inbound socket, we might get several address results,
9c07d253
WD
316 * e.g. for the machine's ipv4 and ipv6 name.
317 *
b8771f96
MP
318 * If binding a wildcard, then any one of them should do. If an address
319 * was specified but it's insufficiently specific then that's not our
9c07d253
WD
320 * fault.
321 *
b8771f96
MP
322 * However, some of the advertized addresses may not work because e.g. we
323 * don't have IPv6 support in the kernel. In that case go on and try all
324 * addresses until one succeeds.
9c07d253 325 *
06963d0f
MP
326 * @param bind_address Local address to bind, or NULL to allow it to
327 * default.
328 **/
b0fd253a
WD
329static int *open_socket_in(int type, int port, const char *bind_address,
330 int af_hint)
f0fca04e 331{
f0fca04e 332 int one=1;
b0fd253a 333 int s, *sp, *socks, maxs;
13e29995 334 struct addrinfo hints, *all_ai, *resp;
06963d0f
MP
335 char portbuf[10];
336 int error;
337
a3a84107 338 memset(&hints, 0, sizeof hints);
d5d4b282 339 hints.ai_family = af_hint;
06963d0f
MP
340 hints.ai_socktype = type;
341 hints.ai_flags = AI_PASSIVE;
a3a84107 342 snprintf(portbuf, sizeof portbuf, "%d", port);
13e29995 343 error = getaddrinfo(bind_address, portbuf, &hints, &all_ai);
06963d0f 344 if (error) {
7ef6aa64
MP
345 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
346 bind_address, gai_strerror(error));
b0fd253a
WD
347 return NULL;
348 }
349
350 /* Count max number of sockets we might open. */
351 for (maxs = 0, resp = all_ai; resp; resp = resp->ai_next, maxs++) {}
352 socks = new_array(int, maxs + 1);
353 if (!socks) {
354 rprintf(FERROR,
355 RSYNC_NAME "couldn't allocate memory for sockets");
356 return NULL;
06963d0f 357 }
06963d0f 358
13e29995
MP
359 /* We may not be able to create the socket, if for example the
360 * machine knows about IPv6 in the C library, but not in the
361 * kernel. */
b0fd253a 362 sp = socks + 1; /* Leave room for count at start of array. */
13e29995
MP
363 for (resp = all_ai; resp; resp = resp->ai_next) {
364 s = socket(resp->ai_family, resp->ai_socktype,
365 resp->ai_protocol);
366
b0fd253a 367 if (s == -1) {
13e29995
MP
368 /* See if there's another address that will work... */
369 continue;
b0fd253a 370 }
9c07d253 371
13e29995
MP
372 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
373 (char *)&one, sizeof one);
9c07d253 374
b0fd253a
WD
375#ifdef IPV6_V6ONLY
376 if (resp->ai_family == AF_INET6) {
377 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
378 (char *)&one, sizeof one);
379 }
380#endif
381
e028b9ff
WD
382 /* Now we've got a socket - we need to bind it. */
383 if (bind(s, resp->ai_addr, resp->ai_addrlen) < 0) {
13e29995
MP
384 /* Nope, try another */
385 close(s);
386 continue;
b8771f96 387 }
e23d790f 388
b0fd253a 389 *sp++ = s;
f0fca04e 390 }
b0fd253a 391 *socks = sp - socks - 1; /* Save count. */
f0fca04e 392
b0fd253a
WD
393 if (all_ai)
394 freeaddrinfo(all_ai);
b8771f96 395
b0fd253a
WD
396 if (*socks == 0) {
397 rprintf(FERROR,
398 RSYNC_NAME ": open inbound socket on port %d failed: "
399 "%s\n", port, strerror(errno));
400 free(socks);
401 return NULL;
402 }
403 return socks;
f0fca04e
AT
404}
405
406
7c1b4daa
MP
407/*
408 * Determine if a file descriptor is in fact a socket
409 */
f0fca04e
AT
410int is_a_socket(int fd)
411{
ac2a1a44 412 int v;
a3a84107
WD
413 socklen_t l = sizeof (int);
414
415 /* Parameters to getsockopt, setsockopt etc are very
416 * unstandardized across platforms, so don't be surprised if
417 * there are compiler warnings on e.g. SCO OpenSwerver or AIX.
418 * It seems they all eventually get the right idea.
419 *
420 * Debian says: ``The fifth argument of getsockopt and
421 * setsockopt is in reality an int [*] (and this is what BSD
422 * 4.* and libc4 and libc5 have). Some POSIX confusion
423 * resulted in the present socklen_t. The draft standard has
424 * not been adopted yet, but glibc2 already follows it and
425 * also has socklen_t [*]. See also accept(2).''
426 *
427 * We now return to your regularly scheduled programming. */
9c07d253 428 return getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0;
f0fca04e
AT
429}
430
431
067669da
WD
432static RETSIGTYPE sigchld_handler(UNUSED(int val))
433{
ca20c7fd
WD
434#ifdef WNOHANG
435 while (waitpid(-1, NULL, WNOHANG) > 0) {}
436#endif
cb984e62 437 signal(SIGCHLD, sigchld_handler);
ca20c7fd
WD
438}
439
440
39993af5 441void start_accept_loop(int port, int (*fn)(int, int))
f0fca04e 442{
b0fd253a
WD
443 fd_set deffds;
444 int *sp, maxfd, i, j;
06963d0f 445 extern char *bind_address;
13e29995 446 extern int default_af_hint;
f0fca04e 447
f0fca04e 448 /* open an incoming socket */
b0fd253a
WD
449 sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
450 if (sp == NULL)
65417579 451 exit_cleanup(RERR_SOCKETIO);
f0fca04e
AT
452
453 /* ready to listen */
b0fd253a
WD
454 FD_ZERO(&deffds);
455 maxfd = -1;
456 for (i = 1; i <= *sp; i++) {
457 if (listen(sp[i], 5) == -1) {
458 for (j = 1; j <= i; j++)
459 close(sp[j]);
460 free(sp);
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
b0fd253a
WD
492 fd = -1;
493 for (i = 1; i <= *sp; i++) {
494 if (FD_ISSET(sp[i], &fds)) {
495 fd = accept(sp[i], (struct sockaddr *)&addr,
496 &addrlen);
497 break;
498 }
499 }
f0fca04e 500
b0fd253a 501 if (fd < 0)
9c07d253 502 continue;
f0fca04e 503
ca20c7fd 504 signal(SIGCHLD, sigchld_handler);
31f440e6 505
c4a5c57d 506 if ((pid = fork()) == 0) {
9f639210 507 int ret;
b0fd253a 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 }
772 if (fork() == 0) {
773 close(fd[0]);
774 close(0);
775 close(1);
776 dup(fd[1]);
777 dup(fd[1]);
5d264037
MP
778 if (verbose > 3) {
779 /* Can't use rprintf because we've forked. */
9c07d253
WD
780 fprintf(stderr,
781 RSYNC_NAME ": execute socket program \"%s\"\n",
782 prog);
5d264037 783 }
9c07d253 784 exit(system(prog));
eecd22ff 785 }
9c07d253 786 close(fd[1]);
eecd22ff
MP
787 return fd[0];
788}