Show helper program with -v when opening connection.
[rsync/rsync.git] / socket.c
... / ...
CommitLineData
1/* -*- c-file-style: "linux" -*-
2
3 rsync -- fast file replication program
4
5 Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
6 Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
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
23/**
24 * @file socket.c
25 *
26 * Socket functions used in rsync.
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.
32 **/
33
34#include "rsync.h"
35
36static const char default_name[] = "UNKNOWN";
37
38static int lookup_name(const struct sockaddr_storage *ss,
39 socklen_t ss_len,
40 char *name_buf, size_t name_buf_len,
41 char *port_buf, size_t port_buf_len);
42
43static int check_name(const struct sockaddr_storage *ss,
44 socklen_t ss_len,
45 char *name_buf,
46 const char *port_buf);
47
48/* Establish a proxy connection on an open socket to a web roxy by
49 * using the CONNECT method. */
50static int establish_proxy_connection(int fd, char *host, int port)
51{
52 char buffer[1024];
53 char *cp;
54
55 snprintf(buffer, sizeof(buffer), "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
56 if (write(fd, buffer, strlen(buffer)) != strlen(buffer)) {
57 rprintf(FERROR, "failed to write to proxy: %s\n",
58 strerror(errno));
59 return -1;
60 }
61
62 for (cp = buffer; cp < &buffer[sizeof(buffer) - 1]; cp++) {
63 if (read(fd, cp, 1) != 1) {
64 rprintf(FERROR, "failed to read from proxy: %s\n",
65 strerror(errno));
66 return -1;
67 }
68 if (*cp == '\n')
69 break;
70 }
71
72 if (*cp != '\n')
73 cp++;
74 *cp-- = '\0';
75 if (*cp == '\r')
76 *cp = '\0';
77 if (strncmp(buffer, "HTTP/", 5) != 0) {
78 rprintf(FERROR, "bad response from proxy - %s\n",
79 buffer);
80 return -1;
81 }
82 for (cp = &buffer[5]; isdigit(*cp) || (*cp == '.'); cp++)
83 ;
84 while (*cp == ' ')
85 cp++;
86 if (*cp != '2') {
87 rprintf(FERROR, "bad response from proxy - %s\n",
88 buffer);
89 return -1;
90 }
91 /* throw away the rest of the HTTP header */
92 while (1) {
93 for (cp = buffer; cp < &buffer[sizeof(buffer) - 1];
94 cp++) {
95 if (read(fd, cp, 1) != 1) {
96 rprintf(FERROR, "failed to read from proxy: %s\n",
97 strerror(errno));
98 return -1;
99 }
100 if (*cp == '\n')
101 break;
102 }
103 if ((cp > buffer) && (*cp == '\n'))
104 cp--;
105 if ((cp == buffer) && ((*cp == '\n') || (*cp == '\r')))
106 break;
107 }
108 return 0;
109}
110
111
112/**
113 * Try to set the local address for a newly-created socket. Return -1
114 * if this fails.
115 **/
116int try_bind_local(int s,
117 int ai_family, int ai_socktype,
118 const char *bind_address)
119{
120 int error;
121 struct addrinfo bhints, *bres_all, *r;
122
123 memset(&bhints, 0, sizeof(bhints));
124 bhints.ai_family = ai_family;
125 bhints.ai_socktype = ai_socktype;
126 bhints.ai_flags = AI_PASSIVE;
127 if ((error = getaddrinfo(bind_address, NULL, &bhints, &bres_all))) {
128 rprintf(FERROR, RSYNC_NAME ": getaddrinfo %s: %s\n",
129 bind_address, gai_strerror(error));
130 return -1;
131 }
132
133 for (r = bres_all; r; r = r->ai_next) {
134 if (bind(s, r->ai_addr, r->ai_addrlen) == -1)
135 continue;
136 return s;
137 }
138
139 /* no error message; there might be some problem that allows
140 * creation of the socket but not binding, perhaps if the
141 * machine has no ipv6 address of this name. */
142 return -1;
143}
144
145
146/**
147 * Open a socket to a tcp remote host with the specified port .
148 *
149 * Based on code from Warren. Proxy support by Stephen Rothwell.
150 * getaddrinfo() rewrite contributed by KAME.net.
151 *
152 * Now that we support IPv6 we need to look up the remote machine's
153 * address first, using @p af_hint to set a preference for the type
154 * of address. Then depending on whether it has v4 or v6 addresses we
155 * try to open a connection.
156 *
157 * The loop allows for machines with some addresses which may not be
158 * reachable, perhaps because we can't e.g. route ipv6 to that network
159 * but we can get ip4 packets through.
160 *
161 * @param bind_address Local address to use. Normally NULL to bind
162 * the wildcard address.
163 *
164 * @param af_hint Address family, e.g. AF_INET or AF_INET6.
165 **/
166int open_socket_out(char *host, int port, const char *bind_address,
167 int af_hint)
168{
169 int type = SOCK_STREAM;
170 int error;
171 int s;
172 struct addrinfo hints, *res0, *res;
173 char portbuf[10];
174 char *h;
175 int proxied = 0;
176 char buffer[1024];
177 char *cp;
178
179 /* if we have a RSYNC_PROXY env variable then redirect our
180 * connetcion via a web proxy at the given address. The format
181 * is hostname:port */
182 h = getenv("RSYNC_PROXY");
183 proxied = (h != NULL) && (*h != '\0');
184
185 if (proxied) {
186 strlcpy(buffer, h, sizeof(buffer));
187 cp = strchr(buffer, ':');
188 if (cp == NULL) {
189 rprintf(FERROR,
190 "invalid proxy specification: should be HOST:PORT\n");
191 return -1;
192 }
193 *cp++ = '\0';
194 strcpy(portbuf, cp);
195 h = buffer;
196 } else {
197 snprintf(portbuf, sizeof(portbuf), "%d", port);
198 h = host;
199 }
200
201 memset(&hints, 0, sizeof(hints));
202 hints.ai_family = af_hint;
203 hints.ai_socktype = type;
204 error = getaddrinfo(h, portbuf, &hints, &res0);
205 if (error) {
206 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: %s %s: %s\n",
207 h, portbuf, gai_strerror(error));
208 return -1;
209 }
210
211 s = -1;
212 /* Try to connect to all addresses for this machine until we get
213 * through. It might e.g. be multi-homed, or have both IPv4 and IPv6
214 * addresses. We need to create a socket for each record, since the
215 * address record tells us what protocol to use to try to connect. */
216 for (res = res0; res; res = res->ai_next) {
217 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
218 if (s < 0)
219 continue;
220
221 if (bind_address)
222 if (try_bind_local(s, res->ai_family, type,
223 bind_address) == -1) {
224 close(s);
225 s = -1;
226 continue;
227 }
228
229 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
230 close(s);
231 s = -1;
232 continue;
233 }
234 if (proxied &&
235 establish_proxy_connection(s, host, port) != 0) {
236 close(s);
237 s = -1;
238 continue;
239 } else
240 break;
241 }
242 freeaddrinfo(res0);
243 if (s < 0) {
244 rprintf(FERROR, RSYNC_NAME ": failed to connect to %s: %s\n",
245 h, strerror(errno));
246 return -1;
247 }
248 return s;
249}
250
251
252/**
253 * Open an outgoing socket, but allow for it to be intercepted by
254 * $RSYNC_CONNECT_PROG, which will execute a program across a TCP
255 * socketpair rather than really opening a socket.
256 *
257 * We use this primarily in testing to detect TCP flow bugs, but not
258 * cause security problems by really opening remote connections.
259 *
260 * This is based on the Samba LIBSMB_PROG feature.
261 *
262 * @param bind_address Local address to use. Normally NULL to get the stack default.
263 **/
264int open_socket_out_wrapped (char *host,
265 int port,
266 const char *bind_address,
267 int af_hint)
268{
269 char *prog;
270
271 if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL)
272 return sock_exec (prog);
273 else
274 return open_socket_out (host, port, bind_address,
275 af_hint);
276}
277
278
279
280/**
281 * Open a socket of the specified type, port and address for incoming data
282 *
283 * Try to be better about handling the results of getaddrinfo(): when
284 * opening an inbound socket, we might get several address results,
285 * e.g. for the machine's ipv4 and ipv6 name.
286 *
287 * If binding a wildcard, then any one of them should do. If an address
288 * was specified but it's insufficiently specific then that's not our
289 * fault.
290 *
291 * However, some of the advertized addresses may not work because e.g. we
292 * don't have IPv6 support in the kernel. In that case go on and try all
293 * addresses until one succeeds.
294 *
295 * @param bind_address Local address to bind, or NULL to allow it to
296 * default.
297 **/
298static int open_socket_in(int type, int port, const char *bind_address,
299 int af_hint)
300{
301 int one=1;
302 int s;
303 struct addrinfo hints, *all_ai, *resp;
304 char portbuf[10];
305 int error;
306
307 memset(&hints, 0, sizeof(hints));
308 hints.ai_family = af_hint;
309 hints.ai_socktype = type;
310 hints.ai_flags = AI_PASSIVE;
311 snprintf(portbuf, sizeof(portbuf), "%d", port);
312 error = getaddrinfo(bind_address, portbuf, &hints, &all_ai);
313 if (error) {
314 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
315 bind_address, gai_strerror(error));
316 return -1;
317 }
318
319 /* We may not be able to create the socket, if for example the
320 * machine knows about IPv6 in the C library, but not in the
321 * kernel. */
322 for (resp = all_ai; resp; resp = resp->ai_next) {
323 s = socket(resp->ai_family, resp->ai_socktype,
324 resp->ai_protocol);
325
326 if (s == -1)
327 /* See if there's another address that will work... */
328 continue;
329
330 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
331 (char *)&one, sizeof one);
332
333 /* now we've got a socket - we need to bind it */
334 if (bind(s, all_ai->ai_addr, all_ai->ai_addrlen) < 0) {
335 /* Nope, try another */
336 close(s);
337 continue;
338 }
339
340 return s;
341 }
342
343 rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: "
344 "%s\n",
345 port,
346 strerror(errno));
347
348 freeaddrinfo(all_ai);
349 return -1;
350}
351
352
353/*
354 * Determine if a file descriptor is in fact a socket
355 */
356int is_a_socket(int fd)
357{
358 int v;
359 socklen_t l;
360 l = sizeof(int);
361
362 /* Parameters to getsockopt, setsockopt etc are very
363 * unstandardized across platforms, so don't be surprised if
364 * there are compiler warnings on e.g. SCO OpenSwerver or AIX.
365 * It seems they all eventually get the right idea.
366 *
367 * Debian says: ``The fifth argument of getsockopt and
368 * setsockopt is in reality an int [*] (and this is what BSD
369 * 4.* and libc4 and libc5 have). Some POSIX confusion
370 * resulted in the present socklen_t. The draft standard has
371 * not been adopted yet, but glibc2 already follows it and
372 * also has socklen_t [*]. See also accept(2).''
373 *
374 * We now return to your regularly scheduled programming. */
375 return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
376}
377
378
379void start_accept_loop(int port, int (*fn)(int ))
380{
381 int s;
382 extern char *bind_address;
383 extern int default_af_hint;
384
385 /* open an incoming socket */
386 s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
387 if (s == -1)
388 exit_cleanup(RERR_SOCKETIO);
389
390 /* ready to listen */
391 if (listen(s, 5) == -1) {
392 close(s);
393 exit_cleanup(RERR_SOCKETIO);
394 }
395
396
397 /* now accept incoming connections - forking a new process
398 for each incoming connection */
399 while (1) {
400 fd_set fds;
401 int fd;
402 struct sockaddr_storage addr;
403 socklen_t addrlen = sizeof addr;
404
405 /* close log file before the potentially very long select so
406 file can be trimmed by another process instead of growing
407 forever */
408 log_close();
409
410 FD_ZERO(&fds);
411 FD_SET(s, &fds);
412
413 if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
414 continue;
415 }
416
417 if(!FD_ISSET(s, &fds)) continue;
418
419 fd = accept(s,(struct sockaddr *)&addr,&addrlen);
420
421 if (fd == -1) continue;
422
423 signal(SIGCHLD, SIG_IGN);
424
425 /* we shouldn't have any children left hanging around
426 but I have had reports that on Digital Unix zombies
427 are produced, so this ensures that they are reaped */
428#ifdef WNOHANG
429 while (waitpid(-1, NULL, WNOHANG) > 0);
430#endif
431
432 if (fork()==0) {
433 close(s);
434 /* open log file in child before possibly giving
435 up privileges */
436 log_open();
437 _exit(fn(fd));
438 }
439
440 close(fd);
441 }
442}
443
444
445enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
446
447struct
448{
449 char *name;
450 int level;
451 int option;
452 int value;
453 int opttype;
454} socket_options[] = {
455 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
456 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
457 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
458#ifdef TCP_NODELAY
459 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
460#endif
461#ifdef IPTOS_LOWDELAY
462 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
463#endif
464#ifdef IPTOS_THROUGHPUT
465 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
466#endif
467#ifdef SO_SNDBUF
468 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
469#endif
470#ifdef SO_RCVBUF
471 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
472#endif
473#ifdef SO_SNDLOWAT
474 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
475#endif
476#ifdef SO_RCVLOWAT
477 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
478#endif
479#ifdef SO_SNDTIMEO
480 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
481#endif
482#ifdef SO_RCVTIMEO
483 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
484#endif
485 {NULL,0,0,0,0}};
486
487
488
489/****************************************************************************
490set user socket options
491****************************************************************************/
492void set_socket_options(int fd, char *options)
493{
494 char *tok;
495 if (!options || !*options) return;
496
497 options = strdup(options);
498
499 if (!options) out_of_memory("set_socket_options");
500
501 for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) {
502 int ret=0,i;
503 int value = 1;
504 char *p;
505 int got_value = 0;
506
507 if ((p = strchr(tok,'='))) {
508 *p = 0;
509 value = atoi(p+1);
510 got_value = 1;
511 }
512
513 for (i=0;socket_options[i].name;i++)
514 if (strcmp(socket_options[i].name,tok)==0)
515 break;
516
517 if (!socket_options[i].name) {
518 rprintf(FERROR,"Unknown socket option %s\n",tok);
519 continue;
520 }
521
522 switch (socket_options[i].opttype) {
523 case OPT_BOOL:
524 case OPT_INT:
525 ret = setsockopt(fd,socket_options[i].level,
526 socket_options[i].option,(char *)&value,sizeof(int));
527 break;
528
529 case OPT_ON:
530 if (got_value)
531 rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
532
533 {
534 int on = socket_options[i].value;
535 ret = setsockopt(fd,socket_options[i].level,
536 socket_options[i].option,(char *)&on,sizeof(int));
537 }
538 break;
539 }
540
541 if (ret != 0)
542 rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
543 strerror(errno));
544 }
545
546 free(options);
547}
548
549/****************************************************************************
550become a daemon, discarding the controlling terminal
551****************************************************************************/
552void become_daemon(void)
553{
554 int i;
555
556 if (fork()) {
557 _exit(0);
558 }
559
560 /* detach from the terminal */
561#ifdef HAVE_SETSID
562 setsid();
563#else
564#ifdef TIOCNOTTY
565 i = open("/dev/tty", O_RDWR);
566 if (i >= 0) {
567 ioctl(i, (int) TIOCNOTTY, (char *)0);
568 close(i);
569 }
570#endif /* TIOCNOTTY */
571#endif
572 /* make sure that stdin, stdout an stderr don't stuff things
573 up (library functions, for example) */
574 for (i=0;i<3;i++) {
575 close(i);
576 open("/dev/null", O_RDWR);
577 }
578}
579
580/**
581 * Return the IP addr of the client as a string
582 **/
583char *client_addr(int fd)
584{
585 struct sockaddr_storage ss;
586 socklen_t length = sizeof ss;
587 static char addr_buf[100];
588 static int initialised;
589
590 if (initialised) return addr_buf;
591
592 initialised = 1;
593
594 if (getpeername(fd, (struct sockaddr *)&ss, &length)) {
595 exit_cleanup(RERR_SOCKETIO);
596 }
597
598 getnameinfo((struct sockaddr *)&ss, length,
599 addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
600 return addr_buf;
601}
602
603
604static int get_sockaddr_family(const struct sockaddr_storage *ss)
605{
606 return ((struct sockaddr *) ss)->sa_family;
607}
608
609
610/**
611 * Return the DNS name of the client.
612 *
613 * The name is statically cached so that repeated lookups are quick,
614 * so there is a limit of one lookup per customer.
615 *
616 * If anything goes wrong, including the name->addr->name check, then
617 * we just use "UNKNOWN", so you can use that value in hosts allow
618 * lines.
619 **/
620char *client_name(int fd)
621{
622 struct sockaddr_storage ss;
623 socklen_t ss_len = sizeof ss;
624 static char name_buf[100];
625 static char port_buf[100];
626 static int initialised;
627
628 if (initialised) return name_buf;
629
630 strcpy(name_buf, default_name);
631 initialised = 1;
632
633 if (getpeername(fd, (struct sockaddr *)&ss, &ss_len)) {
634 /* FIXME: Can we really not continue? */
635 rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
636 fd, strerror(errno));
637 exit_cleanup(RERR_SOCKETIO);
638 }
639
640 if (!lookup_name(&ss, ss_len, name_buf, sizeof name_buf, port_buf, sizeof port_buf))
641 check_name(&ss, ss_len, name_buf, port_buf);
642
643 return name_buf;
644}
645
646
647/**
648 * Look up a name from @p ss into @p name_buf.
649 **/
650static int lookup_name(const struct sockaddr_storage *ss,
651 socklen_t ss_len,
652 char *name_buf, size_t name_buf_len,
653 char *port_buf, size_t port_buf_len)
654{
655 int name_err;
656
657#ifdef INET6
658 if (get_sockaddr_family(ss) == AF_INET6 &&
659 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
660 /* OK, so ss is in the IPv6 family, but it is really
661 * an IPv4 address: something like
662 * "::ffff:10.130.1.2". If we use it as-is, then the
663 * reverse lookup might fail or perhaps something else
664 * bad might happen. So instead we convert it to an
665 * equivalent address in the IPv4 address family. */
666 struct sockaddr_in6 sin6;
667 struct sockaddr_in *sin;
668
669 memcpy(&sin6, ss, sizeof(sin6));
670 sin = (struct sockaddr_in *)ss;
671 memset(sin, 0, sizeof(*sin));
672 sin->sin_family = AF_INET;
673 ss_len = sizeof(struct sockaddr_in);
674#ifdef HAVE_SOCKADDR_LEN
675 sin->sin_len = ss_len;
676#endif
677 sin->sin_port = sin6.sin6_port;
678 /* FIXME: Isn't there a macro we can use here rather
679 * than grovelling through the struct? It might be
680 * wrong on some systems. */
681 memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
682 sizeof(sin->sin_addr));
683 }
684#endif
685
686 /* reverse lookup */
687 name_err = getnameinfo((struct sockaddr *) ss, ss_len,
688 name_buf, name_buf_len,
689 port_buf, port_buf_len,
690 NI_NAMEREQD | NI_NUMERICSERV);
691 if (name_err != 0) {
692 strcpy(name_buf, default_name);
693 rprintf(FERROR, RSYNC_NAME ": name lookup failed: %s\n",
694 gai_strerror(name_err));
695 return name_err;
696 }
697
698 return 0;
699}
700
701
702
703/* Do a forward lookup on name_buf and make sure it corresponds to ss
704 * -- otherwise we may be being spoofed. If we suspect we are, then
705 * we don't abort the connection but just emit a warning. */
706static int check_name(const struct sockaddr_storage *ss,
707 socklen_t ss_len,
708 char *name_buf,
709 const char *port_buf)
710{
711 struct addrinfo hints, *res, *res0;
712 int error;
713
714 memset(&hints, 0, sizeof(hints));
715 hints.ai_family = PF_UNSPEC;
716 hints.ai_flags = AI_CANONNAME;
717 hints.ai_socktype = SOCK_STREAM;
718 error = getaddrinfo(name_buf, port_buf, &hints, &res0);
719 if (error) {
720 strcpy(name_buf, default_name);
721 rprintf(FERROR,
722 RSYNC_NAME ": forward name lookup for %s:%s failed: %s\n",
723 name_buf, port_buf,
724 gai_strerror(error));
725 return error;
726 }
727
728
729 /* We expect that one of the results will be the same as ss. */
730 for (res = res0; res; res = res->ai_next) {
731 if (res->ai_family != get_sockaddr_family(ss))
732 continue;
733 if (res->ai_addrlen != ss_len)
734 continue;
735 if (memcmp(res->ai_addr, ss, res->ai_addrlen) == 0)
736 break;
737 }
738
739 if (res == NULL) {
740 strcpy(name_buf, default_name);
741 /* We hit the end of the list without finding an
742 * address that was the same as ss. */
743 rprintf(FERROR, RSYNC_NAME
744 ": no address record for \"%s\" corresponds to peer name: spoofed address?\n",
745 name_buf);
746 }
747
748 freeaddrinfo(res0);
749 return 0;
750}
751
752
753/*******************************************************************
754this is like socketpair but uses tcp. It is used by the Samba
755regression test code
756The function guarantees that nobody else can attach to the socket,
757or if they do that this function fails and the socket gets closed
758returns 0 on success, -1 on failure
759the resulting file descriptors are symmetrical
760 ******************************************************************/
761static int socketpair_tcp(int fd[2])
762{
763 int listener;
764 struct sockaddr_in sock;
765 struct sockaddr_in sock2;
766 socklen_t socklen = sizeof(sock);
767 int connect_done = 0;
768
769 fd[0] = fd[1] = listener = -1;
770
771 memset(&sock, 0, sizeof(sock));
772
773 if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
774
775 memset(&sock2, 0, sizeof(sock2));
776#ifdef HAVE_SOCK_SIN_LEN
777 sock2.sin_len = sizeof(sock2);
778#endif
779 sock2.sin_family = PF_INET;
780
781 bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
782
783 if (listen(listener, 1) != 0) goto failed;
784
785 if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
786
787 if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
788
789 set_nonblocking(fd[1]);
790
791 sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
792
793 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
794 if (errno != EINPROGRESS) goto failed;
795 } else {
796 connect_done = 1;
797 }
798
799 if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
800
801 close(listener);
802 if (connect_done == 0) {
803 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
804 && errno != EISCONN) goto failed;
805 }
806
807 set_blocking (fd[1]);
808
809 /* all OK! */
810 return 0;
811
812 failed:
813 if (fd[0] != -1) close(fd[0]);
814 if (fd[1] != -1) close(fd[1]);
815 if (listener != -1) close(listener);
816 return -1;
817}
818
819
820
821/**
822 * Run a program on a local tcp socket, so that we can talk to it's
823 * stdin and stdout. This is used to launch ssh and similar
824 * connection helper programs for rsync.
825 *
826 * @return a socket which is attached to a subprocess running
827 * "prog". stdin and stdout are attached. stderr is left attached to
828 * the original stderr
829 **/
830int sock_exec(const char *prog)
831{
832 int fd[2];
833
834 if (verbose > 0) {
835 rprintf(FINFO, RSYNC_NAME
836 ": open connection using \"%s\"\n",
837 prog);
838 }
839
840 if (socketpair_tcp(fd) != 0) {
841 rprintf (FERROR, RSYNC_NAME
842 ": socketpair_tcp failed (%s)\n",
843 strerror(errno));
844 return -1;
845 }
846 if (fork() == 0) {
847 close(fd[0]);
848 close(0);
849 close(1);
850 dup(fd[1]);
851 dup(fd[1]);
852 if (verbose > 3) {
853 /* Can't use rprintf because we've forked. */
854 fprintf (stderr,
855 RSYNC_NAME ": execute socket program \"%s\"\n",
856 prog);
857 }
858 exit (system (prog));
859 }
860 close (fd[1]);
861 return fd[0];
862}
863
864
865