/*
  File:  proxy_init.c 

  Description:  Initialization functions for proxy data structure.
*/

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <time.h>
#include "config.h"
#include "proxy_protos.h"

/* allocate memory for the main data structure */

struct mdata *
init_mdata ( char *l_name, unsigned short l_port, char *s_name, 
	     unsigned short s_port, char *log_file, int verbose )
{
  struct hostent *he;
  struct mdata   *md = NULL;
  int             ok = 0;

  /* first try to resolve the server's IP address */

  if ( (he = gethostbyname(s_name)) ) {

    /* now allocate memory for the main data structure */

    if ( (md = calloc(1,sizeof(struct mdata))) ) {

      /* get max number of open files */

      md->nofile = getdtablesize();

      /* verbosity */

      md->verbose = verbose;

      /* set the server address in the main data structure */

      md->server_port   = s_port;
      md->local_port    = l_port;
      md->sa.sin_family = AF_INET;
      md->sa.sin_port   = htons(s_port);
      memcpy(&(md->sa.sin_addr), he->h_addr_list[0], sizeof(unsigned long));
      memcpy(md->server_name, s_name, sizeof(md->server_name)-1);

      he = gethostbyname(l_name);
      md->la.sin_family = AF_INET;
      md->la.sin_port   = htons(l_port);
      memcpy(&(md->la.sin_addr), he->h_addr_list[0], sizeof(unsigned long));
      memcpy(md->local_name, l_name, sizeof(md->local_name)-1);

      /* try to open the log file if one was specified. */

      memcpy(md->log_file, log_file, sizeof(md->log_file)-1);
      if ( md->log_file[0] ) {
	md->log_fp = fopen(md->log_file,"a");
	setlinebuf(md->log_fp);
	log_msg(md,"===> %s version %s started",PACKAGE,VERSION);
	log_msg(md,"Local host:  %s",md->local_name);
	log_msg(md,"Local port:  %u",md->local_port);
	log_msg(md,"Server host: %s",md->server_name);
	log_msg(md,"Server port: %u",md->server_port);
      }

      /* otherwise, just use stderr. */

      if ( md->log_fp == NULL )
	md->log_fp = stderr;

      /* allocate state structures for the file descriptors */ 
      
      md->r = calloc(md->nofile,sizeof(struct rdata));
      
      /* allocate a memory pool for the queue buffers */

      md->m = g_mem_chunk_create(qdata,65536,G_ALLOC_AND_FREE);

      ok = (md->r && md->m);

    }
  }

  if ( !ok ) {
    deinit_mdata(md);
    md = NULL;
  }

  return md;
}


/* set up event queue, bind to local port, listen for connections */

int
pay_attention ( struct mdata *md )
{
  struct kevent      ke;
  int                err = 1;

  /* create the kernel event queue */

  if ( (md->kq = kqueue()) != -1 ) {
    
    /* create a socket for binding to port PROXY_PORT */

    if ((md->server_sock = socket(PF_INET, SOCK_STREAM, 0)) != -1) {

      /* make reusable */

      setsockopt(md->server_sock,
		 SOL_SOCKET,
		 SO_REUSEADDR,
		 (void *)&err,
		 sizeof(int));

      if ( bind(md->server_sock,(struct sockaddr *)&(md->la),sizeof(md->la)) != -1 ) {

	/* listen for incoming connections */
	
	if ( listen(md->server_sock,SOMAXCONN) != -1 ) {

	  md->r[md->server_sock].status = FD_OPEN;

	  /* register the file descriptor with the event queue */
	  
	  ke.ident   = md->server_sock;
	  ke.filter  = EVFILT_READ;
	  ke.flags   = EV_ADD;
	  ke.udata   = accept_client;

	  if ( kevent(md->kq,&ke,1,NULL,0,NULL) != -1 ) {

	    err = 0;
	    
	  } else {

	    md->kevent_errors++;

	  }
	}
      }
    }
  }

  return !err;
}



syntax highlighted by Code2HTML, v. 0.9.1