;PUPDIR.MAC;14    27-FEB-81 16:58:27    EDIT BY TAFT
; Make existence of name server conditional on whether Tenex
; maintains a local copy of Pup-network.directory or keeps a cache.
;PUPDIR.MAC;13     2-SEP-79 15:59:07    EDIT BY TAFT
;PUPDIR.MAC;12    29-JUL-79 15:52:19    EDIT BY TAFT
; Fix bug in directory version number logging
;PUPDIR.MAC;11    18-JAN-79 16:54:15    EDIT BY TAFT
; Do net dir version consistency check after receiving entire dir,
; not after first data packet (which might be empty!)
;PUPDIR.MAC;8     4-SEP-78 13:00:23    EDIT BY TAFT
; Do an install upon discovering that Tenex's installed directory
; is older than the directory file.
;PUPDIR.MAC;7     7-APR-77 17:07:52    EDIT BY TAFT
; Check for leftover characters after PUPNM does name lookup
;PUPDIR.MAC;6    18-MAR-77 17:09:49    EDIT BY TAFT
; SEARCH PSVDEF

; Copyright 1979, 1981 by Xerox Corporation

	TITLE PUPDIR -- NETWORK DIRECTORY LOOKUP AND UPDATE FOR PUPSRV
	SUBTTL E. A. Taft / October, 1976

	SEARCH PUPDEF,PSVDEF,STENEX
	USEVAR TOPVAR,TOPPVR	; This is part of the top fork


; Network Directory Lookup server
; This is one of the services provided on the Miscellaneous
;  services socket

NETLUK::TLNN F,(NTDSVF)		; Network directory server enabled?
	 POPJ P,		; No
	HRROI A,TEMP+100	; Put in temp area
	SETZM TEMP+100		; In case null
	MOVEI B,PBCONT(PB)	; Init byte ptr into packet
	HRLI B,(POINT 8)
	LDB C,PUPLEN		; Get Pup Length
	MOVNI C,-MNPLEN(C)	; Subtract overhead, negate
	SKIPGE C		; Don't if empty
	 SOUT			; Move text to buffer, null on end
	HRROI A,TEMP+100	; Point to buffered text
	MOVE B,[1B0+100B17+TEMP]  ; Region to return addresses in
	PUPNM			; Do the conversion
	 JRST NETLUF		; Failed
	LDB C,A			; Make sure PUPNM ate the whole string
	JUMPN C,[MOVEI A,PUPNX3	; No, pretend syntax error
		JRST NETLUF]
	HLLZ B,B		; Ok, isolate count
	MOVN B,B		; Negate it
	HRRI B,TEMP		; Point to first address
	MOVEI A,PBCONT(PB)	; Init byte ptr into packet
	HRLI A,(POINT 8)
NETLU1:	HLRZ C,0(B)		; Get a net
	IDPB C,A		; Store it
	HRRZ C,0(B)		; Get a host
	IDPB C,A
	TLC A,(30B11)		; Change byte size to 16
	MOVE C,1(B)		; Get a socket
	ROT C,-↑D16		; Right-justify high 16 bits
	IDPB C,A		; Put in packet
	ROT C,↑D16		; Right-justify low 16 bits
	IDPB C,A		; Put in packet
	TLC A,(30B11)		; Back to 8-bit bytes
	AOBJN B,.+1		; Advance pointer
	AOBJN B,NETLU1		; Repeat for all addresses
	PUSHJ P,ENDPUP##	; Done, compute length
	PUSHJ P,SWPPRT##	; Swap source and destination
	MOVEI A,221		; Pup Type of reply
	PUSHJ P,SNDPUP##	; Send it
	 POPJ P,		; Failed
	HRROI B,TEMP+100	; Ok, get ptr to name string
	TLNE F,(DEBUGF)		; Log only if debugging
	 LOG 
	POPJ P,

; Here on failure, A/ jsys error code
NETLUF:	HRROI B,TEMP+100	; Failed, get ptr to text
	LOG 
	HRROI B,[ASCIZ /Syntax error/]
	CAIN A,PUPNX1
	 HRROI B,[ASCIZ /Name not found/]
	CAIN A,PUPNX4
	 HRROI B,[ASCIZ /Inconsistent expression/]
	MOVEI A,222		; Error reply type
	JRST REPSTR##		; Reply with this message

