/*
 * Server for Dynamic Host Configuration Protocol IPv6
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * Copyright (c) International Business Machines Corp., 2002
 *
 * Author: Suresh Kodati <skodati@in.ibm.com>
 */

#include <netinet/in.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <time.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <bits/errno.h>

#include "dhcp6.h"
#include "dhcp6common.h"
#include <ifaddrs.h>


/* prefix length */
#define LINK_LOCAL_PLEN 10

/* address status */
#define UN_ASSIGNED 0
#define TEMP_ALLOCATED 1
#define ASSIGNED 2

/* 2^32 */
#define POW32 4294967296

/* values for some states */

#define DOLISTEN  	0
#define RELEASING 	1
#define DECLINING 	2
#define REQUESTING  	3
#define SOLICITING  	4
#define RENEWING  	5

//stores the lease database 
#define LEASE_FILE "dhcp6.lease"
//stores the configuration such as dns subnet etc.,
#define CONF_FILE "dhcp6.conf"
//stores the denied client entries
#define DHCP_DENY "dhcp6deny"



struct IAlist{
	struct dhc6_iaaddr_option IAaddr;
	struct IAlist *next;
};

struct client_status{
	struct duid_type_1 DUID;
	uint32_t IAID;
	int IA_RELEASE;
	time_t T1;
	time_t T2;
};

struct alloc_address{
	struct in6_addr addr;
	int pfix;
	struct alloc_address *next;
};

struct  dhc6ext_head{
	uint16_t option_code;
	uint16_t option_len;
};

struct addr_list{
	struct in6_addr address;
	struct in6_addr LinkLocaladress;
	int status;
	uint32_t dhcIAID;
	struct duid_type_1 duid;
	time_t T1;
	time_t T2;
};


struct client_status CLIENT_STAT;
struct duid_type_1 duid_cur;
struct alloc_address *alloc_addr;
struct addr_list *addrlist;


int STATE = DOLISTEN;
int sigStatus = 0;
int NUMADDR=0;
int PREF_VAL;
int LIFETIME;
int DBUG=1;
int DAEMON=0;
int Insock, Outsock;
char *device=NULL;

char* version="DHCPv6 Server version 0.01 based on draft 23";



/* Prints the usage and usually exits from there */
void usage(void)
{
	printf("\nError in parameter parsing");
	printf("\nUse server -I <interface> [-d] [-D] [-v]\n");
}

int get_prefix_length()
{
	char a[3];
	if( get_config_value(CONF_FILE, "prefix", a) == -1){
		return -1;
	}
	return(atoi(a));
}


int get_pref_val()
{
	char a[3];
	if( get_config_value(CONF_FILE, "preference", a) == -1){
		return -1;
	}
	return(atoi(a));
}


int get_life_time()
{
	char a[3];
	if( get_config_value(CONF_FILE, "lifetime", a) == -1){
		return -1;
	}
	return(atoi(a));
}

void server_process_ia_option(char *option,  int num)
{
	
	struct dhc6_ia_option p;
	memcpy(&p,option+num , sizeof(struct dhc6_ia_option));
	CLIENT_STAT.IAID = p.iaid;
}


void server_process_duid_option(char *option, int num)
{
	 memcpy(&(CLIENT_STAT.DUID), option+num+4 , sizeof(CLIENT_STAT.DUID));
}


void  release_address_from_file(uint32_t IAID, struct duid_type_1 DUID, 
		struct in6_addr ADDR)
{
	uint32_t iaid;
	struct duid_type_1 duid;
	time_t t1, t2;
	char ADDRCHAR[40];
	char addrchar[40];
	FILE *fp=NULL;
	int truncval = 0;
	int once=2;
	
	long pos1, pos_cur;

	inet_ntop(AF_INET6, &ADDR, ADDRCHAR, 40);
	dPrint(DBUG, "  Deleting the address %s from database..", ADDRCHAR);

	fp = fopen(LEASE_FILE, "r+");
	if(fp == NULL){
		dPrint(DBUG, "Error: Openign lease file");
		exit(0);
	}
	
	while(1){
		pos1 = ftell(fp);
	
		if ( fscanf(fp, "%s %d ", addrchar, &iaid) == EOF){
			dPrint(DBUG, "Error: in the database 1");
			break;
		}

		if( fread(&duid, sizeof(duid), 1, fp) == 0){
			dPrint(DBUG, "Error: Value in the database 2");
			break;
		}
		if ( fscanf(fp, " %lu %lu", &t1, &t2) == EOF){
			dPrint(DBUG, "Error: Value in the database 3");
			break;
		}
		truncval += 76;

		if( (IAID == iaid) && !memcmp(&DUID, &duid, sizeof(DUID)) && 
			!( strcmp(ADDRCHAR, addrchar))) {
			dPrint(DBUG, "  Value found in the database");
		
			while(1){	

				if ( fscanf(fp, "%s %d ", addrchar, &iaid) 
						== EOF){
					break;
				}
				if( fread(&duid, sizeof(duid), 1, fp) == 0){
					break;
				}
				if ( fscanf(fp, " %lu %lu", &t1, &t2) == EOF){
					break;
				}
				
				pos_cur = ftell(fp);
				fseek(fp, pos1- pos_cur, SEEK_CUR);
				fprintf(fp, "%s %d", addrchar, iaid);
				fwrite(&duid, sizeof(duid), 1, fp);
				fprintf(fp, " %lu %lu\n", t1, t2);
				pos1 = ftell(fp);
				fseek(fp, pos_cur-pos1, SEEK_CUR); 
				truncval += 76;
			}
		
			fclose(fp);
			truncval = truncval-76-once;
			if(truncval < 0)truncval = 0;
			if(truncate("dhcp6.lease", truncval)!=0){
				perror("Error is");
				dPrint(DBUG, "Erro: truncated failed");	
			}
			if(once == 2)once=0;
			dPrint(DBUG, "DONE");
			return;
		}else{
			dPrint(DBUG, "Address not matching %s %d", addrchar, 
				iaid);
		}
	}
	fclose(fp);
	return;
}


