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