; Directory version info (Misc services socket)

DIRVER::PUSHJ P,CHKVER		; Check my version of net dir
	LDB A,[POINT 16,PBCONT(PB),15]  ; Get version from Pup
	CAMN A,MYVER		; Same as mine?
	 POPJ P,		; Yes, done
	CAML A,MYVER		; Newer than mine?
	 JRST [	SETZM DIRTIM	; Yes, force dir check to happen
		SETZM PRBTIM	; Force probe to happen
		POPJ P,]
	TLNN F,(NTDSVF)		; Older than mine, do I have a local copy?
	 POPJ P,		; No, nothing more to do
	MOVE A,MYVER		; Yes, get my version
	DPB A,[POINT 16,PBCONT(PB),15]  ; Tell him about it
	PUSHJ P,SWPPRT##	; Swap Pup source and destination
	MOVEI A,240		; Reply Pup type
	PUSHJ P,SNDPUP##	; Send it off
	 POPJ P,		; Failed
	TLNE F,(DEBUGF)		; Log only if debugging
	 LOG 
	POPJ P,


; Request to send network directory (Misc services socket)

DIRSND::TLNN F,(NTDSVF)		; Do I have a local copy?
	 POPJ P,		; No, ignore
	PUSHJ P,GTCPRT##	; Get foreign connection port
	MOVE D,C		; Put in ac's passed to fork
	MOVSI C,0(A)
	HRRI C,0(B)
	MOVEI A,SNDDIR		; Starting PC for fork
	PUSHJ P,MKDFRK		; Make fork for sending dir
	 POPJ P,		; Failed
	POPJ P,

; Check and update state of network directory server
; Returns +1
; Clobbers A-D, PB, SV, FX

DIRCHK::TIME			; Get now
	ADD A,[DCKINT*↑D1000]	; Compute time of next check
	MOVEM A,DIRTIM		; Store it
	MOVEI SV,SV.MSC		; This is part of the misc server
	MOVEI FX,77		; Dummy fork index

; Check state of our special net dir fork, if there is one
	SKIPE A,DIRFRK		; Is there a net dir fork?
	 RFSTS			; Yes, read its status
	TLNN A,2		; Voluntary or forced termination?
	 JRST DIRCH1		; No
	MOVE A,DIRFRK		; Yes, get fork handle again
	RUNTM			; Get time used
	ADDM A,SRVTIM##(SV)	; Charge to misc services
	TLNE F,(DEBUGF)		; Log only if debugging
	 LOG 
	MOVE A,DIRFRK
	SETZM DIRFRK		; Clear handle
	KFORK			; Kill fork

; Initiate a net directory version probe if necessary
DIRCH1:	PUSHJ P,CHKVER		; Ensure version number is updated
	TIME			; Get now
	CAMGE A,PRBTIM		; Time to probe for new directory?
	 JRST DIRCH4		; No, done
	MOVEI A,PRBDIR		; Yes, set starting pc
	PUSHJ P,MKDFRK		; Create and start fork
	 JRST DIRCH4		; Failed
	TIME			; Succeeded, set time of next probe
	ADD A,[DPRINT*↑D1000]
	MOVEM A,PRBTIM

DIRCH4:	SETOB SV,FX		; No service now in progress
	POPJ P,


; Make and start fork for sending or receiving directory
;	A/ starting address of fork
;	C, D/ arguments to pass to fork in the same ac's
; Returns +1:  unsuccessful
;	 +2:  successful
; Clobbers A-D

MKDFRK:	SKIPE DIRFRK		; Does a fork already exist?
	 POPJ P,		; Yes, don't start another
	HRLM A,0(P)		; Save starting address
	MOVSI A,(1B1+1B3)	; Caps same as mine, set ac's
	SETZ B,			; Ac's same as mine
	CFORK			; Create fork
	 JRST [	ELOG 
		POPJ P,]
	MOVEM A,DIRFRK		; Save fork handle
	PUSHJ P,SETMAP##	; Setup inferior fork's map
	MOVE A,DIRFRK		; Get fork handle
	HLRZ B,0(P)		; Starting address
	SFORK			; Start the fork
	TLNE F,(DEBUGF)		; Log only if debugging
	 LOG 
	JRST SKPRET##		; Return +2

