/*===========================================================================
  Copyright (C) 1995-2009 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 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence 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.c
.LANGUAGE    C
.AUTHOR      IPG-ESO Garching
.CATEGORY    Host operating system interfaces. Interprocess Communication
.COMMENTS    Interprocess communication routines. The routines allow the
	     creation of asynchronous communication channels between processes
	     possibly located in different nodes.
	     Three modes of operation are foreseen depending on the 
	     communication channel: 
		local communication (fast channel for processes residing in 
				the same node), 
		network communication (medium channel for processes located 
				in processors interconnected with a local 
				area network), 
	     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. Operations include asynchronous 
	     input/output, wait for completion and control operations.
	     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.1] 910828  CG. New implementation.
.HISTORY [2.1] 920527  If no S_IFSOCK  no local unix sockets. CG.
.HISTORY [3.1] 21-Apr-1993   Posix compliant

.VERSION

 090324		last modif
------------------------------------------------------------*/

/*
 * Define _POSIX_SOURCE to indicate
 * that this is a POSIX program
 * Except for Maciontosh, SUN & GNU-SUN & HP-UX & OSF & AIX & ULTRIX & SGI 
 * because the POSIX definition
 * causes undefines (eg. u_long) in socket includes.
 */
#if !defined(__APPLE__) && !defined(__hpux) && !defined(sun) && !defined(__sun) && !defined(__osf__) && !defined(_AIX) && !defined(ultrix) && !defined(__sgi) && !defined(__linux__) && !defined(__FreeBSD__) && !defined(Cygwin)
#   define _POSIX_SOURCE 1
#endif

#include <sys/types.h>          /* generic definitions */
#include <sys/socket.h>         /* sockets definitions */
#include <sys/stat.h>           /* stat(2v); */

#ifdef S_IFSOCK                 /* defined in stat.h if Unix domain sockets */
#   include <sys/un.h>          /* struct sockaddr_un (Unix domain) */
#endif /* S_IFSOCK */

#include <netinet/in.h>         /* struct sockaddr_in (Internet domain) */
#include <netdb.h>              /* getservbyname(3n), gethostbyname(3n); */
#include <sys/time.h>           /* struct timeval timeout */
#include <signal.h>             /* signal(3v); */
#include <errno.h>              /* error definitions */
#include <sys/errno.h>          /* error definitions */
#include <stdio.h>              /* generic definitions */
#include <stdlib.h>             /* function definitions */
#include <string.h>             /* string definitions */
#include <unistd.h>             /* string definitions */
#include <proto_os.h>           /* ANSI-C prototyping */

#include <osxdef.h>             /* MIDAS osx definitions */


/* OSF1 and HP-UX don't know socklen_t ... */

#if defined(__osf__) || defined(__hpux)
#   define XSOCKLEN int
#else
#   define XSOCKLEN socklen_t
#endif


/*
static FILE *fid;
static int first_time = 0;
static char  logname[24] = "osxlogA.dat";

FILE *fopen();
*/


#ifndef SUN_LEN
#   define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
#endif

static int  indxIPCC[MAX_IPCC] =
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
             -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
static struct ipccstat IPCC[MAX_IPCC];

#define NULL_PTR(x) (x *)0
#define RET_ERROR(x) { oserror=(x); return(-1); }

static char msg0[] = "OSX: Channel out of table";
static char messg[80];

#ifndef FD_SET                  /* If it is not the Berkeley select */
typedef int osxfds;
#   	define FD_SET(n, p) 	(*(p) |= (1 << (n)) )
#else
typedef fd_set osxfds;
#endif

/*
int  osxin(m)
int m;

{
if (m == 0)
   (void) strcpy(logname,"osxlogB.dat");
else if (m == 1)
   (void) strcpy(logname,"osxlogC.dat");

return 0;
}
*/

/*

*/

static int writen (fd, ptr, nbytes)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Write "n" bytest into a descriptor. Use in place of 
	 write() when fd is a stream socket
.RETURNS If succesful, the number of bytes actaully written is 
	 returned. Otherwise, a -1 is returned.
.REMARKS System dependencies:
 -- UNIX: write(2)
------------------------------------------------------------*/
int fd;
char *ptr;
int nbytes;

{
int nleft, nwritten;


nleft = nbytes;
while (nleft > 0)
   {
   nwritten = write (fd, ptr, nleft);
   if (nwritten <= 0) return (nwritten);           /* error */

   nleft -= nwritten;
   ptr += nwritten;
   }

return (nbytes - nleft);
}

