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