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 >
Wrap
C/C++ Source or Header
|
2003-08-12
|
5KB
|
207 lines
/*
server.c
Copyright (c) 2002,2003 Thomas J Pinkl <tom@pinkl.com>
Network communications routines.
Version 1.00 02/22/2002
*/
#include "telnetcpcd.h"
/*
global variables
*/
int signo_child = 0; /* what signal did we receive? */
int handle_connection(int);
void disconnect(int sockfd);
void reset_signals(void);
void record_child_signal(int sig);
void child_sighandler(int);
/*
create the server TCP socket then accept concurrent
client connections. this function does not return.
*/
void server(int tcp_port)
{
extern struct config_t conf; /* built from config file */
extern int signo; /* parent signal number */
int sockfd;
/*
create a blocking TCP server socket
*/
sockfd = create_server_socket(tcp_port,BLOCKING);
if (sockfd == -1) {
syslog(LOG_ERR,"cannot create server tcp socket");
exit(1);
}
syslog(LOG_DEBUG,"server socket is fd %d",sockfd);
/*
accept socket connections. for a concurrent server,
we fork a child process for each new connection.
for an iterative server, we handle the connection
within this process.
this function does not return.
*/
if (strcmp(conf.servertype,"concurrent") == 0) {
concurrent_server(sockfd,handle_connection,&signo,parent_sighandler);
} else {
iterative_server(sockfd,handle_connection,&signo,parent_sighandler);
}
exit(1); /* not reached */
}
/*
this function is called by concurrent_server() and by
iterative_server(), after accepting a client connection.
*/
int gsockfd = -1; /* global copy of child socket fd */
/* for our signal handler */
int handle_connection(int sockfd)
{
extern struct config_t conf; /* built from config file */
extern int gsockfd; /* global copy of sockfd */
int ret; /* return value from rfc2217() */
gsockfd = sockfd; /* save our socket fd */
syslog(LOG_DEBUG,"client socket is fd %d",sockfd);
/*
if the server type is concurrent, then the process that is
executing this code is a child of the "master" daemon (ie.
the one that's listening on the socket). if that's the case,
then we want to reset some of the signal handlers that we
inherited from our parent.
*/
if (strcmp(conf.servertype,"concurrent") == 0)
reset_signals(); /* reset child's signal handlers */
if (chdir(conf.directory) != 0) { /* set working directory */
syslog(LOG_ERR,"cannot chdir(%s): %s",conf.directory,strerror(errno));
_exit(1);
}
if (setgid(conf.gid) != 0) {
syslog(LOG_ERR,"setgid(%d) error: %s",conf.gid,strerror(errno));
_exit(1);
}
if (setuid(conf.uid) != 0) {
syslog(LOG_ERR,"setuid(%d) error: %s",conf.uid,strerror(errno));
_exit(1);
}
ret = rfc2217(sockfd);
disconnect(sockfd);
return(ret);
}
void disconnect(int sockfd)
{
extern int gsockfd; /* global copy of sockfd */
shutdown(sockfd,SHUT_RDWR);
syslog(LOG_INFO,"closed socket fd %d",sockfd);
gsockfd = -1;
}
/*
reset the signal handlers that we inherited from
our parent, except for SIGCLD. we catch the
likely signals with a function that simply records
which signal we received.
*/
void reset_signals(void)
{
extern int signo_child; /* what signal did we receive? */
struct sigaction act; /* for signals */
act.sa_handler = record_child_signal; /* function to handle signals */
sigemptyset(&act.sa_mask); /* required before sigaction() */
act.sa_flags = 0; /* no SA_RESTART */
sigaction(SIGTERM,&act,NULL); /* same handler for all 5 signals */
sigaction(SIGINT,&act,NULL);
sigaction(SIGQUIT,&act,NULL);
sigaction(SIGHUP,&act,NULL);
sigaction(SIGUSR1,&act,NULL);
sigaction(SIGUSR2,&act,NULL);
sigaction(SIGPIPE,&act,NULL);
signo_child = 0; /* init */
}
/*
this is our generic signal handling function for the child process.
it gets called for any signal we care to handle and simply sets the
global signo_child variable to the signal number.
it's then up to code elsewhere in the system to check signo_child and
act accordingly.
*/
void record_child_signal(int sig)
{
extern int signo_child; /* what signal did we receive? */
#ifdef REARMSIGS
struct sigaction act;
#endif
signo_child = sig;
#ifdef REARMSIGS
act.sa_handler = record_child_signal;
sigemptyset(&act.sa_mask);
act.sa_flags = 0; /* no SA_RESTART */
sigaction(sig,&act,NULL);
#endif
}
/*
generic signal handler. we log which signal occurred, tidy up
a bit, then we terminate.
does not return.
*/
void child_sighandler(int sig)
{
extern int gsockfd; /* global copy of sockfd */
syslog(LOG_ERR,"received signal %d (%s)",sig,signame(sig));
if (gsockfd >= 0)
disconnect(gsockfd);
_exit(128 + sig);
}
void handle_pending_signal(void)
{
extern int signo_child; /* what signal did we receive? */
switch (signo_child) {
case 0: /* none */
break;
case SIGINT: /* modem break condition */
rfc2217_sigint();
break;
case SIGUSR1:
sigusr1(signo_child); /* increment debug level */
break;
case SIGUSR2:
sigusr2(signo_child); /* decrement debug level */
break;
default:
child_sighandler(signo_child); /* does not return */
break;
}
signo_child = 0; /* clear pending signal; very important! */
}
int get_pending_signal(void)
{
extern int signo_child; /* what signal did we receive? */
return(signo_child);
}