/*
 *	Network Queueing System (NQS)
 *  This version of NQS is Copyright (C) 1992  John Roman
 *
 *  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 1, 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 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
*  PROJECT:     Network Queueing System
*  AUTHOR:      John Roman
*
*  Modification history:
*
*       Version Who     When            Description
*       -------+-------+---------------+-------------------------
*       V01.10  JRR                     Initial version.
*       V01.2   JRR     28-Feb-1992	Added Cosmic V2 changes.
*	V01.3	JRR	17-Jun-1992	Added header.
*	V01.4	JRR	07-Dec-1992	Modified for C prototypes.
*	V01.5	JRR	23-Feb-1993	Added Boeing enhancement for Mids.
*	V01.6	JRR	12-Aug-1993	Removed non-networked code.
*	V01.7	JRR	15-Mar-1994	Debugging work.
*/
/*++ pipeqreq.c - Network Queueing System
 *
 * $Source: /usr2/jrroma/nqs/nqs-3.35.6/lib/RCS/pipeqreq.c,v $
 *
 * DESCRIPTION:
 *
 *	Attempt to queue a request at the designated pipe queue
 *	destination.
 *
 *
 *	WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING
 *	WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING
 *	WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING
 *
 *
 *		This module cannot be readily changed,
 *		since it is responsible for building
 *		part of the contents of an NPK_QUEREQ
 *		network packet, a packet which must
 *		be recognizable by other NQS machines.
 *
 *
 *	END OF WARNING *** END OF WARNING *** END OF WARNING *** END OF WARNING
 *	END OF WARNING *** END OF WARNING *** END OF WARNING *** END OF WARNING
 *	END OF WARNING *** END OF WARNING *** END OF WARNING *** END OF WARNING
 *
 *
 *	Author:
 *	-------
 *	Brent A. Kingsbury, Sterling Software Incorporated.
 *	May 20, 1986.
 *
 *
 * STANDARDS VIOLATIONS:
 *   None.
 *
 * REVISION HISTORY: ($Revision: 1.7 $ $Date: 1994/03/30 20:32:38 $ $State: Exp $)
 * $Log: pipeqreq.c,v $
 * Revision 1.7  1994/03/30  20:32:38  jrroma
 * Version 3.35.6
 *
 * Revision 1.6  93/09/10  13:55:18  jrroma
 * Version 3.35
 * 
 * Revision 1.5  93/07/13  21:31:32  jrroma
 * Version 3.34
 * 
 * Revision 1.4  92/12/22  15:46:21  jrroma
 * Version 3.30
 * 
 * Revision 1.3  92/06/18  13:24:26  jrroma
 * Added gnu header
 * 
 * Revision 1.2  92/02/28  15:23:49  jrroma
 * Added Cosmic V2 changes.
 * 
 * Revision 1.1  92/02/28  15:21:24  jrroma
 * Initial revision
 * 
 *
 */

#include "nqs.h"			/* NQS types and definitions */
#include "netpacket.h"			/* NQS Network packet types */
#include "nqspacket.h"			/* NQS local packet types */
#include "transactcc.h"			/* NQS transaction completion codes */
#include <errno.h>



