Refactor code in send_sums to remove repeated ternaries.
[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 ((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 **/
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 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 **/
250int 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 **/
284static 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 */
342int 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
365void 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
431enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
432
433struct
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/****************************************************************************
476set user socket options
477****************************************************************************/
478void 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/****************************************************************************
536become a daemon, discarding the controlling terminal
537****************************************************************************/
538void 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 **/
569char *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
590static 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 **/
599char *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/*******************************************************************
698this is like socketpair but uses tcp. It is used by the Samba
699regression test code
700The function guarantees that nobody else can attach to the socket,
701or if they do that this function fails and the socket gets closed
702returns 0 on success, -1 on failure
703the resulting file descriptors are symmetrical
704 ******************************************************************/
705static 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/*******************************************************************
765run a program on a local tcp socket, this is used to launch smbd
766when regression testing
767the return value is a socket which is attached to a subprocess
768running "prog". stdin and stdout are attached. stderr is left
769attached to the original stderr
770 ******************************************************************/
771int 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