/* Sets the server id using the duid */
void dhc6_set_server_id( struct dhc6_duid_opt *dhc6duid)
{

	dhc6duid->option_code = OPTION_SERVERID;
	memcpy(&dhc6duid->duid, &duid_cur, sizeof(duid_cur));
	dhc6duid->option_len  = sizeof (struct dhc6_duid_opt)-4;

}

void server_set_ia_option(struct dhc6_ia_option *dhc6Ia )
{
	time_t t;
	time(&t);
	dhc6Ia->option_code = OPTION_IA;
	dhc6Ia->iaid = CLIENT_STAT.IAID;
	dhc6Ia->T1 = t;
	dhc6Ia->T2 = t + LIFETIME;
	dhc6Ia->option_len = sizeof( struct dhc6_ia_option)-4;
	CLIENT_STAT.T1 = dhc6Ia->T1;
	CLIENT_STAT.T2 = dhc6Ia->T2;

}


void server_set_status_code(struct dhc6_status_code_option *dhc6StatCode)
{
	dhc6StatCode->option_code = OPTION_STATUSCODE ;
	dhc6StatCode->option_len = sizeof(*dhc6StatCode)-4;
	dhc6StatCode->status = DHC6_SUCCESS;
}

void server_set_pref(struct dhc6_pref_option  *dhc6Pref)
{
	dhc6Pref->option_code = OPTION_PREF;
	dhc6Pref->pref = get_pref_val();
	dhc6Pref->option_len = sizeof( struct dhc6_pref_option)-4;
}


void server_print_config_value(void)
{
	printf("\n *********************** Configuration File info **********************");
	printf("\nTotal number of addresses  = %d", NUMADDR);
	printf("\nPreference Value           = %d", PREF_VAL);
	printf("\nLifeTime                   = %d", LIFETIME);
	printf("\n **********************************************************************\n");
}

void next_addr(struct in6_addr from_addr, struct in6_addr *next)
{
	from_addr.s6_addr16[7]= htons(ntohs(from_addr.s6_addr16[7])+1);
	memcpy(next, &from_addr, sizeof(struct in6_addr));
}

int server_set_client_addr(struct in6_addr *add)
{
	int i;

	for ( i = 0; i< NUMADDR; i++){
		if((addrlist[i].dhcIAID == CLIENT_STAT.IAID) &&  
			(memcmp(&addrlist[i].duid, &CLIENT_STAT.DUID, 
			sizeof(&addrlist[i].duid)) == 0) &&
			(addrlist[i].status== UN_ASSIGNED)){

			addrlist[i].dhcIAID = CLIENT_STAT.IAID;
			addrlist[i].status = TEMP_ALLOCATED;
			memcpy(&(addrlist[i].duid), &CLIENT_STAT.DUID, 
				sizeof(struct duid_type_1));
			memcpy(add, &addrlist[i].address, 
				sizeof(struct in6_addr));
			dPrint(DBUG,"Address picked up from database");
			return 0;
		}
	}
		

	for ( i = 0; i< NUMADDR; i++){
		if(addrlist[i].status==UN_ASSIGNED){
			memcpy(add,  &addrlist[i].address, 
				sizeof(struct in6_addr));
			addrlist[i].status = TEMP_ALLOCATED;
			addrlist[i].dhcIAID = CLIENT_STAT.IAID;
			memcpy(&(addrlist[i].duid), &CLIENT_STAT.DUID, 
				sizeof(struct duid_type_1));
			memcpy(add, &addrlist[i].address, 
				sizeof(struct in6_addr));
			return 0 ;
		}
	}
	dPrint(DBUG, "Address not available");
	exit(0); 
	
}

int server_get_client_addr(struct in6_addr add)
{
	int i;
	FILE *fplease;
	char rem[50];

	i =  ntohs(add.s6_addr16[7]- addrlist[0].address.s6_addr16[7]);

	if(memcmp(&add,  &addrlist[i].address, sizeof(struct in6_addr)) == 0 
		&& addrlist[i].dhcIAID == CLIENT_STAT.IAID&&
			(memcmp(&addrlist[i].duid, &CLIENT_STAT.DUID, 
				sizeof(&addrlist[i].duid)) == 0)){
		addrlist[i].status = ASSIGNED;
		inet_ntop(AF_INET6, &addrlist[i].address,rem,40);

		fplease = fopen(LEASE_FILE, "a+");
		if( fplease == NULL){
			dPrint(DBUG, "Error Opening lease file");
			exit(0);
		}

		fprintf(fplease, "%s %d ",rem, CLIENT_STAT.IAID);
		fwrite(&CLIENT_STAT.DUID, sizeof(CLIENT_STAT.DUID), 1, fplease);
		fprintf(fplease, " %d %d",(int)CLIENT_STAT.T1, (int)CLIENT_STAT.T2);
		
		fprintf(fplease, "\n");
		fclose(fplease);
		return 0 ;
	}

	inet_ntop(AF_INET6, &add,rem,40);
	dPrint(DBUG,"Address %s not meant for this client", rem);
	return (-1);
}




void get_range_addr(struct in6_addr *add1, struct in6_addr *add2)
{
	char rem[50];

	if( get_config_value(CONF_FILE, "start", rem) == -1){
		dPrint(0, "Error: reading configuration file");
		exit(0);
	}

	dPrint(DBUG, "Configure for starting address %s and end address ", rem);
	inet_pton(AF_INET6, rem, add1);
	if( get_config_value(CONF_FILE, "end", rem) == -1){
		dPrint(0, "Error: reading configuration file");
		exit(0);
	}

	dPrint(DBUG, "%s\n", rem);
	inet_pton(AF_INET6, rem, add2);
}

void initialise_addr_list(struct in6_addr address)
{
	int i;
	addrlist = (struct addr_list *)malloc((sizeof(struct addr_list))* NUMADDR);
	if( addrlist == NULL){
		dPrint(DBUG, "Error: Allocating memory");
		exit(0);
	}
	for(i = 0; i< NUMADDR; i++){	
		memcpy(&addrlist[i].address, &address, sizeof(struct in6_addr));
		addrlist[i].status = UN_ASSIGNED;
		next_addr(address, &address);
	}
	printf("\nInitialised the data\n");
}

