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