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