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