/*** pipeqreq
 *
 *
 *	long pipeqreq():
 *
 *	Attempt to queue a request at the designated pipe queue
 *	destination.  If successful, *sd will contain the socket
 *	descriptor of the connection.
 *
 *	Expected returns values:
 *		TCML_ACCESSDEN:	 Queue access denied at local host destination.
 *		TCMP_ACCESSDEN:  Queue access denied at remote peer
 *				 destination.
 *		TCML_BADCDTFIL:	 Local machine destination garbled the request.
 *		TCMP_BADCDTFIL:  Remote peer destination machine garbled the
 *				 request.
 *		TCMP_CONNBROKEN: Connection broken.
 *		TCMP_CONNTIMOUT: Connection timed-out.
 *		TCMP_CONTINUE:	 Request queued successfully, continue
 *				 queueing operation via 2-phase commit.
 *		TCML_ENFILE:	 File descriptor shortage at local host
 *				 destination.
 *		TCMP_ENFILE:	 File descriptor shortage at remote peer
 *				 destination.
 *		TCML_ENOSPC:	 File system resource shortage at local host
 *				 destination.
 *		TCMP_ENOSPC:	 File system resource shortage at remote peer
 *				 destination.
 *		TCML_ERRORRETRY: An error condition occurred at the local host
 *				 destination which may go away in the near
 *				 future.
 *		TCMP_ERRORRETRY: An error condition occurred at the remote peer
 *				 destination which may go away in the near
 *				 future.
 *		TCML_ETIMEDOUT:	 Connect(2) timed out at local host.
 *		TCML_FATALABORT: Non-retriable error condition at local host
 *				 destination.
 *		TCMP_FATALABORT: Non-retriable error condition at remote peer
 *				 destination.
 *		TCML_INSQUESPA:	 Insufficient queue space at local host
 *				 destination.
 *		TCMP_INSQUESPA:  Insufficient queue space at remote peer
 *				 destination.
 *		TCML_INTERNERR:	 Internal error on local host destination.
 *		TCMP_INTERNERR:	 Internal error at remote peer destination.
 *		TCML_NOLOCALDAE: No NQS local daemon at local host destination!
 *		TCMP_NOLOCALDAE: No NQS local daemon at remote peer destination.
 *		TCMP_NONETDAE:   No NQS net daemon at remote peer destination.
 *		TCML_NOSUCHFORM: No such form at local host destination.
 *		TCMP_NOSUCHFORM: No such form at remote peer destination.
 *		TCML_NOSUCHQUE:	 No such queue at local host destination.
 *		TCMP_NOSUCHQUE:  No such queue at remote peer destination.
 *		TCML_PATHLEN:	 Resolved path of batch request exceeds maximum
 *				 supported length at local host destination.
 *		TCMP_PATHLEN:	 Resolved path of batch request exceeds maximum
 *				 supported length at remote peer destination.
 *		TCML_PROTOFAIL:	 NQS protocol failure error at local host.
 *		TCMP_PROTOFAIL:  NQS protocol failure error at remote peer
 *				 destination, or protocol failure between the
 *				 local host and the remote peer.
 *		TCML_QUEDISABL:	 Destination queue at local host is disabled.
 *		TCMP_QUEDISABL:	 Destination queue at remote peer is disabled.
 *		TCML_QUOTALIMIT: Destination queue quota limits exceeded at
 *				 local host.
 *		TCMP_QUOTALIMIT: Destination queue quota limits exceeded at
 *				 remote peer host.
 *		TCML_REQCOLLIDE: Request collided with existing request at
 *				 local host destination.
 *		TCMP_REQCOLLIDE: Request collided with existing request at
 *				 remote peer destination.
 *		TCML_SUBMITTED:	 Request successfully submitted to local
 *				 host destination.
 *		TCMP_SUBMITTED:	 Request successfully submitted to remote
 *				 peer destination.
 *		TCMP_RRFUNKNMID: Machine-id value in request is unknown at
 *				 remote peer destination.
 *		TCML_UNAFAILURE: Unanticipated failure at local host.
 *		TCMP_UNAFAILURE: Unanticipated failure at remote peer.
 *		TCML_WROQUETYP:	 Destination queue at local host is wrong
 *				 type for request.
 *		TCMP_WROQUETYP:	 Destination queue at remote peer is wrong
 *				 type for request.
 */
