#include "tcpflow.h"

static char *debug_prefix = NULL;
extern stats_t stats;
extern char daemond;

#define BUFSIZE 1024


/*************************************************************************/


/* Simple wrapper around the malloc() function */
void *check_malloc(size_t size)
{
  void *ptr;

  if ((ptr = malloc(size)) == NULL) {
    DEBUG(0) ("Malloc failed - out of memory?");
    exit(1);
  }
  return ptr;
}


/*
 * Remember our program name and process ID so we can use them later
 * for printing debug messages
 */
void init_debug(char *argv[])
{
  debug_prefix = MALLOC(char, strlen(argv[0]) + 16);
  sprintf(debug_prefix, "%s[%d]", argv[0], (int) getpid());
}


/*
 * Print a debugging message, given a va_list
 */
void print_debug_message(char *fmt, va_list ap)
{
  /* print debug prefix */
  fprintf(stderr, "%s: ", debug_prefix);

  /* print the var-arg buffer passed to us */
  vfprintf(stderr, fmt, ap);

  /* add newline */
  fprintf(stderr, "\n");
  (void) fflush(stderr);
}

/* Print a debugging or informational message */
void debug_real(char *fmt, ...)
{
  va_list ap;

  va_start(ap, fmt);
  print_debug_message(fmt, ap);
  va_end(ap);
}
  

/* Print a debugging or informatioal message, then exit  */
void die(char *fmt, ...)
{
  va_list ap;

  va_start(ap, fmt);
  print_debug_message(fmt, ap);
  exit(1);
}


/* Copy argv into a newly malloced buffer.  Arguments are concatenated
 * with spaces in between each argument. */
char *copy_argv(char *argv[])
{
  char **arg;
  char *buf;
  int total_length = 0;

  for (arg = argv; *arg != NULL; arg++)
    total_length += (strlen(*arg) + 1); /* length of arg plus space */

  if (total_length == 0)
    return NULL;

  total_length++; /* add room for a null */

  buf = MALLOC(char, total_length);

  *buf = 0;
  for (arg = argv; *arg != NULL; arg++) {
    strcat(buf, *arg);
    strcat(buf, " ");
  }

  return buf;
}

/* Print flow name */
char *flow_name(flow_t flow)
{
static char name[48];

  sprintf(name,
	  "%d.%d.%d.%d:%d->%d.%d.%d.%d:%d",
	  (u_int8_t) ((flow.src & 0xff000000) >> 24),
	  (u_int8_t) ((flow.src & 0x00ff0000) >> 16),
	  (u_int8_t) ((flow.src & 0x0000ff00) >> 8),
	  (u_int8_t)  (flow.src & 0x000000ff),
	  flow.sport,
	  (u_int8_t) ((flow.dst & 0xff000000) >> 24),
	  (u_int8_t) ((flow.dst & 0x00ff0000) >> 16),
	  (u_int8_t) ((flow.dst & 0x0000ff00) >> 8),
	  (u_int8_t)  (flow.dst & 0x000000ff),
	  flow.dport);

return name;
}

/* Print flow state name */
char *flow_state_name(flow_state_t *state, int bytes_tx, int bytes_rx)
{
static char name[1024];
int duration_minutes;

  sprintf(name,
	  "%d.%d.%d.%d:%d->%d.%d.%d.%d:%d: packets rx=%lu tx=%lu, bytes rx=%d tx=%d, seconds=%d",
	  (u_int8_t) ((state->flow.src & 0xff000000) >> 24),
	  (u_int8_t) ((state->flow.src & 0x00ff0000) >> 16),
	  (u_int8_t) ((state->flow.src & 0x0000ff00) >> 8),
	  (u_int8_t)  (state->flow.src & 0x000000ff),
	  state->flow.sport,
	  (u_int8_t) ((state->flow.dst & 0xff000000) >> 24),
	  (u_int8_t) ((state->flow.dst & 0x00ff0000) >> 16),
	  (u_int8_t) ((state->flow.dst & 0x0000ff00) >> 8),
	  (u_int8_t)  (state->flow.dst & 0x000000ff),
	  state->flow.dport,
          state->packet_rx,
          state->packet_tx,
          bytes_rx,
          bytes_tx,
          (int)(state->time_last_access - state->time_creation)
          );

return name;
}

/* Print statistics on SIGALRM signal */
void statistics()
{
extern int time_stats;

   if( daemond )
      syslog( LOG_INFO, "Stats= mallocs: %lu, cleans: %lu, reuses: %lu, flows: %lu, Packets: %lu drops: %lu (%d\%)\n", 
         stats.mallocs, stats.cleans, stats.reuse, 
         (stats.mallocs-stats.cleans), stats.packets, stats.drops,
         stats.packets?(stats.drops*100/stats.packets):0 );
    else
      printf( "Stats= mallocs: %lu, cleans: %lu, reuses: %lu, flows: %lu, Packets: %lu drops: %lu (%d\%)\n", 
         stats.mallocs, stats.cleans, stats.reuse, 
         (stats.mallocs-stats.cleans), stats.packets, stats.drops,
         stats.packets?(stats.drops*100/stats.packets):0 );

   signal(SIGALRM, statistics);
   alarm(time_stats);
}

void init_daemon( int pid )
{
   if( pid ) exit( 0 );

   umask( 027 );

   if( setsid() == -1 ) {
       die( "Can't setsid\n" );
       exit( -1 );
   }

   /* send logs to syslog */
   openlog( "tcpstatflow", LOG_PID, LOG_USER );

   /* close file descriptors */
   close( STDIN_FILENO );                        /* STDIN */
   close( STDOUT_FILENO );                       /* STDERR */
   close( STDERR_FILENO );                       /* STDERR */

   open( "/dev/null", O_RDWR );                  /* STDIN */
   dup( STDIN_FILENO );                          /* STDOUT */
   dup( STDIN_FILENO );                          /* STDERR */
}
