home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / sredird / telnetcpcd-1.09.tar.gz / telnetcpcd-1.09.tar / server.c < prev    next >
C/C++ Source or Header  |  2003-08-12  |  5KB  |  207 lines

  1. /*
  2.     server.c
  3.  
  4.     Copyright (c) 2002,2003 Thomas J Pinkl <tom@pinkl.com>
  5.  
  6.     Network communications routines.
  7.  
  8.     Version 1.00    02/22/2002        
  9. */
  10.  
  11. #include "telnetcpcd.h"
  12.  
  13. /*
  14.     global variables
  15. */
  16. int signo_child = 0;                    /* what signal did we receive? */
  17.  
  18. int handle_connection(int);
  19. void disconnect(int sockfd);
  20. void reset_signals(void);
  21. void record_child_signal(int sig);
  22. void child_sighandler(int);
  23.  
  24. /*
  25.     create the server TCP socket then accept concurrent 
  26.     client connections.  this function does not return.
  27. */
  28. void server(int tcp_port)
  29. {
  30.     extern struct config_t conf;        /* built from config file */
  31.     extern int signo;                    /* parent signal number */
  32.     int sockfd;
  33.  
  34.     /*
  35.         create a blocking TCP server socket
  36.     */
  37.     sockfd = create_server_socket(tcp_port,BLOCKING);
  38.     if (sockfd == -1) {
  39.         syslog(LOG_ERR,"cannot create server tcp socket");
  40.         exit(1);
  41.     }
  42.     syslog(LOG_DEBUG,"server socket is fd %d",sockfd);
  43.  
  44.     /*
  45.         accept socket connections.  for a concurrent server, 
  46.         we fork a child process for each new connection.
  47.         for an iterative server, we handle the connection 
  48.         within this process.  
  49.  
  50.         this function does not return.
  51.     */
  52.     if (strcmp(conf.servertype,"concurrent") == 0) {
  53.         concurrent_server(sockfd,handle_connection,&signo,parent_sighandler);
  54.     } else {
  55.         iterative_server(sockfd,handle_connection,&signo,parent_sighandler);
  56.     }
  57.     exit(1);                            /* not reached */
  58. }
  59.  
  60. /*
  61.     this function is called by concurrent_server() and by 
  62.     iterative_server(), after accepting a client connection.
  63. */
  64. int gsockfd = -1;                        /* global copy of child socket fd */
  65.                                         /* for our signal handler */
  66. int handle_connection(int sockfd)
  67. {
  68.     extern struct config_t conf;        /* built from config file */
  69.     extern int gsockfd;                    /* global copy of sockfd */
  70.     int ret;                            /* return value from rfc2217() */
  71.  
  72.     gsockfd = sockfd;                    /* save our socket fd */
  73.     syslog(LOG_DEBUG,"client socket is fd %d",sockfd);
  74.  
  75.     /*
  76.         if the server type is concurrent, then the process that is 
  77.         executing this code is a child of the "master" daemon (ie. 
  78.         the one that's listening on the socket).  if that's the case, 
  79.         then we want to reset some of the signal handlers that we 
  80.         inherited from our parent.
  81.     */
  82.     if (strcmp(conf.servertype,"concurrent") == 0) 
  83.         reset_signals();                /* reset child's signal handlers */
  84.  
  85.     if (chdir(conf.directory) != 0)    {    /* set working directory */
  86.         syslog(LOG_ERR,"cannot chdir(%s): %s",conf.directory,strerror(errno));
  87.         _exit(1);
  88.     }
  89.     if (setgid(conf.gid) != 0) {
  90.         syslog(LOG_ERR,"setgid(%d) error: %s",conf.gid,strerror(errno));
  91.         _exit(1);
  92.     }
  93.     if (setuid(conf.uid) != 0) {
  94.         syslog(LOG_ERR,"setuid(%d) error: %s",conf.uid,strerror(errno));
  95.         _exit(1);
  96.     }
  97.     ret = rfc2217(sockfd);
  98.     disconnect(sockfd);
  99.     return(ret);
  100. }
  101.  
  102. void disconnect(int sockfd)
  103. {
  104.     extern int gsockfd;                    /* global copy of sockfd */
  105.  
  106.     shutdown(sockfd,SHUT_RDWR);
  107.     syslog(LOG_INFO,"closed socket fd %d",sockfd);
  108.     gsockfd = -1;
  109. }
  110.  
  111. /*
  112.     reset the signal handlers that we inherited from 
  113.     our parent, except for SIGCLD.  we catch the
  114.     likely signals with a function that simply records
  115.     which signal we received.
  116. */
  117. void reset_signals(void)
  118. {
  119.     extern int signo_child;                /* what signal did we receive? */
  120.     struct sigaction act;                /* for signals */
  121.  
  122.     act.sa_handler = record_child_signal;    /* function to handle signals */
  123.  
  124.     sigemptyset(&act.sa_mask);            /* required before sigaction() */
  125.     act.sa_flags = 0;                    /* no SA_RESTART */
  126.     sigaction(SIGTERM,&act,NULL);        /* same handler for all 5 signals */
  127.     sigaction(SIGINT,&act,NULL);
  128.     sigaction(SIGQUIT,&act,NULL);
  129.     sigaction(SIGHUP,&act,NULL);
  130.     sigaction(SIGUSR1,&act,NULL);
  131.     sigaction(SIGUSR2,&act,NULL);
  132.     sigaction(SIGPIPE,&act,NULL);
  133.  
  134.     signo_child = 0;                    /* init */
  135. }
  136.  
  137. /*
  138.     this is our generic signal handling function for the child process.  
  139.     it gets called for any signal we care to handle and simply sets the 
  140.     global signo_child variable to the signal number. 
  141.  
  142.     it's then up to code elsewhere in the system to check signo_child and 
  143.     act accordingly.
  144. */
  145. void record_child_signal(int sig)
  146. {
  147.     extern int signo_child;                /* what signal did we receive? */
  148. #ifdef REARMSIGS
  149.     struct sigaction act;
  150. #endif
  151.  
  152.     signo_child = sig;
  153.  
  154. #ifdef REARMSIGS
  155.     act.sa_handler = record_child_signal;
  156.     sigemptyset(&act.sa_mask);
  157.     act.sa_flags = 0;                    /* no SA_RESTART */
  158.     sigaction(sig,&act,NULL);
  159. #endif
  160. }
  161.  
  162. /*
  163.     generic signal handler.  we log which signal occurred, tidy up 
  164.     a bit, then we terminate.
  165.  
  166.     does not return.
  167. */
  168. void child_sighandler(int sig)
  169. {
  170.     extern int gsockfd;                    /* global copy of sockfd */
  171.  
  172.     syslog(LOG_ERR,"received signal %d (%s)",sig,signame(sig));
  173.     if (gsockfd >= 0)
  174.         disconnect(gsockfd);
  175.     _exit(128 + sig);
  176. }
  177.  
  178. void handle_pending_signal(void)
  179. {
  180.     extern int signo_child;                /* what signal did we receive? */
  181.  
  182.     switch (signo_child) {
  183.     case 0:                                /* none */
  184.         break;
  185.     case SIGINT:                        /* modem break condition */
  186.         rfc2217_sigint();
  187.         break;
  188.     case SIGUSR1:
  189.         sigusr1(signo_child);            /* increment debug level */
  190.         break;
  191.     case SIGUSR2:
  192.         sigusr2(signo_child);            /* decrement debug level */
  193.         break;
  194.     default:
  195.         child_sighandler(signo_child);     /* does not return */
  196.         break;
  197.     }
  198.     signo_child = 0;                    /* clear pending signal; very important! */
  199. }
  200.  
  201. int get_pending_signal(void)
  202. {
  203.     extern int signo_child;                /* what signal did we receive? */
  204.  
  205.     return(signo_child);
  206. }
  207.