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