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