home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / rsync221.zip / socket.c < prev    next >
C/C++ Source or Header  |  1999-03-04  |  10KB  |  389 lines

  1. /* 
  2.    Copyright (C) Andrew Tridgell 1998
  3.    
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2 of the License, or
  7.    (at your option) any later version.
  8.    
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.    
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18.  
  19. /*
  20.   socket functions used in rsync 
  21.  
  22.   */
  23.  
  24. #include "rsync.h"
  25.  
  26. /* open a socket to a tcp remote host with the specified port 
  27.    based on code from Warren */
  28. int open_socket_out(char *host, int port)
  29. {
  30.     int type = SOCK_STREAM;
  31.     struct sockaddr_in sock_out;
  32.     int res;
  33.     struct hostent *hp;
  34.   
  35.  
  36.     res = socket(PF_INET, type, 0);
  37.     if (res == -1) {
  38.         return -1;
  39.     }
  40.  
  41.     hp = gethostbyname(host);
  42.     if (!hp) {
  43.         rprintf(FERROR,"unknown host: %s\n", host);
  44.         return -1;
  45.     }
  46.  
  47.     memcpy(&sock_out.sin_addr, hp->h_addr, hp->h_length);
  48.     sock_out.sin_port = htons(port);
  49.     sock_out.sin_family = PF_INET;
  50.  
  51.     if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
  52.         close(res);
  53.         rprintf(FERROR,"failed to connect to %s - %s\n", host, strerror(errno));
  54.         return -1;
  55.     }
  56.  
  57.     set_nonblocking(res);
  58.  
  59.     return res;
  60. }
  61.  
  62.  
  63. /****************************************************************************
  64. open a socket of the specified type, port and address for incoming data
  65. ****************************************************************************/
  66. static int open_socket_in(int type, int port)
  67. {
  68.     struct hostent *hp;
  69.     struct sockaddr_in sock;
  70.     char host_name[200];
  71.     int res;
  72.     int one=1;
  73.  
  74.     /* get my host name */
  75.     if (gethostname(host_name, sizeof(host_name)) == -1) { 
  76.         rprintf(FERROR,"gethostname failed\n"); 
  77.         return -1; 
  78.     } 
  79.  
  80.     /* get host info */
  81.     if ((hp = gethostbyname(host_name)) == 0) {
  82.         rprintf(FERROR,"gethostbyname: Unknown host %s\n",host_name);
  83.         return -1;
  84.     }
  85.   
  86.     memset((char *)&sock,0,sizeof(sock));
  87.     memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length);
  88.     sock.sin_port = htons(port);
  89.     sock.sin_family = hp->h_addrtype;
  90.     sock.sin_addr.s_addr = INADDR_ANY;
  91.     res = socket(hp->h_addrtype, type, 0);
  92.     if (res == -1) { 
  93.         rprintf(FERROR,"socket failed\n"); 
  94.         return -1; 
  95.     }
  96.  
  97.     setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
  98.  
  99.     /* now we've got a socket - we need to bind it */
  100.     if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) == -1) { 
  101.         rprintf(FERROR,"bind failed on port %d\n", port);
  102.         close(res); 
  103.         return -1;
  104.     }
  105.  
  106.     return res;
  107. }
  108.  
  109.  
  110. /****************************************************************************
  111. determine if a file descriptor is in fact a socket
  112. ****************************************************************************/
  113. int is_a_socket(int fd)
  114. {
  115.     int v,l;
  116.     l = sizeof(int);
  117.     return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
  118. }
  119.  
  120.  
  121. void start_accept_loop(int port, int (*fn)(int ))
  122. {
  123.     int s;
  124.  
  125.     /* open an incoming socket */
  126.     s = open_socket_in(SOCK_STREAM, port);
  127.     if (s == -1)
  128.         exit_cleanup(RERR_SOCKETIO);
  129.  
  130.     /* ready to listen */
  131.     if (listen(s, 5) == -1) {
  132.         close(s);
  133.         exit_cleanup(RERR_SOCKETIO);
  134.     }
  135.  
  136.  
  137.     /* now accept incoming connections - forking a new process
  138.        for each incoming connection */
  139.     while (1) {
  140.         fd_set fds;
  141.         int fd;
  142.         struct sockaddr addr;
  143.         int in_addrlen = sizeof(addr);
  144.  
  145.         FD_ZERO(&fds);
  146.         FD_SET(s, &fds);
  147.  
  148.         if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
  149.             continue;
  150.         }
  151.  
  152.         if(!FD_ISSET(s, &fds)) continue;
  153.  
  154.         fd = accept(s,&addr,&in_addrlen);
  155.  
  156.         if (fd == -1) continue;
  157.  
  158.         signal(SIGCHLD, SIG_IGN);
  159.  
  160.         /* we shouldn't have any children left hanging around
  161.            but I have had reports that on Digital Unix zombies
  162.            are produced, so this ensures that they are reaped */
  163. #ifdef WNOHANG
  164.         waitpid(-1, NULL, WNOHANG);
  165. #endif
  166.  
  167.         if (fork()==0) {
  168.             close(s);
  169.  
  170.             set_nonblocking(fd);
  171.  
  172.             _exit(fn(fd));
  173.         }
  174.  
  175.         close(fd);
  176.     }
  177. }
  178.  
  179.  
  180. enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
  181.  
  182. struct
  183. {
  184.   char *name;
  185.   int level;
  186.   int option;
  187.   int value;
  188.   int opttype;
  189. } socket_options[] = {
  190.   {"SO_KEEPALIVE",      SOL_SOCKET,    SO_KEEPALIVE,    0,                 OPT_BOOL},
  191.   {"SO_REUSEADDR",      SOL_SOCKET,    SO_REUSEADDR,    0,                 OPT_BOOL},
  192.   {"SO_BROADCAST",      SOL_SOCKET,    SO_BROADCAST,    0,                 OPT_BOOL},
  193. #ifdef TCP_NODELAY
  194.   {"TCP_NODELAY",       IPPROTO_TCP,   TCP_NODELAY,     0,                 OPT_BOOL},
  195. #endif
  196. #ifdef IPTOS_LOWDELAY
  197.   {"IPTOS_LOWDELAY",    IPPROTO_IP,    IP_TOS,          IPTOS_LOWDELAY,    OPT_ON},
  198. #endif
  199. #ifdef IPTOS_THROUGHPUT
  200.   {"IPTOS_THROUGHPUT",  IPPROTO_IP,    IP_TOS,          IPTOS_THROUGHPUT,  OPT_ON},
  201. #endif
  202. #ifdef SO_SNDBUF
  203.   {"SO_SNDBUF",         SOL_SOCKET,    SO_SNDBUF,       0,                 OPT_INT},
  204. #endif
  205. #ifdef SO_RCVBUF
  206.   {"SO_RCVBUF",         SOL_SOCKET,    SO_RCVBUF,       0,                 OPT_INT},
  207. #endif
  208. #ifdef SO_SNDLOWAT
  209.   {"SO_SNDLOWAT",       SOL_SOCKET,    SO_SNDLOWAT,     0,                 OPT_INT},
  210. #endif
  211. #ifdef SO_RCVLOWAT
  212.   {"SO_RCVLOWAT",       SOL_SOCKET,    SO_RCVLOWAT,     0,                 OPT_INT},
  213. #endif
  214. #ifdef SO_SNDTIMEO
  215.   {"SO_SNDTIMEO",       SOL_SOCKET,    SO_SNDTIMEO,     0,                 OPT_INT},
  216. #endif
  217. #ifdef SO_RCVTIMEO
  218.   {"SO_RCVTIMEO",       SOL_SOCKET,    SO_RCVTIMEO,     0,                 OPT_INT},
  219. #endif
  220.   {NULL,0,0,0,0}};
  221.  
  222.     
  223.  
  224. /****************************************************************************
  225. set user socket options
  226. ****************************************************************************/
  227. void set_socket_options(int fd, char *options)
  228. {
  229.     char *tok;
  230.     if (!options || !*options) return;
  231.  
  232.     options = strdup(options);
  233.     
  234.     if (!options) out_of_memory("set_socket_options");
  235.  
  236.     for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) {
  237.         int ret=0,i;
  238.         int value = 1;
  239.         char *p;
  240.         int got_value = 0;
  241.  
  242.         if ((p = strchr(tok,'='))) {
  243.             *p = 0;
  244.             value = atoi(p+1);
  245.             got_value = 1;
  246.         }
  247.  
  248.         for (i=0;socket_options[i].name;i++)
  249.             if (strcmp(socket_options[i].name,tok)==0)
  250.                 break;
  251.  
  252.         if (!socket_options[i].name) {
  253.             rprintf(FERROR,"Unknown socket option %s\n",tok);
  254.             continue;
  255.         }
  256.  
  257.         switch (socket_options[i].opttype) {
  258.         case OPT_BOOL:
  259.         case OPT_INT:
  260.             ret = setsockopt(fd,socket_options[i].level,
  261.                      socket_options[i].option,(char *)&value,sizeof(int));
  262.             break;
  263.             
  264.         case OPT_ON:
  265.             if (got_value)
  266.                 rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
  267.  
  268.             {
  269.                 int on = socket_options[i].value;
  270.                 ret = setsockopt(fd,socket_options[i].level,
  271.                          socket_options[i].option,(char *)&on,sizeof(int));
  272.             }
  273.             break;      
  274.         }
  275.         
  276.         if (ret != 0)
  277.             rprintf(FERROR,"Failed to set socket option %s\n",tok);
  278.     }
  279.  
  280.     free(options);
  281. }
  282.  
  283. /****************************************************************************
  284. become a daemon, discarding the controlling terminal
  285. ****************************************************************************/
  286. void become_daemon(void)
  287. {
  288.     int i;
  289.  
  290.     if (fork()) {
  291.         _exit(0);
  292.     }
  293.  
  294.     /* detach from the terminal */
  295. #ifdef HAVE_SETSID
  296.     setsid();
  297. #else
  298. #ifdef TIOCNOTTY
  299.     i = open("/dev/tty", O_RDWR);
  300.     if (i >= 0) {
  301.         ioctl(i, (int) TIOCNOTTY, (char *)0);      
  302.         close(i);
  303.     }
  304. #endif /* TIOCNOTTY */
  305. #endif
  306.     /* make sure that stdin, stdout an stderr don't stuff things
  307.            up (library functions, for example) */
  308.     for (i=0;i<3;i++) {
  309.         close(i); 
  310.         open("/dev/null", O_RDWR);
  311.     }
  312. }
  313.  
  314. /*******************************************************************
  315.  return the IP addr of the client as a string 
  316.  ******************************************************************/
  317. char *client_addr(int fd)
  318. {
  319.     struct sockaddr sa;
  320.     struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
  321.     int     length = sizeof(sa);
  322.     static char addr_buf[100];
  323.     static int initialised;
  324.  
  325.     if (initialised) return addr_buf;
  326.  
  327.     initialised = 1;
  328.  
  329.     if (getpeername(fd, &sa, &length)) {
  330.         exit_cleanup(RERR_SOCKETIO);
  331.     }
  332.     
  333.     strlcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr), sizeof(addr_buf));
  334.     return addr_buf;
  335. }
  336.  
  337.  
  338. /*******************************************************************
  339.  return the DNS name of the client 
  340.  ******************************************************************/
  341. char *client_name(int fd)
  342. {
  343.     struct sockaddr sa;
  344.     struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
  345.     int     length = sizeof(sa);
  346.     static char name_buf[100];
  347.     struct hostent *hp;
  348.     char **p;
  349.     char *def = "UNKNOWN";
  350.     static int initialised;
  351.  
  352.     if (initialised) return name_buf;
  353.  
  354.     initialised = 1;
  355.  
  356.     strcpy(name_buf,def);
  357.  
  358.     if (getpeername(fd, &sa, &length)) {
  359.         exit_cleanup(RERR_SOCKETIO);
  360.     }
  361.  
  362.     /* Look up the remote host name. */
  363.     if ((hp = gethostbyaddr((char *) &sockin->sin_addr,
  364.                 sizeof(sockin->sin_addr),
  365.                 AF_INET))) {
  366.         strlcpy(name_buf,(char *)hp->h_name,sizeof(name_buf));
  367.     }
  368.  
  369.  
  370.     /* do a forward lookup as well to prevent spoofing */
  371.     hp = gethostbyname(name_buf);
  372.     if (!hp) {
  373.         strcpy(name_buf,def);
  374.         rprintf(FERROR,"reverse name lookup failed\n");
  375.     } else {
  376.         for (p=hp->h_addr_list;*p;p++) {
  377.             if (memcmp(*p, &sockin->sin_addr, hp->h_length) == 0) {
  378.                 break;
  379.             }
  380.         }
  381.         if (!*p) {
  382.             strcpy(name_buf,def);
  383.             rprintf(FERROR,"reverse name lookup mismatch - spoofed address?\n");
  384.         } 
  385.     }
  386.  
  387.     return name_buf;
  388. }
  389.