void server_load_lease_base(void)
{
	int i;
	FILE *fp;
	char lease_char[50];
	struct in6_addr lease_add;
	int iaid;
	time_t t1, t2, tnow;
	struct duid_type_1 duid_list;

	dPrint(DBUG, "Reading configuration file");
	fp = fopen(LEASE_FILE, "r");
	if(fp == NULL){
		dPrint(DBUG, "Error opening lease file");
		exit(0);
	}
	
	memset(lease_char, '\0', 50);
	while (1){
		memset(lease_char, '\0', 50);
		if((fscanf(fp, "%s %d ", lease_char, &iaid) == EOF)){
			fclose(fp);
			return;
		}
		fread(&duid_list, sizeof(duid_list), 1, fp);
		inet_pton(AF_INET6, lease_char, &lease_add);
		fscanf(fp, " %lu %lu", &t1, &t2);
		time(&tnow);

/* has nothing to do with this item if the time has expired 
 * releases the address from the lease file
 */ 

		if(tnow > t2){
			dPrint(DBUG, "Lease period of %d is expired and deleting", lease_char);
			release_address_from_file(iaid, duid_list, lease_add);
			continue;
			
		}

		dPrint(DBUG, "Loaded Address %s", lease_char);

		i =  ntohs(lease_add.s6_addr16[7]- addrlist[0].address.s6_addr16[7]);

		if( memcmp(&addrlist[i].address, &lease_add, 
				sizeof(struct in6_addr)) == 0){
			  addrlist[i].status = ASSIGNED;
			  addrlist[i].dhcIAID = iaid;
			  memcpy(&addrlist[i].duid, &duid_list, sizeof(duid_list));
			  addrlist[i].T1 = t1;
			  addrlist[i].T2 = t2;
		}
	}
	fclose(fp);
	return;
}


/* sets the signal status to 1 to enable reconfiguring */

void signal_handler(int signalno)
{
	sigStatus = 1;	
	dPrint(DBUG, "Signal for reconcfig init is received");
}


/* Not complete has to find what are all the clients has been reconfigured
 * 1) This loop has to be initiated by an external signal and the server initiates
 * reconfigure with all the client that has already configured
 * 2) The server receives gets the  information about the clients from the
 *	configuration
 */

void server_reconfig(void)
{
	char rec[BUFSIZ];
	struct dhc6_msg *dh6msg;
	int error;
	struct addrinfo hints, *res;
	int i;
	int len=0;
	struct sockaddr_in6 dst;
	int hlim;
	char addr_char[INET6_ADDRSTRLEN];

	dh6msg = (struct dhc6_msg *)rec;
	memset(dh6msg, 0, sizeof(dh6msg));
	dh6msg->msg_type = DHC6_RECONFIGINIT;

	memset(&hints, 0, sizeof(hints));
	hints.ai_family =  PF_INET6;
	hints.ai_socktype= SOCK_DGRAM;
	hints.ai_protocol = IPPROTO_UDP;

/* Reconfig messages should be unicasted to all the clients that
 * the server has configured previously. Server should go into
 * the list of all clients
 */

	for(i = 0; i< 3; i++){
		if(addrlist[i].status == ASSIGNED ){
			
			dPrint(DBUG, "\nSending the reconfigure  message\n");
			inet_ntop(AF_INET6, &addrlist[i].address, addr_char, sizeof(addr_char));
		
			error = getaddrinfo(addr_char, DHC6_CLIENT_PORT, 
				&hints, &res);
			memcpy(&dst, res->ai_addr, res->ai_addrlen);

			dPrint(DBUG, "\nMessage sent to %s", addr_char);

			hlim=0;

			if (setsockopt(Outsock, IPPROTO_IPV6, 
				IPV6_MULTICAST_HOPS, &hlim,sizeof(hlim)) < 0) {
				dPrint(DBUG,"setsockopt(IPV6_MULTICAST_HOPS)");
				exit(0);
			}

			error =sendto( Outsock, rec, len+3, 0, res->ai_addr, res->ai_addrlen);
		}
	}
	freeaddrinfo(res);
}	


/* Processes the ia addr option, in RELEASE in DECLINE and SOLICITING
 * REQUESTING,
 * REQUESTING and SOLICITING can be clubbed together to some level 
 */

void server_process_iaaddr_option(char *option, int num)
{
	struct dhc6_iaaddr_option p;
	int i ;
	char addr_char[INET6_ADDRSTRLEN];
	struct alloc_address *tempAlloc=NULL;

	memcpy(&p, option+num, sizeof(struct dhc6_iaaddr_option));

/* Assuming all the addresses in increasing order from addrlist[0] */

	i =  ntohs(p.addr.s6_addr16[7]- addrlist[0].address.s6_addr16[7]);
	
	switch(STATE){
	case RELEASING:
	case DECLINING:
		if(!memcmp(&p.addr, &addrlist[i].address, sizeof(p.addr))){
			if(CLIENT_STAT.IAID == addrlist[i].dhcIAID
				&& !memcmp(&addrlist[i].duid,  
					&(CLIENT_STAT.DUID), 
						sizeof(struct duid_type_1))) {
			
				inet_ntop(AF_INET6, &addrlist[i].address, addr_char, sizeof(addr_char));
				dPrint(DBUG, "\n ADDRESS %s,RELEASED", addr_char);
				addrlist[i].status = UN_ASSIGNED;
				CLIENT_STAT.IA_RELEASE = 1;
/* relese the address from database */
				release_address_from_file(CLIENT_STAT.IAID, 
					CLIENT_STAT.DUID, p.addr);
				return;
			}
		}
		inet_ntop(AF_INET6, &p.addr, addr_char, sizeof(addr_char));
		dPrint(DBUG, "Error ADDRESS %s NOT ASSIGNED TO THE CLIENT", addr_char);
		return;
	case RENEWING:
		dPrint(DBUG, "+++++++++++++++++++++++++++++++++++++++RENEWING");
		 if(!memcmp(&p.addr, &addrlist[i].address, sizeof(p.addr))){
			if(CLIENT_STAT.IAID == addrlist[i].dhcIAID
				&& !memcmp(&addrlist[i].duid,  
				&(CLIENT_STAT.DUID), sizeof(struct duid_type_1))) {

				inet_ntop(AF_INET6, &addrlist[i].address, addr_char, sizeof(addr_char));
				dPrint(DBUG, "\n ADDRESS %s,RELEASED", addr_char);
				addrlist[i].status = UN_ASSIGNED;
				CLIENT_STAT.IA_RELEASE = 1;
				release_address_from_file(CLIENT_STAT.IAID, 
					CLIENT_STAT.DUID, p.addr);
				server_get_client_addr(p.addr);
				return;
			}
		}	
	case SOLICITING:
		if(alloc_addr  == NULL){
			alloc_addr = (struct alloc_address *) malloc
					(sizeof(struct alloc_address));
			if(alloc_addr == NULL){
				dPrint(DBUG,"Error: Allocating memory");
				exit(0);
			}
			server_set_client_addr(&alloc_addr->addr);
			alloc_addr->pfix = get_prefix_length();
			alloc_addr->next = NULL;
			return;
		}
		tempAlloc = alloc_addr;
		while(alloc_addr->next != NULL){
			alloc_addr = alloc_addr->next;
		}
		
		alloc_addr->next = (struct alloc_address *) malloc(
					sizeof(struct alloc_address));
		if(alloc_addr->next == NULL){
			dPrint(DBUG,"Error: Allocating memory");
			       exit(0);
		}

		alloc_addr = alloc_addr->next;
		server_set_client_addr(&alloc_addr->addr);
		alloc_addr->pfix = get_prefix_length();
		alloc_addr->next = NULL;
		alloc_addr = tempAlloc;
		return;

	case  REQUESTING:

		if(alloc_addr  == NULL){
			alloc_addr = (struct alloc_address *) malloc(
				sizeof(struct alloc_address));
			if(alloc_addr == NULL){
				dPrint(DBUG,"Error: Allocating memory");
				exit(0);
			}
			if( server_get_client_addr(p.addr) == -1){
				free(alloc_addr);
				return;
			}

			alloc_addr->addr = p.addr;
			alloc_addr->pfix = get_prefix_length();
			alloc_addr->next = NULL;
			return;
		}
		tempAlloc = alloc_addr;
		while(alloc_addr->next != NULL){
			alloc_addr = alloc_addr->next;
		}
		
		if( server_get_client_addr(p.addr) == -1){
				alloc_addr = tempAlloc;	
				return;
		}

		alloc_addr->next = (struct alloc_address *) malloc(
					sizeof(struct alloc_address));
		if(alloc_addr->next == NULL){
			dPrint(DBUG,"Error: Allocating memory");
			exit(0);
		}
		alloc_addr = alloc_addr->next;
			
		alloc_addr->addr = p.addr;
		alloc_addr->pfix = get_prefix_length();
		alloc_addr->next = NULL;
		alloc_addr = tempAlloc;
		return;
	};
}


/* This fucntion processes various option received from the client message
 * 	 received,
 * 	Note: It should return -1 incase of any malformed option so that server
 *	sends appropriate message back to client
 */

void server_process_option(char *option)
{

	struct dhc6ext_head extension;
	int len=0;
	int num;
	
	memset(&CLIENT_STAT, 0, sizeof(CLIENT_STAT));
	 
	while(1){
		num = len;
		memcpy(&extension, option+len, sizeof(extension));	
		if(extension.option_code == 0)
			return;
		if(extension.option_len==0){ 
			dPrint(DBUG, "Invalid extension size 0"); 
			return;
		}
		len += extension.option_len+4;

		switch(extension.option_code ){
			case  OPTION_CLIENTID:
				dPrint(DBUG, "\n DUID OPTION RECEIVED");
				server_process_duid_option(option, num);
				break;
			case  OPTION_IA:
				dPrint(DBUG, "\n IA Option received");
				server_process_ia_option(option, num);
				break;
			case OPTION_IAADDR:
				dPrint(DBUG, "\n IA Address Option received");
				server_process_iaaddr_option(option, num);
				break;
			default:
				dPrint(DBUG,"Cannot process the option no = %d", extension.option_code);
				return;
		}

	}
}

/* Generates duid of type 1 */

void generate_duid()
{
	time_t t2,t3;
	struct tm *brk;
	uint32_t remi, i;
	struct ifreq ifhw;
	struct in6_addr link_local_addr;
	struct in6_addr link_local_prefix;

	char addr_char[INET6_ADDRSTRLEN];
	int s;
	uint16_t hwtype;

	duid_cur.identifier = 1;	

	brk=(struct tm *)malloc( sizeof(struct tm));
	if( brk == NULL){
		dPrint(DBUG, "Error: Allocating memory");
		exit(0);
	}
	brk->tm_sec=0;
	brk->tm_min=0;
	brk->tm_hour=0;
	brk->tm_mday=0;
	brk->tm_mon=0;
	brk->tm_year=100;
	t2=mktime(brk);

	t3=time(NULL);
	i=difftime(t3,t2);
	remi=(uint32_t)drem(i,POW32);
	duid_cur.time_since_2000= remi;


	dPrint(DBUG, "\nTime since 2000 is %d", duid_cur.time_since_2000);

	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
		dPrint(DBUG,"Error opening socket:");	
		exit(0);
	}
	strncpy(ifhw.ifr_name,device, sizeof(ifhw.ifr_name));

/* To get the HW type */

	ioctl(s, SIOCGIFHWADDR, &ifhw);
	hwtype=ifhw.ifr_hwaddr.sa_family;
	duid_cur.hw_type= hwtype;

	if (inet_pton(AF_INET6, "fe80::", &link_local_prefix) != 1) {
		dPrint(DBUG,"Error in Obtaining Linklocal prefix");
		exit(0);
	}

	if (getifaddr(&link_local_addr, device, &link_local_prefix,LINK_LOCAL_PLEN) != 0) {
		dPrint(DBUG,"Getifaddr failed in generate duid");
		exit(0);
	}
	duid_cur.link_local_addr = link_local_addr;

	inet_ntop(AF_INET6, &link_local_addr, addr_char, sizeof(addr_char));
	dPrint(DBUG, "\nDUID Link Localo Addr is %s", addr_char);
	dPrint(DBUG,"DUID Succeessfilly generated with address");
	free(brk);
}


/* This function sends the advertisement to the client as per the
 *	SOLICIT Message received 
 */

void server_send_advt(struct addrinfo *client, struct dhc6_msg *dh6msg)
{
	struct dhc6_msg *dh6Advt;
	int error;
	int len=0;
	struct dhc6_pref_option prefopt;
	struct alloc_address *tempAlloc=NULL;
	struct IAlist *IA=NULL, *IARef=NULL;
	struct dhc6_ia_option iaopt;
	
	char addr_char[INET6_ADDRSTRLEN];

	char adv[BUFSIZ];
	int hlim;

/* it should be able to find the interface from whcih it received the
 *	solicit and   send the advertisement to that only
 */

	dh6Advt =  (struct dhc6_msg *)adv; 
	memset(dh6Advt, 0, sizeof(*dh6Advt));
	dh6Advt->msg_type =  DHC6_ADVERTISE;
	dh6Advt->trans_id=dh6msg->trans_id;

/* Sets the pref option	*/

	server_set_pref(&prefopt);
	memcpy((dh6Advt->dhc6_ext+len), &prefopt, sizeof(struct dhc6_pref_option));
	len += sizeof(struct dhc6_pref_option);

/* Sets the ia iptions */

	server_set_ia_option(&iaopt);
	memcpy((dh6Advt->dhc6_ext+len), &iaopt, sizeof(struct  dhc6_ia_option));
	len += sizeof(struct dhc6_ia_option);

/* for each of the iaaddr option to copies the TEMP_ALLOCATED
 *	Address
 */

	tempAlloc = alloc_addr;
	while(tempAlloc){
		dPrint(DBUG, "\n Allocating address\n");
		if( !IA){
			IA = (struct IAlist *)malloc( sizeof(struct IAlist));
			if(IA == NULL){
				dPrint(DBUG, "Error in allocating memory");
				exit(0);
			}
		}
		else{
			IA->next = (struct IAlist *)malloc( sizeof(struct IAlist));
			if(IA->next == NULL){
				dPrint(DBUG, "Error in allocating memory");
				exit(0);
			}
			IA = IA->next;
		}
		IA->IAaddr.option_code = OPTION_IAADDR;
		IA->IAaddr.option_len = sizeof(struct dhc6_iaaddr_option)-4;
		IA->IAaddr.prefix_len = get_prefix_length();
		IA->IAaddr.addr = tempAlloc->addr;
		IA->IAaddr.status_ia = DHC6_SUCCESS;

		inet_ntop(AF_INET6, &tempAlloc->addr,addr_char, sizeof(addr_char));
		dPrint(DBUG, "Advt offering address %s", addr_char);

		IA->next = NULL;
		if( IARef == NULL)
			IARef = IA;
		tempAlloc = tempAlloc->next;
	}
	
	free(alloc_addr);
	alloc_addr = NULL;
	IA = IARef;

	 while( IA != NULL){
		 memcpy((dh6Advt->dhc6_ext)+len, &IA->IAaddr, 
				sizeof(struct dhc6_iaaddr_option));

		 len +=  sizeof(struct dhc6_iaaddr_option);
		 IA= IA->next;
	 }


	hlim=0;
	if (setsockopt(Outsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hlim,sizeof(hlim)) < 0) {
		dPrint(DBUG,"setsockopt(IPV6_MULTICAST_HOPS)");
		exit(0);
	}
	error =sendto( Outsock, adv, len+3, 0, client->ai_addr, client->ai_addrlen);
	if(error != len+3){
		dPrint(DBUG,"error transmitting in send advt");
		exit(0);
	} 
	dPrint(DBUG, "Advertisement sent\n");
}	


/* This function processes the solicit message received from the client and
 *	Initiates sending advertisements to the client
 */

void server_process_sol(struct addrinfo *client, struct dhc6_msg *dh6msg)
{
	STATE = SOLICITING;

	server_process_option(dh6msg->dhc6_ext);

/* Some mechanisms like client denial can go here
 * right now it simply send advertise to everything
 */

	server_send_advt(client, dh6msg);	
	
}
 
void server_process_reb(struct addrinfo *client, struct dhc6_msg *dh6Req)
{
	char rep[BUFSIZ];
	struct dhc6_msg *dh6_reply;
	int error;
	int hlim;
	int len = 0;
	struct IAlist *IA;
	struct dhc6_ia_option iaopt;
 
	dPrint(DBUG,"\n Sent for processing");
	server_process_option(dh6Req->dhc6_ext);

	dh6_reply = (struct dhc6_msg *)rep;
	memset(dh6_reply, 0, sizeof(*dh6_reply));
	dh6_reply->msg_type =  DHC6_REPLY;
	dh6_reply->trans_id = dh6Req->trans_id;

	server_set_ia_option(&iaopt);
	memcpy((dh6_reply->dhc6_ext+len), &iaopt, sizeof(struct  dhc6_ia_option));
	len += sizeof(struct dhc6_ia_option);

	IA = (struct IAlist *)malloc( sizeof(struct IAlist));
	if( IA == NULL){
		dPrint(DBUG, "Error: Allocating memory");
		exit(0);
	}
	IA->IAaddr.option_code = OPTION_IAADDR;
	IA->IAaddr.option_len = sizeof(struct dhc6_iaaddr_option)-4;
	IA->IAaddr.prefix_len = get_prefix_length();

	IA->next =(struct IAlist *)malloc( sizeof(struct IAlist));
	if( IA->next == NULL){
		dPrint(DBUG, "Error: Allocating memory");
		exit(0);
	}
	IA->next->IAaddr.option_code = OPTION_IAADDR;
	IA->next->IAaddr.option_len = sizeof(struct dhc6_iaaddr_option)-4;
	IA->next->IAaddr.prefix_len = 48;
	IA->next->next = NULL;

	 while( IA != NULL){
		 memcpy((dh6_reply->dhc6_ext)+len, &IA->IAaddr, 
				sizeof(struct dhc6_iaaddr_option));
		 len +=  sizeof(struct dhc6_iaaddr_option);
		 IA= IA->next;
	 }

	hlim=0;
	if (setsockopt(Outsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hlim,
			sizeof(hlim)) < 0) {
		dPrint(DBUG,"setsockopt(IPV6_MULTICAST_HOPS)");
		exit(0);
	}
 
	error =sendto( Outsock, rep, len+3, 0, client->ai_addr, client->ai_addrlen);
	if(error != len+3){
		dPrint(DBUG,"error transmitting in process reb");
		exit(0);
	}
	dPrint(DBUG, "\nReply sent");
	free(IA);
	return;
 
}
 

/* Processes delcline message */

void server_process_dec(struct addrinfo *client, struct dhc6_msg *dh6Req)
{
 
	char rep[BUFSIZ];
	struct dhc6_msg *dh6_reply;
	int error;
	int hlim;

	struct dhc6_status_code_option statuscode;
	int len = 0;
 
	dPrint(DBUG,"\n Sent for processing");

	STATE = DECLINING;
	server_process_option(dh6Req->dhc6_ext);
	STATE =  DOLISTEN;
 
	dh6_reply = (struct dhc6_msg *)rep;
	memset(dh6_reply, 0, sizeof(*dh6_reply));
	dh6_reply->msg_type =  DHC6_REPLY;
	dh6_reply->trans_id = dh6Req->trans_id;

	if(CLIENT_STAT.IA_RELEASE == 1){
		dPrint(DBUG, "Status code is SUCCESS");
		server_set_status_code(&statuscode);
		memcpy(dh6_reply->dhc6_ext+len, &statuscode, 
			(sizeof(struct dhc6_status_code_option)));
		len += sizeof(struct dhc6_status_code_option);
	}	
	else
		return;

	hlim=0;
	if (setsockopt(Outsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hlim,sizeof(hlim)) < 0) {
		dPrint(DBUG,"setsockopt(IPV6_MULTICAST_HOPS)");
		exit(0);
	}
 
	error =sendto( Outsock, rep, len+3, 0, client->ai_addr, client->ai_addrlen);

	
	if(error != len+3){
		dPrint(DBUG,"error transmitting in process dec");
		exit(0);
	}
	dPrint(DBUG, "\nReply sent");
	return;
 
}
 

/* Processes renew messagei */

void server_process_ren(struct addrinfo *client, struct dhc6_msg *dh6Req)
{
 
	char rep[BUFSIZ];
	struct dhc6_msg *dh6_reply;
	int error;
	int hlim;
	int len = 0;
	struct IAlist *IA;
	struct dhc6_ia_option iaopt;

	STATE = RENEWING;

	dPrint(DBUG,"\n Sent for processing");
	server_process_option(dh6Req->dhc6_ext);
 
	dh6_reply = (struct dhc6_msg *)rep;
	memset(dh6_reply, 0, sizeof(*dh6_reply));
	dh6_reply->msg_type =  DHC6_REPLY;
	dh6_reply->trans_id = dh6Req->trans_id;


	server_set_ia_option(&iaopt);
	memcpy((dh6_reply->dhc6_ext+len), &iaopt, sizeof(struct  dhc6_ia_option));
	len += sizeof(struct dhc6_ia_option);

	IA = (struct IAlist *)malloc( sizeof(struct IAlist));
	if( IA == NULL){
		dPrint(DBUG, "Error: Allocating memory");
		exit(0);
	}
	IA->IAaddr.option_code = OPTION_IAADDR;
	IA->IAaddr.option_len = sizeof(struct dhc6_iaaddr_option)-4;
	IA->IAaddr.prefix_len = get_prefix_length();
	IA->next =(struct IAlist *)malloc( sizeof(struct IAlist));
	if(IA->next == NULL){
		dPrint(DBUG, "Error: Allocating memory");
		exit(0);
	}
	IA->next->IAaddr.option_code = OPTION_IAADDR;
	IA->next->IAaddr.option_len = sizeof(struct dhc6_iaaddr_option)-4;
	IA->next->IAaddr.prefix_len = 48;
	IA->next->next = NULL;

	 while( IA != NULL){
		 memcpy((dh6_reply->dhc6_ext)+len, &IA->IAaddr, 
			sizeof(struct dhc6_iaaddr_option));
		 len +=  sizeof(struct dhc6_iaaddr_option);
		 IA= IA->next;
	 }

	hlim=0;
	if (setsockopt(Outsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hlim,sizeof(hlim)) < 0) {
		dPrint(DBUG,"setsockopt(IPV6_MULTICAST_HOPS)");
		exit(0);
	}
 
	error =sendto( Outsock, rep, len+3, 0, client->ai_addr, client->ai_addrlen);
	if(error != len+3){
		dPrint(DBUG,"error transmitting in process ren");
		exit(0);
	}
	dPrint(DBUG, "\nReply sent");
	free(IA);
	return;
 
}


/* Processes the release message */

void server_process_rel(struct addrinfo *client, struct dhc6_msg *dh6Req)
{
 
	char rep[BUFSIZ];
	struct dhc6_msg *dh6_reply;
	int error;
	int hlim;
	int len = 0;

	struct dhc6_status_code_option statuscode;

 
	dPrint(DBUG,"\n Sent for processing");
	
	STATE = RELEASING;
	server_process_option(dh6Req->dhc6_ext);
	STATE  = DOLISTEN;

	dh6_reply = (struct dhc6_msg *)rep;
	memset(dh6_reply, 0, sizeof(*dh6_reply));
	dh6_reply->msg_type =  DHC6_REPLY;
	dh6_reply->trans_id = dh6Req->trans_id;

	if(CLIENT_STAT.IA_RELEASE == 1){
		dPrint(DBUG,"\nStatus code is SUCCESS");
		server_set_status_code(&statuscode);
		memcpy(dh6_reply->dhc6_ext+len, &statuscode, 
			sizeof(struct dhc6_status_code_option));
		len += sizeof(struct dhc6_status_code_option);
	}	
	else
		return;

	hlim=0;
	if (setsockopt(Outsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hlim,sizeof(hlim)) < 0) {
		dPrint(DBUG,"setsockopt(IPV6_MULTICAST_HOPS)");
		exit(0);
	}
 
	error = sendto( Outsock, rep, len+3, 0, client->ai_addr, client->ai_addrlen);

	
	if(error != len+3){
		dPrint(DBUG,"error transmitting in process rel");
		exit(0);
	}
	dPrint(DBUG, "\nReply sent");

	memset(&CLIENT_STAT, 0, sizeof(CLIENT_STAT));
	return;
 
}


/* Processes the REQUEST message from the client and send REPLY
 *	message accordingly
 */

void server_process_req(struct addrinfo *client, struct dhc6_msg *dh6Req)
{
	
	char rep[BUFSIZ];
	struct dhc6_msg *dh6_reply;
	int error;
	int hlim;
	struct alloc_address *tempAlloc=NULL;

	struct dhc6_pref_option prefopt;
	struct dhc6_ia_option iaopt;
	char addr_char[INET6_ADDRSTRLEN];
	

	int len = 0;
	struct IAlist *IA=NULL, *IARef=NULL;

	dPrint(DBUG,"\nRequest sent for processing");
	STATE = REQUESTING;
	free(alloc_addr);
	alloc_addr = NULL;
	server_process_option(dh6Req->dhc6_ext);	
	STATE = DOLISTEN;

	dh6_reply = (struct dhc6_msg *)rep;
	memset(dh6_reply, 0, sizeof(*dh6_reply));

	server_set_pref(&prefopt);
	memcpy((dh6_reply->dhc6_ext+len), &prefopt, sizeof(struct dhc6_pref_option));
	len += sizeof(struct dhc6_pref_option);

	server_set_ia_option(&iaopt);
	memcpy((dh6_reply->dhc6_ext+len), &iaopt, sizeof(struct  dhc6_ia_option));
	len += sizeof(struct dhc6_ia_option);

	tempAlloc = alloc_addr;
	while(tempAlloc){
		dPrint(DBUG, "\n Allocating address");
		if( !IA){
			IA = (struct IAlist *)malloc( sizeof(struct IAlist));
			if( IA == NULL){
				dPrint(DBUG, "Error: Allocating memory");
				exit(0);
			}
		}
		else{
			IA->next = (struct IAlist *)malloc( sizeof(struct IAlist));
			if(IA->next == NULL){
				dPrint(DBUG, "Error in allocating memory");
				exit(0);
			}
			IA = IA->next;
		}
		IA->IAaddr.option_code = OPTION_IAADDR;
		IA->IAaddr.option_len = sizeof(struct dhc6_iaaddr_option)-4;
		IA->IAaddr.prefix_len = get_prefix_length();
		IA->IAaddr.addr = tempAlloc->addr;

		inet_ntop(AF_INET6, &tempAlloc->addr,addr_char, sizeof(addr_char));
		dPrint(DBUG, "  request offering address %s", addr_char);

		IA->next = NULL;
		if( IARef == NULL)
			IARef = IA;
		tempAlloc = tempAlloc->next;
	}

	IA = IARef;

	 while( IA != NULL){
		 memcpy((dh6_reply->dhc6_ext)+len, &IA->IAaddr, sizeof(struct dhc6_iaaddr_option));
			
		 len +=  sizeof(struct dhc6_iaaddr_option);
		 IA= IA->next;
	 }
	
	dh6_reply->msg_type =  DHC6_REPLY;
	dh6_reply->trans_id = dh6Req->trans_id;

	hlim=0;

	if (setsockopt(Outsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hlim,sizeof(hlim)) < 0) {
		dPrint(DBUG,"setsockopt(IPV6_MULTICAST_HOPS)");
		exit(0);
	}

	error =sendto( Outsock, rep, len+3, 0, client->ai_addr, client->ai_addrlen);
	if(error != len+3){
		dPrint(DBUG," error transmitting in process req");
		exit(0);
	}
	dPrint(DBUG, "\nReply sent");
	free(alloc_addr);
	alloc_addr=NULL;
	free(tempAlloc);
	return;	
	
}


/* This function is to proess the incoming packets, reads the packet type
 *	and passes according to the pakcet type
 */

void server_process()
{

	ssize_t msgLen;
	char buf[BUFSIZ];
	struct sockaddr_storage from;
	socklen_t fromlen = sizeof(from);
	struct dhc6_msg *dh6msg;
	char addr_char[NI_MAXHOST], port_char[NI_MAXSERV];
	struct addrinfo hints, *res;
	
	memset(buf, 0, sizeof(buf));
	
	if( (msgLen = recvfrom( Insock, buf, sizeof(buf), 0,
			(struct sockaddr *) &from,&fromlen)) < 0){
		dPrint(DBUG,"\n Error receving packet");
		exit(0);
	}
	if (msgLen < 3){
		dPrint(DBUG,"\n Error size less then struct");
		return;
	}
	
	dh6msg = (struct dhc6_msg *)buf;

	getnameinfo((struct sockaddr *)&from, fromlen,
		    addr_char, sizeof(addr_char), port_char, sizeof(port_char),
		    NI_NUMERICHOST|NI_NUMERICSERV);
	dPrint(DBUG, "Packet from source address is %s, port %s", addr_char, port_char);

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_INET6;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_flags = AI_NUMERICHOST;
	if (getaddrinfo(addr_char, DHC6_CLIENT_PORT,
			&hints, &res)) {
		dPrint(DBUG, "\n getaddrinfo() failed; %s port %s", addr_char, DHC6_CLIENT_PORT);
		exit(0);
	}
	
	switch(dh6msg->msg_type){
	case DHC6_SOLICIT:
		dPrint(DBUG, "Solicit received");
		server_process_sol(res, dh6msg);
		break;
	case DHC6_REQUEST:
		dPrint(DBUG,"request received");
		server_process_req(res, dh6msg);
		break;

	case DHC6_RELEASE:
		dPrint(DBUG,"\nRELEASE received");
		server_process_rel(res, dh6msg);
		break;
	case DHC6_RENEW:
		dPrint(DBUG,"\nRENEW received");
		server_process_ren(res, dh6msg);
		break;
	case DHC6_REBIND:
		dPrint(DBUG, "\nREBIND received");
		server_process_reb(res, dh6msg);
		break;
	case DHC6_DECLINE:
		dPrint(DBUG, "\n DECLINE received");
		server_process_dec(res, dh6msg);
		break;
	
	default:
		dPrint(DBUG, "\nMessage ID is %d\n", dh6msg->msg_type);
		dPrint(DBUG, "Un recognised message format");
		break;
	}
	freeaddrinfo(res);
	return;

}
	

/* This function is to receive all the packet from the inbound traffic and sends it for
 *	further processing (server6process());
 */

void server_recv_loop()
{
	int retVal;
	fd_set r;
	
	while(1){
		FD_ZERO(&r);
		FD_SET(Insock, &r);
		dPrint(DBUG,"Selecting the packets\n ");
	
		retVal = select(Insock + 1, &r, NULL, NULL, NULL);
	
		if(sigStatus){
			dPrint(DBUG,"\n Signal here ");
			server_reconfig();		
			sigStatus = 0;
			continue;	
		}
	
		switch(retVal){
			case -1:
			case 0:
				dPrint(DBUG,"Error receiving packet");
				exit(0);
			default:
				dPrint(DBUG,"Out for processing");
				break;
		}
/* If set, send it for processing*/
		if( FD_ISSET(Insock,&r)){
			server_process();
		}
	}
}


/* This function performs basic initiation of the server, client opening sockets
 * for inbound and out bound traffic, and setting options for the socket
 */

void server_init()
{
	int error;
	int on = 1;
	struct addrinfo hints;
	struct addrinfo *res, *res2;
	struct ipv6_mreq mreq6; 
	int intFaceIndex; 
	struct in6_addr from_addr, to_addr;

/* Time to open sockets for in bound and outbound traffic */
	if( (intFaceIndex = if_nametoindex(device)) < 0){
		dPrint(DBUG,"Server: Error in finding interface index\n");
		exit(0);
	}
	
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_INET6;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_protocol = IPPROTO_UDP;
	hints.ai_flags = AI_PASSIVE;

/* Open a socket for inbound traffic */
	if( (error = getaddrinfo(NULL,  DHC6_AGENT_PORT, &hints, &res)) ){
		dPrint(DBUG,"Server: Error opening server port :");
		exit(0);
	}
	
	if( (Insock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0){
		dPrint(DBUG,"Server: Error opening inbound socket");
		exit(0);
	}	
	
/* Set the options  to receivce ipv6 traffic */
	if (setsockopt(Insock, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) {
		dPrint(DBUG,"Server: Error setting up socket option IPV6_PKTINFO ");
		exit(0);
	}
	if (setsockopt(Insock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
		dPrint(DBUG,"Server: Error setting socket options SO_REUSEADDR");
		exit(0);
	}
 
	if (bind(Insock, res->ai_addr, res->ai_addrlen) < 0) {
		dPrint(DBUG,"Server: Error binding in bound socket");
		exit(0);
	}
	freeaddrinfo(res);
	hints.ai_flags = 0;
	
	if((error = getaddrinfo(DHC6_ALLAGENT_ADDR, DHC6_AGENT_PORT, &hints, &res2))){
		dPrint(DBUG,"Server: Error all agent addrinfo");
		exit(0);
	}
	memset(&mreq6, 0, sizeof(mreq6));
	mreq6.ipv6mr_interface = intFaceIndex;
	memcpy(&mreq6.ipv6mr_multiaddr, &((struct sockaddr_in6 *)res2->ai_addr)->sin6_addr,
		sizeof(mreq6.ipv6mr_multiaddr));
/* Add to the all agent multicast address */
	if (setsockopt(Insock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6))) {
		dPrint(DBUG,"Server: Error joining ipv6 group");
		exit(0);
	}
	freeaddrinfo(res2);
 
	hints.ai_flags = 0;
/* Open a socket for inbound traffic */
	if((error = getaddrinfo(NULL, DHC6_CLIENT_PORT, &hints, &res))) {;
		dPrint(DBUG,"Erro get addrinfo for client port");
		exit(0);
	}
	
	if( (Outsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
		dPrint(DBUG,"Error creating ooutbound socket\nVerify the interface name");
		exit(0);
	}
/* set options for multicast transmission */ 
	if (setsockopt(Outsock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &intFaceIndex, sizeof(intFaceIndex)) < 0) {
		dPrint(DBUG,"Error setting outbound socket");
		exit(0);
	}
 
	freeaddrinfo(res);
	get_range_addr(&from_addr, &to_addr);
	NUMADDR = get_number(from_addr, to_addr);

	if(NUMADDR < 1){
		dPrint(DBUG, "Error in Address range Specification");
		exit(0);
	}
	
	initialise_addr_list(from_addr);
	server_load_lease_base();

	PREF_VAL = get_pref_val();
	LIFETIME = get_life_time();

	server_print_config_value();

	generate_duid();
	dPrint(DBUG,"Server Initialised Completed");
	
	if(DAEMON){
		int dmon;
		dmon = daemon(1,0);
		if(dmon ==-1){
			dPrint(DBUG, "\nUnable to run as daemon\n");
			exit(0);
		}
		dPrint(DBUG, "\n Running as daemon");
	}
}


int main(int argc, char **argv)
{
	int caseval;

/* Parameter Parsing goes here */

	if(argc <= 1){
		usage();
		exit(0);
	}


	while((caseval = getopt(argc, argv, "vDdI:n:")) != EOF) {
		switch(caseval){

			case 'd':
				dPrint(0, "Server:Debug level set");
				DBUG = 0;
				break;
			case 'I':

				dPrint(0, "\nServer: Interface = %s", optarg);
				device = optarg;
				break;
			case 'D':
				dPrint(0, "Server: Running as daemon");
				DAEMON = 1;
				break;
			case 'v':
				dPrint(0, "%s", version);
				exit(0);

			default :
				usage();
				exit(0);
		}
	}

	if (optind < argc) {
		fprintf(stderr, "\n Unknown option(s) ");
		while (optind < argc)
		   fprintf (stderr, "%s ", argv[optind++]);
		usage();
		exit(0);
	}
	
		
	server_init();

/*	The signal SIGUSR1 call the the signalhandler 
 *	signalHandler sets the status as 1 and calls the handler
 */
	signal(SIGUSR1, signal_handler);

/* server goes to a loop to get the packets from the client */
	server_recv_loop();
	exit(0);
}
