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