; Inferior fork started here to handle request for new directory
;	C/ net,,host   D/ socket to which directory is to be sent

SNDDIR:	MOVEI FX,77		; Dummy fork table index
	JSYS FRKINI##		; Initialize stack, etc.
	MOVEI A,400000		; Init interrupt system
	MOVE B,[LEVTAB##,,DCHNTB]
	SIR
	EIR
	PUSHJ P,OPNPRT		; Open EFTP port
	 HALTF			; Failed, quit
	MOVEI PB,EFTPKT		; Make pointer to Pup
	MOVSI A,(1B2+1B17)	; Old file, name from string
	HRROI B,[ASCIZ /PUP-NETWORK.DIRECTORY/]
	GTJFN
	 JRST [	ELOG 
		JRST SNDDI9]	; Go clean up
	MOVEM A,FILJFN		; Ok, save JFN
	MOVE B,[8B5+1B19+1B25]	; Open for reading, 8 bit, thawed
	OPENF
	 JRST [	ELOG 
		MOVE A,FILJFN
		RLJFN
		 PUSHJ P,SCREWUP##
		JRST SNDDI9]	; Go clean up

; Loop to send directory
SNDDI2:	MOVE A,FILJFN		; Read next block of data from file
	MOVE B,[POINT 8,EFTPKT+PBCONT]  ; Where to put it
	MOVNI C,↑D512		; Number of bytes
	SIN			; Read block into packet
	ADDI C,↑D512		; Compute number of bytes read
	JUMPE C,SNDDI5		; Jump if none (eof)
	MOVEI A,EFTBLK		; Get pointer to EFTP socket info
	MOVEI B,EFTPKT		; Pointer to Pup
	MOVEI D,↑D15000		; Time out in 15 seconds
	PUSHJ P,ESDATA##	; EFTP send data
	 JRST [	ELOG 
		JRST SNDDI8]	; Go clean up
	JRST SNDDI2		; Succeeded, loop

; Here when reach end of file
SNDDI5:	MOVEI A,EFTBLK		; Get pointer to EFTP socket info
	MOVEI D,↑D15000		; Time out in 15 seconds
	PUSHJ P,ESEND##		; EFTP send end
	 JRST [	ELOG 
		JRST SNDDI8]	; Go clean up
	LOG 

; Here to clean up (PRBDIR code comes here too)
SNDDI8:	MOVE A,FILJFN		; Close the file
	CLOSF
	 PUSHJ P,SCREWUP##
SNDDI9:	MOVEI A,EFTBLK		; EFTP close
	PUSHJ P,ECLOSE##
	MOVE A,PUPJFN		; Close Pup JFN
	CLOSF
	 PUSHJ P,SCREWUP##
	HALTF			; Done

; Inferior fork started here to probe for new directory

PRBDIR:	MOVEI FX,77		; Dummy fork table index
	JSYS FRKINI##		; Initialize stack, etc.
	MOVEI A,400000		; Init interrupt system
	MOVE B,[LEVTAB##,,DCHNTB]
	SIR
	EIR
	SETZB C,D		; Let foreign port be wildcard
	PUSHJ P,OPNPRT		; Open EFTP port
	 HALTF			; Failed, quit

; Broadcast our current version on all directly-connected nets
	MOVEI PB,EFTPKT		; Where to build version Pup
	TLNE F,(NTDSVF)		; Do I have a local copy of the directory?
	 SKIPA P2,MYVER		; Yes, send local version number
	 SETZ P2,		; No, send zero
	DPB P2,[POINT 16,PBCONT(PB),15]  ; Store as first data word
	MOVEI A,MNPLEN+2	; Set Pup length
	DPB A,PUPLEN
	HLLZ P1,PUPROU##	; Init AOBJN pointer

PRBDI1:	MOVE B,RTADR##(P1)	; Get RT entry for net
	TRNE B,-1		; Directly connected?
	TLNN B,(1B1)		; Able to be broadcast upon
	 JRST PRBDI2		; No, bypass
	MOVEI A,1(P1)		; Yes, get net number
	SETZB B,C		; Let Tenex default host and socket
	PUSHJ P,STSPRT##	; Set source port in Pup
	MOVEI C,4		; Dest socket = Misc services
	PUSHJ P,STDPRT##	; Set destination port in Pup
	SETZM PBHEAD+1(PB)	; Zero Pup ID just for kicks
	MOVEI A,240		; Pup type = "net dir version"
	DPB A,PUPTYP
	SETZ A,			; Zero transport control byte
	DPB A,PUPTCB
	HRRZ A,PUPJFN		; Get port JFN
	HRLI A,(1B1)		; Compute checksum
	MOVEI B,PBHEAD(PB)	; Set address
	HRLI B,MXPBLN
	PUPO			; Send it off
	 ELOG 
PRBDI2:	AOBJN P1,PRBDI1		; Repeat for all nets

; Wait 10 seconds for all the responses to come back
	MOVEI P1,↑D10
PRBDI3:	MOVEI A,↑D1000		; Dismiss for 1 second
	DISMS
PRBDI4:	HRRZ A,PUPJFN
	HRLI A,(1B0+1B1)	; Don't wait, check checksum
	MOVEI B,PBHEAD(PB)	; Where to put it
	HRLI B,MXPBLN
	PUPI			; Input a Pup
	 JRST [	CAIN A,PUPX3	; Failed, empty queue?
		 JRST PRBDI5	; Yes, wait some more
		ELOG 
		JRST PRBDI4]
	LDB A,PUPTYP		; Get type
	CAIE A,240		; Net dir version?
	 JRST PRBDI4		; No, ignore
	LDB A,[POINT 16,PBCONT(PB),15]  ; Yes, get his dir version
	CAIG A,(P2)		; Greater than best so far?
	 JRST PRBDI4		; No, ignore
	MOVEI P2,(A)		; Yes, remember new
	LDB P3,PPUPSN		; Remember source net/host
	LDB P4,PPUPSH
	JRST PRBDI4		; Keep looking

PRBDI5:	SOJG P1,PRBDI3		; Wait 10 seconds
	CAMG P2,MYVER		; Did anyone have a newer version?
	 JRST SNDDI9		; No, go clean up and quit

; PRBDIR (cont'd)

; Found someone with a directory newer than ours.
	TLNE F,(NTDSVF)		; Do I maintain a local copy?
	 JRST PRBDIE		; Yes, go get a new one
	MOVEM P2,MYVER		; No, simply set new version and flush cache
	TLNN F,(ENABLF)		; Am I enabled?
	 JRST SNDDI9		; No, don't try to set new version
	MOVE A,[SIXBIT /PUPNDV/]
	MOVE B,MYVER
	OPRFN
	 ELOG 
	JRST SNDDI9		; Clean up and quit

; Request that he EFTP it to us
PRBDIE:	MOVEI P1,↑D12		; Try every 5 seconds for 1 minute
PRBDI6:	MOVEI A,(P3)		; His net number
	SETZB B,C		; Let Tenex default host and socket
	PUSHJ P,STSPRT##	; Set source port in Pup
	MOVEI B,(P4)		; Foreign host number
	MOVEI C,4		; Dest socket = Misc services
	PUSHJ P,STDPRT##	; Set destination port in Pup
	SETZM PBHEAD+1(PB)	; Zero Pup ID just for kicks
	HRRZ A,PUPJFN		; Get local port address
	CVSKT
	 PUSHJ P,SCREWUP##
	MOVEI A,(P3)		; Use his net as our net
	HRRZ B,RTADR##-1(A)	; Our host address on that net
	PUSHJ P,STCPRT##	; Set connection port
	MOVEI A,MNPLEN+6	; Set Pup length
	DPB A,PUPLEN
	MOVEI A,241		; Pup type = "send net dir"
	DPB A,PUPTYP
	SETZ A,			; Zero transport control byte
	DPB A,PUPTCB
	HRRZ A,PUPJFN		; Get port JFN
	HRLI A,(1B1)		; Compute checksum
	MOVEI B,PBHEAD(PB)	; Set address
	HRLI B,MXPBLN
	PUPO			; Send it off
	 ELOG 
	MOVEI A,EFTBLK		; Pointer to EFTP socket info
	MOVEI B,PBHEAD(PB)	; Where to put Pup
	MOVEI D,↑D5000		; Time out in 5 seconds
	PUSHJ P,ERDATA##	; EFTP receive data
	 JRST [	CAIN A,-1	; Failed, timed out?
		 SOJG P1,PRBDI6	; Yes, send another request
		ELOG 
		JRST SNDDI9]	; Clean up and quit

; Got first packet of EFTP data
; Now open local temp file to put it in
	MOVSI A,(1B0+1B17)	; For output use, name from string
	HRROI B,[ASCIZ /PUP-NETWORK.TEMP/]
	GTJFN
	 JRST [	ELOG 
		JRST PRBDI9]	; Go abort transfer
	MOVEM A,FILJFN		; Ok, save JFN
	MOVE B,[8B5+1B20]	; Open for write
	OPENF
	 JRST [	ELOG 
		MOVE A,FILJFN
		RLJFN
		 PUSHJ P,SCREWUP##
		JRST PRBDI9]	; Go abort transfer
	SETOM NDIRVR		; Haven't seen net dir version yet

; PRBDIR (cont'd)

; Loop to receive EFTP data
PRBDI7:	JUMPE C,PRBD7A		; Jump if zero-length data packet
	SKIPL NDIRVR		; Seen dir version yet?
	 JRST .+3		; Yes
	LDB A,[POINT 16,EFTPKT+PBCONT+3, 15]  ; No, get it
	MOVEM A,NDIRVR		; (assume first non-empty data packet is at
				; least 14 bytes long)
	MOVE A,FILJFN		; File to output to
	MOVE B,[POINT 8,EFTPKT+PBCONT]  ; Where to get data from
	MOVNS C			; Number of bytes
	SOUT			; Write block from packet
PRBD7A:	MOVEI A,EFTBLK		; Pointer to EFTP socket info
	MOVEI B,0(PB)		; Where to put Pup
	MOVEI D,↑D15000		; Time out in 15 seconds
	PUSHJ P,ERDATA##	; EFTP receive data
	 JRST [	CAIN A,-2	; Normal end?
		 JRST PRBDI8	; Yes
		ELOG 
		MOVE A,FILJFN	; Delete file
		DELF
		 MOVE A,FILJFN
		CLOSF
		 PUSHJ P,SCREWUP##
		JRST PRBDI9]	; Go abort transfer
	JRST PRBDI7		; Got good data, loop

; Here when reached normal end
PRBDI8:	CAME P2,NDIRVR		; Make sure version consistent with claim
	 JRST [	MOVE A,NDIRVR
		ELOG 
		JRST PRBD8B]	; Go delete temp file
	LOG 
	MOVE A,FILJFN		; Get file JFN
	HRLI A,(1B0)		; Don't release when closing
	CLOSF
	 PUSHJ P,SCREWUP##
	MOVSI A,(1B0+1B1+1B17)	; New file only
	HRRI A,0(P2)		; Version number
	HRROI B,[ASCIZ /PUP-NETWORK.DIRECTORY/]
	GTJFN			; Create new directory version
	 JRST [	ELOG 
		JRST PRBD8B]
	MOVE B,A		; New name
	MOVE A,FILJFN		; Old name
	RNAMF			; Rename temp file as new dir
	 JRST [	ELOG 
		JRST PRBD8A]
	MOVE A,B		; Release JFN
	RLJFN
	 PUSHJ P,SCREWUP##
	TLNN F,(ENABLF)		; Are we enabled?
	 JRST SNDDI9		; No, don't try to install new dir
	MOVE A,[SIXBIT /PUPDIR/]  ; Install net dir
	OPRFN
	 ELOG 
	JRST SNDDI9		; Done, clean up

; Assorted failures
PRBD8A:	MOVE A,B		; Release new net dir JFN
	RLJFN
	 PUSHJ P,SCREWUP##
PRBD8B:	MOVE A,FILJFN		; Delete temp file
	DELF
	 CAI
	JRST SNDDI9		; Go clean up

; Abort transfer
PRBDI9:	MOVEI A,EFTBLK		; Pointer to EFTP socket info
	HRROI B,[ASCIZ /External receiver abort/]
	MOVEI C,2		; External receiver abort
	PUSHJ P,ESABT##		; EFTP send abort
	JRST SNDDI9		; Go clean up

; Open port for EFTP
;	C/ foreign net,,host   D/ foreign socket
; Returns +1:  failed (error already logged)
;	+2:  succeeded
; Sets up PUPJFN, EFTBLK
; Clobbers A-D

OPNPRT:	HRROI A,EFTPKT		; Buffer name here temporarily
	HLRZ B,C		; Separate net and host
	HRRZS C
	WRITE   ; Make foreign port name string
	MOVSI A,(1B2+1B17)
	HRROI B,EFTPKT
	GTJFN			; Create a Pup port
	 JRST [	ELOG 
		POPJ P,]
	MOVEM A,PUPJFN		; Ok, save JFN
	MOVE B,[16B9+1B19+1B20]	; Raw packet mode, read+write
	OPENF			; Open the port
	 JRST [	ELOG 
		MOVE A,PUPJFN
		RLJFN
		 PUSHJ P,SCREWUP
		POPJ P,]
	MOVE B,A		; Ok, copy JFN
	MOVEI A,EFTBLK		; Where to build EFTP socket info
	SETO C,			; Free choice of interrupt channel
	PUSHJ P,EOPEN##		; EFTP open
	 JRST [	ELOG 
		MOVE A,PUPJFN	; Close the port
		CLOSF
		 PUSHJ P,SCREWUP
		POPJ P,]
	JRST SKPRET##		; Succeeded, return +2


; Check local network directory version number and update
; if necessary
; Returns +1
; Clobbers A-C

CHKVER:	TLNN F,(NTDSVF)		; Server enabled?
	 JRST CHKVE1		; No
	MOVSI A,(1B2+1B17)	; Old file, name from string
	HRROI B,[ASCIZ /PUP-NETWORK.DIRECTORY/]
	GTJFN
	 JRST [	SETZM MYVER	; If not found, say version 0
		POPJ P,]
	MOVE B,[1,,7]		; FDBVER
	MOVEI C,C		; Where to put it
	GTFDB			; Read version number
	RLJFN
	 PUSHJ P,SCREWUP##
	HLRZ C,C		; Move to rh
	CAMG C,MYVER		; Has it increased?
	 JRST .+3		; No
	SETZM DIRTIM		; Yes, force new probe
	SETZM PRBTIM
	MOVEM C,MYVER		; Store updated version number
	TLNN F,(ENABLF)		; Are we enabled?
	 POPJ P,		; No, don't try to install new dir
	MOVEI A,377777		; Nil destination
	MOVE B,[1B3+2B17+[EXP 0, 4]] ; Lookup misc services socket
	PUPNM			; (assume it must be in the directory)
	 POPJ P,
	HLRZ A,C		; Get installed version
	CAML A,MYVER		; Older than file version?
	 POPJ P,		; No, done
	MOVE A,[SIXBIT /PUPDIR/]  ; Yes, install new net dir
	OPRFN
	 ELOG 
	POPJ P,

; Not maintaining local copy of Pup-network.directory
CHKVE1:	TLNN F,(ENABLF)		; Am I enabled?
	 POPJ P,		; No, don't try to get local version
	MOVE A,[SIXBIT /PUPNDV/]
	SETO B,			; Get current version, don't flush cache
	OPRFN
	 PUSHJ P,SCREWUP##
	MOVEM B,MYVER
	POPJ P,

; Initialize network directory module
; Returns +1
; Clobbers A-C

DIRINI::HRRZ A,PUPPAR##		; Get word 2 of Pup parameter table
	HRLI A,2
	GETAB
	 PUSHJ P,SCREWUP##
	TLNN A,(1B1)		; Caching network directory?
	 TLO F,(NTDSVF)		; No, enable running name server

	PUSHJ P,CHKVER		; Determine current net dir version
	TIME			; Get now
	ADDI A,↑D60000		; First probe one minute from now
	MOVEM A,DIRTIM
	MOVEM A,PRBTIM
	POPJ P,


GS DIRTIM		; Time for next call to DIRCHK
GS PRBTIM		; Time for next probe for new directory
GS MYVER		; Local network directory version
LS DIRFRK		; Directory fork handle, 0 => none

; The following storage is really local to the net dir fork,
; but there is so little of it that we haven't bothered to
; assign that fork its own pc.

LS FILJFN		; Local file JFN
LS PUPJFN		; Pup JFN for EFTP
LS EFTBLK,↑D20		; EFTP socket info block
LS EFTPKT,MXPBLN	; Packet buffer for EFTP
LS DCHNTB,↑D36		; CHNTAB for this fork
LS NDIRVR		; Version number of net dir being received

	END