static int readn (fd, ptr, nbytes)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Read "n" bytest from a descriptor. Use in place of 
	 read() when fd is a stream socket
.RETURNS If succesful, the number of bytes actaully read is 
	 returned. Otherwise, a -1 is returned.
.REMARKS System dependencies:
 -- UNIX: read(2)
------------------------------------------------------------*/
int fd;
char *ptr;
int nbytes;

{
int nleft, nread;


nleft = nbytes;
while (nleft > 0)
   {
   nread = read (fd, ptr, nleft);
   if (nread < 0) 		/* error, return < 0 */
      return (nread);		
   else if (nread == 0)         /* EOF */
      break;
   nleft -= nread;
   ptr += nread;
   }

return (nbytes - nleft);        /* return >= 0 */
}

static int osxstat (fd, sec, usec)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Examines the read status of a file descriptor.
	 The timeout (sec, usec) specifies a maximum interval to 
	 wait for data to be available in the descriptor.
	 To effect a poll, the timeout (sec, usec) should be 0.
.RETURNS a non-negative value on data available. 
	 0 indicates that the time limit referred by timeout expired.
	 On failure, it returns -1 and errno is set to indicate the
	 error.
.REMARKS System dependencies:
 -- UNIX: select(2)
------------------------------------------------------------*/
int fd, sec, usec;

{
int ret;
int width;
struct timeval timeout;
osxfds readfds;

/*
fprintf(fid,"osxstat: fd = %d\n",fd);
printf("osxstat: fd = %d\n",fd);
*/

memset ((char *) &readfds, 0, sizeof (readfds));
FD_SET (fd, &readfds);
width = fd + 1;
timeout.tv_sec = sec;
timeout.tv_usec = usec;
ret =
select (width, &readfds, NULL_PTR (osxfds), NULL_PTR (osxfds),
        &timeout);

return (ret);
}

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)
         - NETW  (communication channel using the network)
         - IPC_READ  (open the channel in READ mode or SERVER)
         - IPC_WRITE (open the channel in WRITE mode or CLIENT)
.RETURNS Upon successful completion a positive number with the 
         channel identification is returned or -1 in case of error.
.REMARKS System dependencies:
 -- UNIX: socket(2), bind(2), listen(2), gethostbyname(3n),
          getservbyname(3n), mknod(2), open(2)
------------------------------------------------------------*/
char *channame[2];                      /* physical channel name */
int mode;                               /* open mode */

