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