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