Google
 

Trailing-Edge - PDP-10 Archives - decuslib10-08 - 43,50512/qsrmsg.b36
There are no other files named qsrmsg.b36 in the archive.
MODULE QSRMSG=
!Routines to talk to QUASAR
!FACILITY: NETSPL
!ENVIRONMENT: TOPS-10 6.03 or later
!		also requires use of condition handlers for NETSPL
!
!THESE ROUTINES USE AND MODIFY GLOBAL STORAGE
BEGIN

!
! Table of Contents
!

FORWARD ROUTINE
IPCINI,
GET_QUASAR_PID,
HELLO,
DONEXTJOB,
RELJOB,
REQJOB,
QMRECV,
QSRACK,
GETPID,
IPCSND,		!Send a message to [SYSTEM]IPCC
MSSEND,		!Send a message to anywhere
MSRECV,		!Receive a message
IPCQCK;		!Check IPCF receive queue

!
! Libraries & REQUIRE files
!
REQUIRE 'INTR.REQ';
LIBRARY 'DAPLIB';

!
! Version
!
THIS_IS [QSRM]	VERSION [1]	EDIT [4]	DATE [25,OCT,79]
![4]	No ACKs for REQJOB and RELJOB
![3]	Set mode of local file to ASCII if requested

!
! Macros
!
MACRO SEND_QUASAR(PACK,FLG)=
	BEGIN
	COMPILETIME PAGEFLG=%IF %NULL(FLG) %THEN 0 %ELSE FLG %FI;
	EXTERNAL ROUTINE MSGSND;
	MSGSND(PACK,PAGEFLG)
	END%;

MACRO PREFIX='NJR' %;

!
!LITERALS
!
LITERAL IPCFR_=%O'142';		!IPCF receive
LITERAL IPCFS_=%O'143';		!IPCF send
LITERAL IPCFQ_=%O'144';		!IPCF query
GLOBAL LITERAL SIIPC=%O'126';	!GETTAB for PID of [SYSTEM]IPCC
GLOBAL LITERAL SIQSR=%O'2000126';!GETTAB for PID of [SYSTEM]QUASAR
GLOBAL LITERAL SIQPV=%O'22000126';!GETTAB for PID of [SYSTEM]PRIVATE_QUASAR

LITERAL _IPCSC=6;	!Create a PID
LITERAL _PCIPC=%O'-24';
LITERAL PROGRAMNAME=%SIXBIT'NETSPL';
LITERAL NETDEV=%SIXBIT'TSK';
LITERAL UNTIL_RESET=1;	!PID goes away on reset if so
LITERAL UNTIL_LOGOUT=0;		!Keep PID until log out

!
!GLOBAL DATA AREAS
!
GLOBAL QSRGETTAB: INITIAL(SIQSR); !This way so can be patched to private quasar
GLOBAL IPCFINT: INT_BLOCK;	!Interrupt block for IPCF packet arrival
GLOBAL HIMSG: QSR$HI;		!Hello message for Quasar

!
!Externals
!
EXTERNAL ROUTINE
	RCVACK: NOVALUE,
	ERTEXT,
	ALLOC,	!Get core
	FBINI,	!Initialize file block
	NETQDEV,
	GETTAB,
	MSGSND;
EXTERNAL QSRPID;			!QUASAR's PID goes here

GLOBAL ROUTINE IPCINI=
!Set up interrupts for IPCF packets
!Arguments: none
!Implicit outputs: IPCFINT and HIMSG initialized, QSRPID set up
!Returned value: 1 if successful
BEGIN
EXTERNAL ROUTINE
	NETQDEV,
	INTINI;

GETPID(UNTIL_RESET);		!We want a PID
INTINI(IPCFINT);
IPCFINT[INT$WHAT]=_PCIPC;	!Condition is arrival of IPCF packet
INTERRUPTS(ADD,IPCFINT);

HIMSG[QSR$HI_STATUS]=0;		!Initialize HELLO message block
HIMSG[QSR$HI_VERS]=QSRVER;
HIMSG[QSR$HI_AVAIL]=1;			!Avaliable for scheduling
HIMSG[QSR$MS_TYP]=QSR$MS_HELLO;		!Set message type
HIMSG[QSR$MS_CNT]=QSR$HI_SIZE;		!and length
HIMSG[QSR$HI_NAME]=PROGRAMNAME;		!and our name
HIMSG[QSR$HI_SDEV]=NETQDEV();		!our queue name
HIMSG[QSR$HI_PDEV]=NETDEV;		!Processing device

