/********************************************************
 * server.c
 *
 * Some ad hoc tools for setting up a server
 * (uses an internet domain, datagram socket)
 *
 * Sixth Annual DIMACS Implementation Challenge
 * Author:  Michael Goldwasser (wass@cs.princeton.edu)
 * Created: Jan 16, 1997
 *******************************************************/


#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include "oracle.h"
#include "messages.h"
#include "server.h"




typedef struct SSocket {
  int                 sock;
  struct sockaddr_in  name;

  Oracle*             ora;     /* data struct for handlers */
  int                 quiet;   /* echo messages received? */
} SSocket;






char* ServerReceive(
  char*         msg,
  Oracle*       ora
)
{
  char buf[MAX_MSIZE];
  char code[MAX_CODE+1];
  char arg1[10];
  char arg2[10];
  char* answer;
  char* assoc;
  int  i,j, temp;
  double dtemp;

  /* compare first word versus the protocol */
  sscanf(msg,"%s %s %s",code,arg1,arg2);

  if (strcmp(code,Protocol_NumPoints)==0) {
    temp = InqNumPoints(ora);
    sprintf(buf,"%d",temp);
  } else if (strcmp(code,Protocol_NumQuery)==0) {
    temp = InqNumQuery(ora);
    sprintf(buf,"%d",temp);
  } else if (strcmp(code,Protocol_Dist)==0) {
    dtemp = InqDist(ora,atoi(arg1),atoi(arg2));
    sprintf(buf,"%lf",dtemp);
  } else if (strcmp(code,Protocol_NumFields)==0) {
    temp = InqNumFields(ora,atoi(arg1));
    sprintf(buf,"%d",temp);
  } else if (strcmp(code,Protocol_Field)==0) {
    assoc = InqField(ora,atoi(arg1),atoi(arg2));
    strncpy(buf,assoc,MAX_MSIZE);
    free(assoc);
  } else {
    sprintf(buf,"%s",Protocol_Unknown);
  }


  answer = strdup(buf);

  return(answer);
}




void wait(
  SSocket*   ss
)
{
  char   buf[MAX_MSIZE];
  char*  answer;
  int    recvlen;
  struct sockaddr_in from;
  int    fromlen;


  fromlen = sizeof(from);

  /* infinite loop */
  for(;;) {
    /* show that we are willing to listen */
    recvlen = recvfrom(ss->sock, buf, sizeof(buf), 0,
		       (struct sockaddr *) &from, &fromlen);
    if (recvlen == -1) {
      perror("recvfrom");
      exit(1);
    }
    buf[recvlen]=0;
            
    if (!ss->quiet) {
      printf("Server recv msg: %s\n",buf);
    }

    /* answer the query */
    answer = ServerReceive(buf,ss->ora);

    if (strlen(answer)==0) {
      /*-- can't send an empty message, but client is waiting --*/
      free(answer);
      answer = strdup(" ");
    }
    if (!ss->quiet) {
      printf("  Server answered: %s\n",answer);
    }

    if (sendto(ss->sock, answer, strlen(answer), 0,
	       (struct sockaddr *) &from, fromlen) == -1) {
      perror("sendto");
      exit(1);
    }
    free(answer);


  }
}




void ServerOpen(
  int     port,
  Oracle* ora,
  int     quiet
)
{
  SSocket* ss;

  ss = (SSocket *) malloc(sizeof(SSocket));
  ss->quiet = quiet;
  ss->ora = ora;


  /* Grab an Internet domain socket */
  ss->sock = socket(AF_INET, SOCK_DGRAM, 0);
  if (ss->sock<0) {
    perror("opening datagram socket");
    exit(1);
  }


  /* Create name with wildcards. */
  ss->name.sin_family = AF_INET;
  ss->name.sin_addr.s_addr = INADDR_ANY;
  ss->name.sin_port = htons(port);


  /* bind the socket to the port number */
  if (bind(ss->sock, (struct sockaddr *) &(ss->name), sizeof(ss->name)) == -1) {
    perror("Binding datagram socket for server");
    exit(1);
  }


  printf("Server is now running at port: 0x%x\n",port);

  wait(ss);

  close(ss->sock);

}

