1 /* -*- c-file-style: "linux" -*-
3 Copyright (C) 1998-2001 by Andrew Tridgell <tridge@samba.org>
4 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
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.
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.
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.
22 socket functions used in rsync
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
)
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",
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",
58 if (strncmp(buffer
, "HTTP/", 5) != 0) {
59 rprintf(FERROR
, "bad response from proxy - %s\n",
63 for (cp
= &buffer
[5]; isdigit(*cp
) || (*cp
== '.'); cp
++)
68 rprintf(FERROR
, "bad response from proxy - %s\n",
72 /* throw away the rest of the HTTP header */
74 for (cp
= buffer
; cp
< &buffer
[sizeof(buffer
) - 1];
76 if (read(fd
, cp
, 1) != 1) {
77 rprintf(FERROR
, "failed to read from proxy: %s\n",
84 if ((cp
> buffer
) && (*cp
== '\n'))
86 if ((cp
== buffer
) && ((*cp
== '\n') || (*cp
== '\r')))
93 /* open a socket to a tcp remote host with the specified port
94 based on code from Warren
95 proxy support by Stephen Rothwell */
96 int open_socket_out(char *host
, int port
, struct in_addr
*address
)
98 int type
= SOCK_STREAM
;
99 struct sockaddr_in sock_out
;
100 struct sockaddr_in sock
;
109 /* if we have a RSYNC_PROXY env variable then redirect our
110 * connetcion via a web proxy at the given address. The format
111 * is hostname:port */
112 h
= getenv("RSYNC_PROXY");
113 proxied
= (h
!= NULL
) && (*h
!= '\0');
116 strlcpy(buffer
, h
, sizeof(buffer
));
117 cp
= strchr(buffer
, ':');
120 "invalid proxy specification: should be HOST:PORT\n");
131 res
= socket(PF_INET
, type
, 0);
136 hp
= gethostbyname(h
);
138 rprintf(FERROR
,"unknown host: \"%s\"\n", h
);
143 memcpy(&sock_out
.sin_addr
, hp
->h_addr
, hp
->h_length
);
144 sock_out
.sin_port
= htons(p
);
145 sock_out
.sin_family
= PF_INET
;
148 sock
.sin_addr
= *address
;
150 sock
.sin_family
= hp
->h_addrtype
;
151 bind(res
, (struct sockaddr
* ) &sock
,sizeof(sock
));
154 if (connect(res
,(struct sockaddr
*)&sock_out
,sizeof(sock_out
))) {
155 rprintf(FERROR
,"failed to connect to %s - %s\n", h
, strerror(errno
));
160 if (proxied
&& establish_proxy_connection(res
, host
, port
) != 0) {
169 /****************************************************************************
170 open a socket of the specified type, port and address for incoming data
171 ****************************************************************************/
172 static int open_socket_in(int type
, int port
, struct in_addr
*address
)
174 struct sockaddr_in sock
;
178 memset((char *)&sock
,0,sizeof(sock
));
179 sock
.sin_port
= htons(port
);
180 sock
.sin_family
= AF_INET
;
182 sock
.sin_addr
= *address
;
184 sock
.sin_addr
.s_addr
= INADDR_ANY
;
186 res
= socket(AF_INET
, type
, 0);
188 rprintf(FERROR
,"socket failed: %s\n",
193 setsockopt(res
,SOL_SOCKET
,SO_REUSEADDR
,(char *)&one
,sizeof(one
));
195 /* now we've got a socket - we need to bind it */
196 if (bind(res
, (struct sockaddr
* ) &sock
,sizeof(sock
)) == -1) {
197 rprintf(FERROR
,"bind failed on port %d: %s\n", port
,
199 if (errno
== EACCES
&& port
< 1024) {
200 rprintf(FERROR
, "Note: you must be root to bind "
201 "to low-numbered ports");
212 * Determine if a file descriptor is in fact a socket
214 int is_a_socket(int fd
)
220 /* Parameters to getsockopt, setsockopt etc are very
221 * unstandardized across platforms, so don't be surprised if
222 * there are compiler warnings on e.g. SCO OpenSwerver or AIX.
223 * It seems they all eventually get the right idea.
225 * Debian says: ``The fifth argument of getsockopt and
226 * setsockopt is in reality an int [*] (and this is what BSD
227 * 4.* and libc4 and libc5 have). Some POSIX confusion
228 * resulted in the present socklen_t. The draft standard has
229 * not been adopted yet, but glibc2 already follows it and
230 * also has socklen_t [*]. See also accept(2).''
232 * We now return to your regularly scheduled programming. */
233 return(getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, (char *)&v
, &l
) == 0);
237 void start_accept_loop(int port
, int (*fn
)(int ))
240 extern struct in_addr socket_address
;
242 /* open an incoming socket */
243 s
= open_socket_in(SOCK_STREAM
, port
, &socket_address
);
245 exit_cleanup(RERR_SOCKETIO
);
247 /* ready to listen */
248 if (listen(s
, 5) == -1) {
250 exit_cleanup(RERR_SOCKETIO
);
254 /* now accept incoming connections - forking a new process
255 for each incoming connection */
259 struct sockaddr addr
;
260 socklen_t in_addrlen
= sizeof(addr
);
262 /* close log file before the potentially very long select so
263 file can be trimmed by another process instead of growing
270 if (select(s
+1, &fds
, NULL
, NULL
, NULL
) != 1) {
274 if(!FD_ISSET(s
, &fds
)) continue;
276 /* See note above prototypes. */
277 fd
= accept(s
,&addr
, &in_addrlen
);
279 if (fd
== -1) continue;
281 signal(SIGCHLD
, SIG_IGN
);
283 /* we shouldn't have any children left hanging around
284 but I have had reports that on Digital Unix zombies
285 are produced, so this ensures that they are reaped */
287 while (waitpid(-1, NULL
, WNOHANG
) > 0);
293 /* open log file in child before possibly giving
305 enum SOCK_OPT_TYPES
{OPT_BOOL
,OPT_INT
,OPT_ON
};
314 } socket_options
[] = {
315 {"SO_KEEPALIVE", SOL_SOCKET
, SO_KEEPALIVE
, 0, OPT_BOOL
},
316 {"SO_REUSEADDR", SOL_SOCKET
, SO_REUSEADDR
, 0, OPT_BOOL
},
317 {"SO_BROADCAST", SOL_SOCKET
, SO_BROADCAST
, 0, OPT_BOOL
},
319 {"TCP_NODELAY", IPPROTO_TCP
, TCP_NODELAY
, 0, OPT_BOOL
},
321 #ifdef IPTOS_LOWDELAY
322 {"IPTOS_LOWDELAY", IPPROTO_IP
, IP_TOS
, IPTOS_LOWDELAY
, OPT_ON
},
324 #ifdef IPTOS_THROUGHPUT
325 {"IPTOS_THROUGHPUT", IPPROTO_IP
, IP_TOS
, IPTOS_THROUGHPUT
, OPT_ON
},
328 {"SO_SNDBUF", SOL_SOCKET
, SO_SNDBUF
, 0, OPT_INT
},
331 {"SO_RCVBUF", SOL_SOCKET
, SO_RCVBUF
, 0, OPT_INT
},
334 {"SO_SNDLOWAT", SOL_SOCKET
, SO_SNDLOWAT
, 0, OPT_INT
},
337 {"SO_RCVLOWAT", SOL_SOCKET
, SO_RCVLOWAT
, 0, OPT_INT
},
340 {"SO_SNDTIMEO", SOL_SOCKET
, SO_SNDTIMEO
, 0, OPT_INT
},
343 {"SO_RCVTIMEO", SOL_SOCKET
, SO_RCVTIMEO
, 0, OPT_INT
},
349 /****************************************************************************
350 set user socket options
351 ****************************************************************************/
352 void set_socket_options(int fd
, char *options
)
355 if (!options
|| !*options
) return;
357 options
= strdup(options
);
359 if (!options
) out_of_memory("set_socket_options");
361 for (tok
=strtok(options
, " \t,"); tok
; tok
=strtok(NULL
," \t,")) {
367 if ((p
= strchr(tok
,'='))) {
373 for (i
=0;socket_options
[i
].name
;i
++)
374 if (strcmp(socket_options
[i
].name
,tok
)==0)
377 if (!socket_options
[i
].name
) {
378 rprintf(FERROR
,"Unknown socket option %s\n",tok
);
382 switch (socket_options
[i
].opttype
) {
385 ret
= setsockopt(fd
,socket_options
[i
].level
,
386 socket_options
[i
].option
,(char *)&value
,sizeof(int));
391 rprintf(FERROR
,"syntax error - %s does not take a value\n",tok
);
394 int on
= socket_options
[i
].value
;
395 ret
= setsockopt(fd
,socket_options
[i
].level
,
396 socket_options
[i
].option
,(char *)&on
,sizeof(int));
402 rprintf(FERROR
, "failed to set socket option %s: %s\n", tok
,
409 /****************************************************************************
410 become a daemon, discarding the controlling terminal
411 ****************************************************************************/
412 void become_daemon(void)
420 /* detach from the terminal */
425 i
= open("/dev/tty", O_RDWR
);
427 ioctl(i
, (int) TIOCNOTTY
, (char *)0);
430 #endif /* TIOCNOTTY */
432 /* make sure that stdin, stdout an stderr don't stuff things
433 up (library functions, for example) */
436 open("/dev/null", O_RDWR
);
440 /*******************************************************************
441 return the IP addr of the client as a string
442 ******************************************************************/
443 char *client_addr(int fd
)
446 struct sockaddr_in
*sockin
= (struct sockaddr_in
*) (&sa
);
447 socklen_t length
= sizeof(sa
);
448 static char addr_buf
[100];
449 static int initialised
;
451 if (initialised
) return addr_buf
;
455 if (getpeername(fd
, &sa
, &length
)) {
456 exit_cleanup(RERR_SOCKETIO
);
459 strlcpy(addr_buf
,(char *)inet_ntoa(sockin
->sin_addr
), sizeof(addr_buf
));
464 /*******************************************************************
465 return the DNS name of the client
466 ******************************************************************/
467 char *client_name(int fd
)
470 struct sockaddr_in
*sockin
= (struct sockaddr_in
*) (&sa
);
471 socklen_t length
= sizeof(sa
);
472 static char name_buf
[100];
475 char *def
= "UNKNOWN";
476 static int initialised
;
478 if (initialised
) return name_buf
;
482 strcpy(name_buf
,def
);
484 if (getpeername(fd
, &sa
, &length
)) {
485 exit_cleanup(RERR_SOCKETIO
);
488 /* Look up the remote host name. */
489 if ((hp
= gethostbyaddr((char *) &sockin
->sin_addr
,
490 sizeof(sockin
->sin_addr
),
492 strlcpy(name_buf
,(char *)hp
->h_name
,sizeof(name_buf
));
496 /* do a forward lookup as well to prevent spoofing */
497 hp
= gethostbyname(name_buf
);
499 strcpy (name_buf
,def
);
500 rprintf (FERROR
, "reverse name lookup for \"%s\" failed\n",
503 for (p
=hp
->h_addr_list
;*p
;p
++) {
504 if (memcmp(*p
, &sockin
->sin_addr
, hp
->h_length
) == 0) {
509 strcpy(name_buf
,def
);
510 rprintf(FERROR
,"reverse name lookup mismatch - spoofed address?\n");
518 Convert a string to an IP address. The string can be a name or
519 dotted decimal number.
521 Returns a pointer to a static in_addr struct -- if you call this
522 more than once then you should copy it.
524 struct in_addr
*ip_address(const char *str
)
526 static struct in_addr ret
;
530 rprintf (FERROR
, "ip_address received NULL name\n");
534 /* try as an IP address */
535 if (inet_aton(str
, &ret
) != 0) {
539 /* otherwise assume it's a network name of some sort and use
541 if ((hp
= gethostbyname (str
)) == 0) {
542 rprintf(FERROR
, "gethostbyname failed for \"%s\": unknown host?\n",str
);
546 if (hp
->h_addr
== NULL
) {
547 rprintf(FERROR
, "gethostbyname: host address is invalid for host \"%s\"\n",str
);
551 if (hp
->h_length
> sizeof ret
) {
552 rprintf(FERROR
, "gethostbyname: host address for \"%s\" is too large\n",
557 if (hp
->h_addrtype
!= AF_INET
) {
558 rprintf (FERROR
, "gethostname: host address for \"%s\" is not IPv4\n",
563 /* This is kind of difficult. The only field in ret is
564 s_addr, which is the IP address as a 32-bit int. On
565 UNICOS, s_addr is in fact a *bitfield* for reasons best
566 know to Cray. This means we can't memcpy in to it. On the
567 other hand, h_addr is a char*, so we can't just assign.
569 Since there's meant to be only one field inside the in_addr
570 structure we will try just copying over the top and see how
572 memcpy (&ret
, hp
->h_addr
, hp
->h_length
);