PR#3
PREFIX /A2OSX.SRC
NEW
INC 1
AUTO 6
				.LIST OFF	
*--------------------------------------
DNS.CLEAR		ldx #K.DNSCACHE.SIZE*S.DNSCACHE
.1				stz DNS.CACHE-1,x
				dex
				bne .1
				clc
				rts
*--------------------------------------
* DNS.QUERY
*  In:
*	PULLW = hostname PTR to PSTR 
*   PULLW = PTR to IP to fill with cached data
*  Out:
*   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 hDNSSocket1
				bne .10
				lda #ERR.DNS.ERROR
				sec
				rts

.10				jsr DNS.PSTR2DNS

				ldx #0
				ldy #DNS.MSG.NAME-DNS.MSG
				
.1				lda DNS.Hostname,x
				sta DNS.MSG,y
				beq .2
				inx
				iny
				bne .1
				
.2				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
				
				>PUSHW DNS.MSG.LEN
				>PUSHW L.DNS.MSG
				>PUSHB hDNSSocket1
				jsr SKT.SEND
				
				lda hDNSSocket2
				beq .3
				
				>PUSHW DNS.MSG.LEN
				>PUSHW L.DNS.MSG
				>PUSHB hDNSSocket2
				jsr SKT.SEND
				
.3				lda #ERR.DNS.PENDING
.9				sec
				rts
*--------------------------------------
* DNS.ADD
*  In:
*	PULLW = hostname PSTR to Add
*   PULLW = PTR to IP
*--------------------------------------
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
				>SYSCALL SYS.NewPStrYA
				bcs .9
				
				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	>LDYA L.DNS.CACHE
				clc
				rts
*--------------------------------------
DNS.FIND.BY.NAME
				>LDYA L.DNS.CACHE
				>STYA ZPCachePtr
				
				lda #K.DNSCACHE.SIZE
				sta TmpOffset
				
.1				lda (ZPCachePtr)
				beq .6					empty DNS cache entry?
				
				ldy #S.DNSCACHE.hNAME
				lda (ZPCachePtr),y
				>SYSCALL SYS.GetMemPtrA
				bcs *
				>STYA ZPTmpPtr1
				
				lda (ZPPtrDNS)
				cmp (ZPTmpPtr1)
				bne .6
				
				tay
				
.2				lda (ZPPtrDNS),y
				cmp (ZPTmpPtr1),y
				bne .6
				dey
				bne .2
				
				clc
				rts
				
.6				lda ZPCachePtr
				clc
				adc #S.DNSCACHE
				sta ZPCachePtr
				bcc .7
				inc ZPCachePtr+1
				
.7				dec TmpOffset
				bne .1
				sec
				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 #K.DNSCACHE.SIZE
				sta TmpOffset
				lda #$ff
				sta TmpDWord
				sta TmpDWord+1
				sta TmpDWord+2
				sta TmpDWord+3
				
.1				lda (ZPCachePtr)
				beq .8					empty DNS cache entry?
				bpl .6					pending.....skip
				
				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				lda ZPCachePtr
				clc
				adc #S.DNSCACHE
				sta ZPCachePtr
				bcc .7
				inc ZPCachePtr+1
				
.7				dec TmpOffset
				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
				
				lda #K.DNSCACHE.SIZE
				sta TmpOffset
				
.1				lda (ZPCachePtr)
				beq .7					empty DNS cache entry?
				
				ldy #S.DNSCACHE.TTL
				ldx #4
				clc
.2				lda (ZPCachePtr),y
				sbc #0
				sta (ZPCachePtr),y
				iny
				dex
				bne .2
				bcs .7
				jsr DNS.FREE
				
.7				lda ZPCachePtr
				clc
				adc #S.DNSCACHE
				sta ZPCachePtr
				bcc .8
				inc ZPCachePtr+1
				
.8				dec TmpOffset
				bne .1
				clc
				rts
*--------------------------------------
DNS.FREE		ldy #S.DNSCACHE.hNAME
				lda (ZPCachePtr),y
				beq .1
				>SYSCALL SYS.FreeMemA
.1				lda #0
				sta (ZPCachePtr)
				rts
*--------------------------------------
DNS.POLL		lda hDNSSocket1
				beq .8
				jsr SKT.RCVDA
				bcs .8
				jsr DNS.DecodeMsg
				
				lda hDNSSocket2
				beq .8
				jsr SKT.RCVDA
				bcs .8
				jsr DNS.DecodeMsg
				
.8				clc
				rts
*--------------------------------------
DNS.DecodeMsg	sta hFrame1
				>SYSCALL SYS.GetMemPtrA
				>STYA ZPFrameBase1
				
				ldy #S.DNS.F+1
				lda (ZPFrameBase1),y
				and /S.DNS.F.QR
				beq .9

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

				ldy #S.DNS				Point to DATA

				tax
				beq .3					no QUERY to skip
				
.1				lda (ZPFrameBase1),y
				beq .2
				bpl	.11					Pointer ?
				iny						yes, skip 2 bytes
				iny
				bra .2
				
.11				tya
				sec
				adc (ZPFrameBase1),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 (ZPFrameBase1),y
				beq .32
				bpl .31					Pointer ? 
				iny						yes, skip 2 bytes
				iny
				bra .32
	
.31 			tya
				sec
				adc (ZPFrameBase1),y	Skip LEN+1 bytes
				tay
				bra .3
				
.32				iny						skip S.DNS.QTYPE HIGH
				lda (ZPFrameBase1),y
				cmp #S.DNS.QTYPE.A
				beq .40
				
				tya
				clc
				adc #7					skip CLASS,TTL+DATALENHIGH
				tay
				sec						skip DATALENLO
				adc (ZPFrameBase1),y    add DATALEN
				tay
				dex
				bne .3
				bra .9
				
.40				iny						skip QCLASS
				iny
				
				iny						next pos
				
				ldx #3
.4				lda (ZPFrameBase1),y
				sta DNS.TmpCache+S.DNSCACHE.TTL,x
				iny
				dex
				bpl .4

				iny						skip DATALEN
				iny
				ldx #0
				
.5				lda (ZPFrameBase1),y
				sta DNS.TmpCache+S.DNSCACHE.IP,x
				iny
				inx
				cpx #4
				bne .5
				
				jsr DNS.UPDATE.BY.ID
				
.9				lda hFrame1
				>SYSCALL SYS.FreeMemA
				rts
*--------------------------------------
DNS.PSTR2DNS	lda (ZPPtrDNS)
				beq .9
				
				cmp #K.DNS.MAXLEN-1
				bcs .9
				
				tay
				
				inc
				sta DNS.HostNameLen

				lda #0					Ending 0
				sta DNS.HostName+1,y

				ldx #0
				
.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.HostName,y
				dey
				bne .1
				stx DNS.HostName
				
				clc
				rts
				
.9				sec
				rts				
*--------------------------------------
MAN
SAVE LIB/LIBTCPIP.S.DNS
LOAD LIB/LIBTCPIP.S
ASM
