static char dqs_io_rcsid[]="$Id: dqs_io.c,v 1.1.1.1 1998/08/18 14:39:11 green Exp $";

/*----------------------------------------------------
 * dqs_io.c Tom Green Mon Jan 31 10:42:46 1994
 *
 * Copyright 1993
 *
 * SUPER COMPUTER COMPUTATIONS RESEARCH INSTITUTE
 *            FLORIDA STATE UNIVERSITY
 *
 *
 * SCRI representatives make no claims about the
 * suitability of this software for any purpose.
 * It is provided "as is" without express or
 * implied warranty.
 *
 * $Log: dqs_io.c,v $
 * Revision 1.1.1.1  1998/08/18 14:39:11  green
 * DQS 3.2.0.5 WIP Import
 *
 * Revision 1.1.1.1  1997/04/10 15:10:32  green
 * DQS 3.1.3.4.1 Distribution
 *
 * Revision 3.10  1996/08/28 23:35:07  nrl
 * Ron Lee repaired a problem when qconf has a
 * communications error on a Solaris 2.5 machine. The repair
 * will work on all other platforms.
 *
 * Revision 3.9  1996/07/19  12:04:05  nrl
 * Changes to fix "non existent resources"
 *
 * Revision 3.8  1996/07/14  14:59:28  nrl
 * Added DEFINES and INCLUDES to GNU configure output
 *
 * Revision 3.7  1996/03/22  04:20:32  nrl
 * Added error cataloguing number to all routines
 *
 * Revision 3.6  1996/01/10  13:52:36  nrl
 * Base for 3.1.3
 *
 * Revision 3.5  1995/05/26  19:07:36  nrl
 * Cleaned up signal handling and the notify option with the
 * help of Ron Lee.
 *
 * Revision 3.4  1995/03/05  03:47:14  nrl
 * Included Axel Brandes job scheduling mechanism to keep one
 * user from hawging the queue.
 *
 * Revision 3.3  1995/01/30  15:21:55  nrl
 * added "tid" verification between execd and qmaster to prevent
 * "ghost" jobs from persisting in visible queue. Changed ERROR messages
 * which were for information only to DEBUG messages.
 *
 * Revision 3.2  1995/01/27  14:09:38  nrl
 * Changed Supspend on completion to continue beyond an unsuspend operation
 * so that jobs can be "stepped" thru the queues. Increased timout
 * retries for connect to make the system more tolerant of network delyas.
 *
 * Revision 3.1  1994/08/14  00:19:03  green
 * added retry code
 *
 * Revision 3.0  1994/03/07  04:13:54  green
 * 3.0 freeze
 *
 * Revision 1.1.1.1  1994/02/01  17:57:42  green
 * DQS 3.0 ALPHA
 *
 *--------------------------------------------------*/


#include "h.h"
#include "def.h"
#include "dqs.h"
#include "struct.h"
#include "func.h"
#include "globals.h"

/************************************************************************/
int dqs_open_tcp (host, port, service, reserved_port)
     char *host;		
     int port; 		
     char *service; 		
     int reserved_port;	
     
     /*
       dqs_open_tcp - open TCP connection.
       
       entry:      host = pointer to hostname
       port = 0, get port number from service entry
       > 0, use specified port number
       service = pointer to service name
       reserved_port  = 0, open socket using non-privileged port
       != 0, open socket using only privileged port
       exit:       returns file descriptor to opened socket
     */
     
