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