NEW
  AUTO 3,1
				.LIST OFF	
*/--------------------------------------
* # DNS.Clear
*  Clear DNS Cache
* **In:** 
* ## RETURN VALUE 
*\--------------------------------------
DNS.Clear		ldx #K.DNSCACHE.SIZE*S.DNSCACHE
.1				stz DNS.CACHE-1,x
				dex
				bne .1
				clc
				rts
*/--------------------------------------
* # DNS.Query
*  Query DNS for specified host
* **In:**
*   PUSHW = PTR to IP to fill with cached data
*	PUSHW = hostname PTR to PSTR 
* ## RETURN VALUE
*   CC: hit: IP filled with address
*   CS: missed 
*\--------------------------------------
DNS.Query		>PULLW ZPPtrDNS			Get host string
				>PULLW ZPPtrIP			Get IP address to fill
				
DNS.Query.I		jsr DNS.FIND.BY.NAME
				bcs DNS.REQUEST
				
				lda (ZPCachePtr)		get status...
				bpl .9					Pending...
				
				lda ZPCachePtr
				clc
				adc #S.DNSCACHE.IP
				sta ZPCachePtr
				bcc .1
				inc ZPCachePtr+1
				
.1				ldy #3

.2				lda (ZPCachePtr),y
				sta (ZPPtrIP),y
				dey
				bpl .2
				clc
				rts

.9				lda #ERR.DNS.PENDING
				sec
				rts
*--------------------------------------
DNS.REQUEST		lda hDNSSocket
				beq .99

				jsr DNS.CSTR2DNS		Y=DNS string len+0
				bcs .99
				
				iny
				lda /S.DNS.QTYPE.A
				sta DNS.MSG,y
				iny
				lda #S.DNS.QTYPE.A
				sta DNS.MSG,y
				
				iny
				lda /S.DNS.QCLASS.IN
				sta DNS.MSG,y
				iny
				lda #S.DNS.QCLASS.IN
				sta DNS.MSG,y
				
				iny
				tya
				sta DNS.MSG.LEN
				lda #0
				sta DNS.MSG.LEN+1
				
				>LDYA A2osX.RANDOM16
				>STYA DNS.MSG.ID
				
				>STYA DNS.TmpCache+S.DNSCACHE.ID
				
				lda #K.DNS.PENDING.TTL
				sta DNS.TmpCache+S.DNSCACHE.TTL
				stz DNS.TmpCache+S.DNSCACHE.TTL+1
				stz DNS.TmpCache+S.DNSCACHE.TTL+2
				stz DNS.TmpCache+S.DNSCACHE.TTL+3
				
				lda #S.DNSCACHE.STATUS.PENDING
				jsr DNS.ADD.I
				bcs .9
				
				jsr DNS.REQUEST.SEND
				bcs .99

				lda #ERR.DNS.PENDING
				sec
				rts

.99				lda #ERR.DNS.ERROR
.9				sec
				rts
*--------------------------------------
DNS.REQUEST.SEND
				>LDYAI UDP.PORT.DNS
				>STYA SA.REMOTE+S.SOCKADDR.PORT
				
				ldy #3
				
.1				lda IPCFG+S.IPCFG.DNS1,y
				sta SA.REMOTE+S.SOCKADDR.ADDR,y
				dey
				bpl .1
				jsr .4
				
				ldy #3
				
.2				lda IPCFG+S.IPCFG.DNS2,y
				beq .8
				sta SA.REMOTE+S.SOCKADDR.ADDR,y
				dey
				bpl .2
				
.4				>PUSHW L.SA.REMOTE

				>PUSHW DNS.MSG.LEN
				>PUSHW L.DNS.MSG
				lda hDNSSocket
				jmp SKT.SendTo
				
.8				clc
				rts				
*--------------------------------------
DNS.CSTR2DNS	lda (ZPPtrDNS)
				beq .9
				
				>LDYA ZPPtrDNS
				>SYSCALL2 strlen

				tax
				bne .9
								
				cpy #K.DNS.MAXLEN-1
				bcs .9
				
				lda #0					Ending 0
				sta DNS.MSG.NAME+1,y

				phy						save len for later
				
				ldx #0
				dey
				
.1				lda (ZPPtrDNS),y
				and #$7f
				cmp #'.'
				beq .2
				
				cmp #'A'
				bcc .10
				cmp #'Z'+1
				bcs .10
				adc #$20
				
.10				inx
				bra .3
				
.2				txa				
				ldx #0
				
.3				sta DNS.MSG.NAME+1,y
				dey
				bpl .1
				
				stx DNS.MSG.NAME
				
				pla						Get back Len
				sec						+1
				adc #S.DNS-S.UDP		compute offset next to NAME
				tay
*				clc
				rts
				
.9				sec
				rts				
