Define _GNU_SOURCE so that we get all necessary prototypes.
[rsync/rsync.git] / socket.c
... / ...
CommitLineData
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. */
36static 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 **/
102int 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 **/
152int 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 **/
251int 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 **/
285static 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 */
343int 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
366void 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
432enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
433
434struct
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/****************************************************************************
477set user socket options
478****************************************************************************/
479void 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/****************************************************************************
537become a daemon, discarding the controlling terminal
538****************************************************************************/
539void 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 **/
570char *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
591static 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 **/
600char *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/*******************************************************************
699this is like socketpair but uses tcp. It is used by the Samba
700regression test code
701The function guarantees that nobody else can attach to the socket,
702or if they do that this function fails and the socket gets closed
703returns 0 on success, -1 on failure
704the resulting file descriptors are symmetrical
705 ******************************************************************/
706static 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/*******************************************************************
766run a program on a local tcp socket, this is used to launch smbd
767when regression testing
768the return value is a socket which is attached to a subprocess
769running "prog". stdin and stdout are attached. stderr is left
770attached to the original stderr
771 ******************************************************************/
772int 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