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