/*
  File:  proxy.c
  
  Description: a general-purpose proxy optimized for a large number 
               of concurrent connections.
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/event.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#include "config.h"
#include "proxy_protos.h"

extern char *optarg;
extern int   optind;

static int sig;

/* usage() */

static void usage ( void );

/* signal handler */

static void sighandler ( int signum );


/* main program */

int 
main ( int argc, char **argv )
{
  struct kevent       ke;
  struct mdata       *md;
  void               (*ef)(struct kevent *, struct mdata * );
  char                ch;
  unsigned short      sp = 0;
  unsigned short      lp = 0;
  char                lh[MAXPATHLEN];
  char                rh[MAXPATHLEN];
  char                lf[MAXPATHLEN];
  struct timespec     ts;
  int                 verbose = 0;

  /* get options */

  memset(lh,0,sizeof(lh));
  memset(rh,0,sizeof(rh));
  memset(lf,0,sizeof(lf));
  while ( (ch = getopt(argc,argv,"a:b:h:p:l:v")) != -1 ) {
    switch (ch) {
    case 'a':
      strncpy(lh,optarg,MAXPATHLEN-1);
      break;
    case 'b':
      lp = (unsigned short)strtoul(optarg,NULL,10);
      break;
    case 'h':
      strncpy(rh,optarg,MAXPATHLEN-1);
      break;
    case 'p':
      sp = (unsigned short)strtoul(optarg,NULL,10);
      break;
    case 'l':
      strncpy(lf,optarg,MAXPATHLEN-1);
      break;
    case 'v':
      verbose = 1;
      break;
    }
  }
  argc -= optind;
  argv += optind;

  /* usage() */

  if ( !sp || !lh[0] || !lp || !rh[0] ) {
    usage();
    exit(1);
  }

  fprintf(stderr,"Local host:  %s\n", lh);
  fprintf(stderr,"Local port:  %u\n", lp);
  fprintf(stderr,"Server host: %s\n", rh);
  fprintf(stderr,"Server port: %u\n", sp);

  /* set up signal handlers */

  signal ( SIGINT,  sighandler );
  signal ( SIGTERM, sighandler );
  signal ( SIGKILL, sighandler );

  if ( fork() ) exit(0);

  /* allocate the main data structure */

  if ( !(md = init_mdata(lh,lp,rh,sp,lf,verbose)) ) {
    perror("init_mdata");
    exit(2);
  }

  /* set up the event queue, bind to the local port, and listen */

  if ( !pay_attention(md) ) {
    perror("pay_attention");
    deinit_mdata(md);
    exit(3);
  }

  /* enter the main event loop until a signal is received */

  log_msg(md, "Entering event loop now");

  /* 100 microsecond timeout */

  ts.tv_sec  = 0;
  ts.tv_nsec = 100000;
  
  while ( !sig ) {
    
    while ( kevent(md->kq,NULL,0,&ke,1,&ts) > 0 ) {
      md->events++;
      ef = ke.udata;
      ef(&ke,md);
    }
    
    md->iterations++;

  }

  /* print some info from this session */

  print_stats(md);

  /* free allocated memory */

  deinit_mdata(md);

  return 0;
}



static void
usage ( void )
{
  fprintf(stderr,"Usage: %s -a <local host> -b <local port> -h <server host> -p <server port> [-l <logfile>] [-v]\n",
	  PACKAGE);
}


/* 
   signal handler, used for SIGINT, SIGTERM, SIGKILL
*/

static void
sighandler ( int signum )
{
  sig = signum;
}



syntax highlighted by Code2HTML, v. 0.9.1