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