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