IF GET_QUASAR_PID() EQL 0 THEN		!QUASAR isn't there!!
	ERROR(QSRNRN);
WIN					!Returned value
END; !IPCINI
ROUTINE GET_QUASAR_PID=
!Find the process ID for QUASAR
!Returns it as value, and stores it in QSRPID
BEGIN
REGISTER R;

R=.QSRGETTAB;
IF CALLI(R,%O'41')		!GETTAB UUO
	THEN QSRPID=.R
	ELSE 0
END;	!GET_QUASAR_PID
GLOBAL ROUTINE HELLO=
!Send a HELLO message
!Implicit parameter: HIMSG (global) should be set up
BEGIN
EXTERNAL ROUTINE RCVACK;

SEND_QUASAR(HIMSG);			!Send it
!No acks for now
!IF .HIMSG[QSR$MS_ACK] THEN RCVACK()	!Get acknowledge and return its value
END; !HELLO
GLOBAL ROUTINE DONEXTJOB(NB,QMSG)=
!Process a NEXTJOB message.  Put information therefrom into an NDB
!NB: address of NDB
!QMSG: Addres of NXTJOB message we got from QUASAR
BEGIN
MAP	NB:	REF NDB,
	QMSG:	REF QSR_EQ;
BIND	FB=.NB[NDB$FB]:	FILE_BLOCK;	!Hook on file block
BIND	FOP=NB[NDB$FOP]: EX;		!FOP field of ATTRIBUTES
LOCAL	FP:	REF QSR$FP,		!Will point to file parameter area
	FD:	REF QSR$FD,		!File data area
	PTR;
EXTERNAL ROUTINE
	WRPPNA;

NB[NDB$EQ]=.QMSG;			!Save pointer to message
NB[NDB$NODEID]=.QMSG[QSR$EQ_NODE];	!Copy NODEID
NB[NDB$ACCFUNC]=
	(CASE .QMSG[QSR$EQ_FUNC] FROM RMC$F_SEND TO RMC$F_EXECUTE OF SET
	[RMC$F_SEND]:	ACC$CREATE;	!Send a file to the remote system
	[RMC$F_GET]:	ACC$OPEN;	!Get a file from the remote system
	[RMC$F_DEL]:	ACC$ERASE;	!Delete a file on the remote system
	[RMC$F_REN]:	ACC$RENAME;	!Rename a file on the remote system
	[RMC$F_DI]:	ACC$LIST;	!List a directory on remote system
	[RMC$F_SUBMIT]:	ACC$CMD;	!Send and Submit a batch stream
	[RMC$F_EXECUTE]:ACC$EXE;	!Submit a batch stream
	[INRANGE,OUTRANGE]:	0;	!Leave it 0, we can't handle it
	TES);

NB[NDB$OPTIONS]=.QMSG[QSR$EQ_OPTIONS];	!Copy over options from RMCOPY
NB[NDB$MASTER]=1;			!Remember we started all this
FB[FILE$MODE]= (IF (.N[RMC$O_ASC] OR .N[RMC$O_ASCB])
		THEN _IOASC ELSE _IOIMG); !Ascii if he asked for it
					!Otherwise image mode
FB[FILE$GODLY]=1;			!Access as if we were requestor
					!This bit must be set to do this


FOP[FB$SUP]=1;				!Always try to supercede
IF .NB[NDB$ACCFUNC] EQL ACC$OPEN
THEN	FOP[FB$DLC]=.NB[NDB$RMC$O_DE];	!Send delete on close to remote system
PTR=CH$PTR(NB[NDB$REQUESTOR]);		!Ascii-ize PPN & store for DAP
WRPPNA((FB[FILE$ALIAS]=.QMSG[QSR$EQ_OWNER]),PTR); !& save for access check also

