/*
* main.c
* The Main line of the Message Server
*
* $Id: main.c,v 1.3 1996/03/29 16:51:01 athan Exp $
*
* $Log: main.c,v $
* Revision 1.3 1996/03/29 16:51:01 athan
* Proper cli arguments now
* Added code for restart, background, verbose, SIGUSR1 support
*
* Revision 1.2 1996/03/28 20:02:07 athan
* General cleanups
*
*
*/
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#if defined(SUNOS)
#include <memory.h>
#endif
#include <sys/wait.h>
#include "config.h"
#include "file.h"
/* Extern Function Prototypes */
extern int accept_connection(void);
extern int check_timeout(long thistime, int *count);
extern void do_login(int newfd, long ltime);
extern void init_comms(void);
extern void load_file(char *fn, struct afile *it);
extern int open_main_socket(int port);
extern void shut_down(void);
/* Extern Variables */
extern char *optarg;
extern int optind, opterr, optopt;
extern struct afile thefile;
/* Local Function Prototypes */
void catch_hup(int i);
void catch_int(int i);
void cleanupanddie(int i);
void catch_alrm(int i);
void do_help(void);
void set_read_msg_file(int i);
void do_server(void);
void sendusr1_to_child(int i);
/* Local Variables */
int status = INIT;
int read_msg_file = 0;
int port = DEFAULT_PORT;
char *msg_file = DEFAULT_MSG_FILE;
int loop = 0;
time_t loopdelay = 1;
int verbose = 0;
struct afile thefile =
{NULL, 0};
int timeout = DEFAULT_TIMEOUT;
int childpid;
int main(int argc, char *argv[])
{
int optret;
int restart = 0;
int background = 0;
int childstatus;
/* Process command line arguments */
while (-1 != (optret = getopt(argc, argv, "p:m:l:t:vrbh")))
{
switch (optret)
{
case 'p': /* Port number */
port = atoi(optarg);
if (getuid() && port < 1024)
{
fprintf(stderr, "%s: Must be uid 0 to use ports below 1024!\n",
argv[0]);
exit(-1);
}
break;
case 'm': /* Message file */
msg_file = strdup(optarg);
if (!msg_file)
{
fprintf(stderr, "%s: Error duplicating file name!\n",
argv[0]);
exit(-1);
}
break;
case 'l': /* Loop until can bind port */
loop = 1;
loopdelay = atoi(optarg);
if (loopdelay < 1)
{
fprintf(stderr, "%s: Loop delay must be at least 1 second\n",
argv[0]);
exit(-1);
}
break;
case 't': /* Connection timeout */
timeout = atoi(optarg);
if (timeout < 0)
{
fprintf(stderr, "%s: Timeout must be positive\n", argv[0]);
exit(-1);
}
case 'v': /* Print (verbose) errors */
verbose++;
break;
case 'r': /* Restart if crash */
restart++;
/* Implies background */
background++;
break;
case 'b': /* Run in background */
background++;
break;
case 'h': /* Help */
printf("%s: Help...\n", argv[0]);
do_help();
exit(0);
break;
case ':': /* Missing argument */
fprintf(stderr, "%s: Missing argument\n", argv[0]);
exit(-1);
break;
case '?': /* Unknown option */
break;
default: /* Erk ? */
printf("%s: Erk, option processing caused an error!\n", argv[0]);
}
}
if (background)
{
childpid = fork();
switch (childpid)
{
case -1: /* Error */
fprintf(stderr, "%s: Failed to fork!\n", argv[0]);
exit(-1);
case 0: /* Child */
setpgrp();
break;
default: /* Parent */
exit(0);
}
}
if (restart)
{
/* Server should restart if it dies for any reason */
while (1)
{
signal(SIGHUP, SIG_IGN);
signal(SIGINT, cleanupanddie);
signal(SIGQUIT, cleanupanddie);
signal(SIGTERM, cleanupanddie);
signal(SIGUSR1, sendusr1_to_child);
childpid = fork();
switch (childpid)
{
case -1: /* Error */
exit(-1);
case 0: /* Child */
do_server();
break;
default: /* Parent */
waitpid(childpid, &childstatus, 0);
if (WEXITSTATUS(childstatus) == 42)
{
/* Child exitted normally */
exit(0);
}
}
sleep(10);
}
}
else
{
do_server();
}
return 0;
}
void do_server(void)
{
int newfd;
int count = 0;
long mytime = 0;
struct itimerval oldtimer, newtimer;
int ret = 0;
signal(SIGTERM, catch_int);
signal(SIGINT, catch_int);
signal(SIGHUP, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
signal(SIGALRM, catch_alrm);
signal(SIGUSR1, set_read_msg_file);
newtimer.it_interval.tv_sec = loopdelay;
newtimer.it_interval.tv_usec = 0;
newtimer.it_value.tv_sec = loopdelay;
newtimer.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &newtimer, &oldtimer);
init_comms();
/* Attempt to open a socket and bind it to the port */
do
{
if ((ret = open_main_socket(port)) < 0)
{
if (verbose || !loop)
{
fprintf(stderr, "Error: Failed to open main socket.\n");
}
if (!loop)
{
exit(-1);
}
sigpause(SIGALRM);
}
}
while (loop && (ret < 0));
if (verbose)
{
fprintf(stderr, "Socket open and bound to port %d\n", port);
}
status = RUNNING;
/* Load the message */
load_file(msg_file, &thefile);
/* Accept new connections */
while (status != SHUTDOWN)
{
if (read_msg_file)
{
load_file(msg_file, &thefile);
read_msg_file = 0;
}
mytime = (long) time(NULL);
/* Check for new connections */
if (-1 != (newfd = accept_connection()))
{
do_login(newfd, mytime);
count++;
}
/* Check for timeout on the logins */
while (check_timeout(mytime, &count) == -1)
{
}
sigpause(SIGALRM);
}
shut_down();
exit(42);
}
void catch_alrm(int i)
{
signal(SIGALRM, catch_alrm);
}
void do_help(void)
{
printf(" Possible command line arguments are:\n"
"\n"
" -p <port> - Set port to listen on\n"
" -m <file> - Set message file to use\n"
" -l <delay (seconds)> - Loop until port is bound\n"
" -t <timeout (seconds)> - Time before connection close\n"
" -v - Verbose messages\n"
" -r - Run with 'angel'\n"
" -b - Run in background (implied by -r)\n"
" -h - This help message\n");
}
void set_read_msg_file(int i)
{
read_msg_file = 1;
signal(SIGUSR1, set_read_msg_file);
}
void catch_int(int i)
{
status = SHUTDOWN;
}
void cleanupanddie(int i)
{
kill(childpid, SIGKILL);
exit(0);
}
void sendusr1_to_child(int i)
{
kill(childpid, SIGUSR1);
signal(SIGUSR1, sendusr1_to_child);
}