static char dqs_io_rcsid[]="$Id: dqs_io.c,v 1.1.1.1 1997/04/10 15:10:32 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  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++;
     }

}
