perm filename DOMSUB.FAI[S,NET] blob
sn#843966 filedate 1987-08-02 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00006 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00003 00002 Record formats
C00011 00003 RRTYPE RRCLAS RRTTL RRDLEN RRNAME TY.A TY.NS TY.CNAME TY.SOA TY.MB TY.MG TY.MR TY.NULL TY.WKS TY.PTR TY.HINFO TY.MINFO TY.MX TY.AXFR TY.ALL TY.XA CL.IN CL.CH CL.ALL AUTHOR MXPREF P NET DOM NETIBF NETOBF DOMIBF DOMOBF DLKBLK DLKNME NAMBLK DATBLK DATPTR SETUDP QUERYB QDCOUNT ANCOUNT NSCOUNT ARCOUNT TEMPBP TTLMIN TTLMAX EFATAL
C00016 00004 SUCCES NICKNM SFTERR NAMERR GETDOM GETDO1 GETDO2 GETDO3 GETDO4 GETDMA GETINP GETIN1 GETIN2 GETIN3 GETIN4 GETIN5 GETIN6 GETIN7 GETIN8 CPOPJ2 CPOPJ1 CPOPJ
C00025 00005 SQUERY SQUPTD SQUPD1 SQUPTR SQUPT1 SQUER0 SQUER1 SQUER2 UNKERR FMTERR SRVFAI NOTIMP REFUSE RDRESP SKIPQR SKIPQ1 RDANS RDAUTH RDADDL RDRRET NAMERX
C00035 00006 READRR READR1 READR2 READR3 READR4 RDDISP RD.MAX RD.ILL RD.SOA RD.NUL RD.WKS RD.HIN RD.MIN RD.A RDOUTP RD.PTR RD.MX RD.DOM RD.DO1 RD.DO2 READC0 READCP READC1 READC2
C00041 ENDMK
C⊗;
;Record formats ;⊗
;Resource records read from or written to the system cache are stored
;in the following format (36-bit words):
;
; +-----------------------------------------------------------------------+
; | TYPE |
; +-----------------------------------------------------------------------+
; | CLASS |
; +-----------------------------------------------------------------------+
; | TIME TO LIVE (in seconds) |
; +-----------------------------------------------------------------------+
; | DATA LENGTH (or immediate data) |
; +---------------+---------------+---------------+---------------+-------+
; | | |
; | DOMAIN NAME, followed by DATA (in 8-bit bytes) | |
; | | |
; +---------------+---------------+---------------+---------------+-------+
;
;The domain name is a sequence of components, each having a length byte
;followed by that many bytes of characters. A zero length byte terminates
;the string. It is followed by data, generally in the same format. The
;length of the data is stored in case the data has some other format. If
;the data is known to fit in one word, it is stored in place of the data
;length. (For Internet addresses, it is 32 bits right-aligned in the
;word.)
;Data length less than 0 means that a reply was received indicating that
;the requested data does not exist (e.g., the name is unknown). These
;records are cached to avoid repeated queries for nonexistent information.
;Messages sent to or received from name servers follow the format in RFC
;883, as modified in RFC 973. Each message has five sections:
;
; +---------------------+
; | Header |
; +---------------------+
; | Question | the question for the name server
; +---------------------+
; | Answer | answering resource records (RRs)
; +---------------------+
; | Authority | RRs pointing toward an authority
; +---------------------+
; | Additional | RRs holding pertinent information
; +---------------------+
;
;There are no padding bytes, so after the header we cannot assume the
;alignment of any fields in such a message.
;
;The header is 12 bytes (shown here in 16-bit words; we store these two
;per word, left-aligned):
;
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | ID |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; |QR| Opcode |AA|TC|RD|RA| | RCODE |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | QDCOUNT |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | ANCOUNT |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | NSCOUNT |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | ARCOUNT |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
;
;The question section looks as follows:
;
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | |
; / QNAME /
; / /
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | QTYPE |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | QCLASS |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
;
;QNAME is in the 8-bit format described above, except that it may be
;"compressed" by including pointers to previous name components. See RFC
;883 for details.
;
;The other sections contain 0 or more resource records (given by the
;counts in the header). A resource record looks like
;
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | |
; / /
; / NAME /
; | |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | TYPE |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | CLASS |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | |
; + TTL +
; | |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; | RDLENGTH |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
; / RDATA /
; / /
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
;
;NAME is in the 8-bit compressed format, as is RDATA if it is a domain
;name. RDLENGTH is the length (in bytes) of RDATA.
;⊗ RRTYPE RRCLAS RRTTL RRDLEN RRNAME TY.A TY.NS TY.CNAME TY.SOA TY.MB TY.MG TY.MR TY.NULL TY.WKS TY.PTR TY.HINFO TY.MINFO TY.MX TY.AXFR TY.ALL TY.XA CL.IN CL.CH CL.ALL AUTHOR MXPREF P NET DOM NETIBF NETOBF DOMIBF DOMOBF DLKBLK DLKNME NAMBLK DATBLK DATPTR SETUDP QUERYB QDCOUNT ANCOUNT NSCOUNT ARCOUNT TEMPBP TTLMIN TTLMAX EFATAL
;Resource record format as stored in system cache. Data follows name,
;unless (based on RRTYPE) it is stored in RRDLEN word.
RRTYPE←←0 ;Type
RRCLAS←←1 ;Class
RRTTL←←2 ;Time to live (in seconds)
RRDLEN←←3 ;Data length (in bytes), or immediate data
RRNAME←←4 ;Start of name
;Resource record types
TY.A←←=1 ;Internet address
TY.NS←←=2 ;Name server
;TY.MD←←=3 (obsolete) ;Mail destination
;TY.MF←←=4 (obsolete) ;Mail forwarder
TY.CNAME←←=5 ;Canonical name
TY.SOA←←=6 ;Start of authority
TY.MB←←=7 ;Mailbox
TY.MG←←=8 ;Mail group
TY.MR←←=9 ;Mail rename
TY.NULL←←=10 ;Null
TY.WKS←←=11 ;Well-known service
TY.PTR←←=12 ;Pointer
TY.HINFO←←=13 ;Host information
TY.MINFO←←=14 ;Mail information
TY.MX←←=15 ;Mail agent
;Query types (in addition to above)
TY.AXFR←←=252 ;Zone of authority transfer
;TY.MAIB←←=253 (obsolete?) ;(MAILB) Mailbox-related records
;TY.MAIA←←=254 (obsolete) ;(MAILA) Mail agent records
TY.ALL←←=255 ;All types
TY.XA←←<0,,-1> ;Inverse address kludge
;Resource record classes
CL.IN←←=1 ;Internet
;CL.CS←←=2 (obsolete) ;CSNET
CL.CH←←=3 ;Chaos
;Query classes (in addition to above)
CL.ALL←←=255 ;All classes
AUTHOR: 0 ;-1 to force authoritative answer
MXPREF: 0 ;MX record preference value
BEGIN DOMSUB
P←17 ;Guess
NET←←0 ;Channel for network I/O
DOM←←1 ;Channel for domain cache
NETIBF: BLOCK 3 ;Buffer headers
NETOBF: BLOCK 3
DOMIBF: BLOCK 3
DOMOBF: BLOCK 3
DLKBLK: BLOCK 100 ;LOOKUP block
DLKNME: BLOCK 1 ;Pointer to end of name in DLKBLK
NAMBLK: BLOCK 100 ;Block for returned name
DATBLK: BLOCK 100 ;Block for returned data
DATPTR: BLOCK 1 ;Pointer used to fill DATBLK
SETUDP: 26 ;MTAPE block for UDP parameters
0 ;Status bits
0 ;Local port
0
0
=53 ;Remote domain server port
0 ;Remote address
;Message header (12 bytes) for domain server query
QUERYB: BYTE (8)0,0,1,0 ;ID, flags (recursion desired)
BYTE (8)0,1,0,0 ;QDCOUNT, ANCOUNT
BYTE (8)0,0,0,0 ;NSCOUNT, ARCOUNT
QDCOUNT:0 ;Storage for RDRESP
ANCOUNT:0
NSCOUNT:0
ARCOUNT:0
TEMPBP: 0
TTLMIN: 5 ;Minimum TTL for records we give system
TTLMAX: =5*=60 ;(debugging) ;Maximum TTL for records we give system
EFATAL: OUTSTR [ASCIZ/Fatal error in domain lookup code. Find a wizard.
/]
JRST 4,EFATAL
;⊗ SUCCES NICKNM SFTERR NAMERR GETDOM GETDO1 GETDO2 GETDO3 GETDO4 GETDMA GETINP GETIN1 GETIN2 GETIN3 GETIN4 GETIN5 GETIN6 GETIN7 GETIN8 CPOPJ2 CPOPJ1 CPOPJ
;Get domain information. Calling sequence:
;
; MOVE 0,[<addr or byte ptr to ASCIZ domain name>]
; MOVE 1,[<query type>]
; MOVE 2,[<query class>]
; PUSHJ P,GETDOM
; <name error: requested information does not exist>
; <soft error: requested information not available>
; <nickname was given: AC 3 points to canonical name>
; <success, 0 contains addr of domain name,
; 1 contains type,
; 2 contains class,
; 3 contains data>
;
;Setting the flag AUTHOR non-0 will force sending a network query before
;checking the system's cache.
;
;After a successful return, to get further answers:
;
; PUSHJ P,GETDMA
; <no more information>
; <success, 0-3 contain same as above>
;
;To translate an Internet address to a domain name, call GETDOM with the
;address in AC 0 and TY.XA as the query type. The returned data will be
;a type TY.A record for the address, i.e. AC 0 will point to the name.
;
;The returned domain name pointed to by AC 0 may differ in capitalization,
;otherwise it is expected to be the same as the query domain name. The
;format of the data returned in AC 3 depends on the type in AC 1, as follows:
;
; TY.A AC 3 contains the 32-bit address.
; TY.SOA Not implemented
; TY.NULL Not implemented
; TY.WKS Not implemented
; TY.HINFO Not implemented
; TY.MINFO Not implemented
; TY.MX AC 3 points to an ASCIZ string for a host name,
; location MXPREF contains the preference value
; Others AC 3 points to an ASCIZ string representing a domain name
;
;If the original name is found to be a nickname, you should call GETDOM
;again with the canonical name that was returned. It is safe to copy AC 3
;into 0 (and reset the type in AC 1).
;
;A name error means a server told us the information does not exist for
;the requested domain. A soft error means we could not get to a server,
;so retrying later may work.
;Return addresses restore ACs saved on entry and skip appropriately.
SUCCES: AOS -1(P) ;Success
NICKNM: AOS -1(P) ;Nickname
SFTERR: AOS -1(P) ;Soft error
NAMERR: POP P,4 ;Name error
POPJ P,
↑GETDOM:PUSH P,4 ;Save some ACs
;Prepare lookup block
MOVEM 1,DLKBLK+RRTYPE
MOVEM 2,DLKBLK+RRCLAS
CAIN 1,TY.XA ;Inverse address query?
JRST [ MOVEM 0,DLKBLK+RRDLEN ;Yes, store address
JRST GETDO4] ;Skip over name parsing
;Convert name argument from ASCIZ to domain format
TLNN 0,-1 ;Byte ptr?
HRLI 0,440700 ;No, make one
MOVE 2,[POINT 8,DLKBLK+RRNAME] ;Destination byte ptr
GETDO1: SETZ 4, ;Component length ← 0
IBP 2 ;Skip length byte
MOVE 3,2 ;Save ptr to length byte
GETDO2: ILDB 1,0 ;Get a byte
CAIE 1,"." ;End of component?
CAIN 1,0 ;Or of string?
JRST GETDO3 ;Yes
IDPB 1,2 ;Copy to domain string
AOJA 4,GETDO2
GETDO3: DPB 4,3 ;Store length byte
JUMPN 1,GETDO1 ;Continue unless end of string
IDPB 1,2 ;End with 0 length byte
MOVEM 2,DLKNME ;Save ptr to end of name
GETDO4: INIT DOM,0 ;Open domain device
SIXBIT/DOM/
DOMOBF,,DOMIBF
PUSHJ P,EFATAL
SKIPN AUTHOR ;Force query if authority desired
LOOKUP DOM,DLKBLK ;See if data in system
JRST [ PUSHJ P,SQUERY ;Not found, ask a server
JRST SFTERR ;No reply
LOOKUP DOM,DLKBLK ;See if server added info for us
JRST SFTERR ;Nope, nothing there
JRST .+1]
;System has information, read it
INBUF DOM,1 ;Prepare to read
PUSHJ P,GETINP ;Read RR, return data in ACs
JRST NAMERR ;Name error
PUSHJ P,EFATAL ;First input failed (can't happen)
CAIN 1,TY.CNAME
JRST NICKNM ;Return a nickname
JRST SUCCES ;Return an ordinary answer
↑GETDMA:PUSH P,4
PUSHJ P,GETINP
JFCL ;Name error
SOS -1(P) ;No input data
POP P,4
JRST CPOPJ1
;GETINP reads one input record from the system. Calling sequence:
;
; PUSHJ P,GETINP
; <name error>
; <no data available>
; <success, ACs 0-3 contain return data>
;
;Return data is same as for GETDOM.
GETINP: IN DOM, ;Get the data
JRST .+2
JRST CPOPJ1 ;Input failed, no more data
MOVE 1,DOMIBF ;Buffer pointer
ADDI 1,2 ;Point to resource record
SKIPGE RRDLEN(1) ;Name error?
POPJ P, ;Yes, return failure
;Copy the name in the reply into NAMBLK.
MOVE 2,[POINT 8,RRNAME(1)]
MOVE 0,[POINT 7,NAMBLK]
GETIN1: ILDB 3,2 ;Get a length byte
JUMPE 3,GETIN3
GETIN2: ILDB 4,2 ;Get a data byte
IDPB 4,0 ;Copy it
SOJG 3,GETIN2
MOVEI 4,"." ;End a name component
IDPB 4,0
JRST GETIN1
GETIN3: DPB 3,0 ;Replace last "." with null
MOVE 0,RRTYPE(1)
CAIN 0,TY.A ;Internet address?
JRST [ MOVE 3,RRDLEN(1);Yes, get it from length field
JRST GETIN8] ;Return it
;Assume data is a domain name, and copy it into an ASCIZ string.
GETIN4: MOVE 0,[POINT 7,DATBLK]
GETIN5: ILDB 3,2 ;Get first length byte
JUMPE 3,GETIN7
GETIN6: ILDB 4,2 ;Get a character
IDPB 4,0 ;Copy it
SOJG 3,GETIN6
MOVEI 4,"." ;End a name component
IDPB 4,0
JRST GETIN5
GETIN7: DPB 3,0 ;Replace last "." with null
MOVEI 3,DATBLK
GETIN8: MOVE 2,RRCLAS(1) ;Set up ACs 0-2
MOVE 1,RRTYPE(1)
MOVEI 0,NAMBLK
CPOPJ2: AOS (P) ;Skip twice for success
CPOPJ1: AOS (P)
CPOPJ: POPJ P,
;⊗ SQUERY SQUPTD SQUPD1 SQUPTR SQUPT1 SQUER0 SQUER1 SQUER2 UNKERR FMTERR SRVFAI NOTIMP REFUSE RDRESP SKIPQR SKIPQ1 RDANS RDAUTH RDADDL RDRRET NAMERX
;Send query to domain server. Returns non-skip if no response,
;skip if response received.
SQUERY: INIT NET,0 ;Open network channel
SIXBIT/IMP/
NETOBF,,NETIBF
PUSHJ P,EFATAL
INBUF NET,1 ;Allocate I/O buffers
OUTBUF NET,1
MOVEI 1,=8 ;Set byte size in buffer headers
DPB 1,[POINT 6,NETIBF+1,11]
DPB 1,[POINT 6,NETOBF+1,11]
MTAPE NET,[17 ↔ 0,,001200] ;Set 20-second input timeout
SETOM SETUDP+2 ;Let system allocate local port
;; MOVE 1,[4415,,200012] ;(Argus)
;; MOVE 1,[4402,,000057] ;(Labrea)
MOVE 1,[4405,,200024] ;(Portia)
MOVEM 1,SETUDP+6 ;Set server address
MTAPE NET,SETUDP
OUTPUT NET, ;Set up output buffer header
MOVE 1,SETUDP+2 ;Get the port we were assigned
DPB 1,[POINT 16,QUERYB,15] ;Use it as the ID byte
MOVE 1,NETOBF ;Output buffer pointer
ADDI 1,2 ;First data word
HRLI 1,QUERYB ;Set up to copy query block
BLT 1,2(1) ;Copy three header words
MOVE 0,DLKBLK+RRTYPE
CAIN 0,TY.XA ;Inverse address query?
JRST SQUPTR ;Yes, make up a PTR query
HRLI 1,DLKBLK+RRNAME ;Start of name to copy
MOVE 2,DLKNME ;Ptr to last byte in source
ADDI 2,-DLKBLK-RRNAME(1);Ptr to last byte in destination
BLT 1,(2) ;Copy name
MOVEM 2,NETOBF+1 ;Store ptr in buffer header
MOVE 1,DLKBLK+RRTYPE ;Copy type from lookup block
JRST SQUER0 ;Finish header and send query
;Subroutine to convert a byte to decimal ASCII and store in query,
;preceded by a length byte.
SQUPTD: MOVEI 3,1 ;Figure out the length
CAIL 2,=10
MOVEI 3,2
CAIL 2,=100
MOVEI 3,3
IDPB 3,NETOBF+1
SQUPD1: IDIVI 2,=10 ;Do the usual decimal conversion
PUSH P,3
JUMPE 2,.+2
PUSHJ P,SQUPD1
POP P,3
ADDI 3,"0"
IDPB 3,NETOBF+1
POPJ P,
;Here to make up and send a PTR query for an inverse address lookup.
SQUPTR: HRLI 1,441000 ;Update output byte ptr
MOVEM 1,NETOBF+1
LDB 2,[POINT 8,DLKBLK+RRDLEN,35]
PUSHJ P,SQUPTD ;Convert 4th byte to decimal
LDB 2,[POINT 8,DLKBLK+RRDLEN,27]
PUSHJ P,SQUPTD ;Convert 3rd byte to decimal
LDB 2,[POINT 8,DLKBLK+RRDLEN,19]
PUSHJ P,SQUPTD ;Convert 2nd byte to decimal
LDB 2,[POINT 8,DLKBLK+RRDLEN,11]
PUSHJ P,SQUPTD ;Convert 1st byte to decimal
MOVE 2,[POINT 7,[ASCIZ/πIN-ADDR∧ARPA/]]
SQUPT1: ILDB 3,2 ;Follow with ".IN-ADDR.ARPA"
IDPB 3,NETOBF+1
JUMPN 3,SQUPT1
MOVEI 1,TY.PTR ;Query type
SQUER0: ROT 1,-=8
IDPB 1,NETOBF+1
ROT 1,=8
IDPB 1,NETOBF+1
MOVE 1,DLKBLK+RRCLAS ;Copy class
ROT 1,-=8
IDPB 1,NETOBF+1
ROT 1,=8
IDPB 1,NETOBF+1
;; OUTSTR [ASCIZ/Domain query ... /]
OUT NET, ;Send the query
JRST SQUER1
PUSHJ P,EFATAL ;Some kind of error
SQUER1: IN NET, ;Wait for response
JRST SQUER2
RELEAS NET, ;Time out or other error
POPJ P,
SQUER2: OUTBUF DOM,1 ;Prepare to give RRs to system
OUTPUT DOM, ;Set up first output buffer
MOVEI 1,=16 ;Temporarily change byte size
DPB 1,[POINT 6,NETIBF+1,11]
ILDB 1,NETIBF+1 ;ID field
;Don't bother checking ID for now. What would we do if it was wrong?
ILDB 1,NETIBF+1 ;Opcode and Flags
ILDB 2,NETIBF+1 ;Read and store other header fields
MOVEM 2,QDCOUNT
ILDB 2,NETIBF+1
MOVEM 2,ANCOUNT
ILDB 2,NETIBF+1
MOVEM 2,NSCOUNT
ILDB 2,NETIBF+1
MOVEM 2,ARCOUNT
MOVEI 2,=8 ;Back to 8-bit bytes
DPB 2,[POINT 6,NETIBF+1,11]
;Various flags in 1 should be checked.
ANDI 1,17 ;Dispatch on RCODE field
CAILE 1,5 ;Highest reply code we know
JRST UNKERR
JRST @[ RDRESP ;No error, read response
FMTERR ;Format error
SRVFAI ;Server failure
NAMERX ;Name error
NOTIMP ;Not implemented
REFUSE](1) ;Refused
UNKERR: OUTSTR [ASCIZ/Unknown error code.
/]
PUSHJ P,EFATAL
FMTERR: OUTSTR [ASCIZ/Format error.
/]
PUSHJ P,EFATAL
SRVFAI: OUTSTR [ASCIZ/Server failure.
/]
PUSHJ P,EFATAL
NOTIMP: OUTSTR [ASCIZ/Not implemented error.
/]
PUSHJ P,EFATAL
REFUSE: OUTSTR [ASCIZ/Query refused.
/]
PUSHJ P,EFATAL
;Read response from server, and store all of the resource records in the
;response into the system cache. These will then be used to answer the
;original query.
;Skip over question section. (We assume it matches the query.)
;QDCOUNT should always be 1, but we don't assume it.
RDRESP: SOSGE QDCOUNT ;Skip unless done question section
JRST RDANS
SKIPQR: ILDB 1,NETIBF+1 ;Get a length byte
JUMPE 1,SKIPQ1 ;Jump at end of QNAME
TRZE 1,300 ;Compressed format?
JRST [ IBP NETIBF+1 ;Yes, this makes it easy to skip over!
JRST SKIPQ1]
IBP NETIBF+1 ;Skip over that many bytes
SOJG 1,.-1
JRST SKIPQR
SKIPQ1: AOS NETIBF+1 ;Skip 4 bytes (type and class)
JRST RDRESP
;Read resource records from answer section.
RDANS: SOSGE ANCOUNT ;Skip unless done answer section
JRST RDAUTH
PUSHJ P,READRR ;Read a resource record
JRST RDANS
;Read resource records from authority section.
RDAUTH: SOSGE ANCOUNT ;Skip unless done authority section
JRST RDADDL
PUSHJ P,READRR ;Read a resource record
JRST RDAUTH
;Read resource records from additional section.
RDADDL: SOSGE ANCOUNT ;Skip unless done additional section
JRST RDRRET
PUSHJ P,READRR ;Read a resource record
JRST RDADDL
RDRRET: RELEAS NET,
JRST CPOPJ1 ;Return from SQUERY
;Name error means the name we sent it is no good. Make up a record
;to indicate this and store it in the system cache.
NAMERX: SETOM DLKBLK+RRDLEN ;Indicate error
MOVE 1,TTLMAX ;Give it maximum TTL
MOVEM 1,DLKBLK+RRTTL
MOVE 1,DOMOBF ;Output buffer pointer
ADDI 1,2 ;First data word
HRLI 1,DLKBLK ;Addr of our query
MOVE 2,DLKNME ;Ptr to last byte in query
ADDI 2,-DLKBLK(1) ;Ptr to last byte in destination
BLT 1,(2) ;Copy the query
MOVEM 2,DOMOBF+1 ;Store final byte ptr for output
OUTPUT DOM, ;Send record to system cache
JRST RDRRET
;⊗ READRR READR1 READR2 READR3 READR4 RDDISP RD.MAX RD.ILL RD.SOA RD.NUL RD.WKS RD.HIN RD.MIN RD.A RDOUTP RD.PTR RD.MX RD.DOM RD.DO1 RD.DO2 READC0 READCP READC1 READC2
;Read a resource record and enter it in the system's cache.
;Macro to copy NUM bytes from input buffer to a word, right-aligned.
DEFINE COPYB(NUM,WORD)<
SETZM WORD
MOVE 1,[POINT 8,WORD,<35-8*NUM>]
REPEAT NUM,<
ILDB 0,NETIBF+1
IDPB 0,1
>;REPEAT NUM
>;DEFINE COPYB
READRR: MOVE 3,DOMOBF ;Pointer to output buffer
ADDI 3,2 ;Start of data
MOVE 2,3 ;Make a copy for byte ptr
ADD 2,[POINT 8,RRNAME] ;Start of name
MOVEM 2,DOMOBF+1 ;Store ptr in buffer hdr
READR1: ILDB 1,NETIBF+1 ;Get a length byte
TRZE 1,300 ;Compressed format?
JRST READR3 ;Yes
IDPB 1,DOMOBF+1 ;Copy length byte
JUMPE 1,READR4 ;Jump when done
READR2: ILDB 0,NETIBF+1 ;Get a byte
IDPB 0,DOMOBF+1 ;Copy it
SOJG 1,READR2
JRST READR1
READR3: PUSHJ P,READCP ;Read compressed name
READR4: COPYB(2,<RRTYPE(3)>) ;Copy type
COPYB(2,<RRCLAS(3)>) ;Copy class
COPYB(4,<RRTTL(3)>) ;Copy time to live
MOVE 0,RRTTL(3) ;Examine TTL
CAMGE 0,TTLMIN ;Force into desired range
MOVE 0,TTLMIN
CAMLE 0,TTLMAX
MOVE 0,TTLMAX
MOVEM 0,RRTTL(3)
COPYB(2,<RRDLEN(3)>) ;Copy data length
MOVE 1,RRTYPE(3) ;Examine type
CAIL 1,RD.MAX ;Bounds check
PUSHJ P,EFATAL
JRST @RDDISP(1) ;Dispatch based on type
RDDISP: RD.ILL
RD.A ;TY.A
RD.DOM ;TY.NS
RD.DOM ;TY.MD (obsolete)
RD.DOM ;TY.MF (obsolete)
RD.DOM ;TY.CNAME
RD.SOA ;TY.SOA
RD.DOM ;TY.MB
RD.DOM ;TY.MG
RD.DOM ;TY.MR
RD.NULL ;TY.NULL
RD.WKS ;TY.WKS
RD.PTR ;TY.PTR
RD.HINFO ;TY.HINFO
RD.MINFO ;TY.MINFO
RD.MX ;TY.MX
RD.MAX←←.-RDDISP
RD.ILL: PUSHJ P,EFATAL ;Type 0 doesn't exist
RD.SOA: PUSHJ P,EFATAL ;These need to be written
RD.NUL: PUSHJ P,EFATAL
RD.WKS: PUSHJ P,EFATAL
RD.HIN: PUSHJ P,EFATAL
RD.MIN: PUSHJ P,EFATAL
RD.A: COPYB(4,<RRDLEN(3)>) ;Copy address into length word
RDOUTP: OUTPUT DOM, ;Send record to system cache
POPJ P, ;Return from READRR
RD.PTR: MOVE 0,DLKBLK+RRTYPE
CAIE 0,TY.XA ;Yes, was this for inv addr query?
JRST RD.DOM ;No, treat as an ordinary record
;Construct an address record from the PTR data.
MOVEI 0,TY.A ;Change type to address
MOVEM 0,RRTYPE(3)
MOVE 0,DLKBLK+RRDLEN ;Get address from query
MOVEM 0,RRDLEN(3)
MOVE 2,3 ;Copy data into name field
ADD 2,[POINT 8,RRNAME]
MOVEM 2,DOMOBF+1
JRST RD.DOM
RD.MX: COPYB(2,MXPREF) ;Copy preference value
;(fall into RD.DOM)
;Copy a domain name into the output buffer.
RD.DOM: ILDB 1,NETIBF+1 ;Get a length byte
TRZE 1,300 ;Compressed format?
JRST RD.DO2 ;Yes
IDPB 1,DOMOBF+1 ;Copy length byte
JUMPE 1,RDOUTP ;Jump when done
RD.DO1: ILDB 0,NETIBF+1 ;Get a byte
IDPB 0,DOMOBF+1 ;Copy it
SOJG 1,RD.DO1
JRST RD.DOM
RD.DO2: PUSHJ P,READCP ;Read compressed name
JRST RDOUTP
;Follow a compressed name pointer to read and copy the rest of a name.
READC0: ILDB 0,TEMPBP ;Here when multiple pointers
JRST .+2
READCP: ILDB 0,NETIBF+1 ;Get the rest of the pointer
LSH 1,=8
ADDI 0,(1) ;Compute the byte offset
IDIVI 0,4 ;0←word offset, 1←byte
ADD 0,[ POINT 8,2 ;Make a byte ptr
POINT 8,2,7 ;(2 is for data offset from NETIBF)
POINT 8,2,15
POINT 8,2,23](1)
ADD 0,NETIBF ;Relocate to input message
MOVEM 0,TEMPBP
READC1: ILDB 1,TEMPBP ;Get a length byte
TRZE 1,300 ;Another pointer?
JRST READC0 ;Yes, what complexity!
IDPB 1,DOMOBF+1 ;Copy length byte
JUMPE 1,CPOPJ ;Return when done
READC2: ILDB 0,TEMPBP ;Get a byte
IDPB 0,DOMOBF+1 ;Copy it
SOJG 1,READC2
JRST READC1
BEND DOMSUB