Subversion Repositories Spectranet

[/] [branches/] [gnubinutils/] [rom/] [dns.asm] - Diff between revs 371 and 384

Show entire file | Details | Blame | View Log

Rev 371 Rev 384
Line 20... Line 20...
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
;THE SOFTWARE.
;THE SOFTWARE.
;
;
; Functions for querying DNS.
; Functions for querying DNS.
;
;
 
.include        "sysvars.inc"
 
.include        "dnsdefs.inc"
 
.include        "w5100_defs.inc"
 
.include        "sockdefs.inc"
 
 
;========================================================================
;========================================================================
; F_gethostbyname
; F_gethostbyname
; Subset of the Unix 'gethostbyname' call. It returns only a list of
; Subset of the Unix 'gethostbyname' call. It returns only a list of
; addresses (currently, either zero or one entries long). The parameter
; addresses (currently, either zero or one entries long). The parameter
Line 33... Line 37...
; Carry flag is set on error, and A contains the return code when an
; Carry flag is set on error, and A contains the return code when an
; error occurs.
; error occurs.
;
;
; Parameters: HL = pointer to null-terminated string containing address
; Parameters: HL = pointer to null-terminated string containing address
;             DE = pointer to a buffer in which to return the result
;             DE = pointer to a buffer in which to return the result
F_gethostbyname
.text
 
.globl F_gethostbyname
 
F_gethostbyname:
        push hl
        push hl
        push de
        push de
        call F_ipstring2long    ; Was a dotted decimal IP address passed?
        call F_ipstring2long    ; Was a dotted decimal IP address passed?
        pop de
        pop de
        pop hl
        pop hl
Line 54... Line 60...
; Parameters: HL = pointer to null-terminated string containing address
; Parameters: HL = pointer to null-terminated string containing address
;                  to query
;                  to query
;             DE = pointer to a 4 byte buffer in which to return result
;             DE = pointer to a 4 byte buffer in which to return result
; Returns   : A  = Status (carry is set on error)
; Returns   : A  = Status (carry is set on error)
;
;
F_dnsAquery
.globl F_dnsAquery
 
F_dnsAquery:
        ld (v_queryresult), de  ; save the query result pointer
        ld (v_queryresult), de  ; save the query result pointer
 
 
        ; set up the query string to resolve in the workspace area
        ; set up the query string to resolve in the workspace area
        ld de, buf_workspace+12 ; write it after the header
        ld de, buf_workspace+12 ; write it after the header
        call F_dnsstring        ; string to convert in hl
        call F_dnsstring        ; string to convert in hl
Line 90... Line 97...
        ld hl, dns_port         ; set query UDP port
        ld hl, dns_port         ; set query UDP port
        ld (v_dnssockinfo+4), hl ; to port 53
        ld (v_dnssockinfo+4), hl ; to port 53
        ld hl, 0
        ld hl, 0
        ld (v_dnssockinfo+6), hl ; make sure source port is unset
        ld (v_dnssockinfo+6), hl ; make sure source port is unset
 
 
.resolveloop
.resolveloop2:
        ld c, SOCK_DGRAM        ; Open a UDP socket
        ld c, SOCK_DGRAM        ; Open a UDP socket
        call F_socket
        call F_socket
        ret c                   ; bale out on error
        ret c                   ; bale out on error
        ld (v_dnsfd), a         ; save the file descriptor
        ld (v_dnsfd), a         ; save the file descriptor
 
 
Line 105... Line 112...
        ldi
        ldi
        ldi
        ldi
 
 
        ld a, 3                 ; number of retries
        ld a, 3                 ; number of retries
        ld (v_dnsretries), a
        ld (v_dnsretries), a
.sendquery
.sendquery2:
        ld a, (v_dnsfd)
        ld a, (v_dnsfd)
        ld hl, v_dnssockinfo    ; reset hl to the sockinfo structure
        ld hl, v_dnssockinfo    ; reset hl to the sockinfo structure
        ld de, buf_workspace    ; point de at the workspace
        ld de, buf_workspace    ; point de at the workspace
        ld bc, (v_querylength)  ; bc = length of query
        ld bc, (v_querylength)  ; bc = length of query
        call F_sendto           ; send the block of data
        call F_sendto           ; send the block of data
        jr c, .errorcleanup     ; recover if there's an error
        jr c, .errorcleanup2    ; recover if there's an error
 
 
        ; Wait for only a finite amount of time before giving up
        ; Wait for only a finite amount of time before giving up
        call F_waitfordnsmsg
        call F_waitfordnsmsg
        jr nc, .getresponse
        jr nc, .getresponse2
        ld a, (v_dnsretries)
        ld a, (v_dnsretries)
        dec a
        dec a
        ld (v_dnsretries), a
        ld (v_dnsretries), a
        jr nz, .sendquery
        jr nz, .sendquery2
        ld a, DNS_TIMEOUT
        ld a, DNS_TIMEOUT
        jr .errorcleanup        ; retries exhausted
        jr .errorcleanup2       ; retries exhausted
 
 