{
int   n;
int xcid, cid;

char  *name1;


static struct stat statbuf;
static struct hostent *hp;
static struct servent *sp;
static struct sockaddr_in pin;

struct sigaction act;
int sockopt = 1;
#ifdef S_IFSOCK                 /* defined in stat.h if Unix domain sockets */
static struct sockaddr_un pun;
#endif



/* Ignore 'broken pipes' signal. */

act.sa_handler = SIG_IGN;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
if (sigaction (SIGPIPE, &act, (struct sigaction *) NULL) != 0)
   {
   oserror = errno;
   (void) strcpy(messg,"osxopen: sigaction failed");
   goto error_ret3;
   }


/*
if (first_time == 0)
   {
   first_time = 1;

   fid = fopen(logname,"w"); 
   fprintf(fid,"writing into logfile %s; \n",logname);
   }

fprintf(fid,"osxopen: %s mode: %d\n",channame[0],mode); 
printf("osxopen: %s mode: %d\n",channame[0],mode); 
*/



/* obtain the file descriptor for the socket comm. */

 
switch (mode & (LOCAL | NETW))
   {
   case LOCAL:                 /* open socket in server mode, locally */
#ifdef S_IFSOCK                 /* defined in stat.h if Unix domain sockets */
   if ((xcid = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
      {
      (void) sprintf(messg,"osxopen(LOCAL) failed: errno = %d",errno);
      oserror = errno;
      goto error_ret3;
      }

/* 
   fprintf(fid,"osxopen(LOCAL): xcid = %d\n",xcid); 
   printf("osxopen(LOCAL): xcid = %d\n",xcid); 
*/
   memset ((char *) &pun, 0, sizeof (pun));
   pun.sun_family = AF_UNIX;
   (void) strcpy (pun.sun_path, channame[0]);

#else
   (void) strcpy(messg,"osxopen: local sockets not available");
   oserror = -1;
   goto error_ret3;
#endif
   break;


   case NETW:                  /* open socket in server mode, locally */
   if ((xcid = socket (AF_INET, SOCK_STREAM, 0)) < 0) 
      {
      (void) sprintf(messg,"osxopen(NETW) failed: errno = %d",errno);
      oserror = errno;
      goto error_ret3;
      }

/* 
   fprintf(fid,"osxopen(NETW): xcid = %d\n",xcid); 
   printf("osxopen(NETW): xcid = %d\n",xcid); 
*/

   memset ((char *) &pin, 0, sizeof (pin));
   pin.sin_family = AF_INET;

   /* channame[0] could indicate a port number or a service */

   if ((pin.sin_port = atoi (channame[0])) == 0)
      {
      					/* get service reference */
      if ((sp = getservbyname (channame[0], "tcp")) == NULL)
         {
         (void) strcpy(messg,"osxopen: unable to open service");
         oserror = -1;
         goto error_ret2;
         }
      pin.sin_port = sp->s_port;
      }

   /* allow process to reuse both the IP address and port number */

   if (setsockopt (xcid, SOL_SOCKET, SO_REUSEADDR,
                   (char *) &sockopt, sizeof (sockopt)) != 0)
      {
      (void) strcpy(messg,"osxopen: unable to reuse sockets");
      oserror = -1;
      goto error_ret2;
      }
   break;

   default:
   (void) strcpy(messg,"osxopen: unknown open mode");
   oserror = -1;
   goto error_ret3;
   }


/* find empty slot in indxIPCC for cid */

for (n=0; n<MAX_IPCC; n++)
   {
   if (indxIPCC[n] == -1)
      {
      indxIPCC[n] = xcid;		/* holds fd of socket */
      cid = n;				/* that's the index into IPCC */
      goto next_step;
      }
   }

(void) strcpy(messg,"osxopen: channel out of table");
oserror = -2;
goto error_ret2;


next_step:
n = strlen(channame[0]) + 1;
name1 = (char *) malloc ((size_t) n);
(void) strcpy(name1, channame[0]);

IPCC[cid].chname = name1;
IPCC[cid].phname = (char *) 0;
IPCC[cid].omode = mode & (IPC_READ | IPC_WRITE);
IPCC[cid].type = mode & (LOCAL | NETW);
IPCC[cid].status = 0;
IPCC[cid].accept = 0;


/* handle READ or WRITE for local or network sockets */

switch (mode)
   {
#ifdef S_IFSOCK
   case LOCAL | IPC_READ:	/* open socket in server mode, locally */
   				/* unlink the socket_file if existing */
/*
fprintf(fid,"osxopen:  case LOCAL | IPC_READ\n");
printf("osxopen:  case LOCAL | IPC_READ\n");
*/

   if (stat (channame[0], &statbuf) == 0)
      {
      if ((statbuf.st_mode & S_IFSOCK) == S_IFSOCK ||
          (statbuf.st_mode & S_IFIFO) == S_IFIFO)
         {
         if (unlink (channame[0]) == -1)
            {
            (void) sprintf(messg,"local unlink(%s) failed",channame[0]);
            goto error_ret0;
            }
         }
      }

   if (bind (xcid, (struct sockaddr *) &pun, SUN_LEN (&pun)) < 0)
      {
      (void) sprintf(messg,"local bind() failed: errno = %d",errno);
      goto error_ret0;
      }

   /* Start accepting connections */

   if (listen (xcid, LOCAL_QUEUE_LENGTH) == -1)
      {
      (void) sprintf(messg,"local listen() failed: errno = %d",errno);
      goto error_ret0;
      }
   break;

   case LOCAL | IPC_WRITE:	/* open channel in client mode, locally */

/*
fprintf(fid,"osxopen:  case LOCAL | IPC_WRITE\n");
printf("osxopen:  case LOCAL | IPC_WRITE\n");
*/

   if (connect (xcid, (struct sockaddr *) &pun, sizeof (pun)) < 0)
      {
      (void) sprintf(messg,"local write connect() failed: errno = %d",errno);
      goto error_ret0;
      }
   IPCC[cid].accept = xcid;
   break;
#endif

   case NETW | IPC_READ:	/* open channel in server mode, network */

   pin.sin_addr.s_addr = htonl (INADDR_ANY);

/*
fprintf(fid,"osxopen:  case NETW | IPC_READ\n");
printf("osxopen:  case NETW | IPC_READ\n");
*/

   if (bind (xcid, (struct sockaddr *) &pin, sizeof (pin)) < 0)
      {
      (void) sprintf(messg,"NETW bind() failed: errno = %d",errno);
      goto error_ret0;
      }

   if (listen (xcid, NETW_QUEUE_LENGTH) == -1)
      {
      (void) sprintf(messg,"NETW listen() failed: errno = %d",errno);
      goto error_ret0;
      }
   break;

   case NETW | IPC_WRITE:	/* open channel in client mode, network */

/*
fprintf(fid,"osxopen:  case NETW | IPC_WRITE\n");
printf("osxopen:  case NETW | IPC_WRITE\n");
*/

   if ((hp = gethostbyname (channame[1])) == NULL)
      {
      (void) strcpy(messg,"osxopen: unable to open host");
      goto error_ret0;
      }
   memcpy ((char *) &pin.sin_addr, hp->h_addr_list[0], hp->h_length);

   if (connect (xcid, (struct sockaddr *) &pin, sizeof (pin)) < 0)
      {
      (void) sprintf(messg,"NETW connect() failed: errno = %d",errno);
      goto error_ret0;
      }

   IPCC[cid].accept = xcid;
   break;

   default:
   (void) strcpy(messg,"osxopen: unknown open mode");
   oserror = -1;
   goto error_ret1;
   }


/*
fprintf(fid,"osxopen: xcid = %d, cid = %d, IPCC[%d].accept = %d\n", xcid,cid,cid,IPCC[cid].accept);
printf("osxopen: xcid = %d, cid = %d, IPCC[%d].accept = %d\n", xcid,cid,cid,IPCC[cid].accept);
*/

return (xcid);


/* problems, problems, ... */

error_ret0:
oserror = errno;

error_ret1:
indxIPCC[cid] = -1;

error_ret2:
(void) close (xcid);

error_ret3:
oserrmsg = messg;
return (-1);
}


/*
int  osxexit(m)
int  m;

{
int   ret;

fprintf(fid,"osxexit .......\n");
ret = fclose(fid);

return 0;
}
*/


int osxclose (xcid)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.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:
 -- UNIX: close(2), unlink(2)
------------------------------------------------------------*/
int xcid;                                /* channel identification */

{
int  n, cid;

char   *name1;




/* find slot in indxIPCC containing xcid */

for (n=0; n<MAX_IPCC; n++)
   {
   if (indxIPCC[n] == xcid)
      {
      cid = n;                  /* that's the index into IPCC */
      goto next_step;
      }
   }

oserrmsg = msg0;
RET_ERROR (-1);



next_step:
indxIPCC[cid] = -1;			/* mark index as free */

close (xcid);

/*
fprintf(fid,"osxclose: xcid = %d, cid = %d\n",xcid,cid);
printf("osxclose: xcid = %d, cid = %d\n",xcid,cid);
*/


/* close any connection accepted */

if ((IPCC[cid].accept != xcid) && (IPCC[cid].accept != 0))
   close (IPCC[cid].accept);


/* suppress the associated unix socket file */

if ((IPCC[cid].type == LOCAL) && (IPCC[cid].omode == IPC_READ))
   {
   if (unlink (IPCC[cid].chname) == -1) RET_ERROR (errno);
   }

name1 = (IPCC[cid].chname);
if (name1 != (char *) 0) free (name1);


/*
fprintf(fid,"osxclose: cchname = %s,\n",name1);
printf("osxclose: chname = %s,\n",name1);
*/

return (0);
}


int osxread (xcid, pbuf, nobyt)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.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, osxread return the number of bytes
	 actually read and placed in the buffer. If the returned values is
         0, then EOF has been reached. Otherwise, a -1 is returnde and the
	 gloval variable oserror is set to indicate the error.
         (The function osxwait must be called after the asynchronous read.
	 NOT IMPLEMENTED YET)
.REMARKS System dependencies:
 -- UNIX: accept(2),close(2),read(2)
------------------------------------------------------------*/
int xcid;			/* channel identification */
char *pbuf;			/* pointer to input buffer */
int nobyt;			/* number of input bytes */

{
int   n, cid, ns, nb, stat;




/* find slot in indxIPCC containing xcid */

for (n=0; n<MAX_IPCC; n++)
   {
   if (indxIPCC[n] == xcid)
      {
      cid = n;                  /* that's the index into IPCC */
      goto next_step;
      }
   }

oserrmsg = msg0;
RET_ERROR (-1);



next_step:
if (nobyt <= 0) return (0);


/*
fprintf(fid,"osxread: xcid = %d, cid = %d\n",xcid,cid);
printf("osxread: xcid = %d, cid = %d\n",xcid,cid);
*/

if ((ns = IPCC[cid].accept) == 0)
   {
   if ((stat = osxstat (xcid, 0, 0)) == -1) RET_ERROR (errno);

   if (stat == 0) RET_ERROR (ENOTCONN);

   if ((ns = accept (xcid, (struct sockaddr *) 0, (XSOCKLEN *) 0)) == -1)
      RET_ERROR (errno);

   IPCC[cid].accept = ns;
   }

if ((nb = readn (ns, pbuf, nobyt)) == -1) RET_ERROR (errno);

if (nb == 0)
   {
   if (IPCC[cid].omode == IPC_READ) IPCC[cid].accept = 0;

   if (close (ns) == -1) RET_ERROR (errno);
   }

return (nb);
}


int osxwrite (xcid, pbuf, nobyt)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.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  returns the number of bytes actually
	 written. Otherwise -1 is returned an the global variable oserror
	 is set to indicate the error.
.REMARKS System dependencies:
 -- UNIX: connect(2), write(2), ospwait(0)
------------------------------------------------------------*/
int xcid;			/* channel identification */
char *pbuf;			/* pointer to output buffer */
int nobyt;			/* number of output bytes */

{
int   n, cid, stat, nb, ns;



/* find slot in indxIPCC containing xcid */

for (n=0; n<MAX_IPCC; n++)
   {
   if (indxIPCC[n] == xcid)
      {
      cid = n;                  /* that's the index into IPCC */
      goto next_step;
      }
   }

oserrmsg = msg0;
RET_ERROR (-1);



next_step:

/*
fprintf(fid,"osxwrite: xcid = %d, cid = %d\n",xcid,cid);
printf("osxwrite: xcid = %d, cid = %d\n",xcid,cid);
*/
 
if ((ns = IPCC[cid].accept) == 0)
   {
   if ((stat = osxstat (xcid, 0, 0)) == -1) RET_ERROR (errno);

   if (stat == 0) RET_ERROR (ENOTCONN);

   if ((ns = accept (xcid, (struct sockaddr *) 0, (XSOCKLEN *) 0)) == -1)
      RET_ERROR (errno);

   IPCC[cid].accept = ns;
   }


if ((nb = writen (ns, pbuf, nobyt)) < 0)
   {
   if (IPCC[cid].omode == IPC_READ)
      {
      IPCC[cid].accept = 0;

      if (close (ns) == -1) RET_ERROR (errno);
      RET_ERROR (ENOTCONN);
      }
   }


return (nb);
}

int osxinfo (xcid, sec, usec)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Gets status of the interprocess communication channel.
.RETURNS Upon successful the status of the channel is returned:
	 DATARDY if there is data to be read.
	 NODATA  if there is no data available.
	 NOCONN  if there is no connection.
	 On error -1 is returned , and the variable oserror set.
.REMARKS System dependencies:
 -- UNIX: select
------------------------------------------------------------*/
int xcid;			/* channel identification */
int sec, usec;			/* Timeout in seconds and microseconds */

{
int   n, cid, ns, stat;



/* find slot in indxIPCC containing xcid */

for (n=0; n<MAX_IPCC; n++)
   {
   if (indxIPCC[n] == xcid)
      {
      cid = n;                  /* that's the index into IPCC */
      goto next_step;
      }
   }

oserrmsg = msg0;
RET_ERROR (-1);



next_step:

/*
fprintf(fid,"osxinfo: xcid = %d, cid = %d, IPCC[cid].accept = %d\n",
xcid,cid,IPCC[cid].accept);
printf("osxinfo: xcid = %d, cid = %d, IPCC[cid].accept = %d\n",
xcid,cid,IPCC[cid].accept);
*/

if ((ns = IPCC[cid].accept) == 0)
   {
   if ((stat = osxstat (xcid, sec, usec)) == -1) RET_ERROR (errno);

   if (stat == 0) return (NOCONN);

   if ((ns = accept (xcid, (struct sockaddr *) 0, (XSOCKLEN *) 0)) == -1)
      RET_ERROR (errno);

   IPCC[cid].accept = ns;
   }


if ((stat = osxstat (ns, sec, usec)) < 0) return (NOCONN);

return (stat ? DATARDY : NODATA);
}


int osxgetservbyname (service)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Interface to the getservbyname().
.RETURNS The port number, or -1 if no port.
.REMARKS System dependencies:
 -- UNIX: getservbyname
------------------------------------------------------------*/
char *service;

{
struct servent *sp;

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