/* @(#)osx.c	19.1 (ES0-DMD) 02/25/03 13:56:14 */
/*===========================================================================
  Copyright (C) 1995 European Southern Observatory (ESO)
 
  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., 675 Massachusetss Ave, Cambridge, 
  MA 02139, USA.
 
  Corresponding concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.TYPE        Module
.NAME        osx
.LANGUAGE    C
.AUTHOR      K. Banse		ESO-IPG, Garching
.CATEGORY    Host operating system interfaces. Interprocess Communication
.COMMENTS    Interprocess communication routines for VMS. These routines 
             allow the creation of asynchronous communication channels 
             between processes.
	     The communication channel is open by giving the channel name 
	     and the mode of opening. The function returns an integer number 
	     used to address the channel.
	     The routines return always
            	a non-negative integer number on successful return.
            	Otherwise, a value of -1 is set to indicate an error
            	condition and the variable ``oserror'' contains the 
            	symbolic error code.
	     Symbolic error codes for each function to be defined.

.HISTORY 1.00	890720	adapted from prototype version by M. Pucillo, Trieste
.HISTORY 1.10	891102	fix related problem in osxopen (return kid!) KB
.HISTORY 1.20	891211	fix 4th par. in SYS$ASSIGN (to NULL pointer) TM
.HISTORY 1.30	900115	replace $DESCRIPTOR construct by exact commands  KB
.HISTORY 1.40	910909	redesign the osx !!   KB
------------------------------------------------------------*/

#include <stdio.h>
#include <errno.h>
#include <osparms.h>

/* VMS dependent include section */

#include <ssdef.h>
#include <descrip.h>
#include <iodef.h>

#define  BIT_0  0x1


typedef struct
    {
    short cond_value;
    short count;
    int   info;
    } iostat_blk;

struct ipccstat	IPCC[MAX_IPCC];

static short    channel[MAX_IPCC];
static iostat_blk  iosb[MAX_IPCC];

static unsigned int  retval;

extern int oserror;

extern int errno;


int osxopen(channame, mode)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Opens communication channel for read or write. The variable mode
         defines the way of opening the file by constructing
         the OR of the following flags: 
         - LOCAL (local communication channel)
         - CLIENT (client mode of opening : no priv. required)
         - IPC_READ  (open the channel in READ mode)
         - IPC_WRITE (open the channel in WRITE mode)
.RETURNS Upon successful completion a positive number with the 
         channel identification is returned or -1 in case of error.
.REMARKS System dependencies:
 --  VMS : SYS$CREMBX, $DESCRIPTOR, LIB$SIGNAL, open(2)
------------------------------------------------------------*/
char *channame[2];		/* physical channel name */
int  mode;			/* open mode */

{
static int    cid = 0;
int        kid;

unsigned short chan;
unsigned int  maxmsg = 4096;
unsigned int  bufquo = 8192;
char          bzero = 0;
char          bone  = 1;
unsigned int  izero = 0;

struct  dsc$descriptor_s  lognam_desc;

lognam_desc.dsc$w_length = strlen(channame[0]);
lognam_desc.dsc$a_pointer = channame[0];
lognam_desc.dsc$b_class = DSC$K_CLASS_S;
lognam_desc.dsc$b_dtype = DSC$K_DTYPE_T;

if (cid >= MAX_IPCC) 
   {
   oserror = EINVAL;
   return (-1);
   }


for (kid=1; kid<=cid; kid++)		/* look for free (closed) entry  */
   {
   if (IPCC[kid].status == CLOSED)  goto slot_found;
   }

kid = ++ cid;


slot_found:

switch (mode) 
   {

   case 0: /* open channel in read mode, locally */
	   /* --------- local server ----------- */


   retval = SYS$CREMBX(bone,&chan,maxmsg,bufquo,izero,izero,&lognam_desc);

   if (retval != SS$_NORMAL) LIB$SIGNAL (retval);

   IPCC[kid].status    = OPENED_READ;
   IPCC[kid].omode     = IPC_READ;
   IPCC[kid].type      = LOCAL;
   channel[kid]        = chan;
   break;

   case 1: /* open channel in write mode, locally */
	   /* --------- local server ------------ */
	   /* default IPCC number is set to 0 at opening */


   retval = SYS$CREMBX(bone,&chan,maxmsg,bufquo,izero,izero,&lognam_desc);
   if (retval != SS$_NORMAL) LIB$SIGNAL (retval);

   IPCC[kid].status    = OPENED_WRITE;
   IPCC[kid].omode     = IPC_WRITE;
   IPCC[kid].type      = LOCAL;
   channel[kid]        = chan;
   break;

   case 4: /* open channel in read mode, locally */
	   /* --------- local client ----------- */


   retval = SYS$ASSIGN(&lognam_desc,&chan,bzero,(struct dsc$descriptor *)NULL);
   if (retval != SS$_NORMAL) LIB$SIGNAL (retval);

   IPCC[kid].status    = OPENED_READ;
   IPCC[kid].omode     = IPC_READ;
   IPCC[kid].type      = LOCAL | CLIENT;
   channel[kid]        = chan;
   break;

   case 5: /* open channel in write mode, locally */
	   /* --------- local client ------------ */
	   /* default IPCC number is set to 0 at opening */


   retval = SYS$ASSIGN(&lognam_desc,&chan,bzero,(struct dsc$descriptor *)NULL);
   if (retval != SS$_NORMAL) LIB$SIGNAL (retval);

   IPCC[kid].status    = OPENED_WRITE;
   IPCC[kid].omode     = IPC_WRITE;
   IPCC[kid].type      = LOCAL | CLIENT;
   channel[kid]        = chan;
   break;

   default:
   oserror = EINVAL;
   break;
   }

return(oserror == 0 ? kid : -1);

}



