inet.c
上传用户:pycemail
上传日期:2007-01-04
资源大小:329k
文件大小:25k
源码类别:

Ftp客户端

开发平台:

Unix_Linux

  1. /*
  2.  * ProFTPD - FTP server daemon
  3.  * Copyright (c) 1997, 1998 Public Flood Software
  4.  *  
  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.
  9.  *
  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.
  14.  *
  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
  18.  */
  19. /*
  20.  * Inet support functions, many wrappers for netdb functions
  21.  */
  22. #include "conf.h"
  23. #include "privs.h"
  24. #if 0
  25. #ifdef HAVE_NETINET_IN_SYSTM_H
  26. #include <netinet/in_systm.h>
  27. #endif
  28. #include <netinet/ip.h>
  29. #include <netinet/tcp.h>
  30. #endif
  31. #define CHECK_INET_POOL  if(!inet_pool) _create_inet_pool()
  32. extern server_rec *main_server;
  33. /* A private work pool for all inet_ functions to use
  34.  */
  35. static pool *inet_pool = NULL;
  36. static int tcp_proto = 6; /* Generally, this is "tcp" */
  37. static int reverse_dns = 1; /* Use reverse dns? */
  38. /* Cleanup for inet_pool
  39.  */
  40. static void _inet_pool_cleanup(void *ignore)
  41. {
  42.   inet_pool = NULL;
  43. }
  44. /* Create the private inet pool
  45.  */
  46. static void _create_inet_pool()
  47. {
  48.   inet_pool = make_sub_pool(permanent_pool);
  49.   /* Necessary to register a cleanup, in case the whole process
  50.    * execs and we lose our pool.
  51.    */
  52.   register_cleanup(inet_pool,NULL,_inet_pool_cleanup,_inet_pool_cleanup);
  53. }
  54. /*
  55.  * Called by others after running a number of inet_ functions in order
  56.  * to free up memory.
  57.  */
  58. void clear_inet_pool()
  59. {
  60.   if(!inet_pool) /* Sanity check */
  61.     return;
  62.   kill_cleanup(inet_pool,NULL,_inet_pool_cleanup);
  63.   destroy_pool(inet_pool);
  64.   inet_pool = NULL;
  65. }
  66. /* All inet_ interface functions take a pool as the first arg, which
  67.  * is where any returned allocated memory is taken from.  For purposes
  68.  * of uniformity the pool is included in all calls, even those that
  69.  * don't need to return allocated memory.
  70.  */
  71. /* Enable or disable reverse dns lookups */
  72. int inet_reverse_dns(pool *pool, int enable)
  73. {
  74.   int old;
  75.   old = reverse_dns;
  76.   reverse_dns = enable;
  77.   return old;
  78. }
  79. /* Find a service and return it's port number
  80.  */
  81. int inet_getservport(pool *pool, char *serv, char *proto)
  82. {
  83.   struct servent *servent;
  84.   servent = getservbyname(serv,proto);
  85.   /* getservbyname returns the port in network byte order */
  86.   return (servent ? ntohs(servent->s_port) : -1);
  87. }
  88. /* Validate anything returned from the 'outside', since it's untrusted
  89.  * information.
  90.  */
  91. char *inet_validate(char *buf) {
  92.   char *p;
  93.   
  94.   /* Validate anything returned from a DNS.
  95.    */
  96.   for(p = buf; p && *p; p++) {
  97.     /* Per RFC requirements, these are all that are valid from a DNS.
  98.      */
  99.     if(!isalnum(*p) && *p != '.' && *p != '-') {
  100.       /* We set it to _ because we know that's an invalid, yet safe, option
  101.        * for a DNS entry.
  102.        */
  103.       *p = '_';
  104.     }
  105.   }
  106.   
  107.   return buf;
  108. }
  109. /* Return the hostname (wrapper for gethostname(), except returns FQDN)
  110.  */
  111. char *inet_gethostname(pool *pool)
  112. {
  113.   char buf[256];
  114.   struct hostent *host;
  115.   if(gethostname(buf,255) != -1) {
  116.     host = gethostbyname(buf);
  117.     if(host)
  118.       return inet_validate(pstrdup(pool,host->h_name));
  119.     return inet_validate(pstrdup(pool,buf));
  120.   }
  121.   return NULL;
  122. }
  123. /* Return the FQDN of an address
  124.  */
  125. char *inet_fqdn(pool *pool, const char *addr)
  126. {
  127.   struct hostent *host;
  128.   if((host = gethostbyname(addr)) != NULL)
  129.     return inet_validate(pstrdup(pool,host->h_name));
  130.   return NULL;
  131. }
  132. /* DNS/hosts lookup for a particular name
  133.  */
  134. p_in_addr_t *inet_getaddr(pool *pool, char *name)
  135. {
  136.   struct hostent *host;
  137.   p_in_addr_t *res;
  138.   res = (p_in_addr_t*)pcalloc(pool,sizeof(p_in_addr_t));
  139.   /* Try dotted quad notation first */
  140. #ifdef HAVE_INET_ATON
  141.   if(inet_aton(name,res))
  142.     return res;
  143. #else
  144.   /* This is a bit unclean, because inet_addr() is obsolete, and
  145.    * returns -1 (255.255.255.255) if the input is invalid.  The caller
  146.    * _might_ just be trying to resolve "255.255.255.255", in which case
  147.    * this entire function will fail.  Hopefully, you have inet_aton().
  148.    * <grin>
  149.    */
  150.   if((res->s_addr = inet_addr(name)) != -1)
  151.     return res;
  152. #endif
  153.   host = gethostbyname(name);
  154.   if(host) {
  155.     memcpy(res, host->h_addr_list[0], sizeof(p_in_addr_t));
  156.     return res;
  157.   }
  158.     
  159.   return NULL;
  160. }
  161. /* Wrapper for inet_ntoa, except stores result in dynamically allocated
  162.  * memory.
  163.  */
  164. char *inet_ascii(pool *pool, p_in_addr_t *addr)
  165. {
  166.   char *res = NULL;
  167.   if((res = inet_ntoa(*addr)) != NULL)
  168.     res = pstrdup(pool,res);
  169.   return res;
  170. }
  171. /* Given an ip addresses, return the FQDN */
  172. char *inet_getname(pool *pool, p_in_addr_t *addr)
  173. {
  174.   char *res = NULL;
  175.   struct hostent *host = NULL;
  176.   if(reverse_dns)
  177.     host = gethostbyaddr((const char *)addr, sizeof(p_in_addr_t), AF_INET);
  178.   
  179.   if(!host) {
  180.     res = pstrdup(pool,inet_ntoa(*addr));
  181.     return NULL;
  182.   }
  183.   
  184.   res = pstrdup(pool,host->h_name);
  185.   
  186.   return inet_validate(res);
  187. }
  188. static void _conn_cleanup(void *cv) { 
  189.   conn_t *c = (conn_t*)cv;
  190.   if(c->inf)
  191.     io_close(c->inf);
  192.   if(c->outf && c->outf != c->inf)
  193.     io_close(c->outf);
  194.   if(c->listen_fd != -1)
  195.     close(c->listen_fd);
  196.   if(c->rfd != -1)
  197.     close(c->rfd);
  198.   if(c->wfd != -1)
  199.     close(c->wfd);
  200. }
  201. /*
  202.  * Copy a connection structure, also creates a sub pool for the new
  203.  * connection.
  204.  */
  205. conn_t *inet_copy_connection(pool *p, conn_t *c)
  206. {
  207.   conn_t *res;
  208.   pool *subpool;
  209.   subpool = make_sub_pool(p);
  210.   res = (conn_t*)palloc(subpool,sizeof(conn_t));
  211.   memcpy(res,c,sizeof(conn_t));
  212.   res->pool = subpool;
  213.   res->inf = res->outf = NULL;
  214.   if(c->local_ipaddr) {
  215.     res->local_ipaddr = (p_in_addr_t*)palloc(res->pool,sizeof(p_in_addr_t));
  216.     *res->local_ipaddr = *c->local_ipaddr;
  217.   }
  218.   if(c->remote_ipaddr) {
  219.     res->remote_ipaddr = (p_in_addr_t*)palloc(res->pool,sizeof(p_in_addr_t));
  220.     *res->remote_ipaddr = *c->remote_ipaddr;
  221.   }
  222.   if(c->remote_name)
  223.     res->remote_name = pstrdup(res->pool,c->remote_name);
  224.   if(c->iplist)
  225.     res->iplist = copy_array(subpool,c->iplist);
  226.   register_cleanup(res->pool,(void*)res,_conn_cleanup,_conn_cleanup);
  227.   return res;
  228. }
  229. /*
  230.  * Pre-bind a socket to a port, use to bind to a low-numbered port
  231.  */
  232. int inet_prebind_socket(pool *p, p_in_addr_t *bind_addr, int port)
  233. {
  234.   int save_errno,res = -1,s,on = 1,tries;
  235.   struct sockaddr_in servaddr;
  236. #ifdef SOLARIS2
  237.   if(port != INPORT_ANY && port < 1024) {
  238.     block_signals();
  239.     PRIVS_ROOT
  240.   }
  241. #endif
  242.   s = socket(AF_INET, SOCK_STREAM, 0);
  243. #ifdef SOLARIS2
  244.   if(port != INPORT_ANY && port < 1024) {
  245.     PRIVS_RELINQUISH
  246.     unblock_signals();
  247.   }
  248. #endif
  249.   if(s < 0)
  250.     return -1;
  251.   setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
  252.   servaddr.sin_family = AF_INET;
  253.   if(!bind_addr)
  254.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  255.   else
  256.     servaddr.sin_addr = *bind_addr;
  257.   servaddr.sin_port = htons(port);
  258.   
  259.   if(port != INPORT_ANY && port < 1024) {
  260.     block_signals();
  261.     PRIVS_ROOT
  262.   }
  263.   for(tries = 1; tries < 10; tries++) {
  264.     if(bind(s,(struct sockaddr *)&servaddr,sizeof(servaddr)) >= 0)
  265.     { res = s; break; }
  266.     if(errno != EADDRINUSE) break;
  267.     if(port != INPORT_ANY && port < 1024) {
  268.       PRIVS_RELINQUISH
  269.       unblock_signals();
  270.     }
  271.     timer_sleep(tries);
  272.     if(port != INPORT_ANY && port < 1024) {
  273.       block_signals();
  274.       PRIVS_ROOT
  275.     }
  276.   }
  277.   save_errno = errno;
  278.   if(port != INPORT_ANY && port < 1024) {
  279.     PRIVS_RELINQUISH
  280.     unblock_signals();
  281.   }
  282.   errno = save_errno;
  283.   return res;
  284. }
  285. /*
  286.  * Initialize a new connection record, also creates a new subpool
  287.  * just for the new connection.
  288.  */
  289. conn_t *inet_create_connection(pool *p, xaset_t *servers, int fd,
  290.                                p_in_addr_t *bind_addr, int port, int retry_bind)
  291. {
  292.   pool *subpool;
  293.   conn_t *c;
  294.   array_header *tmp;
  295.   server_rec *s;
  296.   struct sockaddr_in servaddr;
  297.   int i,res = 0,len,one = 1,hold_errno;
  298.   CHECK_INET_POOL;
  299.   
  300.   if((!servers || !servers->xas_list) && !main_server)
  301.     return NULL;
  302.   /* Build the accept IPs dynamically using the inet work pool,
  303.    * once built, move into the conn struc.
  304.    */
  305.   tmp = make_array(inet_pool, 5, sizeof(p_in_addr_t));
  306.   subpool = make_sub_pool(p);
  307.   c = (conn_t*)pcalloc(subpool,sizeof(conn_t));
  308.   c->pool = subpool;
  309.   
  310.   if(servers && servers->xas_list) {
  311.     for(s = (server_rec*)servers->xas_list; s; s=s->next)
  312.       if(s->ipaddr)
  313.         *((p_in_addr_t*)push_array(tmp)) = *s->ipaddr;
  314.   } else
  315.     *((p_in_addr_t*)push_array(tmp)) = *main_server->ipaddr;
  316.   c->local_port = port;
  317.   c->iplist = copy_array(c->pool,tmp);
  318.   c->niplist = c->iplist->nelts;
  319.   c->rfd = c->wfd = -1;
  320.   /* If fd == -1, there is no currently open socket, so create one */
  321.   if(fd == -1) {
  322. /* Certain version of solaris apparently require us to be root
  323.  * in order to create a socket inside a chroot ??
  324.  */
  325. /* FreeBSD 2.2.6 (possibly other versions as well), has a security
  326.  * "feature" which disallows SO_REUSEADDR from working if the socket
  327.  * owners don't match.  The easiest thing to do is simply make sure
  328.  * the socket is created as root.
  329.  */
  330. #if defined(SOLARIS2) || defined(FREEBSD2) || defined(FREEBSD3) || defined(OPENBSD2)
  331. # ifdef SOLARIS2
  332.     if(port != INPORT_ANY && port < 1024) {
  333. # endif
  334.       block_signals();
  335.       PRIVS_ROOT
  336. # ifdef SOLARIS2
  337.     }
  338. # endif
  339. #endif
  340.     fd = socket(AF_INET, SOCK_STREAM, tcp_proto);
  341. #if defined(SOLARIS2) || defined(FREEBSD2) || defined(FREEBSD3) || defined(OPENBSD2)
  342. # ifdef SOLARIS2
  343.     if(port != INPORT_ANY && port < 1024) {
  344. # endif
  345.       PRIVS_RELINQUISH
  346.       unblock_signals();
  347. # ifdef SOLARIS2
  348.     }
  349. # endif
  350. #endif
  351.     if(fd == -1) {
  352.       log_pri(LOG_ERR,"socket() failed in inet_create_connection(): %s",
  353.               strerror(errno));
  354.       end_login(1);
  355.     }
  356.     /* Allow address reusing */
  357.     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one));
  358.     memset(&servaddr,0,sizeof(servaddr));
  359.     servaddr.sin_family = AF_INET;
  360.     if(bind_addr)
  361.       bcopy(bind_addr,&servaddr.sin_addr,
  362.             sizeof(servaddr.sin_addr));
  363.     else
  364.       servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  365.     servaddr.sin_port = htons(port);
  366.     if(port != INPORT_ANY && port < 1024) {
  367.       block_signals();
  368.       PRIVS_ROOT
  369.     }
  370.     /* According to one expert, the very nature of the FTP protocol,
  371.      * and it's multiple data-connections creates problems with
  372.      * "rapid-fire" connections (transfering lots of files) causing
  373.      * an eventual "Address already in use" error.  As a result, this
  374.      * nasty kludge retries ten times (once per second) if the
  375.      * port being bound to is INPORT_ANY)
  376.      */
  377.     for(i = 10; i; i--) {
  378.       res = bind(fd,(struct sockaddr*)&servaddr,sizeof(servaddr));
  379.       hold_errno = errno;
  380.       if(res == -1 && errno == EINTR) { i++; continue; }
  381.       if(res != -1 || errno != EADDRINUSE || (port != INPORT_ANY && !retry_bind))
  382.         break;
  383.       if(port != INPORT_ANY && port < 1024) {
  384.         PRIVS_RELINQUISH
  385.         unblock_signals();
  386.       }
  387.       timer_sleep(1);
  388.       if(port != INPORT_ANY && port < 1024) {
  389.         block_signals();
  390.         PRIVS_ROOT
  391.       }
  392.     }
  393.     if(res == -1) {
  394.       if(port != INPORT_ANY && port < 1024) {
  395.         PRIVS_RELINQUISH
  396.         unblock_signals();
  397.       }
  398.       log_pri(LOG_ERR,"attempted bind to %s, port %d",
  399.               inet_ntoa(servaddr.sin_addr),
  400.               port);
  401.       log_pri(LOG_ERR,"bind() failed in inet_create_connection(): %s",
  402.               strerror(hold_errno));
  403.   log_pri(LOG_ERR,"Check the ServerType directive to ensure you are configured correctly.");
  404.       end_login(1);
  405.     }
  406.     if(port != INPORT_ANY && port < 1024) {
  407.       PRIVS_RELINQUISH
  408.       unblock_signals();
  409.     }
  410.     /* We use getsockname here because the caller might be binding
  411.      * to INPORT_ANY (0), in which case our port number will be
  412.      * dynamic.
  413.      */
  414.     len = sizeof(servaddr);
  415.     if(getsockname(fd, (struct sockaddr*)&servaddr, &len) != -1) {
  416.       if(!c->local_ipaddr)
  417.         c->local_ipaddr = (p_in_addr_t*)pcalloc(c->pool,sizeof(p_in_addr_t));
  418.       *c->local_ipaddr = servaddr.sin_addr;
  419.       c->local_port = ntohs(servaddr.sin_port);
  420.     }
  421.   }
  422.   c->listen_fd = fd;
  423.   register_cleanup(c->pool,(void*)c,_conn_cleanup,_conn_cleanup);
  424.   return c;
  425. }
  426. void inet_close(pool *pool, conn_t *c)
  427. {
  428.   /* It's not necessary to close the fds or schedule IOFILEs for
  429.    * removal, because the creator of the connection (either
  430.    * inet_create_connection() or inet_copy_connection() will
  431.    * have registered a pool cleanup handler (_conn_cleanup())
  432.    * which will do all this for us.  Simply destroy the pool
  433.    * and all the dirty work gets done. :-)
  434.    */
  435.   destroy_pool(c->pool);
  436. }
  437. int inet_set_proto_options(pool *pool, conn_t *c,
  438. int nodelay,
  439. int lowdelay,
  440. int throughput,
  441. int nopush)
  442. {
  443.   int tos = 0;
  444. #ifdef TCP_NODELAY
  445.   if(get_param_int(main_server->conf,"tcpNoDelay",FALSE) != 0) {
  446.     if(c->wfd != -1)
  447.       setsockopt(c->wfd,IPPROTO_TCP,TCP_NODELAY,(void*)&nodelay,sizeof(nodelay));
  448.     if(c->rfd != -1)
  449.       setsockopt(c->rfd,IPPROTO_TCP,TCP_NODELAY,(void*)&nodelay,sizeof(nodelay));
  450.   }
  451. #endif
  452. #ifdef IPTOS_LOWDELAY
  453.   if(lowdelay)
  454.     tos = IPTOS_LOWDELAY;
  455. #endif
  456. #ifdef IPTOS_THROUGHPUT
  457.   if(throughput)
  458.     tos |= IPTOS_THROUGHPUT;
  459. #endif
  460. #ifdef IP_TOS
  461.   if(c->wfd != -1)
  462.     setsockopt(c->wfd,IPPROTO_IP,IP_TOS,(void*)&tos,sizeof(tos));
  463.   if(c->rfd != -1)
  464.     setsockopt(c->rfd,IPPROTO_IP,IP_TOS,(void*)&tos,sizeof(tos));
  465. #endif
  466. #ifdef TCP_NOPUSH
  467.   if(c->wfd != -1)
  468.     setsockopt(c->wfd,IPPROTO_TCP,TCP_NOPUSH,(void*)&nopush,sizeof(nopush));
  469.   if(c->rfd != -1)
  470.     setsockopt(c->rfd,IPPROTO_TCP,TCP_NOPUSH,(void*)&nopush,sizeof(nopush));
  471. #endif
  472.   return 0;
  473. }
  474. /*
  475.  * Set socket options on a connection. If set_buffers is non-zero the
  476.  * socket snd/rcv buffers will be set according the the server
  477.  * information.
  478.  */
  479. int inet_setoptions(pool *pool, conn_t *c, int rcvbuf, int sndbuf)
  480. {
  481.   int no_keep_alive = 0;
  482.   struct linger li;
  483.   int len,crcvbuf,csndbuf;
  484.   li.l_onoff = 0;
  485.   li.l_linger = 0;
  486.   if(c->wfd != -1) {
  487.     setsockopt(c->wfd,SOL_SOCKET,SO_KEEPALIVE,(void*)&no_keep_alive,sizeof(int));
  488.     setsockopt(c->wfd,SOL_SOCKET,SO_LINGER,(void*)&li,sizeof(li));
  489.     /* Linux and "most" newer networking OSes probably use a highly
  490.      * adaptive window size system, which generally wouldn't require
  491.      * user-space modification at all.  Thus, check the current
  492.      * sndbuf and rcvbuf sizes before changing them, and only change
  493.      * them if we are making them larger than their current size.
  494.      */
  495.     len = sizeof(csndbuf);
  496.     getsockopt(c->wfd,SOL_SOCKET,SO_SNDBUF,(void*)&csndbuf,&len);
  497.     if(sndbuf && sndbuf > csndbuf)
  498.       setsockopt(c->wfd,SOL_SOCKET,SO_SNDBUF,(void*)&sndbuf,sizeof(sndbuf));
  499.     c->sndbuf = (sndbuf ? sndbuf : csndbuf);
  500.   }
  501.   if(c->rfd != -1) {
  502.     setsockopt(c->rfd,SOL_SOCKET,SO_KEEPALIVE,(void*)&no_keep_alive,sizeof(int));
  503.     setsockopt(c->wfd,SOL_SOCKET,SO_LINGER,(void*)&li,sizeof(li));
  504.     len = sizeof(crcvbuf);
  505.     getsockopt(c->rfd,SOL_SOCKET,SO_RCVBUF,(void*)&crcvbuf,&len);
  506.     if(rcvbuf && rcvbuf > crcvbuf)
  507.       setsockopt(c->rfd,SOL_SOCKET,SO_RCVBUF,(void*)&rcvbuf,sizeof(rcvbuf));
  508.     c->rcvbuf = (rcvbuf ? rcvbuf : crcvbuf);
  509.   }
  510.  
  511.   return 0;
  512. }
  513. #ifdef SO_OOBINLINE
  514. static
  515. void _set_oobinline(int fd)
  516. {
  517.   int on = 1;
  518.   if(fd != -1)
  519.     setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (void*)&on, sizeof(on));
  520. }
  521. #endif
  522. #ifdef F_SETOWN
  523. static
  524. void _set_owner(int fd)
  525.   if(fd != -1)
  526.     fcntl(fd, F_SETOWN, getpid());
  527. }
  528. #endif
  529. /* Put a socket in async mode (so SIGURG is raised on OOB)
  530.  */
  531. int inet_setasync(pool *pool, conn_t *c)
  532. {
  533. #ifdef SO_OOBINLINE
  534.   _set_oobinline(c->listen_fd);
  535.   _set_oobinline(c->rfd);
  536.   _set_oobinline(c->wfd);
  537. #endif
  538. #ifdef F_SETOWN
  539.   _set_owner(c->listen_fd);
  540.   _set_owner(c->rfd);
  541.   _set_owner(c->wfd);
  542. #endif
  543.   return 0;
  544. }
  545. /*
  546.  * Put a socket in nonblocking mode.
  547.  */
  548. int inet_setnonblock(pool *pool, conn_t *c)
  549. {
  550.   int flags;
  551.   int res = -1;
  552.   errno = EBADF; /* Default */
  553.   if(c->mode == CM_LISTEN) {
  554.     flags = fcntl(c->listen_fd,F_GETFL);
  555.     res = fcntl(c->listen_fd,F_SETFL,flags | O_NONBLOCK);
  556.   } else {
  557.     if(c->rfd != -1) {
  558.       flags = fcntl(c->rfd,F_GETFL);
  559.       res = fcntl(c->rfd,F_SETFL,flags | O_NONBLOCK);
  560.     }
  561.     if(c->wfd != -1) {
  562.       flags = fcntl(c->wfd,F_GETFL);
  563.       res = fcntl(c->wfd,F_GETFL,flags | O_NONBLOCK);
  564.     }
  565.   }
  566.   return res;
  567. }
  568. int inet_setblock(pool *pool, conn_t *c)
  569. {
  570.   int flags;
  571.   int res = -1;
  572.   errno = EBADF; /* Default */
  573.   if(c->mode == CM_LISTEN) {
  574.     flags = fcntl(c->listen_fd,F_GETFL);
  575.     res = fcntl(c->listen_fd,F_SETFL,flags & (U32BITS ^ O_NONBLOCK));
  576.   } else {
  577.     if(c->rfd != -1) {
  578.       flags = fcntl(c->rfd,F_GETFL);
  579.       res = fcntl(c->rfd,F_SETFL,flags & (U32BITS ^ O_NONBLOCK));
  580.     }
  581.     if(c->wfd != -1) {
  582.       flags = fcntl(c->wfd,F_GETFL);
  583.       res = fcntl(c->wfd,F_SETFL,flags & (U32BITS ^ O_NONBLOCK));
  584.     }
  585.   }
  586.   return res;
  587. }
  588. /*
  589.  * Put a connection in listen mode
  590.  */
  591. int inet_listen(pool *pool, conn_t *c, int backlog)
  592. {
  593.   if(!c || c->mode == CM_LISTEN)
  594.     return -1;
  595.   while(1)
  596.     if(listen(c->listen_fd,backlog) == -1) {
  597.       if(errno == EINTR)
  598.         continue; 
  599.       log_pri(LOG_ERR,"listen() failed in inet_listen(): %s",
  600.               strerror(errno));
  601.       end_login(1);
  602.     } else
  603.       break;
  604.   
  605.   c->mode = CM_LISTEN;  
  606.   return 0;
  607. }
  608. /*
  609.  * Reset a connection back to listen mode.  Enables blocking mode
  610.  * for safety.
  611.  */
  612. int inet_resetlisten(pool *pool, conn_t *c)
  613. {
  614.   c->mode = CM_LISTEN;
  615.   inet_setblock(c->pool,c);
  616.   return 0;
  617. }
  618. int inet_connect(pool *pool, conn_t *c, p_in_addr_t *addr, int port)
  619. {
  620.   struct sockaddr_in remaddr;
  621.   int ret;
  622.   inet_setblock(pool,c);
  623.   remaddr.sin_family = AF_INET;
  624.   remaddr.sin_addr = *addr;
  625.   remaddr.sin_port = htons(port);
  626.   c->mode = CM_CONNECT;
  627.   while( (ret = connect(c->listen_fd,(struct sockaddr*)&remaddr,sizeof(remaddr))) == -1 &&
  628.          errno == EINTR ) ;
  629.   if(ret == -1) {
  630.     c->mode = CM_ERROR;
  631.     c->xerrno = errno;
  632.     return -1;
  633.   }
  634.   c->mode = CM_OPEN;
  635.   inet_get_conn_info(c,c->listen_fd);
  636.   inet_setblock(c->pool,c);
  637.   return 1;
  638. }
  639. /* attempt to connection a connection, returning immediately with
  640.  * 1 if connected, 0 if not connected, or -1 if error.  Only needs to be
  641.  * called once, and can then be selected for writing.
  642.  */
  643. int inet_connect_nowait(pool *pool, conn_t *c, p_in_addr_t *addr, int port)
  644. {
  645.   struct sockaddr_in remaddr;
  646.   inet_setnonblock(pool,c);
  647.   remaddr.sin_family = AF_INET;
  648.   remaddr.sin_addr = *addr;
  649.   remaddr.sin_port = htons(port);
  650.   c->mode = CM_CONNECT;
  651.   if(connect(c->listen_fd,(struct sockaddr*)&remaddr,sizeof(remaddr)) == -1) {
  652.     if(errno != EINPROGRESS && errno != EALREADY) {
  653.       c->mode = CM_ERROR;
  654.       c->xerrno = errno;
  655.       return -1;
  656.     }
  657.     return 0;
  658.   }
  659.   c->mode = CM_OPEN;
  660.   inet_get_conn_info(c,c->listen_fd);
  661.   inet_setblock(c->pool,c);
  662.   return 1;
  663. }
  664. /*
  665.  * Accepts a new connection, returning immediately with -1 if
  666.  * no connection is available.  If a connection is accepted,
  667.  * creating a new conn_t and potential resolving is deferred,
  668.  * and a normal socket fd is returned for the new connection, which
  669.  * can later be used in inet_openrw to fully open and resolve
  670.  * addresses.
  671.  */
  672. int inet_accept_nowait(pool *pool, conn_t *c)
  673. {
  674.   int fd;
  675.   struct sockaddr_in servaddr;
  676.   int len = sizeof(servaddr);
  677.   if(c->mode == CM_LISTEN)
  678.     inet_setnonblock(c->pool,c);
  679.   c->mode = CM_ACCEPT;
  680.   if((fd = accept(c->listen_fd,(struct sockaddr*)&servaddr,&len)) == -1) {
  681.     if(errno != EWOULDBLOCK) {
  682.       c->mode = CM_ERROR;
  683.       c->xerrno = errno;
  684.       return -1;
  685.     }
  686.     c->mode = CM_LISTEN;
  687.     c->xerrno = 0;
  688.     return -1;
  689.   }
  690.   /* Leave the connection in CM_ACCEPT mode, so others can see
  691.    * our state.  Re-enable blocking mode, however.
  692.    */
  693.   inet_setblock(c->pool,c);
  694.   return fd;
  695. }
  696. /*
  697.  * Accepts a new connection, cloning the existing conn_t and returning
  698.  * it, or NULL upon error.
  699.  */
  700. conn_t *inet_accept(pool *pool, conn_t *c, int rfd, int wfd, int resolve)
  701. {
  702.   conn_t *res = NULL;
  703.   int newfd;
  704.   struct sockaddr_in addr;
  705.   int addrlen = sizeof(addr);
  706.   c->mode = CM_ACCEPT;
  707.   if((newfd = accept(c->listen_fd,(struct sockaddr*)&addr,&addrlen)) != -1) {
  708.     c->mode = CM_OPEN;
  709.     res = inet_openrw(pool,c,NULL,newfd,rfd,wfd,resolve);
  710.   } else {
  711.     c->mode = CM_ERROR;
  712.     c->xerrno = errno;
  713.   }
  714.   return res;
  715. }
  716. int inet_get_conn_info(conn_t *c, int fd)
  717. {
  718.   static struct sockaddr_in servaddr;
  719.   int len = sizeof(servaddr);
  720.   if(getsockname(fd,(struct sockaddr*)&servaddr,&len) != -1) {
  721.     if(!c->local_ipaddr)
  722.       c->local_ipaddr = (p_in_addr_t*)pcalloc(c->pool,sizeof(p_in_addr_t));     
  723.     *c->local_ipaddr = servaddr.sin_addr;
  724.     c->local_port = ntohs(servaddr.sin_port);
  725.   } else
  726.     return -1;
  727.   len = sizeof(servaddr);
  728.   if(getpeername(fd,(struct sockaddr*)&servaddr,&len) != -1) {
  729.     c->remote_ipaddr = (p_in_addr_t*)pcalloc(c->pool,sizeof(p_in_addr_t));
  730.     *c->remote_ipaddr = servaddr.sin_addr;
  731.     c->remote_port = ntohs(servaddr.sin_port);
  732.   } else
  733.     return -1;
  734.   return 0;
  735. }
  736. /*
  737.  * Associate already open streams with the connection,
  738.  * returns NULL if either stream points to a non-socket descriptor.
  739.  * If addr is non-NULL, remote address discovery is attempted.
  740.  * If resolve is non-zero, the remote address is reverse resolved.
  741.  */
  742. conn_t *inet_associate(pool *pool, conn_t *c, p_in_addr_t *addr, 
  743.                        IOFILE *inf, IOFILE *outf, int resolve)
  744. {
  745.   int rfd,wfd;
  746.   int socktype;
  747.   int socktype_len = sizeof(socktype);
  748.   conn_t *res;
  749.   rfd = inf->fd;
  750.   wfd = outf->fd;
  751.   if(getsockopt(rfd,SOL_SOCKET,SO_TYPE,(void*)&socktype,&socktype_len) == -1 ||
  752.      socktype != SOCK_STREAM)
  753.     return NULL;
  754.   if(getsockopt(wfd,SOL_SOCKET,SO_TYPE,(void*)&socktype,&socktype_len) == -1 ||
  755.      socktype != SOCK_STREAM)
  756.     return NULL;
  757.   res = inet_copy_connection(pool,c);
  758.   res->rfd = rfd;
  759.   res->wfd = wfd;
  760.   res->inf = inf;
  761.   res->outf = outf;
  762.   res->mode = CM_OPEN;
  763.   inet_get_conn_info(res,wfd);
  764.   /* Get the remote address */
  765.   if(addr) {
  766.     if(!res->remote_ipaddr)
  767.       res->remote_ipaddr = (p_in_addr_t*)palloc(res->pool,sizeof(p_in_addr_t));
  768.     *res->remote_ipaddr = *addr;
  769.   }
  770.   if(resolve && res->remote_ipaddr)
  771.     res->remote_name = inet_getname(res->pool,res->remote_ipaddr);
  772.   if(!res->remote_name)
  773.     res->remote_name = pstrdup(res->pool,inet_ntoa(*res->remote_ipaddr));
  774.   inet_setoptions(res->pool,res,0,0);
  775.   /* inet_setnonblock(res->pool,res); */
  776.   return res;
  777. }
  778.     
  779. /*
  780.  * Open streams for a new socket, if rfd and wfd != -1,
  781.  * two new fds are duped to the respective read/write fds.
  782.  * If the fds specified correspond to the normal stdin and stdout,
  783.  * the streams opened will be assigned to stdin and stdout in
  784.  * an intuitive fashion (so that they may be later be used by
  785.  * printf/fgets type libc functions).  If inaddr is non-NULL,
  786.  * the address is assigned to the connection (as the *source* of
  787.  * the connection).  If it is NULL, remote address discovery will
  788.  * be attempted.  The connection structure appropriate fields are filled
  789.  * in, including the *destination* address.  Finally, if resolve is
  790.  * non-ZERO, inet_openrw will attempt to reverse resolve the remote
  791.  * address.  A new connection structure is created in the specified pool.
  792.  */
  793. conn_t *inet_openrw(pool *pool, conn_t *c, p_in_addr_t *addr, int fd,
  794.                     int rfd,int wfd, int resolve)
  795. {
  796.   conn_t *res;
  797.   int close_fd = TRUE;
  798.   res = inet_copy_connection(pool,c);
  799.   res->listen_fd = -1;
  800.   inet_get_conn_info(res,fd);
  801.   if(addr) {
  802.     if(!res->remote_ipaddr)
  803.       res->remote_ipaddr = (p_in_addr_t*)palloc(res->pool,sizeof(p_in_addr_t));
  804.     *res->remote_ipaddr = *addr;
  805.   }
  806.   if(resolve && res->remote_ipaddr)
  807.     res->remote_name = inet_getname(res->pool,res->remote_ipaddr);
  808.   if(!res->remote_name)
  809.     res->remote_name = pstrdup(res->pool,inet_ntoa(*res->remote_ipaddr));
  810.   if(fd == -1 && c->listen_fd != -1)
  811.     fd = c->listen_fd;
  812.   if(rfd != -1) {
  813.     if(fd != rfd) dup2(fd,rfd);
  814.     else close_fd = FALSE;
  815.   } else
  816.     rfd = dup(fd);
  817.   if(wfd != -1) {
  818.     if(fd != wfd) {
  819.       if(wfd == STDOUT_FILENO)
  820.         fflush(stdout);
  821.       dup2(fd,wfd);
  822.     } else
  823.       close_fd = FALSE;
  824.   } else
  825.     wfd = dup(fd);
  826.   /* Now discard the original socket */
  827.   if(rfd != -1 && wfd != -1 && close_fd)
  828.     close(fd);
  829.   res->rfd = rfd;
  830.   res->wfd = wfd;
  831.   res->inf = io_open(res->pool,res->rfd,IO_READ);
  832.   res->outf = io_open(res->pool,res->wfd,IO_WRITE);
  833.   /* Set options on the sockets */
  834.   inet_setoptions(res->pool,res,0,0);
  835.   inet_setblock(res->pool,res);
  836.   res->mode = CM_OPEN;
  837.   return res;
  838. }
  839. void init_inet()
  840. {
  841.   struct protoent *pr;
  842.   setprotoent(FALSE);
  843.   if((pr = getprotobyname("tcp")) != NULL)
  844.     tcp_proto = pr->p_proto;
  845.   endprotoent();
  846. }