TITLE RMTQUE -- REMOTE PRINTER QUEUE ACTIVE TASK SUBTTL Scott McClure/ESI 20-AUG-84 SEARCH GLXMAC ;SEARCH GALAXY PARAMETERS IFE DEBUG,< ;[10] PROLOG (RMTQUE) > IFN DEBUG,< ;[10] PROLOG (TSTQUE) > SEARCH QSRMAC ;SEARCH QUASAR PARAMETERS SEARCH ORNMAC ;GET OPERATOR SYMBOLS COMMENT $ Abstract: RMTQUE is the run in conjunction with RMTSPL, the first on a source machine and the second on a target machine. This program is the active portion. It reads the primary master queue file looking for any queue entry with a /destination that is remote. This queue entry is then transfered, the file referenced is transfered, the queue entry is removed from the local queue and the file is handled as it would have been had LPTSPL done the printing locally. Each of these tasks is dependent upon a positive acknowledgement from RMTSPL. Any non-fatal failure simply leaves the queue alone causing the system to attempt the transmition on the next pass. Limitations: This system is limited to the DECSYSTEM-20 line by currently sending the 20 External Queue Entry record as a message format between machines and send essentially 36 bit data. Seperate spoolers (RMTSPL) could be created to decode this for other machines or this active portion could be made to use DAPLIB or some other system which knows more machines. There are no current plans to change this. The system will only transfer a single page queue entry. This is not a major problem since about 22 average sized file specs will fit in a single page. The system will only work with queue entry files of less than 513 pages. This is also not a practical problem but should be fixed to maintain consistency with other DEC software. $ ;VERSION AND EDIT INFORMATION QUEMAJ==1 ;MAJOR VERSION QUEMIN==0 ;MINOR VERSION QUEEDT==16 ;EDIT LEVEL QUEWHO==2 ;WHO LAST EDITED - CUST ;ENTRY VECTOR DEFINITION QUEVEC: JRST RMTQUE ;ENTER HERE JRST RMTQUE ;REENTER SAME QUEVER: BYTE (3)QUEWHO(9)QUEMAJ(6)QUEMIN(18)QUEEDT EVECL==.-QUEVEC ;DEBUG SWITCH[10] DEBUG==0 SUBTTL Table of Contents ; TABLE OF CONTENTS FOR RMTQUE ; ; SECTION PAGE ; ------- ---- ; 1. Table of Contents.................................. 2 ; 2. Revision History................................... 3 ; 3. Accumulators and Constants......................... 4 ; 4. Quasar storage..................................... 5 ; 5. RMTQUE Main entry and initilization............... 6 ; 6. CHKQUE Check the queue files for remote request... 7 ; 7. GETIDX Read MQF index page(s)..................... 8 ; 8. NXTSEC Process the next section of MQF............ 9 ; 9. ISNODE Check if entry goes to remote node......... 10 ; 10. MOVEIT Move queue entry to another node........... 11 ; 11. LLGJFN Routine to get logical link JFN............ 12 ; 12. LLOPEN Open logical link to remote................ 13 ; 13. SENDQE Send queue entry to remote node............ 14 ; 14. OPENIT Open file for moving to target node........ 15 ; 15. SNDPAG Send a single (full) page to remote JFN.... 16 ; 16. PUTBCT Store image bit stream in 8 bit message.... 17 ; 17. CANQUE Cancel queue entry......................... 17 ; 18. FILDIS Keep/Delete printed spool files............ 18 ; 19. LLCLOS Routine to close or abort a logical link... 19 ; 20. SNDINT Send interrupt message to server (RMTSPL).. 20 ; 21. RELJFN Routine to release all non-open JFNS....... 20 ; 22. STRMNT Mount the structure for the current file... 21 ; 23. Interrupt tables................................... 22 ; 24. INTCDN Connect/Disconnect interrupt............... 22 ; 25. INTINA Interrupt message handler.................. 22 ; 26. INTDAV Data available from network................ 22 ; 27. Table of NSP disconnect reasons.................... 23 ; 28. Inpure storage..................................... 24 SUBTTL Revision History COMMENT $ EDIT DATE WHO WHY ==== ==== === ===================================== 1 08/20/84 SDM First installed for development area use. 2 08/21/84 SDM Handle unreachable nodes. Store them and ignore queue entry. Don't die! 3 08/28/84 SDM Get paranoid about index page changing after I read it. Set a max of 1 page. 4 08/29/84 SDM If we can't access the input file, tell server not to save file. Let LPTSPL tell user. 5 09/03/84 SDM More paranoia - trap Illegal memory reads and die only if there have been 10 on this pass. 6 09/13/84 SDM Release all unopened JFNS at end of queue scan. 7 09/28/84 SDM One more on IMR trap. Add delay before we try again to allow QUASAR to finish. 8 03/21/85 SDM Clear FILJFN if it can't be opened so we don't try to close it. 9 05/06/85 DLP Change the transfer protocol to send the # of bytes in the file and the file byte size. This will then be used to update the FDB of the remote file so the file will not end in nulls. This is necessary to support the 6.0 LPTSPL which tests for non-printable chars. Also change SNDPAG to support variable sizes of send data to support this. 10 05/06/85 DLP Add debug switch to setup active and passive programs to run independently of production versions. Change the node test to look for /Node:TEST and convert the node to MISB if true. These features setup for conditional assembly. 11 06/04/85 DLP Implement multiple file transfer according to # of files in queue entry. 12 06/05/85 DLP Put user name in /NOTE field if there isn't already something there 13 06/10/85 DLP Fix 'page table does not exist' error. Change the MQF index page to be shared so as to let it change with the queue. Then trap the error at the PMAP% for the queue entry if the index page has changed. 14 06/11/85 DLP Fix 'string exceeds 16 bytes' message. See LLCLOS. Also remove SNDINT and CLSJFN sections (never called). 15 06/12/85 DLP Add a routine to mount a structure if the open fails and try again. 16 06/13/85 DLP Files are not being deleted properly on the source machine if the user is not privilaged. Fix argblk for CHKAC call in FILDIS. $ SUBTTL Accumulators and Constants ;ACCUMULATOR DEFINITIONS E==14 ;POINT TO THIS FILE J==15 ;JOB CONTEXT - BEGINING ADDRESS ;INTERRUPT CHANNEL ASSIGNMENTS XP .ICCDN,0 ;CONNECT/DISCONNECT XP .ICINA,1 ;INTERRUPT MESSAGE XP .ICDAV,2 ;DATA AVAILABLE ;OTHER CONSTANTS XP PDLEN,^D200 ;STACK SIZE XP TRNSIZ,1100 ;SIZE OF TRANSFER BUFFER XP MAXNOD,20 ;MAX LENGTH OF BAD NODE TABLE XP MYNODE,[SIXBIT/MISB /] ;NODE TO CHANGE TO FOR TEST[10] ;INTERRUPT MESSAGE NUMBERS - FIRST 8 BITS ONLY .QEPAG==FLD(1,7B7) ;QUEUE ENTRY PAGE .FIDAT==FLD(2,77B7) ;DATA PAGE .FIEOF==FLD(3,77B7) ;END OF FILE FLAG ;AND THE ANSWERS WE WANT .QEACK==1 ;ACKNOWLEDGE QUEUE ENTRY .FIACK==2 ;ACKNOWLEDGE FILE TRANSFER .FINAK==3 ;HAD PROBLEM IN TRANMIT SUBTTL Local macros DEFINE MQFNAM,PRIMARY-MASTER-QUEUE-FILE.QUASAR\> DEFINE TXT(TEXT), DEFINE $FATAL (MSG,ITXT,%L1) < HRRZ P1,(P) SUBI P1,2 $CALL [$TEXT (,) $TEXT (,<^Q/ %L1/ITXT ^A>) $TEXT (,) HALTF% PJRST .-1 %L1:! TXT] SUPPRESS %L1 > ;End of $FATAL SUBTTL Quasar storage MYIB: $BUILD IB.SZ $SET(IB.PRG,,%%.MOD) ;SET PROGRAM NAME $SET(IB.FLG,IB.DPM,1) ;USE JOB # FOR PID $SET(IB.OUT,,T%TTY) ;DEFAULT TO TTY FOR TEXT $SET(IB.INT,,) ;TURN ON PSI STUFF $SET(IB.PIB,,PIBBLK) ;ADDRESS OF PIB BLOCK $EOB PIBBLK: $BUILD PB.MNS ;MINIMUM SIZE $SET(PB.HDR,PB.LEN,PB.MNS) ;LENTH $EOB QUESAB: $BUILD (SAB.SZ) ;IPCF SEND ARG BLOCK $SET (SAB.LN,,KIL.SZ) ;KILL IS ALL WE SEND $SET (SAB.MS,,KIL.MS) ;POINT TO KILL MESSAGE $SET (SAB.SI,SI.FLG,1) ;USE SI.IDX $SET (SAB.SI,SI.IDX,SP.QSR) ;USE QUASAR INDEX $EOB KIL.MS: $BUILD (KIL.SZ) $SET(.MSTYP,MS.CNT,KIL.SZ) ;MESSAGE LENGTH $SET(.MSTYP,MS.TYP,.QOKIL) ;KILL FUNCTION $SET(.MSFLG,MF.ACK,1) ;ASK FOR ACKNOWLEGE $SET(.MSCOD,,4) ;ACK CODE $SET(KIL.OT,,.OTLPT) ;OBJ TYPE IS LPT $EOB CKAARG: $BUILD (6) ;ARG BLOCK FOR CHKAC $SET(.CKAAC,,1) ;WANT WRITE ACCESS $SET(.CKAEC,,0) ;USER HAS NO CAPABILITIES $EOB SUBTTL RMTQUE Main entry and initilization RMTQUE: RESET ;CLEAR THE WORLD MOVE P,[IOWD PDLEN,PDL] ;BUILD A STACK MOVEI S1,IB.SZ ;SIZE OF THE IB MOVEI S2,MYIB ;WHERE IT IS $CALL I%INIT ;INIT GLXLIB MOVEI S1,.FHSLF ;INIT PSI FOR ME MOVE S2,[LEVTAB,,CHNTAB] ;TABLE ADDRESSES SIR% ;SET 'EM EIR% ;AND ENABLE THE PSI MOVEI S1,.FHSLF ;ME AGAIN MOVX S2,1B<.ICCDN>!1B<.ICINA>!1B<.ICDAV>!1B<.ICIRD> AIC% ;ACTIVATE CHANNELS MOVX S1, ;SHORT, MUST BE THERE HRROI S2,[MQFNAM] ;MASTER QUEUE FILE NAME GTJFN% ;GO GET IT ERCAL DIE ;OOPS, CAN'T GET IT HRRZM S1,MQFJFN ;SAVE IT HRRZS S1 ;CLEAR RIGHT FOR OPEN MOVX S2, ;READ ONLY - QUIETLY OPENF% ERCAL DIE ;GOT TO HAVE IT! MOVEI S1,.NDGLN ;GET LOCAL NODE NAME MOVEI S2,T1 ;T1 IS ARG BLOCK MOVE T1,[POINT 7, LOCNOD] ;POINT TO NAME STORAGE MOVE T2,T1 ;COPY POINTER NODE% ;GET IT! ERCAL DIE ;OR DIE - NEED IT TOO. MOVE T1,T2 ;RESTORE POINTER MOVE T2,[POINT 6, LOCNOD] ;AND MAKE A SIXBIT COPY RMTQ1: ILDB S1,T1 ;GET CHAR CAIG S1,0 ;DONE? JRST RMTQ2 ;CLEAN UP SUBI S1,40 ;MAKE IT SIXBIT IDPB S1,T2 ;STORE IT AWAY JRST RMTQ1 ;DO SOME MORE RMTQ2: IDPB S1,T2 ;STORE THE ZERO $CALL M%ACQP ;GET PAGE FOR MOVEM S1,INPAGE ;THE INPUT BUFFER PG2ADR S1 ;MAKE IT AN ADDRESS MOVEM S1,INADDR ;AND STORE THAT TOO ;FALL THROUGH INTO MAIN LOOP SUBTTL CHKQUE Check the queue files for remote request ;MAIN PROCESSING LOOP - READ QUEUE LOOKING FOR /NODE:NOTHERE. MOVE FILE IF ;FOUND AND CANCEL REQUEST HERE DUPING ON OTHER MACHINE CHKQUE: SKIPE FOUND ;DID WE MOVE SOMETHING? JRST CHKQ1 ;YES - LOOK FOR MORE MOVEI S1,^D60 ;SLEEP A MINUTE $CALL I%SLP ;TO LET QUEUE CHANGE CHKQ1: SETZM FOUND ;START OVER AOSGE CHKCNT ;STILL IN BIG LOOP? JRST CHKQ2 ;YES, DON'T CLEAR BAD TABLE HRREI S1,-12 ;DONE, GET NEG COUNTER MOVEM S1,CHKCNT ;AND PUT IT AWAY MOVEI S1,MAXNOD ;GET LENGTH OF NODE TABLE MOVEI S2,NODTBL ;POINT TO TABLE $CALL .ZCHNK ;CLEAR IT TO START AGAIN SETZM NODTLN ;AND CLEAR THE TABLE COUNTER CHKQ2: $CALL GETIDX ;GET THE INDEX PAGE CLEARM P1 ;CLEAR OUT INDEX REGISTER CKLOOP: MOVE S1,P1 ;GET CURRENT INDEX REG SKIPN INDTAB(S1) ;IS THERE AN INDEX PAGE HERE? JRST CKLOP1 ;NOTHING THERE - GO AROUND $CALL NXTSEC ;PROCESS THE NEXT SECTION HRLI S2,.FHSLF ;NEED TO CLEAR THIS PAGE HRR S2,INDTAB(P1) ;SO NEXT PASS CAN USE IT SETOM S1 ;TELL PMAP TO UNMAP MOVX T1,PM%CNT ;ONE HRRI T1,1 ;PAGE PMAP% ERCAL DIE ;OOPS, PMAP FAILED MOVE S1,INDTAB(P1) ;AND NOW RELEASE THIS PAGE $CALL M%RELP ;IN MY MEMORY TABLE CKLOP1: CAIGE P1,FSSMNS-1 ;ANY LEFT AOJA P1,CKLOOP ;INCREMENT AND DO NEXT $CALL RELJFN ;RELEASE ANY UNOPENED JFNS[6] JRST CHKQUE ;DONE - NEXT PASS SUBTTL GETIDX Read MQF index page(s) GETIDX: CLEARM INDTAB ;CLEAR FIRST WORD MOVE S1,[INDTAB,,INDTAB+1] ;MAKE BLT POINTER BLT S1,INDTAB+FSSMNS-1 ;CLEAR INDEX TABLE MOVE S1,MQFJFN ;GET MY JFN BACK MOVX S2,<1,,.FBUSW> ;GET USER ARE FROM FDB MOVE T1,BLKCNT ;IT GIVES FILE SIZE GTFDB% ;FOR THE MQF ERCAL DIE MOVE T2,BLKCNT ;GET IT BACK ADDI T2,FSSBPS-1 ;ROUND IT UP IDIVI T2,FSSBPS ;CONVERT TO # SECTIONS MOVEM T2,SECCNT ;AND REMEMBER IT CLEAR T3, ;CLEAR A COUNTER GETID1: $CALL M%ACQP ;GET A PAGE MOVEM S1,INDTAB(T3) ;AND SAVE THE # HRLI S1,.FHSLF ; MOVE S2,S1 ;IN S2 FOR PMAP MOVEI S1,FSSBPS ;GET BLOCKS/SECTION IMULI S1,(T2) ;WHICH SECTION? ADDI S1,FSSFIB ;+FIRST BLOCK = DPA HRL S1,MQFJFN ; MOVX T1,(PM%RD) ;READ-LET PAGE CHANGE W/QUEUE[13] PMAP% ;GET THE PAGE IN ERCAL .RETF ;GOT TO GET IT SOJLE T2,.RETT ;RETURN IF DONE AOJA T3,GETID1 ;OR GET THE NEXT INDEX PAGE SUBTTL NXTSEC Process the next section of MQF NXTSEC: $CALL .SAVE1 ;SAVE INDEX REG MOVE S2,INDTAB(S1) ;GET PAGE # OF SECTION INDEX PG2ADR S2 ;CONVERT IT TO AN ADDRESS MOVEM S2,INDEX ;MAKE IT THE CURRENT INDEX IMULI S1,FSSBPS ;GET BASE DATA PAGE ADD(DPA) MOVEM S1,BASE ;AND SAVE IT HRRZ P1,@INDEX ;HOW MANY ENTRIES JUMPE P1,.RETT ;GO HOME IF EMPTY MOVEM P1,QERCNT ;AND SAVE THAT IF THERE MOVE P2,INDEX ;GET ADDRESS OF INDEX ADDI P2,FSSFDB ;POINT TO FIRST DATA BLOCK NXTSE1: SKIPN S2,0(P2) ;GET NEXT ENTRY IF THERE JRST NXTSE2 ;EMPTY, GO TO NEXT ONE AOJE S2,NXTSE2 ;-1 IS CONTINUATION, IGNORE $CALL M%ACQP ;OK, GET OPEN PAGE MOVEM S1,MQPAGE ;SAVE THE DEST PAGE # HRLI S1,.FHSLF ; MOVEM S1,S2 ;INTO S2 FOR PMAP MOVE S1,P2 ;GET THE SOURCE ADDRESS SUB S1,INDEX ;TAKE OUT INDEX ADD S1,BASE ;PUT IN THE RIGHT SECTION HRL S1,MQFJFN ; MOVX T1,PM%RD!PM%CPY ;READ AND MAKE IT PRIVATE[12] PMAP% ;GET IT ERCAL IDXERR ;INDEX PAGE CHANGED, SKIP ENTRY[13] $CALL ISNODE ;IS IT REMOTE? SKIPF ;IF NOT THEN $CALL MOVEIT ;DON'T DO THIS MOVE S1,MQPAGE ;DONE WITH THIS ONE SO, $CALL M%RELP ;GIVE THE PAGE BACK IDXERR: SOSG P1,QERCNT ;DECREMENT AND LOAD COUNT $RETT ;NO MORE - DONE NXTSE2: AOS P2 ;GET NEXT PAGE MOVE S1,INDEX ;GET INDEX ADDRESS[3] ADDI S1,1000 ;POINT TO END OF INDEX PAGE[3] CAMLE P2,S1 ;ARE WE PAST THAT?[3] $RETT ;YES, SOMETHING CHANGED[3] JRST NXTSE1 ;NO, GET NEXT POINTER SUBTTL ISNODE Check if entry goes to remote node ;CALL WITH PAGE # OF CURRENT REQUEST IN MQPAGE, RETURN FALSE IF DESTINATION ;NODE IS LOCAL, TRUE IF NOT ISNODE: MOVE J,MQPAGE ;COLLECT PAGE # PG2ADR J ;MAKE AN ADDRESS LOAD S1,.EQROB(J) ;GET REQUESTED OBJECT FOR TYPE CAIE S1,.OTLPT ;IS THIS FOR THE LPT? $RETF ;NO - RETURN FALSE LOAD S1,.EQROB+.ROBND(J) ;POINT TO NODE NAME AND GET CAMN S1,LOCNOD ;IS IT REMOTE? $RETF ;NO - SAY SO IFN DEBUG,< CAMN S1,[SIXBIT/TEST /] ;IS IT A TEST FILE?[10] MOVE S1,MYNODE ;YES, CHANGE IT FOR TEST[10] > MOVN S2,NODTLN ;GET NEG LENGTH OF BAD NODES TABLE HRLZS S2 ;SET IT UP FOR AOBJN ISNOD1: CAMN S1,NODTBL(S2) ;IS THIS A BAD NODE? $RETF ;YES, TELL CALLER TO IGNORE AOBJN S2,ISNOD1 ;NO MATCH - TRY MORE MOVEM S1,TONODE ;OK, SAVE FOR GTJFN $RETT ;DONE HERE SUBTTL MOVEIT Move queue entry to another node ;HERE HAVING DECIDED THAT WE NEED TO MOVE A QUEUE ENTRY BETWEEN MACHINES. ;THIS BECOMES THE MAINLINE FOR THE REST OF THE WORK. MOVEIT: AOS FOUND ;SAY WE FOUND ONE TO MOVE SETZM SNDERR ;CLEAR THE SEND ERROR FLAG $CALL LLGJFN ;GET THE NODE JFN $CALL LLOPEN ;OPEN THE LOGICAL LINK JUMPF .POPJ ;FAILURE HERE JUST RETURNS $CALL SENDQE ;SEND QUEUE ENTRY TO REMOTE JUMPF MOVE3 ;ON FAILURE JUST GO TO NEXT LOAD T1,.EQSPC(J),EQ.NUM ;GET # OF FILES[11] MOVEM T1,FILES ;SAVE IT[11] LOAD E,.EQLEN+(J),EQ.LOH ;GET HEADER LENGTH[11] ADD E,J ;POINT TO FIRST FP[11] MOVEM E,FPPNT ;SAVE THE FP POINTER[11] MOVE0: $CALL OPENIT ;OPEN THE SOURCE FILE JUMPF MOVE2 ;ON FAILURE SEND BAD EOF[4] MOVN T2,FILSIZ ;HOW MANY TIMES? HRLZS T2 ; MOVE1: MOVX T1,.FIDAT ;THIS IS A FILE DATA PAGE MOVEM T1,MSGWRD ;SAY SO MOVE S2,INPAGE ;S2 GETS HRLI S2,.FHSLF ;PUT SELF WITH SOURCE PAGE # HRL S1,FILJFN ;JFN FOR MOVX T1,PM%RD ;READ ACCESS ONLY HRR S1,T2 ;GET NEXT PAGE # PMAP% ERCAL DIE MOVEI S1,1000 ;# OF BYTES TO SEND[9] MOVEM S1,SBYTS ;SAVE IT[9] MOVE S1,INADDR ;SET UP FOR TRANSFER $CALL SNDPAG ;SEND A PAGE TO REMOTE AOBJN T2,MOVE1 ;DO 'TIL DONE MOVE2: MOVE T1,[POINT 8,MSGWRD] ;EOF INFO MOVX S1,.FIEOF ;THE EOF MESSAGE NUMBER MOVEM S1,MSGWRD ;STORE IT MOVE T1,FILSIZ ;# OF PAGES IN FILE[9] MOVEM T1,TRNBUF ;SAVE IT[9] MOVE T1,FILBYT ;# OF BYTES IN FILE[9] MOVEM T1,TRNBUF+1 ;SAVE IT[9] MOVE T1,FILBSZ ;BYTE SIZE[9] MOVEM T1,TRNBUF+2 ;SAVE IT[9] MOVEI S1,3 ;# BYTES TO SEND[9] MOVEM S1,SBYTS ;SAVE IT[9] MOVEI S1,TRNBUF ;SETUP FOR TRANSFER[9] $CALL SNDPAG ;SEND IT[9] SETZM S1 ;WILL WAIT FOREVER $CALL I%SLP ;FOR THE ACKNOWLEDGMENT MOVE T1,[POINT 8,MESAGE] ;POINTER TO MESSAGE ILDB S1,T1 ;GET MESSAGE BYTE CAIE S1,.FIACK ;IS THIS AN ACK? AOS SNDERR ;NO - SET ERROR[11] $CALL FILDIS ;FINISH THE FILE[11] SKIPE SNDERR ;FILE OK?[11] JRST MOVE3 ;NO - START QUEUE ENTRY OVER[11] SOSE FILES ;ANOTHER FILE?[11] JRST MOVE0 ;YES[11] $CALL CANQUE ;CANCEL THE QUEUE ENTRY MOVE3: $CALL LLCLOS ;CLOSE THE LINK $RETT ;AND DONE SUBTTL LLGJFN Routine to get logical link JFN ;ACCEPTS TONODE/ POINTER TO NODE NAME ;RETURNS TRUE - JFN IN LLJFN ; FALSE - ON FAILURE LLGJFN: HRROI S1,LLNAME ;DESTINATION AREA MOVE S2,DCNOBJ ;START WITH "DCN:" SETZM T1 SOUT% LLGJF2: MOVE S2,[POINT 6,TONODE] ;NODE IS SIXBIT HRLOI T2,-6 ;MAX NODE NAME LENGTH LLGJF3: ILDB T1,S2 CAIG T1,0 ;DONE ON NULL (SPACE) JRST LLGJF4 ADDI T1,40 ;MAKE IT ASCIZ IDPB T1,S1 ;STORE INTO DESTINATION AOJL T2,LLGJF3 ;MORE IF MORE WORD LLGJF4: MOVE S2,DCNOBJ+1 ;FINISH IT WITH TASK SETZM T1 SOUT% LLGJF6: MOVEI T1,0 ;FINISH OFF IDPB T1,S1 ;WITH NULL MOVX S1, ;NEW - SHORT HRROI S2,LLNAME ;POINT TO FULL NAME GTJFN% ;AND GET THE JFN JRST .+1 ;LET LLOPEN TAKE CARE OF ERRORS MOVEM S1,LLJFN ;SAVE THE NEW JFN $RETT DCNOBJ: TXT(DCN:) IFE DEBUG, ;[10] IFN DEBUG, ;[10] SUBTTL LLOPEN Open logical link to remote ;LLOPEN OPENS NETWORK JFN ON DCN: ;ACCEPTS LLJFN JFN OF NETWORK ;RETURNS TRUE - LINK OPEN AND ATTACHED LLOPEN: MOVE S1,LLJFN ;GET JFN OF LINK MOVE S2,[FLD(^D8,OF%BSZ)+OF%RD+OF%WR] OPENF% ;DO IT JRST LLOPN2 ;OOPS, RELEASE AND RETURN LLOPN1: MOVE S1,LLJFN ;GET JFN BACK MOVEI S2,.MOACN ;ENABLE FOR CONNECT INTERRUPTS MOVX T1, MTOPR% ;DO IT. ERJMP LLOPN2 ;GIVE UP MOVX S1,^D10 ;GIVE SERVER LOTS OF TIME $CALL I%SLP ;WAIT FOR THE INTERRUPT MOVE S1,LLJFN ;GET JFN AGAIN MOVEI S2,.MORLS ;GET THE CURRENT LOGICAL LINK MTOPR% ;STATUS ERJMP LLOPN2 ;DAMN, CLOSE IT UP MOVEM T1,LLSTAT ;SAVE STATUS TXNN T1,MO%CON ;ARE WE CONNECTED? JRST LLOPN2 ;NO, BETTER DIE $RETT ;LOOKS OK LLOPN2: MOVE S1,LLJFN ;GET THE JFN AND TXO S1,CZ%ABT ;ABORT IT CLOSF% ;CLOSE IT ERJMP .+1 ;IGNORING ERRORS MOVE S1,TONODE ;GET BAD NODE NAME[2] MOVE S2,NODTLN ;GET NODE TABLE COUNT[2] CAIG S2,MAXNOD ;JUST SKIP IT IF TABLE FULL[2] MOVEM S1,NODTBL(S2) ;PUT THIS BAD NODE IN TABLE[2] AOS NODTLN ;INCREMENT NODE TABLE COUNT[2] $RETF ;AND FLAG AN ERROR[2] SUBTTL SENDQE Send queue entry to remote node SENDQE: GETLIM S1,.EQLIM(J),NOT1 ;GET /NOTE:[12] JUMPN S1,SENDIT ;IF NOT BLANK LEAVE IT ALONE[12] MOVE S1,[POINT 6,.EQLIM+2(J)] ;POINT TO /NOTE:[12] MOVEI T2,-14 ;MAX 12 CHARS[12] HRLZS T2 ;[12] MOVE T1,[POINT 7,.EQOWN(J)] ;POINT TO USER NAME[12] INOTE: ILDB S2,T1 ;GET A CHAR[12] JUMPE S2,SENDIT ;NO MORE CHARS IN USER NAME[12] SUBI S2,40 ;CONVERT TO SIXBIT[12] IDPB S2,S1 ;PUT IT IN /NOTE:[12] AOBJN T2,INOTE ;DO TILL DONE[12] SENDIT: MOVX T1,.QEPAG ;SAY IT'S A QUEUE ENTRY MOVEM T1,MSGWRD ;IN THE MESSAGE WORD MOVEI S1,1000 ;#BYTES TO SEND[9] MOVEM S1,SBYTS ;SAVE IT[9] MOVE S1,MQPAGE ;GET PAGE # OF QE PG2ADR S1 ;MAKE IT AN ADDRESS FOR BP $CALL SNDPAG ;SEND IT OUT SETZM MESAGE ;CLEAR MESSAGE WORD MOVE S1,60 ;ONE MINUTE WAIT $CALL I%SLP ;BACK HERE WHEN DONE MOVE T1,[POINT 8,MESAGE] ;GET POINTER BACK ILDB S1,T1 ;RETURN THE BYTE ACK: CAIN S1,.QEACK ;IS IT THE RIGHT INDEX? $RET ;YES, AOS SNDERR ;NO, SET SEND ERROR $RETF ;AND RETURN FAILURE SUBTTL OPENIT Open file for moving to target node ;ACCEPTS J/ ADDRESS OF THIS JOB ; FPPNT/ CURRENT FILE PARAMETER POINTER OPENIT: MOVE E,FPPNT ;GET POINTER[11] LOAD S2,.FPLEN(E),FP.LEN ;GET FP LENGTH ADD E,S2 ;POINT TO FD[11] OPEN0: HRROI S2,.FDFIL(E) ;POINTER TO FILE SPEC[11] MOVX S1, ;HAS TO BE THERE GTJFN% ;GET IT JRST JFNERR ;FAILURE[15] MOVEM S1,FILJFN ;SAVE THE FILE JFN HRRZ S1,S1 ;KEEP RIGHT HALF MOVE S2,[FLD(36,OF%BSZ)+OF%RD] ;READ IS ALL I NEED OPENF% ;OPEN IT UP JRST OPEN1 ;FLAG AS NOT THERE[4] MOVE S1,FILJFN ;GET FILE JFN[9] MOVSI S2,2 ;GET 2 WORDS <2,,0>[9] HRRI S2,.FBBYV ;WORD 11 <2,,11>[9] MOVEI T1,FDB11 ;ADDR TO STORE IT[9] GTFDB% ;GET FDB DATA[9] ERJMP OPEN2 ;FLAG AS NOT THERE[4] LDB T1,[POINT 6,FDB11,11] ;GET BYTE SIZE[9] MOVEM T1,FILBSZ ;SAVE IT[9] HRRZ T1,FDB11 ;GET # OF PAGES[9] MOVEM T1,FILSIZ ;SAVE LOAD S2,.FDLEN(E),FD.LEN ;GET FD LENGTH[11] ADD E,S2 ;POINT TO NEXT FP[11] MOVEM E,FPPNT ;SAVE UPDATED POINTER[11] $RETT JFNERR: $CALL STRMNT ;TRY MOUNTING THE STRUCTURE[15] JUMPT OPEN0 ;SUCCESS! - GET THE JFN AGAIN[15] ;ON FAIL FALL THRU[15] OPEN1: SETZM FILJFN ;Clear JFN for close operation[8] OPEN2: SETOM FILSIZ ;FLAG AS NON-EXISTENT[4] $RETF SUBTTL SNDPAG Send a single (full) page to remote JFN ;Accepts S1/ page address ; SBYTS/ # of 36-bit bytes to send (octal,use 1000 for full page) ;Returns +1 always SNDPAG: $SAVE ;SAVE THESE, IDIVI REM. IN P2[9] MOVE P1,SBYTS ;# OF BYTES[9] IMULI P1,44 ;CALC # OF...[9] IDIVI P1,10 ;8-BIT WORDS[9] ADDI P1,4 ;ADD MSGWRD[9] MOVEM P1,SNDCNT ;SAVE IT[9] MOVN P1,SBYTS ;GET NEG # OF BYTES[9] MOVEM P1,SBYTS ;SAVE IT[9] MOVS P1,SBYTS ;GET # OF BYTES[9] HRR P1,S1 ;GET ADDRESS ARG PAGE MOVE S2,[POINT 8, TRNBUF] ;POINTER IN 8 BIT BYTES MOVEM S2,TRNPNT ;STORE FOR PUTBCT MOVEI S1,0 ;GET A ZERO MOVEM S1,BITCNT ;STORE FOR PUTBCT SNDPA1: MOVE S1,0(P1) ;PICK UP WORD MOVEI S2,^D36 ;36 BIT WORDS $CALL PUTBCT ;TRANSFER THE WORD AOBJN P1,SNDPA1 ;AND THE NEXT SNDPA2: MOVE S1,LLJFN ;GET TARGET NODE MOVE S2,[POINT 8,MSGWRD] ;POINT TO WHOLE MESSAGE MOVN T1,SNDCNT ;SEND 1001 WORDS SOUTR% ;SEND IT ERCAL DIE MOVEI S1,TRNSIZ+1 ;SIZE OF TRANSFER BUFFER MOVEI S2,MSGWRD ;LOCATION $CALL .ZCHNK ;DONE WITH IT FOR NOW ; MOVE S1,INPAGE ;DONE WITH THIS ONE SO, ; $CALL M%RELP ;GIVE THE PAGE BACK ; $CALL M%ACQP ;GET PAGE FOR ; MOVEM S1,INPAGE ;THE INPUT BUFFER ; PG2ADR S1 ;MAKE IT AN ADDRESS ; MOVEM S1,INADDR ;AND STORE THAT TOO $RETT ;GO BACK SUBTTL PUTBCT Store image bit stream in 8 bit message ;Accepts S1/ right justified byte ; S2/ byte size - ^d36 PUTBCT: $SAVE ;Need these for later. SKIPN T1,BITCNT ;Any residual bitcount? JRST PUTBC1 ;No..start at byte boundry HLLZ T2,BCTADJ ;Yes..get pointer adjustment ADD T2,TRNPNT ;Point to residual bits DPB S1,T2 ;Store them SUB S2,T1 ;Get bits remaining in S1 JUMPLE S2,PUTBC4 ;All done? MOVN T1,T1 ;No..get shift right value LSH S1,0(T1) ;Right justify remaining bits PUTBC1: IDIVI S2,^D8 ;Get S2 bytecount T1 bitcount JUMPE S2,PUTBC3 ;Any full bytes to send? PUTBC2: IDPB S1,TRNPNT ;Yes..store a byte LSH S1,-^D8 ;Get next byte SOJG S2,PUTBC2 ;Do them all PUTBC3: JUMPE T1,PUTBC4 ;Any odd bits? IDPB S1,TRNPNT ;Yes..store them HRRE S2,BCTADJ ;Get negitive bitcount PUTBC4: MOVNM S2,BITCNT ;Save the bitcount $RETT ;All finished BCTADJ: 037400,,-4 ;Pointer adjust,,-bitcount SUBTTL CANQUE Cancel queue entry ;SEND MESSAGE TO QUASAR TO CANCEL A MASTER QUEUE ENTRY CANQUE: MOVE S1,.EQRID(J) ;GET THE REQUEST ID MOVEM S1,KIL.MS+KIL.RQ+.RDBRQ ;SAVE IN KILL MESSAGE MOVEI S1,SAB.SZ ;LENGTH OF ARG BLOCK MOVEI S2,QUESAB ;LOCATION OF ARGS $CALL C%SEND ;SEND TO QUASAR JUMPF [$FATAL ( Can't send KILL to QUASAR - ,^E[-1]/)] $CALL C%BRCV ;WAIT FOR RESPONSE $RET SUBTTL FILDIS Keep/Delete printed spool files FILDIS: $SAVE ;SAVE THE TEMPS SKIPN FILJFN ;IF THERE'S NO FILE $RETT ;JUST RETURN MOVE S2,INPAGE ;PAGE OF FILE HRLI S2,.FHSLF ;FORK HANDLE OF SELF SETOM S1 ;SAY TO UNMAP MOVX T1,PM%CNT ;WITH A COUNT OF HRRI T1,1 ;ONE PMAP% ;UNMAP IT LOAD E,.EQLEN(J),EQ.LOH ;GET THE HEADER LENGTH. ADD E,J ;POINT TO FIRST FILE. MOVE S1,FILJFN ;GET JFN TXO S1,CO%NRJ ;SAY TO KEEP IT ON CLOSE CLOSF% ;CLOSE NO MATTER WHAT ERCAL DIE ;FATAL OUT IF ERROR FILD.1: SKIPE SNDERR ;ERROR IN SENDING? JRST FILD.4 ;YES - JUST RELEASE IT MOVE T2,.FPINF(E) ;GET THE FILE INFO BITS. LOAD S2,.FPLEN(E),FP.LEN ;GET THE FILE INFO LENGTH. LOAD S1,.EQSEQ(J),EQ.PRV ;GET THE USERS PRIVILGE BITS JUMPN S1,FILD.2 ;IF SET, AVOID ACCESS CHECK TXNE T2,FP.SPL ;WAS IT A SPOOLED FILE ??? JRST FILD.3 ;YES,,THEN NO ACCESS CHECK HRROI S1,.EQOWN(J) ;GET THE OWNERS NAME MOVEM S1,CKAARG+.CKALD ;AND SAVE IT[16] HRROI S1,.EQCON(J) ;GET CONNECTED DIRECTORY MOVEM S1,CKAARG+.CKACD ;SAVE IT[16] MOVE S1,FILJFN ;GET JFN FOR CHKAC MOVEM S1,CKAARG+.CKAUD ;SAVE IT[16] MOVEI S1,6 ;LENGTH OF CKAARG TXO S1,CK%JFN ;SAY WE HAVE JFN IN .CKAUD MOVEI S2,CKAARG ;POINT TO CHKAC ARG BLOCK CHKAC% ;CHECK RIGHTS JRST FILD.4 ;NO RIGHTS - RELEASE AND RETURN FILD.2: TXNN T2,FP.DEL ;/delete? JRST FILD.4 ;NO - RELEASE AND RETURN FILD.3: MOVE S1,FILJFN ;JFN FOR THE DELETE DELF% ;DO THE DELETE JRST FILD.4 ;ERR - JUST RELEASE JFN SETZM FILJFN ;CLEAR JFN WORD FILD.4: SKIPN FILJFN ;STILL HAVE A JFN? $RET ;NO - ALL DONE MOVE S1,FILJFN ;STIL HAVE JFN - RETREIVE IT RLJFN% ;AND RELEASE IT JRST .+1 ;IGNORE ERRORS $RET ;RETURN. SUBTTL LLCLOS Routine to close or abort a logical link LLCLOS: SKIPN LLJFN ;Is link open? $CALL [$FATAL (Logical link is not open in LLCLOS)] HRLI S2,0 ;NO ERRORS HRRI S2,.MOCLZ ;Get the close function MOVE S1,LLJFN ;Get the JFN SETZB T1,T2 ;No additional data[14] MTOPR% ERJMP LLCLS3 ;Abort if MTOPR fails JRST LLCLS4 ;OTHERWISE GO CLOSE NORMALLY LLCLS3: MOVE S1,LLJFN ;GET THE JFN TXO S1,CZ%ABT ;Set bit for close CLOSF% ;and be sure. ERCAL [$FATAL (Can't abort close logical link in LLCLOS - ,^E/[-2]/)] SETZM LLJFN ;clear the JFN $RETT ;done. LLCLS4: MOVE S1,LLJFN ;Pick up JFN CLOSF% JRST LLCLS3 ;keep trying SETZM LLJFN ;Clear JFN word $RETT SUBTTL SNDINT Send interrupt message to server (RMTSPL) ;ACCEPTS - T1/MESSAGE NUMBER RIGHT JUSTIFIED IN FIRST 8 BITS ; WITH ANY ADDITIONAL DATA IN NEXT 3 BYTES ;SNDINT: $SAVE ;NEED ABOVE - BETTER KEEP ; MOVEI T2,4 ;ONLY ONE WORD ALWAYS ; MOVE S1,LLJFN ;THE NETWORK LINE ; MOVEI S2,.MOSIM ;SENDING A MESSAGE ; MTOPR% ;SEND IT ; ERCAL DIE ;MUST GO ; $RETT SUBTTL RELJFN Routine to release all non-open JFNS ;CLSJFN::SKIPA S1,[EXP CZ%ABT!.FHSLF] ;ABORT ALL FILE OPERATIONS RELJFN::MOVX S1,CZ%NCL!.FHSLF ;RELEASE ALL NON-OPEN JFNS CLZFF% ERJMP .+1 ;Ignore any errors $RETT ;RETURN SUBTTL STRMNT Routine to mount the structure of the current file[15] ;ACCEPTS E/ address of FD of current file STRMNT: MOVE S1,[POINT 7,.FDSTG(E)] ;POINT TO THE STRUCTURE MOVE S2,[POINT 7,STRBLK+1] ;WHERE TO PUT IT STRMOV: ILDB T1,S1 ;GET A CHAR IDPB T1,S2 ;STORE IT CAIE T1,":" ;DONE? JRST STRMOV ;NOPE - LOOP STRARG: HRLI S1,1 ;LENGTH OF ARGBLK HRRI S1,.MSIMC ;INCR THE MOUNT COUNT FOR THIS JOB HRROI S2,STRBLK+1 ;GET -1,,ADDRRESS OF STRING MOVEM S2,STRBLK ;SAVE IT MOVEI S2,STRBLK ;POINT TO STR STRING MSTR% ;MOUNT IT ERJMP MNTERR ;FAILURE $RETT ;RETURN SUCCESS MNTERR: $RETF ;RETURN FAILURE SUBTTL Interrupt tables LEVTAB: LEV1PC ;ONLY NEED ONE LEVEL EXP 0 EXP 0 CHNTAB: ;CHANNEL TABLE ICHCND: 1,,INTCDN ;CONNECT/DISCONNECT ICHINA: 1,,INTINA ;INTERRUPT MESSAGE ICHDAV: 1,,INTDAV ;DATA AVAILABLE BLANK: BLOCK 15 ICHIMR: 1,,INTIMR ;ILLEGAL MEMORY READ[5] ICHRST: BLOCK CHNTAB+^D36-. ;FILL IT OUT SUBTTL INTCDN Connect/Disconnect interrupt INTCDN: $BGINT (1) $DEBRK SUBTTL INTINA Interrupt message handler INTINA: $BGINT (1) MOVE S1,LLJFN ;GET JFN OF CURRENT REMOTE NODE MOVEI S2,.MORIM ;READ INTERRPT MESSAGE MOVE T1,[POINT 8,MESAGE] ;STORE MESSAGE HERE MTOPR% ;GET IT ERCAL DIE ;OH NO... $DEBRK SUBTTL INTDAV Data available from network INTDAV: $BGINT (1) $DEBRK SUBTTL INTIMR Illegal memory read[5] INTIMR: $BGINT (1) AOS TRPCNT ;COUNT THE ERROR MOVE S1,TRPCNT ;RETRIEVE THAT COUNT CAIL S1,^D10 ;TRY TEN TIMES $STOP (MRE, Memory Read Error ^O/LEV1PC/) ;TOO MANY TIMES, STOP MOVEI S1,^D1000 ;WAIT 1 SECOND[7] DISMS% ;FOR USE OF MEMORY SETZM S1 ;CLEAR IN CASE... $DEBRK SUBTTL Table of NSP disconnect reasons DEFINE DISCR < ER (0,No error) ER (1,Resource allocation failure) ER (2,Target node does not exist) ER (3,Node shutting down) ER (4,Target task does not exist) ER (5,Invalid name field) ER (6,Target task queue overflow) ER (7,Unspecified error condition) ER (8,Third party aborted the logical link) ER (9,) ER (24,Flow control failure) ER (32,Too many connections to node) ER (33,Too many connections to target task) ER (34,Access not permitted) ER (35,Logical link Services mismatch) ER (36,Invalid account) ER (37,Segment size too small) ER (38,) ER (39,No path to target node) ER (40,Flow control violation) ER (41,No current link to target node) ER (42,Confirmation of Disconnect Initiate) ER (43,Image data field too long) > ;END DISCR DEFINITION DEFINE ER (VALUE,TXT) < .DCX'VALUE==^D'VALUE IFDEF %%CUR,<%%DIF==^D'VALUE-%%CUR-1> IFNDEF %%CUR,< %%CUR==0 %%DIF==^D'VALUE> IFG %%DIF,> [ASCIZ\TXT\] %%CUR==^D'VALUE > ;END OF ER DEFINITION DSCTBL: DISCR ;GENERATE TABLE OF REASONS DSCMAX==.-DSCTBL-1 PURGE %%CUR,%%DIF SUBTTL Inpure storage ;STORAGE AREAS $DATA INPAGE ;PAGE # OF INPUT BUFFER $DATA INADDR ;MAKE PAGE # INTO ADDRESS $DATA MSGWRD ;MESSAGE STATUS/TYPE WORD $DATA TRNBUF,TRNSIZ ;TRANSFER AREA $DATA NODTBL,MAXNOD ;TABLE BAD NODE NAMES $DATA NODTLN ;CURRENT COUNT OF BAD NODES $DATA CHKCNT ;COUNT OF TIMES THROUGH LOOP $DATA PDL,PDLEN ;OUR STACK $DATA LEV1PC,1 ;AND INTERRUPT STACK POINTER $DATA MQFJFN ;JFN OF MASTER QUEUE FILE $DATA FOUND ;DID WE FIND ENTRY TO MOVE? $DATA SNDERR ;WAS THERE AND ERROR IN SENDING QE $DATA INDTAB,FSSMNS ;INDEX LOC FOR EACH SECTION $DATA SECCNT ;NUMBER OF SECTIONS IN THIS MQF $DATA BLKCNT ;COUNT THE BLOCKS IN THIS FILE $DATA QERCNT ;COUNT OF QUEUE ENTRY REQUESTS $DATA INDEX ;ADDRESS OF CURRENT INDEX $DATA BASE ;ADJUST FOR LARGE MQFILE $DATA MQPAGE ;PAGE # OF CURRENT REQUEST $DATA LOCNOD ;LOCAL ASCIZ NODE NAME $DATA TONODE ;ASCIZ NAME OF REMOTE NODE $DATA LLNAME,^D45 ;STRING FOR LINK NAME $DATA LLJFN ;JFN OF LOGICAL LINK $DATA LLSTAT ;STATUS OF LOGICAL LINK $DATA LLDISC,20 ;Disconnect cause stored here $DATA FILJFN ;JFN OF PRINT FILE $DATA FDB11 ;FDB WORD 11 STORAGE[9] $DATA FILBYT ;FDB WORD 12, # BYTES IN FILE[9] $DATA FILSIZ ;SIZE OF INPUT FILE $DATA FILBSZ ;FILE BYTE SIZE[9] $DATA TRNPNT ;BYTE POINTER TO TRANSFER AREA $DATA BITCNT ;COUNT OF LEFTOVER BITS $DATA MESAGE ;INCOMING MESSAGE BUFFER $DATA INTMSG ;OUTGOING MESSAGE BUFFER $DATA TRPCNT ;COUNT OF PROBLEMS $DATA SBYTS ;# OF BYTES FOR SNDPAG[9] $DATA SNDCNT ;CALC # OF 8-BIT WORDS IN SNDPAG[9] $DATA FILES ;# OF FILES TO SEND[11] $DATA FPPNT ;FILE PARAMETER POINTER[11] $DATA STRBLK,2 ;STORE STRUCTURE FOR MOUNTING[15] DIE: $FATAL ( Unknown error - ,^E/[-2]/) ;LAST TOPS-20 END