int osxclose(cid)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Closes interprocess communication channel.
         The argument cid is the channel identification as
         obtained from osxopen. 
.RETURNS Value 0 on normal return. 
.REMARKS System dependencies:
 --  VMS: SYS$DASSGN, SYS$DELMBX, LIB$SIGNAL
------------------------------------------------------------*/
int cid;			/* channel identification */

{

if (cid < 0 || cid > MAX_IPCC)
   {
   oserror = EINVAL;
   return (-1);
   }
 
IPCC[cid].status = CLOSED;

if (IPCC[cid].type == LOCAL)
   {
   retval = SYS$DELMBX (channel[cid]);
   if (retval != SS$_NORMAL) LIB$SIGNAL (retval);
   }

retval = SYS$DASSGN (channel[cid]);
if (retval != SS$_NORMAL) LIB$SIGNAL (retval);

return(0);

}



int osxread(cid, pbuf, nobytes)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Synchronous read from interprocess communication channel.
         The argument cid is the channel identification as obtained
         from osxopen. The function reads nobyt bytes from the
         channel and put the information into
         the buffer pointed by pbuf. 
.RETURNS Upon successful completion a value of 0 is returned.
      (   The function osxwait must be called after the asynchronous read. )
.REMARKS System dependencies:
 --  VMS:SYS$QIOW, LIB$SIGNAL
------------------------------------------------------------*/
int  cid;			/* channel identification */
char *pbuf;			/* pointer to input buffer */
int  nobytes;                   /* number of input bytes */

{

unsigned short chan;
unsigned short func = IO$_READVBLK;
unsigned int   nobyt;
char           bzero = 0;
unsigned int   izero = 0, ifour = 4;

chan = channel[cid];
nobyt = (unsigned int)nobytes;

if (cid < 0 || cid > MAX_IPCC )
   {
   oserror = EINVAL;
   return (-1);
   }
   
if (nobyt <= 0) return(0);


/* the server does not wait on I/O - and uses osxinfo for synchronization  */

if (IPCC[cid].type == LOCAL)
   retval = SYS$QIO (ifour, chan, func, &iosb[cid], izero, izero,
                      pbuf, nobyt, izero, izero, izero, izero);

/* the clients do an I/O with wait */

else
   retval = SYS$QIOW (izero, chan, func, &iosb[cid], izero, izero,
                      pbuf, nobyt, izero, izero, izero, izero);


if (retval != SS$_NORMAL) LIB$SIGNAL (retval);

return(0);

}



int osxwrite(cid, pbuf, nobytes)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Synchronous write into interprocess communication channel.
         The argument cid is the channel identification as obtained
         from osxopen. The function writes nobyt bytes from the
         the buffer pointed by pbuf into the channel. 
.RETURNS Upon successful completion a value of 0 is returned.
      (   The function osxwait must be called after the asynchronous write.)
.REMARKS System dependencies:
 --  VMS:SYS$QIOW, LIB$SIGNAL
------------------------------------------------------------*/
int  cid;			/* channel identification */
char *pbuf;			/* pointer to output buffer */
int  nobytes;			/* number of output bytes */
{

unsigned short chan;
unsigned short func = IO$_WRITEVBLK;
unsigned int   nobyt;
char           bzero = 0;
unsigned int   izero = 0;

chan = channel[cid];
nobyt = (unsigned int)nobytes;

if (cid < 0 || cid > MAX_IPCC)
   {
   oserror = EINVAL;
   return (-1);
   }
   
if (nobyt > 0)
   {
   retval = SYS$QIOW (izero, chan, func, &iosb[cid], izero, izero,
                       pbuf, nobyt, izero, izero, izero, izero);
   if (retval != SS$_NORMAL) LIB$SIGNAL (retval);
   }

return(0);

}



int osxinfo(cid, sec, usec)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Gets status of the interprocess communication channel.
.RETURNS Upon successful completion a value of 0 is returned.
.REMARKS System dependencies:
 -- UNIX: none
------------------------------------------------------------*/
int cid;			/* channel identification */
int sec;			/* seconds to wait in osxinfo */
int usec;			/* millisecs to wait in osxinfo */

{ 

short int  iostat;
long int   milsecs, time[2];
unsigned int  efmask;
unsigned int  ithree = 3;

if (cid < 0 || cid > MAX_IPCC || usec < 0)
   {
   oserror = EINVAL;
   return (-1);
   }
 


iostat = iosb[cid].cond_value;		 /* look at status of last read */

if (iostat == SS$_NORMAL)
   return (DATARDY);


/*  init mask to just wait for event flag #4 (from the QIO)  */

efmask = 16;


/* if sec or usec > 0, wait */

if (sec > 0) 
   milsecs = (sec * 1000) + usec;
else
   milsecs = usec;

if (milsecs > 0)
   {
   time[1] = -1;
   time[0] = - (10000 * milsecs);
   retval = SYS$SETIMR(ithree,time,0,0);	/* use event flag 3 */
  
   if (retval & BIT_0) efmask = 24;		/* set also bit 3 to 1  */
   }

retval = SYS$WFLOR(ithree,efmask);
if (retval != SS$_NORMAL) LIB$SIGNAL(retval);


/*  now look again  */

iostat = iosb[cid].cond_value;		 /* look at status of last read */

if (iostat == SS$_NORMAL)
   return (DATARDY);
else 
   return (NOCONN);
}

int osxgetservbyname(service)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Interface to the getservbyname().
.RETURNS The port number, or -1 if no port.
.REMARKS Not implemented yet
------------------------------------------------------------*/
char *service;
{
   return(-1);
/*
   struct servent     *sp;

   if ((sp = getservbyname(service,"tcp")) == NULL) 
      return(-1);
   else
      return(sp->s_port);
*/
}