*/--------------------------------------
* # DNS.Add
*  Add a static DNS record
* **In:**
*  PUSHW = PTR to IP
*  PUSHW = hostname CSTR to Add
*\--------------------------------------
DNS.Add			>PULLW ZPPtrDNS			Get host string
				>PULLW ZPPtrIP			Get host IP address
				
				ldy #3
				
.1				lda (ZPPtrIP),y
				sta DNS.TmpCache+S.DNSCACHE.IP,y
				dey
				bpl .1
				
				stz DNS.TmpCache+S.DNSCACHE.TTL
				stz DNS.TmpCache+S.DNSCACHE.TTL+1
				stz DNS.TmpCache+S.DNSCACHE.TTL+2
				stz DNS.TmpCache+S.DNSCACHE.TTL+3
				
				lda #S.DNSCACHE.STATUS.RESOLVED+S.DNSCACHE.STATUS.STATIC
				
DNS.ADD.I		sta DNS.TmpCache
				
				jsr DNS.FIND.BY.NAME
				bcc .2					Found, go update...

				jsr DNS.FIND.FREE

				>LDYA ZPPtrDNS
				>SYSCALL2 strdup
				bcs .9
				txa
				ldy #S.DNSCACHE.hNAME
				sta (ZPCachePtr),y
								 				
.2				lda DNS.TmpCache
				sta (ZPCachePtr)
				
				ldy #S.DNSCACHE.ID
				
.3				lda DNS.TmpCache,y
				sta (ZPCachePtr),y
				iny
				cpy #S.DNSCACHE
				bne .3
				
				clc
.9				rts
*/--------------------------------------
* # DNS.GetCAche
*  Return a Ptr to DNS Cache Table
* **In:**
* ## RETURN VALUE
*   Y,A = PTR to DNS.CACHE
*\--------------------------------------
DNS.GetCAche	>LDYA L.DNS.CACHE
				clc
				rts
*--------------------------------------
DNS.FIND.BY.NAME
				>LDYA L.DNS.CACHE
				>STYA ZPCachePtr
				
				ldx #K.DNSCACHE.SIZE
				
.1				lda (ZPCachePtr)
				beq .6					empty DNS cache entry?
				
				phx
				
				>PUSHW ZPPtrDNS
				ldy #S.DNSCACHE.hNAME
				lda (ZPCachePtr),y
				>SYSCALL2 GetMemPtr
				
				>SYSCALL2 StrCaseCmp
				plx
				bcc .8
				
.6				lda ZPCachePtr
				clc
				adc #S.DNSCACHE
				sta ZPCachePtr
				bcc .7
				inc ZPCachePtr+1
				
.7				dex
				bne .1
				
				sec
.8				rts
*--------------------------------------
DNS.UPDATE.BY.ID
				>LDYA L.DNS.CACHE
				>STYA ZPCachePtr
			
				ldx #K.DNSCACHE.SIZE
				
.1				lda (ZPCachePtr)
				beq .6					empty DNS cache entry?
				bmi .6					resolved ?

				ldy #S.DNSCACHE.ID
				lda (ZPCachePtr),y
				cmp DNS.TmpCache+S.DNSCACHE.ID
				bne .6
				iny
				lda (ZPCachePtr),y
				cmp DNS.TmpCache+S.DNSCACHE.ID+1
				bne .6

				lda #S.DNSCACHE.STATUS.RESOLVED
				sta (ZPCachePtr)
				
				ldy #S.DNSCACHE.TTL
.2				lda DNS.TmpCache,y
				sta (ZPCachePtr),y
				iny
				cpy #S.DNSCACHE
				bne .2
				
				clc
				rts
				
.6				lda ZPCachePtr
				clc
				adc #S.DNSCACHE
				sta ZPCachePtr
				bcc .7
				inc ZPCachePtr+1
				
.7				dex
				bne .1
				
				sec
				rts
*--------------------------------------
DNS.FIND.FREE	>LDYA L.DNS.CACHE
				>STYA ZPCachePtr
				
				lda #$ff
				sta TmpDWord
				sta TmpDWord+1
				sta TmpDWord+2
				sta TmpDWord+3

				ldx #K.DNSCACHE.SIZE
				
.1				lda (ZPCachePtr)
				beq .8					empty DNS cache entry?

				bit #S.DNSCACHE.STATUS.STATIC+S.DNSCACHE.STATUS.PENDING
				bne .7					Static/Pending.....skip
				
				phx
				
				ldy #S.DNSCACHE.TTL
				ldx #3
				
				sec
				
.2				lda TmpDWord,x			is saved TTL greater then actual TTL?
				sbc (ZPCachePtr),y
				iny
				dex
				bpl .2
				
				bcc .6					no,
				
				ldy #S.DNSCACHE.TTL
				ldx #3
				
