/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#+
#+     Mumps Bioinformatics Software Library
#+     Copyright (C) 2003, 2004, 2008, 2012, 2017 by Kevin C. O'Kane
#+
#+     Kevin C. O'Kane
#+     kc.okane@gmail.com
#+     http://www.cs.uni.edu/~okane
#+     http://threadsafebooks.com/
#+
#+     Sockets implementation by Ben Fain
#+
#+ 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
#+
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>

#include <mumpsc/defines.h>
#include <mumpsc/libmpscpp.h>

@serverbuf@


//structure of message in the queue

struct mymsgbuf {
      long cid;                 /* Client ID */
      char buff0[SERVERBUF+1];  /* Buf0 sent from client*/
      char buff1[SERVERBUF];    /* Buf1 sent from client*/
      struct socketdata { /* Socket Data needed to send data back to client */
            int socket;
            char socketname[108];
            } socketinfo;
      };

char * logtime() {
      time_t t;
      static char tm[64];
      time(&t);
      strcpy(tm,ctime(&t));
      tm[strlen(tm)-1]=0;
      return tm;
      }

int main(int argc, char * argv[]) {

      char buf0[SERVERBUF+1], buf1[SERVERBUF];
      int sigint(int);
      unsigned int Flush=0;
      FILE *Journal;
      char journal[1024];
      int jflag=0;
      int qid,e;
      key_t msgkey;
      int length = sizeof(struct mymsgbuf) - sizeof(long);


      printf("Server started\n");

      for(int i=0; i< argc; i++) {
            if (strcmp(argv[i],"-j")==0) {
                  if (argc>=i+2) {
                        strcpy(journal,argv[i+i]);
                        jflag=1;
                        }
                  else {
                        printf("incorrectly specified journal\n");
                        return 0;
                        }
                  }
            }

      if (jflag) {
            Journal=fopen(journal,"a");

            if (Journal == NULL ) {
                  printf("Journal error\n");
                  }

            printf("%s journal started...\n",journal);
            }

//**********************************************************************
// net initialization goes here $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
//**********************************************************************

// generate unique key for message queue using file and arbitrary char

      msgkey = ftok("/tmp/mumps.tmp", 'A');

// create message queue and return queue id

      qid = msgget(msgkey, IPC_CREAT | 0777);

      printf("%s Begin listening....\n",logtime());

// open socket

      int ssock = socket(AF_UNIX,SOCK_DGRAM,0);

      if (ssock < 0) {
            perror("server socket");
            exit(1);
            }

      int cid,socket,sck,nbytes,type,result;
      struct mymsgbuf clientMsg;
      char name[108];
      struct sockaddr_un nm;

//*********************************************************************
// message loop
//*********************************************************************

      while (1) { // repeat as necessary

// detect a shutdown signal and exit this loop to perform GlobalClose

//*********************************************************************
// read transaction from client here into buf0 and buf1 code goes here
//*********************************************************************

//        int cid,socket,sck,nbytes,type,result;
//        struct mymsgbuf clientMsg;
//        char name[108];
//        struct sockaddr_un nm;

//        if ( (result = msgrcv( qid ,(void *) &clientMsg, length, type,  0)) != -1) {
            if ( msgrcv( qid,(void *) &clientMsg, length, type,  0) != -1) {
//            cid  = clientMsg.cid;

//*            memcpy(buf0,clientMsg.buff0,SERVERBUF+1);
//*            if (buf0[0] != RETRIEVE) memcpy(buf1, clientMsg.buff1, SERVERBUF);

//            socket = clientMsg.socketinfo.socket;
//            memcpy(name, clientMsg.socketinfo.socketname, sizeof(name));


                  if (jflag) {
                        if (buf0[0]==STORE) fprintf(Journal,"%d %s\n%s\n",(int)buf0[0],&buf0[1],buf1);
                        else if (buf0[0]==KILL) fprintf(Journal,"%d %s\n",(int)buf0[0],&buf0[1]);
                        }

//*            e=Mglobal( (int)buf0[0], (unsigned char *) &buf0[1], (unsigned char *) buf1, svPtr);

                  clientMsg.buff0[0] = Mglobal( (int) clientMsg.buff0[0], (unsigned char *) &clientMsg.buff0[1], (unsigned char *) clientMsg.buff1, svPtr);

//*            buf0[0]=e;
//	clientMsg.buff0[0]=e;

// --- leave this code alone

//*********************************************************************
// send buf0 and buf1 back to client code goes here
//*********************************************************************

//            memcpy(clientMsg.buff0,buf0,sizeof(buf0));
//            memcpy(clientMsg.buff1,buf1,sizeof(buf1));

                  nm.sun_family = AF_UNIX;

                  memcpy(nm.sun_path, clientMsg.socketinfo.socketname, sizeof(name));
//            strcpy(nm.sun_path,name);

//*            if ( (sendto(ssock,&buf0, SERVERBUF+1, 0, (struct sockaddr *)&nm, sizeof(struct sockaddr_un)) )<0 ) {
                  if ( (sendto(ssock,clientMsg.buff0, SERVERBUF+1, 0, (struct sockaddr *)&nm, sizeof(struct sockaddr_un)) )<0 ) {
                        perror("Sending Response");
                        exit(EXIT_FAILURE);
                        }

//*            if ( (sendto( ssock, &buf1, SERVERBUF, 0,(struct sockaddr *)&nm, sizeof(struct sockaddr_un))) <0 ) {
                  if ( (sendto( ssock, clientMsg.buff1, SERVERBUF, 0,(struct sockaddr *)&nm, sizeof(struct sockaddr_un))) <0 ) {
                        perror("Sending Response");
                        exit(EXIT_FAILURE);
                        }

                  }
            }

      close(ssock);

      GlobalClose;

      return 0;
      }

