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