FP=.QMSG+.QMSG[QSR$EQ_LENGTH];		!Point to beginning of file area
INCR I FROM 1 TO .QMSG[QSR$EQ_NUMFIL]	!Decipher as many files as we got
DO	BEGIN
	EXTERNAL ROUTINE COPY;
	FD=.FP[QSR$FP_FPSZ]+.FP;		!FD follows FP
	IF .FP[QSR$FP_LOCAL] NEQ 0		!A LOCAL filespec
	THEN	BEGIN
		LOCAL FB: REF FILE_BLOCK;		!Local or log
		IF .FP[QSR$FP_FLG]
		 THEN	BEGIN
			IF .NB[NDB$LOG_FB] EQL 0
			 THEN	BEGIN
				FB=(NB[NDB$LOG_FB]=ALLOC(FB_LEN));
				FBINI(.FB);
				END;
			END
		 ELSE 	BEGIN
			FB=.NB[NDB$FB];
			FB[FILE$FB$DLC]=.NB[NDB$RMC$O_DE]; !/DELETE after transfer
			END;
		FB[FILE$NAME]=.FD[QSR$FD_NAM];
		FB[FILE$DEVICE]=.FD[QSR$FD_STR];
		FB[FILE$EXTENSION]=.FD[QSR$FD_EXT];
		COPY(FD[QSR$FD_PPN],FB[FILE$DIR],SFDMAX+1);
		!Now move directory spec (1 UFD + SFDMAX SFD's)
		END
	ELSE	BEGIN					!Copy ASCIZ string
		LOCAL RFSP;
		!Second remote filespec (if any) is remote RENAME filespec
		RFSP=(IF .NB[NDB$REMOTEFILE] EQL 0	THEN NB[NDB$REMOTEFILE]
							ELSE NB[NDB$REMRENAME]);
		COPY(.FD,.RFSP,.FP[QSR$FP_FDSZ]);
		END;
	FP=.FD+.FP[QSR$FP_FDSZ];			!Point to next file
	END;
IF .HIMSG[QSR$HI_NEXT] EQL .QMSG[QSR$EQ_SEQ]
	THEN HIMSG[QSR$HI_NEXT]=0; 	!Clear NEXT if we just got it

END; !NEXTJOB
GLOBAL ROUTINE RELJOB(NB)=
!Release a job, i.e. tell QUASAR we did it.
!NB: address of NDB for job
BEGIN
MAP NB: REF NDB;	!NDB for transfer
BIND EQ=.NB[NDB$EQ]: QSR_EQ;		!EQ entry that created this
LOCAL RELMSG: QSR$REL;

CLEARV(RELMSG);				!Start out clean
IF EQ EQL 0
THEN	BEGIN
	INFO('No queue entry to release');
	RETURN 0
	END;

!RELMSG[QSR$MS_ACK]=1;			!RSVP
RELMSG[QSR$MS_TYP]=QSR$MS_RELEASE;
RELMSG[QSR$MS_CNT]=QSR$REL_SIZE;
RELMSG[QSR$REL_ITN]=.EQ[QSR$EQ_TASK];	!Get ITN from original message
SEND_QUASAR(RELMSG);

!May cause trouble if next message in queue isn't an ACK
!RCVACK()				!Get our acknowledgement
END; !RELJOB
GLOBAL ROUTINE REQJOB(NB,AFTER)=
!Reque a job
!NB: address of NDB for job
!AFTER: /AFTER parameter
BEGIN
MAP NB: REF NDB;	!NDB for transfer
BIND EQ=.NB[NDB$EQ]: QSR_EQ;	!EQ entry that created this
LOCAL REQMSG: QSR$REQ;

IF EQ EQL 0
THEN	BEGIN
	WRN('No queue entry to re-queue');
	RETURN 0;				!No queue entry there
	END;

CLEARV(REQMSG);				!Start out clean
!Don't need this?? may cause trouble if what we get back
!is another job, not an ACK
!REQMSG[QSR$MS_ACK]=1;			!RSVP

REQMSG[QSR$MS_TYP]=QSR$MS_REQUE;
REQMSG[QSR$MS_CNT]=QSR$REQ_SIZE;
REQMSG[QSR$REQ_ITN]=.EQ[QSR$EQ_TASK];	!Get ITN from original message
REQMSG[QSR$REQ_AFTER]=.AFTER;		!Fill in /AFTER value
SEND_QUASAR(REQMSG);			!Send it out

!May cause trouble if next message in queue isn't an ACK
!RCVACK()				!Get our acknowledgement
END; !REQJOB
GLOBAL ROUTINE QMRECV(PACK)=
!++
! FUNCTIONAL DESCRIPTION:
!	This routine waits (if necessary) for a message from QUASAR.
!	and receives it, returning the address of the message
!
! FORMAL PARAMETERS:
!
!	Address of an IPCF header block
!
! IMPLICIT INPUTS:
!
!	The IPCF receive Q
!
! IMPLICIT OUTPUTS:
!
!	None
!
! ROUTINE VALUE:
!
!	Address of message from QUASAR
!
! SIDE EFFECTS:
!
!	Storage for the message will have been ALLOCated
!	(if not a page-packet), or a page will have been
!	added to the address space (if a page-packet).
!
!--
BEGIN
!
! Externals
!
EXTERNAL ROUTINE
	MSGERROR,
	GETPAG,
	QUEWAT;
!
! Literals
!
LITERAL IPCFR_=%O'142';		!IPCF receive
!

MAP PACK: REF IPCF_HEADER;	!Something to pass to  QUEWAT
LOCAL T;			!A temporary
LOCAL M:REF QSR$MSG_TEXT;	!Will point to the msg received
REGISTER S2;			!For the UUO

WHILE 1 DO 
	BEGIN
	QUEWAT (PACK[0,0,0,0]);		!Wait for the answer
	T = .PACK [IPCF$PAGE_PACK];	!Save page mode flag
	PACK [IPCF$FLAGS] =
	  PACK [IPCF$SEND_PID] =
	    PACK [IPCF$RECV_PID] = 0;
	IF (PACK [IPCF$PAGE_PACK] = .T)	!Restore the flag
		NEQ 0 THEN
		BEGIN
		PACK [IPCF$MSG_LEN] = %O'1000';
		PACK [IPCF$MSG_ADR] = GETPAG();
		M = .PACK [IPCF$MSG_ADR] * %O'1000';
		END
	ELSE	BEGIN
		EXTERNAL ROUTINE ALLOC;
		PACK[IPCF$MSG_ADR]=(M=(ALLOC(.PACK[IPCF$MSG_LEN])));
		END;
	S2<LH> = IPCF$HEADER_LEN;
	S2<RH> = PACK[0,0,0,0];
	IF CALLI (S2, IPCFR_) THEN
	   RETURN .M
	ELSE
		BEGIN
		UNDECLARE %QUOTE PREFIX;
		MACRO PREFIX='RCV'%;
		EXTERNAL ROUTINE FREE;
		MSG('%','','Receive failure ');TSTR(ERTEXT(IPCERR+.S2));
		 TYPE(CRLF);
		FREE(.PACK[IPCF$MSG_ADR],.PACK[IPCF$MSG_LEN]);
		END;
	END
END;
GLOBAL ROUTINE QSRACK=
!Send an ACKNOWLEDGE message to QUASAR
BEGIN
LOCAL ACKMSG:QSR$MSG_TEXT;

CLEARV(ACKMSG);			!Zero block first

ACKMSG[QSR$MS_CNT]=QSR$TEXT_SIZE;	!Size of message
ACKMSG[QSR$MS_TYP]=QSR$MS_TEXT;
ACKMSG[QSR$TEXT_NOMESS]=1;	!No text, just an ACK

SEND_QUASAR(ACKMSG)
END; !QSRACK
GLOBAL ROUTINE GETPID(PIDTYPE)=
!Routine to get a PID from [SYSTEM]IPCC. Requires IPCF priveleges!!
!PIDTYPE: if 1, PID goes away on RESET, otherwise on logout.
!Returns: your new PID
BEGIN
FIELD GP_FIELDS=SET
DFF[GP$USER_CODE,FIRSTWORD,LH],	!Left alone so user can keep his place
DFF[GP$FUNCTION,THISWORD,RH],	!Function code to IPCC
DFF[GP$PIDTYPE,NEXTWORD,35,1,0],!Destroy PID on RESET if set
DFF[GP$JOB,THISWORD,0,34,0]	!Job number
TES;
LITERAL GP_LEN=%O'10';

LOCAL IPCDATA: BLOCK[GP_LEN] FIELD(GP_FIELDS);
EXTERNAL ROUTINE PJOB;

CLEARV(IPCDATA);
IPCDATA[GP$FUNCTION]=_IPCSC;	!Create a pid
IPCDATA[GP$PIDTYPE]=.PIDTYPE;	!Permanent or not
IPCDATA[GP$JOB]=PJOB();
IPCSND(IPCDATA,GP_LEN);
END; !GETPID

GLOBAL ROUTINE IPCSND(MSG_ADDR,MSG_LEN)=
!Send a message to [SYSTEM]IPCC
!MSG_ADDR: address of message data
!MSG_LEN:  length of message data
BEGIN
OWN IPCCPID;	!Remember PID of [SYSTEM]IPCC
LOCAL HDRBLK: IPCF_HEADER;

IF .IPCCPID EQL 0 THEN IPCCPID=GETTAB(SIIPC);
CLEARV(HDRBLK);
HDRBLK[IPCF$PRV_PACK]=1;	!So [SYSTEM]IPCC will listen to us
HDRBLK[IPCF$RECV_PID]=.IPCCPID;
HDRBLK[IPCF$MSG_ADR]=.MSG_ADDR;
HDRBLK[IPCF$MSG_LEN]=.MSG_LEN;
MSSEND(HDRBLK);
DO	BEGIN
	CLEARV(HDRBLK);
	IF IPCQCK(HDRBLK) EQL 0 THEN	!Got a message
	 ERROR(IPCERR);
	IF .HDRBLK[IPCF$PAGE_PACK]
	 THEN HDRBLK[IPCF$MSG_ADR]=(HDRBLK[IPCF$MSG_LEN]=0) !Throw away
	 ELSE	BEGIN
		HDRBLK[IPCF$MSG_ADR]=.MSG_ADDR;
		HDRBLK[IPCF$MSG_LEN]=.MSG_LEN;
		END;
	HDRBLK[IPCF$TRUNC]=1;
	MSRECV(HDRBLK);
	END WHILE .HDRBLK[IPCF$SEND_PID] NEQ .IPCCPID;
	IF .HDRBLK[IPCF$PROC_ERR] NEQ 0
	 THEN	ERROR(IPCERR+.HDRBLK[IPCF$PROC_ERR]);
WIN
END; !IPCSND

GLOBAL ROUTINE MSSEND(HDRBLK)=
!Routine to send a message (to anyone)
!HDRBLK: An IPCF header block, filled in as follows
!HDRBLK[IPCF$RECV_PID]:	PID of recipient.
!HDRBLK[IPCF$MSG_ADR]:	Address of message
!HDRBLK[IPCF$MSG_LEN]:	Length of message
!HDRBLK[IPCF$PRV_PACK] & HDRBLK[IPCF$PAGE_PACK] set if needed
!Returns 1 if successful
BEGIN
REGISTER R;
MAP HDRBLK: REF IPCF_HEADER;
R<RH>=.HDRBLK;		R<LH>=IPCF$HEADER_LEN;
IF CALLI(R,IPCFS_)
 THEN	RETURN WIN
 ELSE	ERROR(IPCERR+.R);
END;	!MSSEND

GLOBAL ROUTINE MSRECV(HDRBLK)=
!Routine to receive a message (from anyone)
!HDRBLK: An IPCF header block, filled in as follows
!HDRBLK[IPCF$MSG_ADR]:	Address of message
!HDRBLK[IPCF$MSG_LEN]:	Length of message
!Returns 1 if successful
!The following will be filled in on return
!HDRBLK[IPCF$SEND_PID]:	PID of sender
!HDRBLK[IPCF$PRV_PACK] & HDRBLK[IPCF$PAGE_PACK] set if appropriate
BEGIN
REGISTER R;
MAP HDRBLK: REF IPCF_HEADER;
R<RH>=.HDRBLK;		R<LH>=IPCF$HEADER_LEN;
IF CALLI(R,IPCFR_)
 THEN	RETURN WIN
 ELSE	ERROR(IPCERR+.R);
END;	!MSRECV

GLOBAL ROUTINE IPCQCK(HDRBLK)=
!Check the IPCF receive queue
!HDRBLK: An IPCF header block, which will be filled in as follows
!HDRBLK[IPCF$FLAGS]
!HDRBLK[IPCF$MSG_LEN]:	Length of message
!HDRBLK[IPCF$MSG_ADR] CONTAINS # OF MESSAGES IN QUEUE
!HDRBLK[IPCF$SEND_PID]:	PID of sender
!HDRBLK[IPCF$PRV_PACK] & HDRBLK[IPCF$PAGE_PACK] set if appropriate
BEGIN
REGISTER R;
MAP HDRBLK: REF IPCF_HEADER;
R<RH>=.HDRBLK;		R<LH>=IPCF$HEADER_LEN;
IF CALLI(R,IPCFQ_)
 THEN	RETURN WIN
 ELSE	BEGIN
	R=IPCERR+.R;
	IF .R EQL IPCNMR THEN RETURN 0;
	ERROR(.R);
	END;
END;	!IPCQCK
END ELUDOM