/*daemon handler */
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <glib.h>

#include "dae.h"

#define default_timeout 6

char version[] = "$Id: gxdhd.c,v 1.13 1999/09/06 15:19:22 remlali Exp $"; /*usefull to 'strings' the binary*/

typedef struct _dae_stat{
	char name[20];		/*name of daemon*/
	char *addr;		/*address of daemon, IP addr, or a pathname+filename*/
	int state;		/*bit 0 (1=admin-Started,0=Stoped) bit 1 (1=send,0=wait_for_hello)*/
	int timeout;		/*timeout in seconds waiting for a daemon status answer*/
	int info_died;		/*hold how many time this daemon has lost contact/died*/
}daestat;

daestat dstat[] ={
"trapd",0, 3, default_timeout, 0,
"corrd",0, 3, default_timeout,0,
"evdpysrvd",0, 3, default_timeout,0,
"",0,0,0,0
/*"pdud",0, 3, default_timeout, ADD WHEN PDUD SUPPORTS KILL*/ 
}; 

aclist *trapfilter;
int masocket;
pid_t daemonp;
glb_enviroment enviroment;
char foo[40];
FILE *fpgxdhd;
char buffer[400];

void quit_call()
{
	logstr(fpgxdhd,"Killing all registered daemons.\n");
	sendsocket(masocket, enviroment.corrd, "kill ");
	sendsocket(masocket, enviroment.trapd, "kill ");
	sendsocket(masocket, enviroment.evdpysrvd, "kill ");
	sendsocket(masocket, enviroment.pdud, "kill ");

	close(masocket);
	unlink(enviroment.gxdhd);
	logstr(fpgxdhd,"gxdhd stoped.\n");
	fclose(fpgxdhd);
	_exit(0);
}
int launch_child(char *daemon){
pid_t pid;

	sprintf(buffer,"%s/%s",enviroment.base,daemon);
	if(!(pid = fork())){
		if(!(fork())) execv(buffer,0);
		_exit(0);
	}
	if(pid < 0 || waitpid(pid,NULL,0) < 0) return 1;
	return 0;
}

daestat *d_lookup(char *name){ /* search in daemon struct, using daemon name as input */
int l=0;

	while(1){
		if(!strlen(dstat[l].name)) return 0;
		if(!strcmp(dstat[l].name, name)) return &dstat[l];
		l++;
	}
}

int main(int argc, char **argv)
{   
char pipestring[100];
int l=0,i,j;
int nbytes;
char foo[40];
char foo2[40];
daestat *ds;

/*daemonize*/
  if(fork() != 0) _exit(0);
  if(setsid() == -1) _exit(0);
  if(fork() != 0) _exit(0);
  umask(777);
  if(chdir("/")<0) _exit(0);
  for(i=sysconf(_SC_OPEN_MAX),j=0;j<i;) close(j++);
  open("/dev/null",O_RDWR); dup(0); dup(0);

/***********/
  load_enviroment();

  fpgxdhd = logopen("gxdhd.log");
  dstat[0].addr = enviroment.trapd;
  dstat[1].addr = enviroment.corrd;
  dstat[2].addr = enviroment.evdpysrvd;
  dstat[3].addr = enviroment.pdud;

  unlink(enviroment.gxdhd);
  unlink(enviroment.corrd);
  unlink(enviroment.trapd);
  unlink(enviroment.evdpysrvd);
  unlink(enviroment.pdud);
  masocket = createsocket(enviroment.gxdhd,1);
  logstr(fpgxdhd,"Starting all daemons\n");
  launch_child("pdud");
  launch_child("trapd");
  launch_child("corrd");
  launch_child("evdpysrvd");

start:
  sleep(2);
  pipestring[0] = 0;
  nbytes = recv(masocket,pipestring,100,0);

  if(!strncmp(pipestring,"kill",4)){
    quit_call();
  }
  else if(!strncmp(pipestring,"status ",7)){			/*from gxstatus asking status of a daemon*/
    wordcpy(foo2, pipestring, 2);				/*get reply address*/
    pipestring[0] = 0;
    for(l=0;strlen(dstat[l].name);l++){
      sprintf(foo,"\n%s: ", dstat[l].name);
      strcat(pipestring,foo);
      if(dstat[l].state & 1) strcat(pipestring,"Started, ");
      else strcat(pipestring,"Stoped, ");
      sprintf(foo,"died %d times.", dstat[l].info_died);
      strcat(pipestring,foo);
    }
    sendsocket(masocket, foo2, pipestring);			/*send daemon status*/
  }

  else if(!strncmp(pipestring,"stop ",5)){			/*from gxstatus asking to stop a daemon*/
    wordcpy(foo,pipestring,2);					/*get daemon name*/
    ds = d_lookup(foo);						/*fetch info about daemon*/
    sprintf(foo2,"Stoping daemon: %s\n",foo);
    logstr(fpgxdhd,foo2);
    sendsocket(masocket, ds->addr, "kill ");			/*send kill signal*/
    ds->state = 0;						/*set daemon as state stoped ( clear bit 0 )*/
    goto start;
  }
  else if(!strncmp(pipestring,"start ",6)){			/*from gxstatus asking to start a daemon*/
    wordcpy(foo,pipestring,2);					/*get daemon name	*/
    ds = d_lookup(foo);						/*fetch info about daemon*/
    unlink(ds->addr);						/*remove old socket*/
    sprintf(foo2,"Starting daemon: %s\n", ds->name);
    logstr(fpgxdhd,foo2);
    launch_child(ds->name);
    ds->timeout = default_timeout;
    ds->state = 3;						/*set daemon in state send_hello and started*/
    goto start;							/*a must! else daemon dont have time to start and reply on hello*/
  }
  else if(!strncmp(pipestring,"reload",6)){			/*from gxstatus asking a daemon to reload configuration*/
    wordcpy(foo,pipestring,2);					/*get daemon name*/
    ds = d_lookup(foo);						/*fetch info about daemon*/
    sprintf(foo2,"Reloading daemon: %s\n",foo);
    logstr(fpgxdhd,foo2);
    sendsocket(masocket, ds->addr, "reload");
    goto start;
  }
  else if(!strncmp(pipestring,"daemon ",7)){			/*answer from a daemon, that had previously received a status query*/
    wordcpy(foo,pipestring,2);					/*get daemon name	*/
    ds = d_lookup(foo);						/*fetch info about daemon*/
    ds->timeout = default_timeout;				/*reset timeout*/
    ds->state |= 2;						/*set daemon in send_hello state*/
  }
  for(l=0;strlen(dstat[l].name);l++){				/*loop through and send hello queries*/
    if(!strlen(dstat[l].name)) break;
    if((dstat[l].state & 1) && (dstat[l].state & 2)){
      sendsocket(masocket, dstat[l].addr, "status");		/*send hello*/
      dstat[l].state &= 1;					/*set in dont send hello state (clear bit 1, leave bit 0 alone)*/
    }
    else if(dstat[l].state & 1){				/*if daemon is in started state, and wait_for_hello*/
      dstat[l].timeout--;
      if(!dstat[l].timeout){					/*daemon has probably died*/
        unlink(dstat[l].addr);					/*remove old socket*/
        sprintf(foo2,"Deamon has died, launching: %s\n",dstat[l].name);
        logstr(fpgxdhd,foo2);
        dstat[l].info_died++;
        launch_child(dstat[l].name);				/*reinit daemon*/
        dstat[l].timeout = default_timeout;
        dstat[l].state = 3;					/*set daemon in started+send_hello state*/
      }
    }
  }	
  goto start;
}
