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