1 /* -*- c-file-style: "linux" -*-
3 Copyright (C) 1998-2001 by Andrew Tridgell
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 socket functions used in rsync
28 /* Establish a proxy connection on an open socket to a web roxy by
29 * using the CONNECT method. */
30 static int establish_proxy_connection(int fd
, char *host
, int port
)
35 slprintf(buffer
, sizeof(buffer
), "CONNECT %s:%d HTTP/1.0\r\n\r\n", host
, port
);
36 if (write(fd
, buffer
, strlen(buffer
)) != strlen(buffer
)) {
37 rprintf(FERROR
, "failed to write to proxy: %s\n",
42 for (cp
= buffer
; cp
< &buffer
[sizeof(buffer
) - 1]; cp
++) {
43 if (read(fd
, cp
, 1) != 1) {
44 rprintf(FERROR
, "failed to read from proxy: %s\n",
57 if (strncmp(buffer
, "HTTP/", 5) != 0) {
58 rprintf(FERROR
, "bad response from proxy - %s\n",
62 for (cp
= &buffer
[5]; isdigit(*cp
) || (*cp
== '.'); cp
++)
67 rprintf(FERROR
, "bad response from proxy - %s\n",
71 /* throw away the rest of the HTTP header */
73 for (cp
= buffer
; cp
< &buffer
[sizeof(buffer
) - 1];
75 if (read(fd
, cp
, 1) != 1) {
76 rprintf(FERROR
, "failed to read from proxy: %s\n",
83 if ((cp
> buffer
) && (*cp
== '\n'))
85 if ((cp
== buffer
) && ((*cp
== '\n') || (*cp
== '\r')))
92 /* open a socket to a tcp remote host with the specified port
93 based on code from Warren
94 proxy support by Stephen Rothwell */
95 int open_socket_out(char *host
, int port
, struct in_addr
*address
)
97 int type
= SOCK_STREAM
;
98 struct sockaddr_in sock_out
;
99 struct sockaddr_in sock
;
108 /* if we have a RSYNC_PROXY env variable then redirect our
109 * connetcion via a web proxy at the given address. The format
110 * is hostname:port */
111 h
= getenv("RSYNC_PROXY");
112 proxied
= (h
!= NULL
) && (*h
!= '\0');
115 strlcpy(buffer
, h
, sizeof(buffer
));
116 cp
= strchr(buffer
, ':');
119 "invalid proxy specification: should be HOST:PORT\n");
130 res
= socket(PF_INET
, type
, 0);
135 hp
= gethostbyname(h
);
137 rprintf(FERROR
,"unknown host: %s\n", h
);
142 memcpy(&sock_out
.sin_addr
, hp
->h_addr
, hp
->h_length
);
143 sock_out
.sin_port
= htons(p
);
144 sock_out
.sin_family
= PF_INET
;
147 sock
.sin_addr
= *address
;
149 sock
.sin_family
= hp
->h_addrtype
;
150 bind(res
, (struct sockaddr
* ) &sock
,sizeof(sock
));
153 if (connect(res
,(struct sockaddr
*)&sock_out
,sizeof(sock_out
))) {
154 rprintf(FERROR
,"failed to connect to %s - %s\n", h
, strerror(errno
));
159 if (proxied
&& establish_proxy_connection(res
, host
, port
) != 0) {
168 /****************************************************************************
169 open a socket of the specified type, port and address for incoming data
170 ****************************************************************************/
171 static int open_socket_in(int type
, int port
, struct in_addr
*address
)
174 struct sockaddr_in sock
;
175 char host_name
[MAXHOSTNAMELEN
];
179 /* get my host name */
180 if (gethostname(host_name
, sizeof(host_name
)) == -1) {
181 rprintf(FERROR
,"gethostname failed\n");
186 if ((hp
= gethostbyname(host_name
)) == 0) {
187 rprintf(FERROR
,"gethostbyname: Unknown host %s\n",host_name
);
191 memset((char *)&sock
,0,sizeof(sock
));
192 memcpy((char *)&sock
.sin_addr
,(char *)hp
->h_addr
, hp
->h_length
);
193 sock
.sin_port
= htons(port
);
194 sock
.sin_family
= hp
->h_addrtype
;
196 sock
.sin_addr
= *address
;
198 sock
.sin_addr
.s_addr
= INADDR_ANY
;
200 res
= socket(hp
->h_addrtype
, type
, 0);
202 rprintf(FERROR
,"socket failed: %s\n",
207 setsockopt(res
,SOL_SOCKET
,SO_REUSEADDR
,(char *)&one
,sizeof(one
));
209 /* now we've got a socket - we need to bind it */
210 if (bind(res
, (struct sockaddr
* ) &sock
,sizeof(sock
)) == -1) {
211 rprintf(FERROR
,"bind failed on port %d: %s\n", port
,
222 * Determine if a file descriptor is in fact a socket
224 int is_a_socket(int fd
)
229 /* Parameters to getsockopt, setsockopt etc are very
230 * unstandardized across platforms, so don't be surprised if
231 * there are compiler warnings on e.g. SCO OpenSwerver. It
232 * seems they all eventually get the right idea.
234 * Debian says: ``The fifth argument of getsockopt and
235 * setsockopt is in reality an int [*] (and this is what BSD
236 * 4.* and libc4 and libc5 have). Some POSIX confusion
237 * resulted in the present socklen_t. The draft standard has
238 * not been adopted yet, but glibc2 already follows it and
239 * also has socklen_t [*]. See also accept(2).''
241 * We now return to your regularly scheduled programming. */
242 return(getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, (char *)&v
, &l
) == 0);
246 void start_accept_loop(int port
, int (*fn
)(int ))
249 extern struct in_addr socket_address
;
251 /* open an incoming socket */
252 s
= open_socket_in(SOCK_STREAM
, port
, &socket_address
);
254 exit_cleanup(RERR_SOCKETIO
);
256 /* ready to listen */
257 if (listen(s
, 5) == -1) {
259 exit_cleanup(RERR_SOCKETIO
);
263 /* now accept incoming connections - forking a new process
264 for each incoming connection */
268 struct sockaddr addr
;
269 int in_addrlen
= sizeof(addr
);
271 /* close log file before the potentially very long select so
272 file can be trimmed by another process instead of growing
279 if (select(s
+1, &fds
, NULL
, NULL
, NULL
) != 1) {
283 if(!FD_ISSET(s
, &fds
)) continue;
285 /* See note above prototypes. */
286 fd
= accept(s
,&addr
,&in_addrlen
);
288 if (fd
== -1) continue;
290 signal(SIGCHLD
, SIG_IGN
);
292 /* we shouldn't have any children left hanging around
293 but I have had reports that on Digital Unix zombies
294 are produced, so this ensures that they are reaped */
296 while (waitpid(-1, NULL
, WNOHANG
) > 0);
302 /* open log file in child before possibly giving
314 enum SOCK_OPT_TYPES
{OPT_BOOL
,OPT_INT
,OPT_ON
};
323 } socket_options
[] = {
324 {"SO_KEEPALIVE", SOL_SOCKET
, SO_KEEPALIVE
, 0, OPT_BOOL
},
325 {"SO_REUSEADDR", SOL_SOCKET
, SO_REUSEADDR
, 0, OPT_BOOL
},
326 {"SO_BROADCAST", SOL_SOCKET
, SO_BROADCAST
, 0, OPT_BOOL
},
328 {"TCP_NODELAY", IPPROTO_TCP
, TCP_NODELAY
, 0, OPT_BOOL
},
330 #ifdef IPTOS_LOWDELAY
331 {"IPTOS_LOWDELAY", IPPROTO_IP
, IP_TOS
, IPTOS_LOWDELAY
, OPT_ON
},
333 #ifdef IPTOS_THROUGHPUT
334 {"IPTOS_THROUGHPUT", IPPROTO_IP
, IP_TOS
, IPTOS_THROUGHPUT
, OPT_ON
},
337 {"SO_SNDBUF", SOL_SOCKET
, SO_SNDBUF
, 0, OPT_INT
},
340 {"SO_RCVBUF", SOL_SOCKET
, SO_RCVBUF
, 0, OPT_INT
},
343 {"SO_SNDLOWAT", SOL_SOCKET
, SO_SNDLOWAT
, 0, OPT_INT
},
346 {"SO_RCVLOWAT", SOL_SOCKET
, SO_RCVLOWAT
, 0, OPT_INT
},
349 {"SO_SNDTIMEO", SOL_SOCKET
, SO_SNDTIMEO
, 0, OPT_INT
},
352 {"SO_RCVTIMEO", SOL_SOCKET
, SO_RCVTIMEO
, 0, OPT_INT
},
358 /****************************************************************************
359 set user socket options
360 ****************************************************************************/
361 void set_socket_options(int fd
, char *options
)
364 if (!options
|| !*options
) return;
366 options
= strdup(options
);
368 if (!options
) out_of_memory("set_socket_options");
370 for (tok
=strtok(options
, " \t,"); tok
; tok
=strtok(NULL
," \t,")) {
376 if ((p
= strchr(tok
,'='))) {
382 for (i
=0;socket_options
[i
].name
;i
++)
383 if (strcmp(socket_options
[i
].name
,tok
)==0)
386 if (!socket_options
[i
].name
) {
387 rprintf(FERROR
,"Unknown socket option %s\n",tok
);
391 switch (socket_options
[i
].opttype
) {
394 ret
= setsockopt(fd
,socket_options
[i
].level
,
395 socket_options
[i
].option
,(char *)&value
,sizeof(int));
400 rprintf(FERROR
,"syntax error - %s does not take a value\n",tok
);
403 int on
= socket_options
[i
].value
;
404 ret
= setsockopt(fd
,socket_options
[i
].level
,
405 socket_options
[i
].option
,(char *)&on
,sizeof(int));
411 rprintf(FERROR
, "failed to set socket option %s: %s\n", tok
,
418 /****************************************************************************
419 become a daemon, discarding the controlling terminal
420 ****************************************************************************/
421 void become_daemon(void)
429 /* detach from the terminal */
434 i
= open("/dev/tty", O_RDWR
);
436 ioctl(i
, (int) TIOCNOTTY
, (char *)0);
439 #endif /* TIOCNOTTY */
441 /* make sure that stdin, stdout an stderr don't stuff things
442 up (library functions, for example) */
445 open("/dev/null", O_RDWR
);
449 /*******************************************************************
450 return the IP addr of the client as a string
451 ******************************************************************/
452 char *client_addr(int fd
)
455 struct sockaddr_in
*sockin
= (struct sockaddr_in
*) (&sa
);
456 int length
= sizeof(sa
);
457 static char addr_buf
[100];
458 static int initialised
;
460 if (initialised
) return addr_buf
;
464 if (getpeername(fd
, &sa
, &length
)) {
465 exit_cleanup(RERR_SOCKETIO
);
468 strlcpy(addr_buf
,(char *)inet_ntoa(sockin
->sin_addr
), sizeof(addr_buf
));
473 /*******************************************************************
474 return the DNS name of the client
475 ******************************************************************/
476 char *client_name(int fd
)
479 struct sockaddr_in
*sockin
= (struct sockaddr_in
*) (&sa
);
480 int length
= sizeof(sa
);
481 static char name_buf
[100];
484 char *def
= "UNKNOWN";
485 static int initialised
;
487 if (initialised
) return name_buf
;
491 strcpy(name_buf
,def
);
493 if (getpeername(fd
, &sa
, &length
)) {
494 exit_cleanup(RERR_SOCKETIO
);
497 /* Look up the remote host name. */
498 if ((hp
= gethostbyaddr((char *) &sockin
->sin_addr
,
499 sizeof(sockin
->sin_addr
),
501 strlcpy(name_buf
,(char *)hp
->h_name
,sizeof(name_buf
));
505 /* do a forward lookup as well to prevent spoofing */
506 hp
= gethostbyname(name_buf
);
508 strcpy(name_buf
,def
);
509 rprintf(FERROR
,"reverse name lookup failed\n");
511 for (p
=hp
->h_addr_list
;*p
;p
++) {
512 if (memcmp(*p
, &sockin
->sin_addr
, hp
->h_length
) == 0) {
517 strcpy(name_buf
,def
);
518 rprintf(FERROR
,"reverse name lookup mismatch - spoofed address?\n");
525 /*******************************************************************
526 convert a string to an IP address. The string can be a name or
527 dotted decimal number
528 ******************************************************************/
529 struct in_addr
*ip_address(const char *str
)
531 static struct in_addr ret
;
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: Unknown host. %s\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 is too large\n");
556 memcpy(&ret
.s_addr
, hp
->h_addr
, hp
->h_length
);