/*-------------------------------------------------------------------------------------------------------
    Purpose: Embryonic process - functionality is assigned dynamically using PSRP
             and PSRP components of the PUPS environment 

    Authors: M.A. O'Neill
             Digital Vision
             Didcot
             Oxfordshire
             OX11 8QY

    Dated:   8th May 1999 
    Version: 1.00
    E-mail:  mao@sable.ox.ac.uk
-------------------------------------------------------------------------------------------------------*/



#include <me.h>
#include <utils.h>
#include <netlib.h>
#include <psrp.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <hipl_hdr.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <shmheap.h>
#include <shmalloc.h>

#include <vstamp.h>

/* Version number -- do not edit! */
#define VTAG 314
_IMPORT appl_vtag = VTAG;


/*--------------------------------------------------------------------------------------------------------
    Function called when checkpoint file reloaded but before user code re-entered ...
--------------------------------------------------------------------------------------------------------*/


void restartfunc()

{   if(appl_verbose == TRUE)
    {  fprintf(stderr,"\n\nrestart function\n\n\n\n");
       fflush(stderr);
    }
}



/*--------------------------------------------------------------------------------------------------------
    Function called when checkpoint file saved ...
--------------------------------------------------------------------------------------------------------*/


void ckptfunc()

{   fprintf(stderr,"\n\ncheckpoint function\n\n\n\n");
    fflush(stderr);
}


/*--------------------------------------------------------------------------------------------------------
    Exit function for testfps() [interrupt when processing transactions to/from remote slave] ...
--------------------------------------------------------------------------------------------------------*/


_PRIVATE int testfps_exitf(int chid)

{   int fdes,
        index;

    index = get_ftab_index_by_id(chid);
    (void)fcclose(ftab[index].stream);

    return(0);
}



/*--------------------------------------------------------------------------------------------------------
    Display process status (to attached PSRP client process) ...
--------------------------------------------------------------------------------------------------------*/


_PRIVATE int psrp_process_status(int argc, char *argv[])
{
   fprintf(psrp_out,"status\n");
   fflush(psrp_out);

   return(PSRP_OK);
}




/*--------------------------------------------------------------------------------------------------------
    Create a slaved interation client (SIC) and talk to it ...
--------------------------------------------------------------------------------------------------------*/


_PRIVATE int testsic(int argc, char *argv[])
{  int  ret;
   char reply[256];
   psrp_channel_type *sic  = (psrp_channel_type *)NULL;

   if(argc != 2)
   {  fprintf(psrp_out,"Usage: testsic <sic server>\n");
      fflush(psrp_out);

      return(PSRP_OK);
   }

   fprintf(psrp_out,"\ncreating (peer-to-peer) SIC to client %s\n\n",argv[2]);
   fflush(psrp_out);

   if((sic = psrp_create_slaved_interaction_client(psrp_out,(char *)NULL,"pslave","sic")) == (psrp_channel_type *)NULL)
   {  fprintf(psrp_out,"SIC creation failed\n");
      fflush(psrp_out);

      return(PSRP_OK);
   }

   /* Send command to slaved PSRP client */  
   (void)psrp_write_sic(sic,"version\n");

   /* Read reply */
   do {    if((ret = psrp_read_sic(sic,reply)) == PSRP_MORE)
           {  (void)fputs(reply,psrp_out);
              (void)fflush(psrp_out);
           } 
      } while(ret == PSRP_MORE);

      /* Send command to slaved PSRP client */
   (void)psrp_write_sic(sic,"chelp\n");

   /* Read reply */
   do {    if((ret = psrp_read_sic(sic,reply)) == PSRP_MORE)
           {  (void)fputs(reply,psrp_out);
              (void)fflush(psrp_out);
           }
      } while(ret == PSRP_MORE);



   (void) psrp_destroy_slaved_interaction_client(psrp_out,sic);
   return(PSRP_OK);
}