.getresponse
.getresponse2:
        ld a, (v_dnsfd)
        ld a, (v_dnsfd)
        ld hl, v_dnssockinfo    ; reset hl to the socket info structure
        ld hl, v_dnssockinfo    ; reset hl to the socket info structure
        ld de, buf_message      ; set de to the message buffer
        ld de, buf_message      ; set de to the message buffer
        ld bc, 512              ; maximum message size
        ld bc, 512              ; maximum message size
        call F_recvfrom
        call F_recvfrom
        jr c, .errorcleanup
        jr c, .errorcleanup2
 
 
        ld a, (v_dnsfd)
        ld a, (v_dnsfd)
        call F_sockclose
        call F_sockclose
 
 
        ld hl, buf_workspace    ; compare the serial number of
        ld hl, buf_workspace    ; compare the serial number of
        ld de, buf_message      ; the sent query and received
        ld de, buf_message      ; the sent query and received
        ld a, (de)              ; answer to check that
        ld a, (de)              ; answer to check that
        cpi                     ; they are the same. If they
        cpi                     ; they are the same. If they
        jr nz, .badmsg          ; are different this indicates something
        jr nz, .badmsg2         ; are different this indicates something
        inc e                   ; is seriously borked.
        inc e                   ; is seriously borked.
        ld a, (de)
        ld a, (de)
        cpi
        cpi
        jr nz, .badmsg
        jr nz, .badmsg2
 
 
        ld a, (buf_message+dns_bitfield2)
        ld a, (buf_message+dns_bitfield2)
        and 0x0F                ; Did we successfully resolve something?
        and 0x0F                ; Did we successfully resolve something?
        jr z, .result           ; yes, so process the answer.
        jr z, .result2          ; yes, so process the answer.
 
 
        ; TODO: query remaining resolvers
        ; TODO: query remaining resolvers
        ld a, HOST_NOT_FOUND
        ld a, HOST_NOT_FOUND
        scf
        scf
        ret
        ret
 
 
.errorcleanup
.errorcleanup2:
        push af
        push af
        ld a, (v_dnsfd)         ; free up the socket we've opened
        ld a, (v_dnsfd)         ; free up the socket we've opened
        call F_sockclose
        call F_sockclose
        pop af
        pop af
        ret
        ret
 
 
.result
.result2:
        call F_getdnsarec       ; retrieve the A record from the answer
        call F_getdnsarec       ; retrieve the A record from the answer
        jr c, .noaddr
        jr c, .noaddr2
        ld de, (v_queryresult)  ; retrieve pointer to result buffer
        ld de, (v_queryresult)  ; retrieve pointer to result buffer
        ldi                     ; copy the IP address
        ldi                     ; copy the IP address
        ldi
        ldi
        ldi
        ldi
        ldi
        ldi
        xor a                   ; clear return status
        xor a                   ; clear return status
        ret
        ret
 
 
.badmsg
.badmsg2:
        ld a, NO_RECOVERY
        ld a, NO_RECOVERY
        scf
        scf
        ret
        ret
.noaddr
.noaddr2:
        ld a, NO_ADDRESS        ; carry is already set
        ld a, NO_ADDRESS        ; carry is already set
        ret
        ret
 
 
