Added "debug_type" to the exclude_list_struct.
[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,
9c07d253
WD
321 * e.g. for the machine's ipv4 and ipv6 name.
322 *
b8771f96
MP
323 * If binding a wildcard, then any one of them should do. If an address
324 * was specified but it's insufficiently specific then that's not our
9c07d253
WD
325 * fault.
326 *
b8771f96
MP
327 * However, some of the advertized addresses may not work because e.g. we
328 * don't have IPv6 support in the kernel. In that case go on and try all
329 * addresses until one succeeds.
9c07d253 330 *
06963d0f
MP
331 * @param bind_address Local address to bind, or NULL to allow it to
332 * default.
333 **/
b0fd253a
WD
334static int *open_socket_in(int type, int port, const char *bind_address,
335 int af_hint)
f0fca04e 336{
f0fca04e 337 int one=1;
b0fd253a 338 int s, *sp, *socks, maxs;
13e29995 339 struct addrinfo hints, *all_ai, *resp;
06963d0f
MP
340 char portbuf[10];
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);
13e29995 348 error = getaddrinfo(bind_address, portbuf, &hints, &all_ai);
06963d0f 349 if (error) {
7ef6aa64
MP
350 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
351 bind_address, 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++) {}
357 socks = new_array(int, maxs + 1);
358 if (!socks) {
359 rprintf(FERROR,
360 RSYNC_NAME "couldn't allocate memory for sockets");
361 return NULL;
06963d0f 362 }
06963d0f 363
13e29995
MP
364 /* We may not be able to create the socket, if for example the
365 * machine knows about IPv6 in the C library, but not in the
366 * kernel. */
b0fd253a 367 sp = socks + 1; /* Leave room for count at start of array. */
13e29995
MP
368 for (resp = all_ai; resp; resp = resp->ai_next) {
369 s = socket(resp->ai_family, resp->ai_socktype,
370 resp->ai_protocol);
371
b0fd253a 372 if (s == -1) {
13e29995
MP
373 /* See if there's another address that will work... */
374 continue;
b0fd253a 375 }
9c07d253 376
13e29995
MP
377 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
378 (char *)&one, sizeof one);
9c07d253 379
b0fd253a
WD
380#ifdef IPV6_V6ONLY
381 if (resp->ai_family == AF_INET6) {
382 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
383 (char *)&one, sizeof one);
384 }
385#endif
386
e028b9ff
WD
387 /* Now we've got a socket - we need to bind it. */
388 if (bind(s, resp->ai_addr, resp->ai_addrlen) < 0) {
13e29995
MP
389 /* Nope, try another */
390 close(s);
391 continue;
b8771f96 392 }
e23d790f 393
b0fd253a 394 *sp++ = s;
f0fca04e 395 }
b0fd253a 396 *socks = sp - socks - 1; /* Save count. */
f0fca04e 397
b0fd253a
WD
398 if (all_ai)
399 freeaddrinfo(all_ai);
b8771f96 400
b0fd253a
WD
401 if (*socks == 0) {
402 rprintf(FERROR,
403 RSYNC_NAME ": open inbound socket on port %d failed: "
404 "%s\n", port, strerror(errno));
405 free(socks);
406 return NULL;
407 }
408 return socks;
f0fca04e
AT
409}
410
411
7c1b4daa
MP
412/*
413 * Determine if a file descriptor is in fact a socket
414 */
f0fca04e
AT
415int is_a_socket(int fd)
416{
ac2a1a44 417 int v;
a3a84107
WD
418 socklen_t l = sizeof (int);
419
420 /* Parameters to getsockopt, setsockopt etc are very
421 * unstandardized across platforms, so don't be surprised if
422 * there are compiler warnings on e.g. SCO OpenSwerver or AIX.
423 * It seems they all eventually get the right idea.
424 *
425 * Debian says: ``The fifth argument of getsockopt and
426 * setsockopt is in reality an int [*] (and this is what BSD
427 * 4.* and libc4 and libc5 have). Some POSIX confusion
428 * resulted in the present socklen_t. The draft standard has
429 * not been adopted yet, but glibc2 already follows it and
430 * also has socklen_t [*]. See also accept(2).''
431 *
432 * We now return to your regularly scheduled programming. */
9c07d253 433 return getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0;
f0fca04e
AT
434}
435
436
067669da
WD
437static RETSIGTYPE sigchld_handler(UNUSED(int val))
438{
ca20c7fd
WD
439#ifdef WNOHANG
440 while (waitpid(-1, NULL, WNOHANG) > 0) {}
441#endif
cb984e62 442 signal(SIGCHLD, sigchld_handler);
ca20c7fd
WD
443}
444
445
39993af5 446void start_accept_loop(int port, int (*fn)(int, int))
f0fca04e 447{
b0fd253a
WD
448 fd_set deffds;
449 int *sp, maxfd, i, j;
06963d0f 450 extern char *bind_address;
13e29995 451 extern int default_af_hint;
f0fca04e 452
f0fca04e 453 /* open an incoming socket */
b0fd253a
WD
454 sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
455 if (sp == NULL)
65417579 456 exit_cleanup(RERR_SOCKETIO);
f0fca04e
AT
457
458 /* ready to listen */
b0fd253a
WD
459 FD_ZERO(&deffds);
460 maxfd = -1;
461 for (i = 1; i <= *sp; i++) {
462 if (listen(sp[i], 5) == -1) {
463 for (j = 1; j <= i; j++)
464 close(sp[j]);
465 free(sp);
466 exit_cleanup(RERR_SOCKETIO);
467 }
468 FD_SET(sp[i], &deffds);
469 if (maxfd < sp[i])
470 maxfd = sp[i];
f0fca04e
AT
471 }
472
473
474 /* now accept incoming connections - forking a new process
a3a84107 475 * for each incoming connection */
f0fca04e
AT
476 while (1) {
477 fd_set fds;
c4a5c57d 478 pid_t pid;
f0fca04e 479 int fd;
2d6dbe29 480 struct sockaddr_storage addr;
d54765c4 481 socklen_t addrlen = sizeof addr;
f0fca04e 482
15b84e14 483 /* close log file before the potentially very long select so
a3a84107
WD
484 * file can be trimmed by another process instead of growing
485 * forever */
15b84e14 486 log_close();
45a83540 487
b0fd253a
WD
488#ifdef FD_COPY
489 FD_COPY(&deffds, &fds);
490#else
491 fds = deffds;
492#endif
f0fca04e 493
b0fd253a 494 if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1)
9c07d253 495 continue;
f0fca04e 496
b0fd253a
WD
497 fd = -1;
498 for (i = 1; i <= *sp; i++) {
499 if (FD_ISSET(sp[i], &fds)) {
500 fd = accept(sp[i], (struct sockaddr *)&addr,
501 &addrlen);
502 break;
503 }
504 }
f0fca04e 505
b0fd253a 506 if (fd < 0)
9c07d253 507 continue;
f0fca04e 508
ca20c7fd 509 signal(SIGCHLD, sigchld_handler);
31f440e6 510
c4a5c57d 511 if ((pid = fork()) == 0) {
9f639210 512 int ret;
b0fd253a 513 close(sp[i]);
15b84e14 514 /* open log file in child before possibly giving
a3a84107 515 * up privileges */
15b84e14 516 log_open();
9f639210
DD
517 ret = fn(fd, fd);
518 close_all();
519 _exit(ret);
c4a5c57d
MP
520 } else if (pid < 0) {
521 rprintf(FERROR,
522 RSYNC_NAME
523 ": could not create child server process: %s\n",
524 strerror(errno));
525 close(fd);
526 /* This might have happened because we're
527 * overloaded. Sleep briefly before trying to
528 * accept again. */
529 sleep(2);
bd37c666 530 } else {
79845f28 531 /* Parent doesn't need this fd anymore. */
bd37c666 532 close(fd);
f0fca04e 533 }
f0fca04e 534 }
b0fd253a 535 free(sp);
f0fca04e
AT
536}
537
538
539enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
540
541struct
542{
543 char *name;
544 int level;
545 int option;
546 int value;
547 int opttype;
548} socket_options[] = {
549 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
550 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
551 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
552#ifdef TCP_NODELAY
553 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
554#endif
555#ifdef IPTOS_LOWDELAY
556 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
557#endif
558#ifdef IPTOS_THROUGHPUT
559 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
560#endif
561#ifdef SO_SNDBUF
562 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
563#endif
564#ifdef SO_RCVBUF
565 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
566#endif
567#ifdef SO_SNDLOWAT
568 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
569#endif
570#ifdef SO_RCVLOWAT
571 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
572#endif
573#ifdef SO_SNDTIMEO
574 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
575#endif
576#ifdef SO_RCVTIMEO
577 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
578#endif
579 {NULL,0,0,0,0}};
580
9c07d253 581
f0fca04e 582
a7dc44d2
MP
583/**
584 * Set user socket options
585 **/
f0fca04e
AT
586void set_socket_options(int fd, char *options)
587{
588 char *tok;
9c07d253
WD
589
590 if (!options || !*options)
591 return;
a6801c39 592
f0fca04e 593 options = strdup(options);
f0fca04e 594
9c07d253
WD
595 if (!options)
596 out_of_memory("set_socket_options");
597
598 for (tok = strtok(options, " \t,"); tok; tok = strtok(NULL," \t,")) {
f0fca04e
AT
599 int ret=0,i;
600 int value = 1;
601 char *p;
602 int got_value = 0;
603
604 if ((p = strchr(tok,'='))) {
605 *p = 0;
606 value = atoi(p+1);
607 got_value = 1;
608 }
609
9c07d253 610 for (i = 0; socket_options[i].name; i++) {
f0fca04e
AT
611 if (strcmp(socket_options[i].name,tok)==0)
612 break;
9c07d253 613 }
f0fca04e
AT
614
615 if (!socket_options[i].name) {
616 rprintf(FERROR,"Unknown socket option %s\n",tok);
617 continue;
618 }
619
620 switch (socket_options[i].opttype) {
621 case OPT_BOOL:
622 case OPT_INT:
623 ret = setsockopt(fd,socket_options[i].level,
a3a84107
WD
624 socket_options[i].option,
625 (char *)&value, sizeof (int));
f0fca04e 626 break;
9c07d253 627
f0fca04e
AT
628 case OPT_ON:
629 if (got_value)
630 rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
631
632 {
633 int on = socket_options[i].value;
634 ret = setsockopt(fd,socket_options[i].level,
a3a84107
WD
635 socket_options[i].option,
636 (char *)&on, sizeof (int));
f0fca04e 637 }
9c07d253 638 break;
f0fca04e 639 }
9c07d253 640
f0fca04e 641 if (ret != 0)
660c6fbd
MP
642 rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
643 strerror(errno));
f0fca04e
AT
644 }
645
646 free(options);
647}
648
a7dc44d2
MP
649/**
650 * Become a daemon, discarding the controlling terminal
651 **/
f0fca04e
AT
652void become_daemon(void)
653{
b11ed3b1
AT
654 int i;
655
c46ded46 656 if (fork()) {
f0fca04e 657 _exit(0);
c46ded46 658 }
f0fca04e
AT
659
660 /* detach from the terminal */
661#ifdef HAVE_SETSID
662 setsid();
663#else
664#ifdef TIOCNOTTY
c46ded46
AT
665 i = open("/dev/tty", O_RDWR);
666 if (i >= 0) {
9c07d253 667 ioctl(i, (int)TIOCNOTTY, (char *)0);
c46ded46 668 close(i);
f0fca04e
AT
669 }
670#endif /* TIOCNOTTY */
671#endif
b11ed3b1 672 /* make sure that stdin, stdout an stderr don't stuff things
a3a84107 673 * up (library functions, for example) */
9c07d253
WD
674 for (i = 0; i < 3; i++) {
675 close(i);
b11ed3b1
AT
676 open("/dev/null", O_RDWR);
677 }
bc2e93eb 678}
ff8b29b8 679
eecd22ff 680
a7dc44d2
MP
681/**
682 * This is like socketpair but uses tcp. It is used by the Samba
683 * regression test code.
9c07d253 684 *
a7dc44d2
MP
685 * The function guarantees that nobody else can attach to the socket,
686 * or if they do that this function fails and the socket gets closed
687 * returns 0 on success, -1 on failure the resulting file descriptors
688 * are symmetrical.
689 **/
eecd22ff
MP
690static int socketpair_tcp(int fd[2])
691{
692 int listener;
693 struct sockaddr_in sock;
694 struct sockaddr_in sock2;
a3a84107 695 socklen_t socklen = sizeof sock;
eecd22ff 696 int connect_done = 0;
9c07d253 697
eecd22ff
MP
698 fd[0] = fd[1] = listener = -1;
699
a3a84107 700 memset(&sock, 0, sizeof sock);
9c07d253
WD
701
702 if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1)
703 goto failed;
eecd22ff 704
a3a84107 705 memset(&sock2, 0, sizeof sock2);
16f72adc 706#if HAVE_SOCKADDR_IN_LEN
a3a84107 707 sock2.sin_len = sizeof sock2;
eecd22ff 708#endif
a3a84107 709 sock2.sin_family = PF_INET;
eecd22ff 710
a3a84107 711 bind(listener, (struct sockaddr *)&sock2, sizeof sock2);
eecd22ff 712
9c07d253
WD
713 if (listen(listener, 1) != 0)
714 goto failed;
eecd22ff 715
9c07d253
WD
716 if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0)
717 goto failed;
eecd22ff 718
9c07d253
WD
719 if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1)
720 goto failed;
eecd22ff
MP
721
722 set_nonblocking(fd[1]);
723
724 sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
725
a3a84107 726 if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) == -1) {
9c07d253
WD
727 if (errno != EINPROGRESS)
728 goto failed;
729 } else
eecd22ff 730 connect_done = 1;
eecd22ff 731
9c07d253
WD
732 if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1)
733 goto failed;
eecd22ff
MP
734
735 close(listener);
736 if (connect_done == 0) {
a3a84107 737 if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0
9c07d253
WD
738 && errno != EISCONN)
739 goto failed;
eecd22ff
MP
740 }
741
9c07d253 742 set_blocking(fd[1]);
eecd22ff
MP
743
744 /* all OK! */
745 return 0;
746
747 failed:
9c07d253
WD
748 if (fd[0] != -1)
749 close(fd[0]);
750 if (fd[1] != -1)
751 close(fd[1]);
752 if (listener != -1)
753 close(listener);
eecd22ff
MP
754 return -1;
755}
756
757
d02984bb
MP
758
759/**
760 * Run a program on a local tcp socket, so that we can talk to it's
255810c0
MP
761 * stdin and stdout. This is used to fake a connection to a daemon
762 * for testing -- not for the normal case of running SSH.
d02984bb
MP
763 *
764 * @return a socket which is attached to a subprocess running
765 * "prog". stdin and stdout are attached. stderr is left attached to
766 * the original stderr
767 **/
eecd22ff
MP
768int sock_exec(const char *prog)
769{
770 int fd[2];
9c07d253 771
eecd22ff 772 if (socketpair_tcp(fd) != 0) {
9c07d253
WD
773 rprintf(FERROR, RSYNC_NAME ": socketpair_tcp failed (%s)\n",
774 strerror(errno));
eecd22ff
MP
775 return -1;
776 }
df5cd107
WD
777 if (verbose >= 2)
778 rprintf(FINFO, "Running socket program: \"%s\"\n", prog);
eecd22ff
MP
779 if (fork() == 0) {
780 close(fd[0]);
781 close(0);
782 close(1);
783 dup(fd[1]);
784 dup(fd[1]);
9c07d253 785 exit(system(prog));
eecd22ff 786 }
9c07d253 787 close(fd[1]);
eecd22ff
MP
788 return fd[0];
789}