/*------------------------------------------------------------------------------------------------------
    Get application information for slot manager ...
------------------------------------------------------------------------------------------------------*/

 
/* Slot information function */
_PRIVATE void embryo_slot(int level)
{   fprintf(stderr,"int dynamic app (PSRP) embryo 1.10: [ANSI C, PUPS MTD D]\n");
 
    if(level > 1)
    {  fprintf(stderr,"(c) 1996 Digital Vision, Didcot\n");
       fprintf(stderr,"Author: M.A. O'Neill\n");
       fprintf(stderr,"Unassigned PSRP dynamic process (PUPS format)\n\n");
    }
    else
       fprintf(stderr,"\n");

    fflush(stderr);
}
 
 
 
 
 
/* Application usage function */
_PRIVATE void embryo_usage()

{   fprintf(stderr,"[-state] ");
    fprintf(stderr,"\n\nSignals\n\n");
    fprintf(stderr,"SIGINIT SIGCHAN SIGPSRP: Process status [PSRP] request (protocol %2.2f)\n",PSRP_PROTOCOL_VERSION);
    fprintf(stderr,"SICLIENT: tell client server is about to segment\n");

#ifdef THREAD_SUPPORT
    fprintf(stderr,"SIGTHREAD: tell client its service thread (on PSRP server) has been terminated\n");
#endif


#ifdef CKPT
    if(checkpointing == TRUE)
       fprintf(stderr,"SIGCHECK SIGVACATE:      CKPT job control\n");
#endif

    fprintf(stderr,"SIGALIVE: check for existence of client on signal dispatch host\n");
    fflush(stderr);
}




#ifdef SLOT
#include <slotman.h>
_EXTERN void (* SLOT)() = embryo_slot;
_EXTERN void (* USE )() = embryo_usage;
#endif



/*-------------------------------------------------------------------------------------------------------
    Public variables and function pointers used by this application ...
-------------------------------------------------------------------------------------------------------*/


_PRIVATE _BYTE test_databag[1024];

/*-------------------------------------------------------------------------------------------------------
    Functions which are private to this application ...
-------------------------------------------------------------------------------------------------------*/


/* Test function */
_PROTOTYPE _PRIVATE int static_test_function_object(int argc, char *argv[]);

/* ASCII text generation function */
_PROTOTYPE _PRIVATE int ascii(int argc, char *argv[]);



/*-------------------------------------------------------------------------------------------------------
    Variables which are private to this module ...
-------------------------------------------------------------------------------------------------------*/



/*-------------------------------------------------------------------------------------------------------------
    Main - decode command tail then interpolate using parameters supplied by user ...
-------------------------------------------------------------------------------------------------------------*/


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