.3				lda (ZPCachePtr),y		Save new lowest TTL
				sta TmpDWord,x
				iny
				dex
				bpl .3
				
				>LDYA ZPCachePtr
				>STYA ZPTmpPtr1			save lowest TTL slot ...
				
.6				plx

.7				lda ZPCachePtr
				clc
				adc #S.DNSCACHE
				sta ZPCachePtr
				bcc .71
				inc ZPCachePtr+1
				
.71				dex
				bne .1					no empty slot found, discard lowest TTL
				
				>LDYA ZPTmpPtr1
				>STYA ZPCachePtr
				jsr DNS.FREE

.8				clc
				rts
*--------------------------------------
DNS.EXPIRE		>LDYA L.DNS.CACHE
				>STYA ZPCachePtr
				
				ldx #K.DNSCACHE.SIZE
				
.1				lda (ZPCachePtr)
				beq .7					empty DNS cache entry?

				bit #S.DNSCACHE.STATUS.STATIC
				bne .7
				
				phx
				
				ldy #S.DNSCACHE.TTL
				ldx #4
				clc
				
.2				lda (ZPCachePtr),y
				sbc #0
				sta (ZPCachePtr),y
				iny
				dex
				bne .2
				
				bcs .6
				
				jsr DNS.FREE
				
.6				plx				
				
.7				lda ZPCachePtr
				clc
				adc #S.DNSCACHE
				sta ZPCachePtr
				bcc .8
				inc ZPCachePtr+1
				
.8				dex
				bne .1

				clc
				rts
*--------------------------------------
DNS.FREE		ldy #S.DNSCACHE.hNAME
				lda (ZPCachePtr),y
				beq .1
				
				>SYSCALL2 FreeMem
.1				lda #0
				sta (ZPCachePtr)
				rts
*--------------------------------------
DNS.POLL		lda hDNSSocket
				beq .8
				jsr SKT.Recv
				bcs .8

				jsr DNS.DecodeMsg
							
.8				clc
				rts
*--------------------------------------
DNS.DecodeMsg	sta hFrameIn
				>SYSCALL2 GetMemPtr
				>STYA ZPFrameInPtr

				ldy #S.DNS.F
				lda (ZPFrameInPtr),y
				and /S.DNS.F.QR
				beq .9

				ldy #S.DNS.ID
				lda (ZPFrameInPtr),y
				sta DNS.TmpCache+S.DNSCACHE.ID
				iny
				lda (ZPFrameInPtr),y
				sta DNS.TmpCache+S.DNSCACHE.ID+1
				
				ldy #S.DNS.ANCOUNT+1
				lda (ZPFrameInPtr),y
				beq .9
				pha						save Answer count...
				
				ldy #S.DNS.QDCOUNT+1
				lda (ZPFrameInPtr),y

				ldy #S.DNS				Point to DATA

				tax
				beq .3					no QUERY to skip
				
.1				lda (ZPFrameInPtr),y
				beq .2
				bpl	.11					Pointer ?
				iny						yes, skip 2 bytes
				iny
				bra .2
				
.11				tya
				sec
				adc (ZPFrameInPtr),y	Skip LEN+1 bytes
				tay
				bra .1
				
.2				iny 
				iny
				iny						Skip QTYPE & QCLASS
				iny
				
				iny						next pos
				
.21				dex						skip another QUERY ?
				bne .1
				
				plx						get back answer count
				
.3				lda (ZPFrameInPtr),y
				beq .32
				bpl .31					Pointer ? 
				iny						yes, skip 2 bytes
				iny
				bra .32
	
.31 			tya
				sec
				adc (ZPFrameInPtr),y	Skip LEN+1 bytes
				tay
				bra .3
				
.32				iny						skip S.DNS.QTYPE HIGH
				lda (ZPFrameInPtr),y
				cmp #S.DNS.QTYPE.A
				beq .40
				
				tya
				clc
				adc #7					skip CLASS,TTL+DATALENHIGH
				tay
				sec						skip DATALENLO
				adc (ZPFrameInPtr),y    	add DATALEN
				tay
				dex
				bne .3
				bra .9
				
.40				iny						skip QCLASS
				iny
				
				iny						next pos
				
				ldx #3
.4				lda (ZPFrameInPtr),y
				sta DNS.TmpCache+S.DNSCACHE.TTL,x
				iny
				dex
				bpl .4

				iny						skip DATALEN
				iny
				ldx #0
				
.5				lda (ZPFrameInPtr),y
				sta DNS.TmpCache+S.DNSCACHE.IP,x
				iny
				inx
				cpx #4
				bne .5
				
				jsr DNS.UPDATE.BY.ID
				
.9				lda hFrameIn
				>SYSCALL2 FreeMem
				clc
				rts
*--------------------------------------
MAN
SAVE USR/SRC/LIB/LIBTCPIP.S.DNS
LOAD USR/SRC/LIB/LIBTCPIP.S
ASM