;========================================================================
;========================================================================
; F_dnsstring
; F_dnsstring
; Convert a string (such as 'spectrum.alioth.net') into the format
; Convert a string (such as 'spectrum.alioth2.net2') into the format
; used in DNS queries and responses. The string is null terminated.
; used in DNS queries and responses. The string is null terminated.
;
;
; The format adds an 8 bit byte count in front of every part of the
; The format adds an 8 bit byte count in front of every part of the
; complete host/domain, replacing the dots, so 'spectrum.alioth.net'
; complete host/domain, replacing the dots, so 'spectrum.alioth2.net2'
; would become [0x08]spectrum[0x06]alioth[0x03]net - the values in
; would become [0x08]spectrum[0x06]alioth[0x03]net - the values in
; square brackets being a single byte (8 bit integer).
; square brackets being a single byte (8 bit integer).
;
;
; Parameters: HL - pointer to string to convert
; Parameters: HL - pointer to string to convert
;             DE - destination address of finished string
;             DE - destination address of finished string
; On exit   : HL - points at next byte after converted data
; On exit   : HL - points at next byte after converted data
;             DE is preserved.
;             DE is preserved.
F_dnsstring
.globl F_dnsstring
 
F_dnsstring:
        ld (v_fieldptr), de     ; Set current field byte count pointer
        ld (v_fieldptr), de     ; Set current field byte count pointer
        inc e                   ; Intial destination address.
        inc e                   ; Intial destination address.
.findsep
.findsep3:
        ld c, 0xFF              ; byte counter, decremented by LDI
        ld c, 0xFF              ; byte counter, decremented by LDI
.loop
.loop3:
        ld a, (hl)              ; What are we looking at?
        ld a, (hl)              ; What are we looking at?
        cp '.'                  ; DNS string field separator?
        cp '.'                  ; DNS string field separator?
        jr z, .dot
        jr z, .dot3
        and a                   ; Null terminator?
        and a                   ; Null terminator?
        jr z, .done
        jr z, .done3
        ldi                     ; copy (hl) to (de), incrementing both
        ldi                     ; copy (hl) to (de), incrementing both
        jr .loop
        jr .loop3
.dot
.dot3:
        push de                 ; save current destination address
        push de                 ; save current destination address
        ld a, c                 ; low order of byte counter (255 - bytes)
        ld a, c                 ; low order of byte counter (255 - bytes)
        cpl                     ; turn it into the byte count
        cpl                     ; turn it into the byte count
        ld de, (v_fieldptr)     ; retrieve field pointer
        ld de, (v_fieldptr)     ; retrieve field pointer
        ld (de), a              ; store byte counter
        ld (de), a              ; store byte counter
        pop de                  ; get current destination address back
        pop de                  ; get current destination address back
        ld (v_fieldptr), de     ; save it
        ld (v_fieldptr), de     ; save it
        inc e                   ; and update pointer to new address
        inc e                   ; and update pointer to new address
        inc hl                  ; address pointer at next character
        inc hl                  ; address pointer at next character
        jr .findsep             ; and get next bit
        jr .findsep3            ; and get next bit
.done
.done3:
        push de                 ; save current destination address
        push de                 ; save current destination address
        xor a                   ; put a NULL on the end of the result
        xor a                   ; put a NULL on the end of the result
        ld (de), a
        ld (de), a
        ld a, c                 ; low order of byte count (255 - bytes)
        ld a, c                 ; low order of byte count (255 - bytes)
        cpl                     ; turn it into a byte count
        cpl                     ; turn it into a byte count
Line 236... Line 244...
; Gets a DNS 'A' record from an answer. The assumption is that the DNS
; Gets a DNS 'A' record from an answer. The assumption is that the DNS
; answer is in buf_message (0x3C00).
; answer is in buf_message (0x3C00).
;
;
; Returns: HL = pointer to IP address
; Returns: HL = pointer to IP address
; Carry flag is set if no A records were in the answer.
; Carry flag is set if no A records were in the answer.
F_getdnsarec
.globl F_getdnsarec
 
F_getdnsarec:
        xor a
        xor a
        ld (v_ansprocessed), a  ; set answers processed = 0
        ld (v_ansprocessed), a  ; set answers processed = 0
        ld hl, buf_message + dns_headerlen
        ld hl, buf_message + dns_headerlen
.questionloop
.questionloop4:
        ld a, (hl)              ; advance to the end of the question record
        ld a, (hl)              ; advance to the end of the question record
        and a                   ; null terminator?
        and a                   ; null terminator?
        inc hl
        inc hl
        jr nz, .questionloop    ; not null, check the next character
        jr nz, .questionloop4   ; not null, check the next character
        inc hl                  ; go past QTYPE
        inc hl                  ; go past QTYPE
        inc hl
        inc hl
        inc hl                  ; go past QCLASS
        inc hl                  ; go past QCLASS
        inc hl
        inc hl