{   int cnt  = 0,
        tdes = 0,
        hdes = (-1);

    unsigned long size;

    char *h_ptr_1 = (char *)NULL,
         *h_ptr_2 = (char *)NULL;

    char buf[256];

    FILE              *tstream    = (FILE *)NULL;
    psrp_channel_type *embryo_sic = (psrp_channel_type *)NULL;
    _BYTE             *tbuf       = (_BYTE *)NULL;
    double            *fbuf       = (double *)NULL;

    /* Do not allow PSRP clients to connect until we are initialised */
    psrp_ignore_requests();

/*-------------------------------------------------------------------------------------------------------------
    Get standard items form the command tail ...
-------------------------------------------------------------------------------------------------------------*/


    std_init(TRUE,
             &argc,
             "1.00",
             "M.A. O'Neill",
             "(PSRP) embryo",
                      "1999",
                        argv);

#ifdef CKPT_SUPPORT

    /* Register a ckpt function */
    register_pups_ckpt_f("ckptfunc",&ckptfunc,(char *)NULL);

    /* Register a restart function */
    register_pups_restart_f("retstartfunc",&restartfunc,(char *)NULL);

#endif /* CKPT_SUPPORT */

    register_pups_exit_f(stderr,"retstartfunc",&restartfunc,(char *)NULL);

    /* Get the application to tell us what it is */
    if((ptr = locate(&init,"state",&argc,args)) != NOT_FOUND)
    {  fprintf(stderr,"    I am a PSRP embryo process, I am waiting to be\n");
       fprintf(stderr,"    told what to do ...\n\n");
       fflush(stderr);

       pups_exit(1);
    }

    /* Complain about any unparsed arguments */
    t_arg_errs(argc,argd,args);

/*-------------------------------------------------------------------------------------------------------------
    Initialise PSRP function dispatch handler - note that the embryo is fully dynamic and prepared
    to import both dynamic functions and data objects ...
-------------------------------------------------------------------------------------------------------------*/


    psrp_init(PSRP_DYNAMIC_FUNCTION | PSRP_STATIC_DATABAG | PSRP_HOMEOSTATIC_STREAMS,NULL);

    /* Attach static functions which can be accessed from PSRP client */
    (void)psrp_attach_static_function(stderr,"status",(void *)&psrp_process_status);
    (void)psrp_attach_static_function(stderr,"testsic",(void *)&testsic);
    (void)psrp_attach_static_function(stderr,"testfps",&static_test_function_object);

    /* We must define static bindinfgs BEFORE loading the default */
    /* dispatch table. In the case of static bindings, the only   */
    /* effect of loading a saved dispatch table is to (possibly)  */
    /* add object aliases                                         */

    (void)psrp_load_default_dispatch_table(stderr);

    /* Tell PSRP clients we are ready to service their requests */
    psrp_accept_requests();


#ifdef SUPPORT_SHARED_HEAPS
    /* Lets attach a shared heap */
    if((hdes = msm_heap_attach("heap1",
                           O_RDWR    | O_CREAT,
                           PROT_READ | PROT_WRITE,
                           MAP_SHARED,
                           LIVE)) == (-1))
        pups_exit(-1);

    /* And another */
    /*if(msm_heap_attach("heap2",
                       O_RDWR    | O_CREAT,
                       PROT_READ | PROT_WRITE,
                       MAP_SHARED,
                       LIVE) == (-1))
       pups_exit(-1);
    */


    /* And another */
    /*if(msm_heap_attach("heap3",
                       O_RDWR    | O_CREAT,
                       PROT_READ | PROT_WRITE,
                       MAP_SHARED,
                       LIVE) == (-1))
       pups_exit(-1);
    */


    /* Allocate some objects on the first shared heap */
    if(shmalloc(hdes,260000,"object1") == (void *)NULL)
    {  fprintf(stderr,"test: failed to allocated shared heap object (%s)\n","object1");
       fflush(stderr);

       /* If this object already exists - which is the reason that the  */
       /* attempt to allocate it failed, lets take a look at the shared */
       /* memory associated with it                                     */
       h_ptr_1 = msm_lockobjectname(hdes,F_LOCK,"object1",WRITE);
       fprintf(stderr,"INITIAL VALUE:  %s\n",h_ptr_1,h_ptr_1);
       msm_lockobjectname(hdes,F_ULOCK,"object1",READ);
    }

    if(shmalloc(hdes,55000,"object2") == (void *)NULL)
    {  fprintf(stderr,"test: failed to allocated shared heap object (%s)\n","object2");
       fflush(stderr);
    }

    /* Remove the object "object2" from the shared heap "heap1" */
    h_ptr_1 = msm_lockobjectname(hdes,F_LOCK,"object2",READWRITE);
    (void)shfree(hdes,h_ptr_1);

    /* And add another shared object */
    if(shmalloc(hdes,355000,"object3") == (void *)NULL)
    {  fprintf(stderr,"test: failed to allocated shared heap object (%s)\n","object3");
       fflush(stderr);
    }

    /* Display the current objects and clients */
    (void)map_show(hdes,stderr);
    (void)client_show(hdes,stderr);


#endif /* SUPPORT_SHARED_HEAPS */


/*-------------------------------------------------------------------------------------------------------------
    This is the event loop of the embryo -- it may well interact with windowed applications such as
    Xmt Widgets or X applications such as TK or file managers ...
-------------------------------------------------------------------------------------------------------------*/



    fprintf(stderr,"\n    %s (%d@%s) is waiting to be allocated an application\n\n",
                                                       appl_name,getpid(),appl_host);
    fflush(stderr);

    while(1)
    {    char strdum[256];
         unsigned long ldum;

         int i,
             idum;


#ifdef SUPPORT_SHARED_HEAPS
         /* Update shared heap object "object1" on heap "heap1"      */
         /* Lock "object1" and return a (local) pointer to it        */
         h_ptr_1 = msm_lockobjectname(hdes,F_LOCK,"object1",READWRITE);

         /* Update "object1" */
         (void)sscanf(h_ptr_1,"%s %s %s %s %s %d",
                      strdum,strdum,strdum,strdum,strdum,&cnt);

         (void)sprintf(h_ptr_1,"[0x%x] %s [%d@%s] cnt is %d!",
                       (unsigned long)h_ptr_1,appl_name,appl_pid,appl_host,++cnt);

         fprintf(stderr,"%s\n",h_ptr_1);
         fflush(stderr);

         (void)usleep(100);

         /* Unlock "object1" so other clients can access it */
         (void)msm_lockobjectname(hdes,F_ULOCK,"object1",READWRITE);


#else
         (void)usleep(100);
#endif /* SUPPORT_SHARED_HEAPS */

    }

    /* Exit from PUPS/PSRP application cleaning up any mess it may have created */
    pups_exit(0);
}




