846225152cf3667439da4f15896a980f4c58429e
[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         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: bind address %s <noport>: %s\n",
180                                         bind_address, gai_strerror(error));
181                                 continue;
182                         }
183                         if (bres->ai_next) {
184                                 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s resolved to multiple hosts\n",
185                                         bind_address);
186                                 freeaddrinfo(bres);
187                                 continue;
188                         }
189                         bind(s, bres->ai_addr, bres->ai_addrlen);
190                 }
191
192                 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
193                         close(s);
194                         s = -1;
195                         continue;
196                 }
197                 if (proxied &&
198                     establish_proxy_connection(s, host, port) != 0) {
199                         close(s);
200                         s = -1;
201                         continue;
202                 } else
203                         break;
204         }
205         freeaddrinfo(res0);
206         if (s < 0) {
207                 rprintf(FERROR, RSYNC_NAME ": failed to connect to %s: %s\n",
208                         h, strerror(errno));
209                 return -1;
210         }
211         return s;
212 }
213
214
215 /**
216  * Open an outgoing socket, but allow for it to be intercepted by
217  * $RSYNC_CONNECT_PROG, which will execute a program across a TCP
218  * socketpair rather than really opening a socket.
219  *
220  * We use this primarily in testing to detect TCP flow bugs, but not
221  * cause security problems by really opening remote connections.
222  *
223  * This is based on the Samba LIBSMB_PROG feature.
224  *
225  * @param bind_address Local address to use.  Normally NULL to get the stack default.
226  **/
227 int open_socket_out_wrapped (char *host,
228                              int port,
229                              const char *bind_address,
230                              int af_hint)
231 {
232         char *prog;
233
234         if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL) 
235                 return sock_exec (prog);
236         else 
237                 return open_socket_out (host, port, bind_address,
238                                         af_hint);
239 }
240
241
242
243 /**
244  * Open a socket of the specified type, port and address for incoming data
245  *
246  * Try to be better about handling the results of getaddrinfo(): when
247  * opening an inbound socket, we might get several address results,
248  * e.g. for the machine's ipv4 and ipv6 name.  
249  * 
250  * If binding a wildcard, then any one of them should do.  If an address
251  * was specified but it's insufficiently specific then that's not our
252  * fault.  
253  * 
254  * However, some of the advertized addresses may not work because e.g. we
255  * don't have IPv6 support in the kernel.  In that case go on and try all
256  * addresses until one succeeds.
257  * 
258  * @param bind_address Local address to bind, or NULL to allow it to
259  * default.
260  **/
261 static int open_socket_in(int type, int port, const char *bind_address,
262                           int af_hint)
263 {
264         int one=1;
265         int s;
266         struct addrinfo hints, *res, *resp;
267         char portbuf[10];
268         int error;
269
270         memset(&hints, 0, sizeof(hints));
271         hints.ai_family = af_hint;
272         hints.ai_socktype = type;
273         hints.ai_flags = AI_PASSIVE;
274         snprintf(portbuf, sizeof(portbuf), "%d", port);
275         error = getaddrinfo(bind_address, portbuf, &hints, &res);
276         if (error) {
277                 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
278                         bind_address, gai_strerror(error));
279                 return -1;
280         }
281         /* XXX: Do we need to care about getting multiple results
282          * back?  I think probably not; if the user passed
283          * bind_address == NULL and we set AI_PASSIVE then we ought to
284          * get a wildcard result. */
285
286         resp = res;
287         while (1) {
288                 s = socket(resp->ai_family, resp->ai_socktype, resp->ai_protocol);
289
290                 if (s >= 0) {
291                         break;  /* got a socket */
292                 } else if ((resp = resp->ai_next)) {
293                         switch (errno) {
294                         case EPROTONOSUPPORT:
295                         case EAFNOSUPPORT:
296                         case EPFNOSUPPORT:
297                                 /* See if there's another address that will work... */
298                                 continue;
299                         }
300                 }
301                 
302                 rprintf(FERROR, RSYNC_NAME ": open inbound socket"
303                         "(dom=%d, type=%d, proto=%d) failed: %s\n",
304                         resp->ai_family, resp->ai_socktype, resp->ai_protocol,
305                         strerror(errno));
306                         goto fail;
307         }
308
309         setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
310
311         /* now we've got a socket - we need to bind it */
312         if (bind(s, res->ai_addr, res->ai_addrlen) < 0) { 
313                 rprintf(FERROR, RSYNC_NAME ": bind failed on port %d\n", port);
314                 close(s);
315                 goto fail;
316         }
317
318         return s;
319
320 fail:
321         freeaddrinfo(res);
322         return -1; 
323 }
324
325
326 /*
327  * Determine if a file descriptor is in fact a socket
328  */
329 int is_a_socket(int fd)
330 {
331         int v;
332         socklen_t l;
333         l = sizeof(int);
334
335         /* Parameters to getsockopt, setsockopt etc are very
336          * unstandardized across platforms, so don't be surprised if
337          * there are compiler warnings on e.g. SCO OpenSwerver or AIX.
338          * It seems they all eventually get the right idea.
339          *
340          * Debian says: ``The fifth argument of getsockopt and
341          * setsockopt is in reality an int [*] (and this is what BSD
342          * 4.* and libc4 and libc5 have).  Some POSIX confusion
343          * resulted in the present socklen_t.  The draft standard has
344          * not been adopted yet, but glibc2 already follows it and
345          * also has socklen_t [*]. See also accept(2).''
346          *
347          * We now return to your regularly scheduled programming.  */
348         return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
349 }
350
351
352 void start_accept_loop(int port, int (*fn)(int ))
353 {
354         int s;
355         extern char *bind_address;
356
357         /* open an incoming socket */
358         s = open_socket_in(SOCK_STREAM, port, bind_address,
359                            global_opts.af_hint);
360         if (s == -1)
361                 exit_cleanup(RERR_SOCKETIO);
362
363         /* ready to listen */
364         if (listen(s, 5) == -1) {
365                 close(s);
366                 exit_cleanup(RERR_SOCKETIO);
367         }
368
369
370         /* now accept incoming connections - forking a new process
371            for each incoming connection */
372         while (1) {
373                 fd_set fds;
374                 int fd;
375                 struct sockaddr addr;
376                 int in_addrlen = sizeof(addr);
377
378                 /* close log file before the potentially very long select so
379                    file can be trimmed by another process instead of growing
380                    forever */
381                 log_close();
382
383                 FD_ZERO(&fds);
384                 FD_SET(s, &fds);
385
386                 if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
387                         continue;
388                 }
389
390                 if(!FD_ISSET(s, &fds)) continue;
391
392                 fd = accept(s,(struct sockaddr *)&addr,&in_addrlen);
393
394                 if (fd == -1) continue;
395
396                 signal(SIGCHLD, SIG_IGN);
397
398                 /* we shouldn't have any children left hanging around
399                    but I have had reports that on Digital Unix zombies
400                    are produced, so this ensures that they are reaped */
401 #ifdef WNOHANG
402                 while (waitpid(-1, NULL, WNOHANG) > 0);
403 #endif
404
405                 if (fork()==0) {
406                         close(s);
407                         /* open log file in child before possibly giving
408                            up privileges  */
409                         log_open();
410                         _exit(fn(fd));
411                 }
412
413                 close(fd);
414         }
415 }
416
417
418 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
419
420 struct
421 {
422   char *name;
423   int level;
424   int option;
425   int value;
426   int opttype;
427 } socket_options[] = {
428   {"SO_KEEPALIVE",      SOL_SOCKET,    SO_KEEPALIVE,    0,                 OPT_BOOL},
429   {"SO_REUSEADDR",      SOL_SOCKET,    SO_REUSEADDR,    0,                 OPT_BOOL},
430   {"SO_BROADCAST",      SOL_SOCKET,    SO_BROADCAST,    0,                 OPT_BOOL},
431 #ifdef TCP_NODELAY
432   {"TCP_NODELAY",       IPPROTO_TCP,   TCP_NODELAY,     0,                 OPT_BOOL},
433 #endif
434 #ifdef IPTOS_LOWDELAY
435   {"IPTOS_LOWDELAY",    IPPROTO_IP,    IP_TOS,          IPTOS_LOWDELAY,    OPT_ON},
436 #endif
437 #ifdef IPTOS_THROUGHPUT
438   {"IPTOS_THROUGHPUT",  IPPROTO_IP,    IP_TOS,          IPTOS_THROUGHPUT,  OPT_ON},
439 #endif
440 #ifdef SO_SNDBUF
441   {"SO_SNDBUF",         SOL_SOCKET,    SO_SNDBUF,       0,                 OPT_INT},
442 #endif
443 #ifdef SO_RCVBUF
444   {"SO_RCVBUF",         SOL_SOCKET,    SO_RCVBUF,       0,                 OPT_INT},
445 #endif
446 #ifdef SO_SNDLOWAT
447   {"SO_SNDLOWAT",       SOL_SOCKET,    SO_SNDLOWAT,     0,                 OPT_INT},
448 #endif
449 #ifdef SO_RCVLOWAT
450   {"SO_RCVLOWAT",       SOL_SOCKET,    SO_RCVLOWAT,     0,                 OPT_INT},
451 #endif
452 #ifdef SO_SNDTIMEO
453   {"SO_SNDTIMEO",       SOL_SOCKET,    SO_SNDTIMEO,     0,                 OPT_INT},
454 #endif
455 #ifdef SO_RCVTIMEO
456   {"SO_RCVTIMEO",       SOL_SOCKET,    SO_RCVTIMEO,     0,                 OPT_INT},
457 #endif
458   {NULL,0,0,0,0}};
459
460         
461
462 /****************************************************************************
463 set user socket options
464 ****************************************************************************/
465 void set_socket_options(int fd, char *options)
466 {
467         char *tok;
468         if (!options || !*options) return;
469
470         options = strdup(options);
471         
472         if (!options) out_of_memory("set_socket_options");
473
474         for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) {
475                 int ret=0,i;
476                 int value = 1;
477                 char *p;
478                 int got_value = 0;
479
480                 if ((p = strchr(tok,'='))) {
481                         *p = 0;
482                         value = atoi(p+1);
483                         got_value = 1;
484                 }
485
486                 for (i=0;socket_options[i].name;i++)
487                         if (strcmp(socket_options[i].name,tok)==0)
488                                 break;
489
490                 if (!socket_options[i].name) {
491                         rprintf(FERROR,"Unknown socket option %s\n",tok);
492                         continue;
493                 }
494
495                 switch (socket_options[i].opttype) {
496                 case OPT_BOOL:
497                 case OPT_INT:
498                         ret = setsockopt(fd,socket_options[i].level,
499                                          socket_options[i].option,(char *)&value,sizeof(int));
500                         break;
501                         
502                 case OPT_ON:
503                         if (got_value)
504                                 rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
505
506                         {
507                                 int on = socket_options[i].value;
508                                 ret = setsockopt(fd,socket_options[i].level,
509                                                  socket_options[i].option,(char *)&on,sizeof(int));
510                         }
511                         break;    
512                 }
513                 
514                 if (ret != 0)
515                         rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
516                                 strerror(errno));
517         }
518
519         free(options);
520 }
521
522 /****************************************************************************
523 become a daemon, discarding the controlling terminal
524 ****************************************************************************/
525 void become_daemon(void)
526 {
527         int i;
528
529         if (fork()) {
530                 _exit(0);
531         }
532
533         /* detach from the terminal */
534 #ifdef HAVE_SETSID
535         setsid();
536 #else
537 #ifdef TIOCNOTTY
538         i = open("/dev/tty", O_RDWR);
539         if (i >= 0) {
540                 ioctl(i, (int) TIOCNOTTY, (char *)0);      
541                 close(i);
542         }
543 #endif /* TIOCNOTTY */
544 #endif
545         /* make sure that stdin, stdout an stderr don't stuff things
546            up (library functions, for example) */
547         for (i=0;i<3;i++) {
548                 close(i); 
549                 open("/dev/null", O_RDWR);
550         }
551 }
552
553 /**
554  * Return the IP addr of the client as a string 
555  **/
556 char *client_addr(int fd)
557 {
558         struct sockaddr ss;
559         int     length = sizeof(ss);
560         static char addr_buf[100];
561         static int initialised;
562
563         if (initialised) return addr_buf;
564
565         initialised = 1;
566
567         if (getpeername(fd, &ss, &length)) {
568                 exit_cleanup(RERR_SOCKETIO);
569         }
570
571         getnameinfo(&ss, length,
572                 addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
573         return addr_buf;
574 }
575
576
577 /**
578  * Return the DNS name of the client 
579  **/
580 char *client_name(int fd)
581 {
582         struct sockaddr 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 (ss.sa_family == 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 != ss.sa_family)
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