/* Anonymous Town Hall Encrypting Network System */
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>

#include <signal.h>
#include <sys/signal.h>

#include <rand.h>

#include "libpgp5.h"
#include "athens.h"

void bcastpks(void);
void newpad(void);
void decpad(void);

/*--------------------------------------------------*/
/* PK ID of next host in ring (to send packet to) */
char chkfile[50];
unsigned char auxpad[DSIZE], scribpad[DSIZE];
unsigned char pathbuf[500 * MAXRING];
unsigned int pblen;
unsigned char msg[MAXUDP];
int msglen;
int sockfd, cl;
struct sockaddr_in remote_addr;
FILE *keyf;
char *av0;

/*--------------------------------------------------*/
/* signal handling */
/* LINUX may apply elsewhere */
#ifdef LINUX
__sighandler_t sighandle(int signum, __sighandler_t h)
#else
void *sighandle(int signum)     /*, __sighandler_t h) */
#endif
{
  unlink(chkfile);
  exit(0);
  return SIG_IGN;
}

/*--------------------------------------------------*/
void main(int argc, char *argv[])
{
  int n;
  int keypipe[2];
  struct ip_mreq mreq;
  unsigned char nc;

  setenv("PGPPATH", ".", 1);
  av0 = argv[0];
  signal(SIGTERM, (void *) sighandle);

  /* Setup communications */
  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  nc = 255;
  setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &nc, sizeof(nc));
  nc = 1;
  setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &nc, sizeof(nc));
  n = 1;
  setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
  cl = sizeof(remote_addr);
  memset(&remote_addr, 0, cl);
  remote_addr.sin_family = AF_INET;
  remote_addr.sin_port = htons(ATHENSPORT);
  remote_addr.sin_addr.s_addr = INADDR_ANY;
  bind(sockfd, SADDR & remote_addr, cl);
  remote_addr.sin_addr.s_addr = inet_addr(ATHENSIP);

  /* form a pipe to the key manager and fork it */
  pipe(keypipe);
  if (!(fork())) {
    dup2(keypipe[0], 0);
    close(keypipe[0]);
    close(keypipe[1]);
    execl("./keymgmt", "ATHENS-KEYMGR", NULL);
  }
  close(keypipe[0]);

  keyf = fdopen(keypipe[1], "wb");
  /* fork the PK gen/broadcast processes */
  if (!(fork()))
    bcastpks();
  /* fork the initial pad generators */
  strcpy(av0, "ATHENS-KEYIPD       ");
  for (n = 0; n < NPADS; n++)
    if (!fork())
      newpad();                 /* gen new pad in child */
  /* (parent) - message handler */
  strcpy(av0, "ATHENS-LISTEN       ");
  mreq.imr_multiaddr.s_addr = inet_addr(ATHENSIP);
  mreq.imr_interface.s_addr = 0;
  setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
  for (;;) {
    if (0 > (msglen = recvfrom(sockfd, msg, MAXUDP, 0, NULL, NULL)))
      exit(-3);
    if (fork())                 /* let child process the next message */
      break;
  }
  strcpy(av0, "ATHENS-MSGDEC       ");
  decpad();
}