long pipeqreq (
	long destmid,			/* Destination machine id */
	char *destqueue,		/* Destination queue */
	struct rawreq *rawreq,		/* Raw request to be packaged */
	int cuid,			/* Client user id */
	char *cusername,		/* Client username */
	int *sd)			/* Where to put socket descriptor */
{
	typedef unsigned long longcard;	/* Less typing */

	long locmid;			/* Local machine id */
	long transactcc;		/* Transaction completion code */
	short timeout;			/* Seconds */
	register short i;		/* Loop var */
	char packet [MAX_PACKET];	/* Message packet buffer */
	int packetsize;			/* Bytes in this packet */
	int integers;			/* Number of integers received */
	int strings;			/* Number of strings received */

	/*
	 * NOTE, We will be relying on the signal (SIGPIPE, fn) handler
	 * created by the call to establish() to convert SIGPIPE signals
	 * to errno = EPIPE.
	 */
	
	interclear ();
	if (localmid ((Mid_t *)&locmid) != 0) {
		return (TCML_SELMIDUNKN);
	}
	if (destmid == locmid) {
		interw32i (rawreq->orig_seqno);
		interw32u (rawreq->orig_mid);
		interwstr (destqueue);
		transactcc = inter (PKT_QUEREQVLPQ);
		return (transactcc);
	}
	/*
	 * Only remote destinations get to this point.
	 * Establish connection to destination machine.
	 */
	*sd = establish (NPK_QUEREQ, destmid, cuid, cusername, &transactcc);
	if (*sd < 0) {
		if (*sd == -2) {
			/*
			 *  Retry is in order.
			 */
			timeout = 1;
			do {
				nqssleep (timeout);
				interclear ();
				*sd = establish (NPK_QUEREQ, destmid,
						 cuid, cusername,
						 &transactcc);
				timeout *= 2;
			} while (*sd == -2 && timeout <= 2);
			/*
			 * Beyond this point, give up on retry.
			 */
			if (*sd < 0) return (transactcc);
		}
		else return (transactcc);
	}
	interclear ();
	/*
	 *  Define packet contents.
	 */
	interwstr (destqueue);		/* Destination queue */
	interw32i ((long) rawreq->magic1);
	interw32u ((longcard) rawreq->create_time);
	interw32u ((longcard) rawreq->enter_time);
	interw32i ((long) rawreq->type);
	interw32i ((long) rawreq->orig_uid);
	interw32u (rawreq->orig_mid);
	interw32i ((long) rawreq->orig_seqno);
	interw32i ((long) rawreq->rpriority);
	interw32i ((long) rawreq->flags);
	interw32u ((longcard) rawreq->start_time);
	interw32i ((long) rawreq->ndatafiles);
	interwstr (rawreq->reqname);
	interwstr (rawreq->username);
	interwstr (rawreq->mail_name);
	interw32u (rawreq->mail_mid);
	if (rawreq->type == RTYPE_DEVICE) {
		/*
		 *  We are packaging a device request.
		 */
		interwstr (rawreq->v.dev.forms);
		interw32i ((long) rawreq->v.dev.copies);
		interw32i ((long) rawreq->v.dev.reserved1);
		interw32i ((long) rawreq->v.dev.reserved2);
		interw32u ((longcard) rawreq->v.dev.size);
		for (i = 0; i < MAX_DEVPREF; i++) {
			interwstr (rawreq->v.dev.devprefname [i]);
			interw32u (rawreq->v.dev.devprefmid [i]);
		}
	}
	else {
		/*
		 *  We are packaging a batch request.
		 */
		interw32i ((long) rawreq->v.bat.umask);
		interwstr (rawreq->v.bat.shell_name);
		interw32i ((long) rawreq->v.bat.explicit);
		interw32i ((long) rawreq->v.bat.infinite);
		/*
		 *  Package per-process corefile size limits.
		 */
		interw32u ((longcard) rawreq->v.bat.ppcoresize.max_quota);
		interw32i ((long) rawreq->v.bat.ppcoresize.max_units);
		interw32u ((longcard) rawreq->v.bat.ppcoresize.warn_quota);
		interw32i ((long) rawreq->v.bat.ppcoresize.warn_units);
		/*
		 *  Package per-process data-segment size limits.
		 */
		interw32u ((longcard) rawreq->v.bat.ppdatasize.max_quota);
		interw32i ((long) rawreq->v.bat.ppdatasize.max_units);
		interw32u ((longcard) rawreq->v.bat.ppdatasize.warn_quota);
		interw32i ((long) rawreq->v.bat.ppdatasize.warn_units);
		/*
		 *  Package per-process permanent file size limits.
		 */
		interw32u ((longcard) rawreq->v.bat.pppfilesize.max_quota);
		interw32i ((long) rawreq->v.bat.pppfilesize.max_units);
		interw32u ((longcard) rawreq->v.bat.pppfilesize.warn_quota);
		interw32i ((long) rawreq->v.bat.pppfilesize.warn_units);
		/*
		 *  Package per-request permanent file space limits.
		 */
		interw32u ((longcard) rawreq->v.bat.prpfilespace.max_quota);
		interw32i ((long) rawreq->v.bat.prpfilespace.max_units);
		interw32u ((longcard) rawreq->v.bat.prpfilespace.warn_quota);
		interw32i ((long) rawreq->v.bat.prpfilespace.warn_units);
		/*
		 *  Package per-process quick file size limits.
		 */
		interw32u ((longcard) rawreq->v.bat.ppqfilesize.max_quota);
		interw32i ((long) rawreq->v.bat.ppqfilesize.max_units);
		interw32u ((longcard) rawreq->v.bat.ppqfilesize.warn_quota);
		interw32i ((long) rawreq->v.bat.ppqfilesize.warn_units);
		/*
		 *  Package per-request quick file space limits.
		 */
		interw32u ((longcard) rawreq->v.bat.prqfilespace.max_quota);
		interw32i ((long) rawreq->v.bat.prqfilespace.max_units);
		interw32u ((longcard) rawreq->v.bat.prqfilespace.warn_quota);
		interw32i ((long) rawreq->v.bat.prqfilespace.warn_units);
		/*
		 *  Package per-process temporary file size limits.
		 */
		interw32u ((longcard) rawreq->v.bat.pptfilesize.max_quota);
		interw32i ((long) rawreq->v.bat.pptfilesize.max_units);
		interw32u ((longcard) rawreq->v.bat.pptfilesize.warn_quota);
		interw32i ((long) rawreq->v.bat.pptfilesize.warn_units);
		/*
		 *  Package per-request temporary file space limits.
		 */
		interw32u ((longcard) rawreq->v.bat.prtfilespace.max_quota);
		interw32i ((long) rawreq->v.bat.prtfilespace.max_units);
		interw32u ((longcard) rawreq->v.bat.prtfilespace.warn_quota);
		interw32i ((long) rawreq->v.bat.prtfilespace.warn_units);
		/*
		 *  Package per-process memory size limits.
		 */
		interw32u ((longcard) rawreq->v.bat.ppmemsize.max_quota);
		interw32i ((long) rawreq->v.bat.ppmemsize.max_units);
		interw32u ((longcard) rawreq->v.bat.ppmemsize.warn_quota);
		interw32i ((long) rawreq->v.bat.ppmemsize.warn_units);
		/*
		 *  Package per-request memory size limits.
		 */
		interw32u ((longcard) rawreq->v.bat.prmemsize.max_quota);
		interw32i ((long) rawreq->v.bat.prmemsize.max_units);
		interw32u ((longcard) rawreq->v.bat.prmemsize.warn_quota);
		interw32i ((long) rawreq->v.bat.prmemsize.warn_units);
		/*
		 *  Package per-process stack-segment size limits.
		 */
		interw32u ((longcard) rawreq->v.bat.ppstacksize.max_quota);
		interw32i ((long) rawreq->v.bat.ppstacksize.max_units);
		interw32u ((longcard) rawreq->v.bat.ppstacksize.warn_quota);
		interw32i ((long) rawreq->v.bat.ppstacksize.warn_units);
		/*
		 *  Package per-process working set size limits.
		 */
		interw32u ((longcard) rawreq->v.bat.ppworkset.max_quota);
		interw32i ((long) rawreq->v.bat.ppworkset.max_units);
		interw32u ((longcard) rawreq->v.bat.ppworkset.warn_quota);
		interw32i ((long) rawreq->v.bat.ppworkset.warn_units);
		/*
		 *  Package per-process CPU time limits.
		 */
		interw32u ((longcard) rawreq->v.bat.ppcputime.max_seconds);
		interw32i ((long) rawreq->v.bat.ppcputime.max_ms);
		interw32u ((longcard) rawreq->v.bat.ppcputime.warn_seconds);
		interw32i ((long) rawreq->v.bat.ppcputime.warn_ms);
		/*
		 *  Package per-request CPU time limits.
		 */
		interw32u ((longcard) rawreq->v.bat.prcputime.max_seconds);
		interw32i ((long) rawreq->v.bat.prcputime.max_ms);
		interw32u ((longcard) rawreq->v.bat.prcputime.warn_seconds);
		interw32i ((long) rawreq->v.bat.prcputime.warn_ms);
		/*
		 *  Package remaining batch request fields.
		 */
		interw32i ((long) rawreq->v.bat.ppnice);
		interw32i ((long) rawreq->v.bat.prdrives);
		interw32i ((long) rawreq->v.bat.prncpus);
		for (i=0; i < MAX_PREDECESSOR; i++) {
			interwstr (rawreq->v.bat.predecessors [i]);
		}
		interw32i ((long) rawreq->v.bat.stderr_acc);
		interw32i ((long) rawreq->v.bat.stdlog_acc);
		interw32i ((long) rawreq->v.bat.stdout_acc);
		interw32u (rawreq->v.bat.stderr_mid);
		interw32u (rawreq->v.bat.stdlog_mid);
		interw32u (rawreq->v.bat.stdout_mid);
		interwstr (rawreq->v.bat.stderr_name);
		interwstr (rawreq->v.bat.stdlog_name);
		interwstr (rawreq->v.bat.stdout_name);
		interw32i ((long) rawreq->v.bat.instacount);
		interw32i ((long) rawreq->v.bat.oustacount);
		interw32i ((long) rawreq->v.bat.instahiermask);
		interw32i ((long) rawreq->v.bat.oustahiermask);
		for (i=0; i < MAX_INSTAPERREQ; i++) {
			interw32u (rawreq->v.bat.instamid [i]);
		}
		for (i=0; i < MAX_OUSTAPERREQ; i++) {
			interw32u (rawreq->v.bat.oustamid [i]);
		}
	}
	/*
	 *  Transmit packet 2 to the destination machine on
	 *  the established socket connection.
	 */
	if ((packetsize = interfmt (packet)) == -1) {
		/*
		 *  The packet contents are too large.
		 */
		close (*sd);	/* Close connection */
		return (TCML_INTERNERR);	/* Local internal error */
	}
	if (write (*sd, packet, packetsize) != packetsize) {
		/*
		 *  Error sending NPK_QUEREQ to destination.
		 */
		close (*sd);	/* Close connection */
		return (TCML_ERRORRETRY);/* Remote server "bit the dust" */
	}
	switch (interread (getsockch)) {
	case 0:
		break;
	case -1:
		return (TCMP_CONNBROKEN);
	case -2:
		return (TCMP_PROTOFAIL);
	}
	integers = intern32i ();
	strings = internstr ();
	if (integers == 1 && strings == 0) {
		return (interr32i (1));
	}
	else return (TCMP_PROTOFAIL);
}