.decodeanswer
.decodeanswer4:
        ld a, (hl)              ; Test for a pointer or a label
        ld a, (hl)              ; Test for a pointer or a label
        and 0xC0                ; First two bits are 1 for a pointer
        and 0xC0                ; First two bits are 1 for a pointer
        jr z, .skiplabel        ; otherwise it's a label so skip it
        jr z, .skiplabel4       ; otherwise it's a label so skip it
        inc hl
        inc hl
        inc hl
        inc hl
.recordtype
.recordtype4:
        inc hl                  ; skip MSB
        inc hl                  ; skip MSB
        ld a, (hl)              ; what kind of record?
        ld a, (hl)              ; what kind of record?
        cp dns_Arecord          ; is it an A record?
        cp dns_Arecord          ; is it an A record?
        jr nz, .skiprecord      ; if not, advance HL to next answer
        jr nz, .skiprecord4     ; if not, advance HL to next answer
.getipaddr
.getipaddr4:
        ld bc, 9                ; The IP address is the 9th byte
        ld bc, 9                ; The IP address is the 9th byte
        add hl, bc              ; further on in an A record response
        add hl, bc              ; further on in an A record response
        ret                     ; so return this.
        ret                     ; so return this.
.skiplabel
.skiplabel4:
        ld a, (hl)
        ld a, (hl)
        and a                   ; is it null?
        and a                   ; is it null?
        jr z, .recordtype       ; yes - process the record type
        jr z, .recordtype4      ; yes - process the record type
        inc hl
        inc hl
        jr .skiplabel
        jr .skiplabel4
.skiprecord
.skiprecord4:
        ld a, (buf_message+dns_ancount+1)
        ld a, (buf_message+dns_ancount+1)
        ld b, a                 ; number of RR answers in B
        ld b, a                 ; number of RR answers in B
        ld a, (v_ansprocessed)  ; how many have we processed already?
        ld a, (v_ansprocessed)  ; how many have we processed already?
        inc a                   ; pre-increment processed counter
        inc a                   ; pre-increment processed counter
        cp b                    ; compare answers processed with total
        cp b                    ; compare answers processed with total
        jr z, .baleout          ; no A records found
        jr z, .baleout4         ; no A records found
        ld (v_ansprocessed), a
        ld (v_ansprocessed), a
        ld bc, 7                ; skip forward
        ld bc, 7                ; skip forward
        add hl, bc              ; 7 bytes - now pointing at data length
        add hl, bc              ; 7 bytes - now pointing at data length
        ld b, (hl)              ; big-endian length MSB
        ld b, (hl)              ; big-endian length MSB
        inc hl
        inc hl
        ld c, (hl)              ; LSB
        ld c, (hl)              ; LSB
        inc hl
        inc hl
        add hl, bc              ; advance hl to the end of the data
        add hl, bc              ; advance hl to the end of the data
        jr .decodeanswer        ; decode the next answer
        jr .decodeanswer4       ; decode the next answer
.baleout
.baleout4:
        scf                     ; set carry flag to indicate error
        scf                     ; set carry flag to indicate error
        ret
        ret
 
 
;------------------------------------------------------------------------
;------------------------------------------------------------------------
; F_waitfordnsmsg
; F_waitfordnsmsg
; Polls for a response from the DNS server to implement a timeout.
; Polls for a response from the DNS server to implement a timeout.
F_waitfordnsmsg
.globl F_waitfordnsmsg
 
F_waitfordnsmsg:
        ld bc, dns_polltime
        ld bc, dns_polltime
.loop
.loop5:
        ld a, (v_dnsfd)
        ld a, (v_dnsfd)
        push bc
        push bc
        call F_pollfd
        call F_pollfd
        pop bc
        pop bc
        ret nz                  ; data ready
        ret nz                  ; data ready
        dec bc
        dec bc
        ld a, b
        ld a, b
        or c
        or c
        jr nz, .loop
        jr nz, .loop5
        scf                     ; indicate timeout
        scf                     ; indicate timeout
        ret
        ret
 
 
 
.data
 
query:           defb 0x01,0x00  ; 16 bit flags field - std. recursive query
 
qdcount:         defb 0x00,0x01  ; we only ever ask one question at a time
 
ancount:         defw 0x0000     ; No answers in a query
 
nscount:         defw 0x0000     ; No NS RRs in a query
 
arcount:         defw 0x0000     ; No additional records
 
queryend: