#include	"trust.h"
#include	"shm.h"

void	exit (int status);

void	MainLoop();
void	CloseSocket();
void	CloseChild();

void main(argc, argv)
int	argc;
char	*argv[];
{
	FILE	*PidFile;

	Soc = 0;
	Acc = 0;
	TrustDB_in = 0;
	TrustDB_out = 0;
	cmdmode = 0;
	cmdin	= 0;
	AuthPort = htons(29000);
	dbInPort = htons(29001);
	dbOutPort = htons(29002);
	logfile = fopen (LOGFILE, "a");
	now = time(NULL);
	fprintf (logfile, "%24.24s Trust start\n", ctime(&now));
	fclose(logfile);
        PidFile = fopen ("/var/run/dstrust.pid","w");
        if (PidFile == NULL)
        {
		logfile = fopen (LOGFILE, "a");
		now = time(NULL);
                fprintf (logfile, "%24.24s Must run on supper user\n", ctime(&now));
		fclose (logfile);
                exit(-1);
        }
        fprintf (PidFile, "%d\n",(int)getpid());
        fclose (PidFile);

	config();

        if (cmdmode == 0)
        {
                cmdin = 0;
        }
        else
        {
                cmdin = open ("/tmp/dstrust-cmdin", O_NONBLOCK | O_RDONLY);
                if (cmdin < 0)
                {
			logfile = fopen(LOGFILE, "a");
			now = time(NULL);
                        fprintf (logfile, "%24.24s ERROR FIFO file not open /tmp/dstrust-cmdin\n");
			fclose (logfile);
                        cmdin = 0;
                }
        }

	InitSocket();
	InitSignal();
	MainLoop();
}

int InitSocket(void)
{
	struct	sockaddr_in	me;
        struct  hostent *hp;
	int	opt;

	if ((Soc=socket(AF_INET,SOCK_STREAM,0)) < 0){
		perror("socket");
		exit(-1);
	}
	opt=1;
	if (setsockopt(Soc,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int)) != 0){
		perror("setsockopt");
		exit(-1);
	}
        memset((char *)&me,0,sizeof(me));
        me.sin_family = AF_INET;
        me.sin_port = AuthPort;
        if (bind(Soc,(struct sockaddr *)&me,sizeof(me)) == -1){
                perror("bind");
                exit(-1);
        }
        if ((TrustDB_in = socket(AF_INET,SOCK_DGRAM,0)) < 0){
                perror("socket:TrustDB_in");
                exit(-1);
        }

	memset((char *)&db_in,0,sizeof(db_in));
	db_in.sin_family=AF_INET;
	db_in.sin_port=dbInPort;
	if (bind(TrustDB_in,(struct sockaddr *)&db_in, sizeof(db_in)) == -1){
		perror("bind:db");
		exit(-1);
	}


        shm_id = shmget (IPC_PRIVATE, sizeof(struct shm_form_t) * MAX_SHM ,
				IPC_CREAT | 0660);
	if (shm_id == -1)
        {
                perror("shmget");
                exit(-1);
        }

	shm_msg = shmat (shm_id, NULL, 0);
	if (shm_msg == (void *)-1)
	{
		perror("shmat");
		shmctl (shm_id, IPC_RMID, NULL);
		exit(-1);
	}

        hp = gethostbyname(TrustDbDomainName);
        memcpy (&dbIP, hp->h_addr_list[0], hp->h_length);

	return(0);
}

void CloseSocket()
{
	if(Soc != 0){
		close(Soc);
		Soc = 0;
	}
	if(Acc != 0){
		close(Acc);
		Acc = 0;
	}
        if(TrustDB_in != 0){
                close(TrustDB_in);
                TrustDB_in = 0;
        }
        if(TrustDB_out != 0){
                close(TrustDB_out);
                TrustDB_out = 0;
        }

        shmdt (shm_msg);
        shmctl (shm_id, IPC_RMID, NULL);

	logfile = fopen (LOGFILE, "a");
	now = time(NULL);
	fprintf (logfile, "%24.24s Trust end\n", ctime(&now));
	fclose (logfile);

	exit(0);
}

void CloseChild()
{
	int	pid;

	pid=wait(0);
	signal(SIGCLD,CloseChild);
}

int InitSignal()
{
	signal(SIGINT,CloseSocket);
	signal(SIGTERM,CloseSocket);
	signal(SIGCLD,CloseChild);

	return(0);
}

void MainLoop(void)
{
	struct sockaddr_in	from;
	int	n;
	int	len,width, pid;
	fd_set	readOk,Mask;
	struct	timeval	timeout;
	char	client[64];

	for (n = 0 ; n < MAX_SHM ; n++)
	{
		shm_msg->shmem[n].mem.type = 0;
		shm_msg->shmem[n].mem.protocol = 0;	/* default ICOM (G1 & G2) */
		shm_msg->shmem[n].e_time.tv_sec = 0;
		shm_msg->shmem[n].e_time.tv_usec = 0;
		memset (shm_msg->shmem[n].mem.srcCall, 0x20, 8); 
		memset (shm_msg->shmem[n].mem.dstCall, 0x20, 8);
	}

	FD_ZERO(&Mask);
	FD_SET(Soc, &Mask);
	FD_SET(TrustDB_in, &Mask);
	FD_SET(cmdin, &Mask);
	width = Soc;
	if (width < cmdin) width = cmdin;
	if (width < TrustDB_in) width = TrustDB_in;
	width += 1;

	listen(Soc,SOMAXCONN);
	while(1){
		readOk = Mask;
		timeout.tv_sec = 0;
		timeout.tv_usec = 500000;
		switch (select(width, (fd_set *)&readOk, NULL, NULL, &timeout)){
			case	-1:
				perror("select");
				break;
			case	0:
				noRoute();
				break;
			default:
				if(FD_ISSET(Soc,&readOk)){
					len=sizeof(from);
					Acc=accept(Soc, (struct sockaddr *)&from,&len);
					if(Acc<0){
						if(errno==EINTR){
							continue;
						}
						perror("accept");
						continue;
					}
					sprintf(client,"%s", inet_ntoa (from.sin_addr));
					RepeaterIP = from.sin_addr;
					if((pid=fork())==0){
						close(Soc);
						Soc=0;
						Repeater();
						exit(0);
					}
					setpgrp(pid, getpid());
					close(Acc);
					Acc=0;
				}
				if (FD_ISSET(TrustDB_in, &readOk))
				{
					insEntry();
				}
				if(FD_ISSET(cmdin,&readOk)){
					KeyIn();
				}
				break;
		}
	}
}

