/* ==== main.c ============================================================
 * Copyright (c) 1995 by Chris Provenzano, proven@mit.edu
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *  This product includes software developed by Chris Provenzano.
 * 4. The name of Chris Provenzano may not be used to endorse or promote 
 *	  products derived from this software without specific prior written
 *	  permission.
 *
 * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY 
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE.
 *
 * Description : The arg parser and main loop for phttpd.
 *
 *  1.00 95/03/14 proven
 *      -Started coding this file.
 */

#include <fcntl.h>			/* For O_RDONLY */
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "accept_buf.h"

void usage(int eval)
{
	fprintf(stderr, "usage: phttpd [-ds] [-D <debug level>] [ -S <logfile>]\n");
	exit(eval);
}

extern int use_syslog;

short port = 8002;

void daemonize()
{
  int x;

  chdir("/");
  if((x = fork()) > 0)
    exit(0);
  else if(x == -1) 
    {
      fprintf(stderr,"kphttpd: unable to fork new process\n");
      perror("fork");
      exit(1);
    }
}


int main(int argc, char ** argv)
{
  struct sockaddr_in connect_addr;
  int connect_port, len;
  pthread_t thread_id;
  char * debug_file;
  int debug_level;
  char ch;

  /* getopt variables */
  extern char *optarg;
  extern int optind;

  /* Initialize */
  pthread_init();
  debug_level = 0;
  debug_file 	= NULL;

  while ((ch = getopt(argc, argv, "dD:sS:")) != (char)EOF)
    switch(ch) 
      {
      case 'd':   
	debug_level++;
	break;
      case 's':
	use_syslog++;
	break;
      case 'D':
	if ((debug_level = atoi(optarg)) <= 0) 
	  {
	    usage(1);
	  }
	break;
      case 'S':
	debug_file = optarg;
	break;
      case '?':
	usage(0);
	break;
      }


  /* Setup syslog */
  if (log_open(debug_level, debug_file, < OK) 
      {
	fprintf(stderr, "Can't open log files\n");
	exit(1);
      }

      /* Do some optomization here */
      /* We don't need float, they all should be FIFO, and detached */

      if (!debug_level) daemonize();
      
      /* Setup signal handler */
      if (pthread_create(&thread_id, NULL, deal_with_signal, NULL)) 
      {
	log_error(LOG_ERR, "Can't create signal thread!");
	exit(1);
      }

      /* Setup server */
      if ((connect_port = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
      {
	log_error(LOG_ERR, "socket");
	exit(1);
      }

      connect_addr.sin_family 		= AF_INET;
      connect_addr.sin_port             = htons(port);
      connect_addr.sin_addr.s_addr	= INADDR_ANY;
      
      len = sizeof(connect_addr);
      if (bind(connect_port, (struct sockaddr *)(&connect_addr), len))
      {
	log_error(LOG_ERR, "bind");
	exit(1);
      }

      listen(connect_port, 8);
      
      while (1) 
      {
	struct sockaddr_in accept_addr;
    	struct accept_buf * buf;

        /* Allocte a new accept buffer */
	buf = accept_buf_malloc();

      no_malloc:
	len = sizeof(struct sockaddr_in);
        if ((buf->fd = accept(connect_port, &accept_addr, &len)) < 0) 
	  {
	    /* This might be just a warning */
	    log_error(LOG_ERR, "accept");
	    break;
	  }

	buf->host = find_peer_name(&accept_addr);
	
        if (pthread_create(&thread_id, NULL, talk_to_client, (void *)buf)) 
	  {
	    log_error(LOG_WARN, "pthread_create");
	    /* Send an error back to the connector */

            /* Close connection and free buffer */
	    close(buf->fd);
	    goto no_malloc;
	  }
	pthread_detach(thread_id);
      }

      /* At least let all the current connections finish */
      pthread_exit(NULL);
    }
}
