/* Main functions.

  The source code may be redistributed, as long it remains intact, and
  with this License included. You may modify or use this source code in
  anyway you see fit, but credit must be given where applicable.

  This software comes with NO warranty, and the author is NOT liable for
  any damages which may come from the use of this software.

  You may not use the name of the author to promote this software.

  shadows@whitefang.com (Thamer AL-Herbish)
  */

#include <config.h>
#include <common.h>
#include <log.h>

extern void initialize_buffer(void);
extern void delete_old(struct timeval period);
extern void start_sniffing(char *device);
extern void log_stats(void);

extern char *optarg;

static void go_background(void);

static struct timeval period = { 0, 0};
static int alarm_period = 0;
char *filter = NULL;
int verbose = 0;
int always_log = 0;

static void catch_alarm(int i)
{
  delete_old(period);
  log_stats();
  alarm(alarm_period);
  return;
}

static void setup_alarm(void)
{
  struct sigaction mysig;

  sigfillset(&mysig.sa_mask);
  sigdelset(&mysig.sa_mask,SIGKILL);
  sigdelset(&mysig.sa_mask,SIGSTOP);
  mysig.sa_flags = SA_RESTART;
  mysig.sa_handler = catch_alarm;

  sigaction(SIGALRM,&mysig,NULL);
  return;
}

void usage(char *s)
{
  fprintf(stderr,"usage: %s [-av] [-i idle_period] [-p check_interval] device filter..\n",s);
  exit(-1);
}

static char *copy_argv(register char **argv)
{
  char **p;
  int len = 0;
  char *buf;
  char *src, *dst;
  
  if(argv == NULL)
    return NULL;
  
  for(p = argv;*p;p++)
    len += (strlen(*p) + 1);
  
  if((buf = (char *)malloc(len)) == NULL) {
    perror("malloc");
    exit(-1);
  }
  
  p = argv;
  dst = buf;
  while ((src = *p++) != NULL) {
    while ((*dst++ = *src++) != '\0')
      ;
    dst[-1] = ' ';
  }
  dst[-1] = '\0';

  if((buf = (char *)realloc(buf,((sizeof(char)*strlen(buf)) + (sizeof(char) * 9)))) == NULL) {
    error_log("Out of mem");
    perror("realloc");
    exit(-1);
  }
  strcpy(&buf[strlen(buf)]," and tcp");
  return buf;
}
  
int main(int argc,char *argv[])
{
  char *device = NULL;
  int c;
  char *n;

  while((c = getopt(argc,argv,"d:i:p:v")) != EOF) {
    switch(c) {
    case 'v':
      {
	verbose++;
	break;
      }
    case 'd':
      {
	device = optarg;
	break;
      }
    case 'i':
      {
	period.tv_sec = (long)atoi(optarg);
	break;
      }
    case 'p':
      {
	alarm_period = atoi(optarg);
	break;
      }
    case 'a':
      {
	always_log++;
	break;
      }

    default:
      {
	usage(argv[0]);
	break;
      }
    }
  }

  n = argv[0];

  argc -= optind;
  argv += optind;

  if(argc < 1)
    usage(n);

  device = argv[0];

  argc--;
  argv++;

  if(argc >= 1)
    filter = copy_argv(&argv[0]);

  if(alarm_period == 0)
    alarm_period = PERIOD;
  if(period.tv_sec == 0)
    period.tv_sec = IDLE_PERIOD;

  initialize_buffer();
  period.tv_usec = 0;

  go_background();
  init_log("synlog");
  setup_alarm();
  alarm(alarm_period);
  start_sniffing(device);

  exit(0);
}

static void close_up(void)
{
  int i;

#ifdef NOFILE
  for(i = 0;i < NOFILE;i++)
    close(i);
#else
  for(i = 0;i < getdtablesize();i++)
    close(i);
#endif
  
  setsid();
  return;
}

static void go_background(void)
{
  switch(fork())  {
   case -1:
    perror("Couldnt fork");
    exit(-1);
   case 0:
    close_up();
    break;
   default:
    exit(0);
  }
  return;
}