{
  
  int retry=0;
  struct sockaddr_in addr;		/* socket address structure */
  struct hostent *he;			/* pointer to host entry */
  int rc;				        /* return code */
  struct servent *se;			/* pointer to service entry */
  int sfd;				/* socket file descriptor */
  uid_t     myuid;   
  DENTER((DQS_EVENT,"dqs_open_tcp"));
  
#if  _BSD == 44
  DPRINTF((DQS_EVENT,"found _BSD == 44 "));
#endif
  
  he = gethostbyname (host);
  if (he == (struct hostent *)NULL)
    {                
      WARNING((DQS_EVENT,"DQS_ERROR_0252 dqs_open_tcp: cannot resolve hostname %s", host));
      DEXITE;
      return (-1);
    } /* if */
  
  /* Initialize socket address structure */
  bzero ((char *)&addr, sizeof(addr));   
  addr.sin_family = AF_INET;
  bcopy ((char *)he->h_addr, (char *)&addr.sin_addr, he->h_length);
  
  /* Set port number */
  if (port > 0) 
    {
      INFO((DQS_EVENT,"DQS_ERROR_0253 dqs_open_tcp: using port %d", port));
      addr.sin_port = port;
    } 
  else 
    {			/* get port number from service entry */
      DPRINTF((DQS_EVENT,"open_tcp: using service %s", service));
      se = getservbyname (service, "tcp");
      if (se == (struct servent *)NULL)
	{
	  WARNING((DQS_EVENT,"DQS_ERROR_0254 dqs_open_tcp: cannot get service entry for %s",service));
	  DEXITE;
	  return (-1);
	} /* if */
      DPRINTF((DQS_EVENT,"dqs_open_tcp: using service port %d", se->s_port));
      addr.sin_port = se->s_port;
    } /* if */
  
  myuid= getuid();
  DPRINTF((DQS_EVENT,"dqs open tcp myuid is %d", myuid) );
 retry_socket:			/* Get a fresh socket file descriptor */
  /* Get socket */
  if (reserved_port) 
    {
      retry=0;
      do{
     	
	DPRINTF((DQS_EVENT,"open_tcp: using reserved port"));
	rc = IPPORT_RESERVED - 1; 
	
	sfd = rresvport (&rc);
	if (sfd < 0) {
	  WARNING((DQS_EVENT,"DQS_ERROR_0255 dqs_open_tcp: rresvport() failed  %d %d",rc, errno));
	  DEXITE;
	  return (-1);
	} /* if */
	if(sfd==0){
	  retry++;
	  if(retry>10){
	    WARNING((DQS_EVENT,"DQS_ERROR_0255a dqs_open_tcp: rresvport() failed  %d %d",rc, errno));
	    DEXITE;
	    return (-1);
	  } /* if */
	}
	
      }while (sfd == 0);      
    } 
  else 
    {
      DPRINTF((DQS_EVENT,"creating socket"));
      if ((sfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) 
	{
	  WARNING((DQS_EVENT,"DQS_ERROR_0256 dqs_open_tcp: unable to create socket"));
	  DEXITE;
	  return (-1);
	} /* if */
    } /* if */
  
  DPRINTF((DQS_EVENT,"SFD=%d",sfd));
  
  /* Connect to peer */
  
 retry_connect:
  rc = connect (sfd, (struct sockaddr *)&addr, sizeof(addr));
  if (rc < 0) {
    if ((retry++ < 20 )&&(me.who!=QMASTER)&&(me.who!=DQS_EXECD))
      {
	sleep(dqs_rand(1,3)) ;
	close (sfd);		/* Solaris must close socket file descriptor */
	goto retry_socket;	/* before retry on connect.  Need new socket */
      }
    perror ("connect");
    close (sfd);
    WARNING((DQS_EVENT,"DQS_ERROR_0257 dqs_open_tcp: cannot connect to peer %s errno= %d"
	     ,host, errno));
    DEXITE;
    return (-1);
  } /* if */
  
  DPRINTF((DQS_EVENT,"dqs_open_tcp: connected to peer %s", host));
  DEXIT;
  return (sfd);
  
} /* dqs_open_tcp */

/************************************************************************/
int dqs_readnbytes(sfd, ptr, n)
     register int sfd;		
     register char *ptr;		
     register int n;			
     
     /*
       dqs_readnbytes - read n bytes from file descriptor 
     */
     
{
  
  int i;				/* number of bytes read */
  int nleft = n;			/* number of bytes still to read */
  
  DENTER_EXT((DQS_EVENT,"dqs_readnbytes"));
  DPRINTF((DQS_EVENT,"TOTAL BYTES TO BE READ %d",n));
  
  /* Read n bytes */
  while (nleft > 0) {
    i = read (sfd, ptr, nleft);
    DPRINTF((DQS_EVENT,"read %d bytes on fd %d", i, sfd));
    
    if (i < 0) {
      DPRINTF((DQS_EVENT,"dqs_readnbytes: returning %d", i));
      DEXITE;
      return (i);
    } else {
      if (i == 0)
	break;
    } /* if */
    nleft -= i;
    ptr += i;
  } /* while */
  
  DPRINTF((DQS_EVENT,"dqs_readnbytes: returning %d", nleft));
  DEXIT;
  return (n-nleft);
  
} /* dqs_readnbytes */

/************************************************************************/
int dqs_writenbytes (sfd, ptr, n)
     register int sfd;		
     register char *ptr;		
     register int n;			
     
     /*
       dqs_writenbytes - write n bytes to file descriptor
     */
     
{
  
  int i;			/* number of bytes written */
  int nleft = n;		/* number of bytes still to write */
  
  DENTER_EXT((DQS_EVENT,"dqs_writenbytes"));
  
  /* Write n bytes */
  while (nleft > 0) {
    DTRACE;
    i = write (sfd, ptr, nleft);
    DPRINTF((DQS_EVENT,"wrote %d bytes on fd %d", i, sfd));
    
    if (i <= 0) {
      DPRINTF((DQS_EVENT, "dqs_writenbytes: returning %d", i));
      DEXITE;
      return (i);
    } /* if */
    nleft -= i;
    ptr += i;
  } /* while */
  
  DEXIT;
  return (n);
  
} /* dqs_writenbytes */

/************************************************************************/
int dqs_readstring(fd,ptr)
     register int fd;
     register char *ptr;
     
     /*
       dqs_readstring - read string file descriptor 
     */
     
{
  
  int i=0;                /* number of bytes read */
  char *cp=ptr;
  
  DENTER_EXT((DQS_EVENT,"dqs_readstring"));
  
  for (;;)
    {
      i+=read(fd,cp,1);
      
      if (!cp[0])
	{
	  DEXIT;
	  return(i);
	}
      if (i>=MAX_STRING_SIZE)
	{
	  WARNING((DQS_EVENT,"DQS_ERROR_0258 MAX_STRING_SIZE exceeded"));
	  DEXITE;
	  return(-1);
	}
      
      cp++;
    }
  
}
