pgplus/bin/
pgplus/help_files/
pgplus/port_redirector/
pgplus/src/configure/makefiles/
/*
 * 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);
}