/*-------------------------------------------------------------------------------------------------------------
    Simple test function to exercise vairous psrp functions ...
-------------------------------------------------------------------------------------------------------------*/


_PRIVATE int static_test_function_object(int argc, char *argv[])

{   int  i,
         init,
         ptr, 
         ret_code;

    char command[256],
         item[256];

    FILE *pipestream = (FILE *)NULL;

#ifdef PSRP_AUTHENTICATE
    if(strin(argv[1],"^") == TRUE && pups_check_pass_set() == FALSE)
    {  fprintf(psrp_out,"testfps: authentication failure\n");
       fflush(psrp_out);

        return(PSRP_OK);
    }
#endif

    if(argc < 2)
    {  fprintf(psrp_out,"usage: testfps <pipestream>\n");
       fflush(psrp_out);

       return(PSRP_OK);
    }

    (void)strcpy(command,"");
    for(i=1; i<argc; ++i)
    {  (void)strcat(command,argv[i]);
       (void)strcat(command," ");
    }

    if((pipestream = xfopen(command,"r",TRUE)) == (FILE *)NULL)
    {  fprintf(psrp_out,"testfps: failed to open pipestream \"%s\"\n",command);
       fflush(psrp_out);

       return(PSRP_OK);
    }

    (void)psrp_set_client_exitf(c_client,"testfps_client",&testfps_exitf);
    (void)set_ftab_id(fileno(pipestream),c_client);

    /* Loop to extract data from pipestream */
    do {   xfgets(item,256,pipestream);

           if(feof(pipestream) == 0)
           {  fprintf(psrp_out,"%s\n",item);
              fflush(psrp_out);
           }
       } while(feof(pipestream) == 0);

    (void)xfclose(pipestream);
    
    return(PSRP_OK);
}



/*--------------------------------------------------------------------------------------------------------------
    Test function to send stream of ASDII text to PSRP client process ...
--------------------------------------------------------------------------------------------------------------*/


_PRIVATE int ascii(int argc, char *argv[])

{   int cnt = 0;
    sigset_t set,
             old_set;

    while(1)
    {    fprintf(stderr,"in ASCII (%d)\n",cnt);
         fflush(stderr);

/*
         fprintf(psrp_out,psrp_client_pid,psrp_chbrk_handler,"ASCII text (%d)\n",cnt);
*/


         fprintf(psrp_out,"ASCII text (%d)\n",cnt);
         fflush(psrp_out);
         sleep(1);

         sigprocmask(SIG_UNBLOCK,&old_set,NULL);

         ++cnt;
         (void)usleep(100);
    }
}