Subversion Repositories Spectranet

[/] [branches/] [gnubinutils/] [rom/] [dns.asm] - Blame information for rev 384

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 49 winston
;The MIT License
2
;
3
;Copyright (c) 2008 Dylan Smith
4
;
5
;Permission is hereby granted, free of charge, to any person obtaining a copy
6
;of this software and associated documentation files (the "Software"), to deal
7
;in the Software without restriction, including without limitation the rights
8
;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
;copies of the Software, and to permit persons to whom the Software is
10
;furnished to do so, subject to the following conditions:
11
;
12
;The above copyright notice and this permission notice shall be included in
13
;all copies or substantial portions of the Software.
14
;
15
;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
;THE SOFTWARE.
22
;
23
; Functions for querying DNS.
24 67 winston
;
25 384 winston
.include        "sysvars.inc"
26
.include        "dnsdefs.inc"
27
.include        "w5100_defs.inc"
28
.include        "sockdefs.inc"
29 67 winston
 
30
;========================================================================
31
; F_gethostbyname
32
; Subset of the Unix 'gethostbyname' call. It returns only a list of
33
; addresses (currently, either zero or one entries long). The parameter
34
; can either be an IP address in dotted decimal format, or a hostname.
35
; No lookup is performed if an IP address is detected; the address is
36
; simply converted to a 4-byte big endian representation of the address.
37
; Carry flag is set on error, and A contains the return code when an
38
; error occurs.
39 49 winston
;
40 67 winston
; Parameters: HL = pointer to null-terminated string containing address
41
;             DE = pointer to a buffer in which to return the result
42 384 winston
.text
43
.globl F_gethostbyname
44
F_gethostbyname:
45 67 winston
        push hl
46
        push de
47
        call F_ipstring2long    ; Was a dotted decimal IP address passed?
48
        pop de
49
        pop hl
50
        ld a, 0                 ; ensure status is 0 (flags unchanged)
51
        ret nc                  ; was an IP - so it's now in the buffer.
52
        call F_dnsAquery        ; no - so try a DNS lookup instead.
53
        ret
54 49 winston
 
55
;========================================================================
56
; F_dnsAquery
57
; Queries a DNS server for an A record, using the servers enumerated
58
; in system variables v_nameserver1 and v_nameserver2
59
;
60
; Parameters: HL = pointer to null-terminated string containing address
61
;                  to query
62
;             DE = pointer to a 4 byte buffer in which to return result
63
; Returns   : A  = Status (carry is set on error)
64
;
65 384 winston
.globl F_dnsAquery
66
F_dnsAquery:
67 49 winston
        ld (v_queryresult), de  ; save the query result pointer
68
 
69
        ; set up the query string to resolve in the workspace area
70
        ld de, buf_workspace+12 ; write it after the header
71
        call F_dnsstring        ; string to convert in hl
72 51 winston
 
73 49 winston
        xor a
74
        ld b, 1                 ; query type A and IN is both 0x01
75
        ld (hl), a              ; MSB of query type (A)
76
        inc hl
77
        ld (hl), b              ; LSB of query type (A)
78
        inc hl
79
        ld (hl), a              ; MSB of class (IN)
80
        inc hl
81
        ld (hl), b              ; LSB of class (IN)
82 51 winston
        ld de, buf_workspace-1  ; find out the length
83 49 winston
        sbc hl, de              ; of the query block
84
        ld (v_querylength), hl  ; and save it in sysvars
85
 
86
        ld hl, v_nameserver1    ; set up the first resolver
87
        ld (v_cur_resolver), hl ; and save it in sysvars area
88
 
89
        call F_rand16           ; generate the DNS query ID
90
        ld (buf_workspace), hl  ; store it at the start of the workspace
91
 
92
        ld hl, query            ; start address of standard query data
93
        ld de, buf_workspace+2  ; destination
94 51 winston
        ld bc, queryend-query   ; bytes to copy
95 49 winston
        ldir                    ; build the query header
96
 
97
        ld hl, dns_port         ; set query UDP port
98
        ld (v_dnssockinfo+4), hl ; to port 53
99
        ld hl, 0
100
        ld (v_dnssockinfo+6), hl ; make sure source port is unset
101
 
102 384 winston
.resolveloop2:
103 49 winston
        ld c, SOCK_DGRAM        ; Open a UDP socket
104
        call F_socket
105
        ret c                   ; bale out on error
106
        ld (v_dnsfd), a         ; save the file descriptor
107
 
108
        ld hl, (v_cur_resolver) ; get pointer to current resolver address
109
        ld de, v_dnssockinfo    ; point de at sockinfo structure
110
        ldi                     ; copy the resolver's ip address
111
        ldi
112
        ldi
113
        ldi
114
 
115 83 winston
        ld a, 3                 ; number of retries
116
        ld (v_dnsretries), a
117 384 winston
.sendquery2:
118 83 winston
        ld a, (v_dnsfd)
119 49 winston
        ld hl, v_dnssockinfo    ; reset hl to the sockinfo structure
120
        ld de, buf_workspace    ; point de at the workspace
121
        ld bc, (v_querylength)  ; bc = length of query
122
        call F_sendto           ; send the block of data
123 384 winston
        jr c, .errorcleanup2    ; recover if there's an error
124 49 winston
 
125 83 winston
        ; Wait for only a finite amount of time before giving up
126
        call F_waitfordnsmsg
127 384 winston
        jr nc, .getresponse2
128 83 winston
        ld a, (v_dnsretries)
129
        dec a
130
        ld (v_dnsretries), a
131 384 winston
        jr nz, .sendquery2
132 83 winston
        ld a, DNS_TIMEOUT
133 384 winston
        jr .errorcleanup2       ; retries exhausted
134 83 winston
 
135 384 winston
.getresponse2:
136 49 winston
        ld a, (v_dnsfd)
137
        ld hl, v_dnssockinfo    ; reset hl to the socket info structure
138
        ld de, buf_message      ; set de to the message buffer
139
        ld bc, 512              ; maximum message size
140
        call F_recvfrom
141 384 winston
        jr c, .errorcleanup2
142 49 winston
 
143
        ld a, (v_dnsfd)
144
        call F_sockclose
145
 
146
        ld hl, buf_workspace    ; compare the serial number of
147
        ld de, buf_message      ; the sent query and received
148
        ld a, (de)              ; answer to check that
149
        cpi                     ; they are the same. If they
150 384 winston
        jr nz, .badmsg2         ; are different this indicates something
151 49 winston
        inc e                   ; is seriously borked.
152
        ld a, (de)
153
        cpi
154 384 winston
        jr nz, .badmsg2
155 49 winston
 
156
        ld a, (buf_message+dns_bitfield2)
157
        and 0x0F                ; Did we successfully resolve something?
158 384 winston
        jr z, .result2          ; yes, so process the answer.
159 49 winston
 
160
        ; TODO: query remaining resolvers
161
        ld a, HOST_NOT_FOUND
162
        scf
163
        ret
164
 
165 384 winston
.errorcleanup2:
166 49 winston
        push af
167
        ld a, (v_dnsfd)         ; free up the socket we've opened
168
        call F_sockclose
169
        pop af
170
        ret
171
 
172 384 winston
.result2:
173 49 winston
        call F_getdnsarec       ; retrieve the A record from the answer
174 384 winston
        jr c, .noaddr2
175 49 winston
        ld de, (v_queryresult)  ; retrieve pointer to result buffer
176
        ldi                     ; copy the IP address
177
        ldi
178
        ldi
179
        ldi
180
        xor a                   ; clear return status
181
        ret
182
 
183 384 winston
.badmsg2:
184 49 winston
        ld a, NO_RECOVERY
185
        scf
186
        ret
187 384 winston
.noaddr2:
188 49 winston
        ld a, NO_ADDRESS        ; carry is already set
189
        ret
190
 
191
;========================================================================
192
; F_dnsstring
193 384 winston
; Convert a string (such as 'spectrum.alioth2.net2') into the format
194 49 winston
; used in DNS queries and responses. The string is null terminated.
195
;
196
; The format adds an 8 bit byte count in front of every part of the
197 384 winston
; complete host/domain, replacing the dots, so 'spectrum.alioth2.net2'
198 49 winston
; would become [0x08]spectrum[0x06]alioth[0x03]net - the values in
199
; square brackets being a single byte (8 bit integer).
200
;
201
; Parameters: HL - pointer to string to convert
202
;             DE - destination address of finished string
203
; On exit   : HL - points at next byte after converted data
204
;             DE is preserved.
205 384 winston
.globl F_dnsstring
206
F_dnsstring:
207 49 winston
        ld (v_fieldptr), de     ; Set current field byte count pointer
208
        inc e                   ; Intial destination address.
209 384 winston
.findsep3:
210 49 winston
        ld c, 0xFF              ; byte counter, decremented by LDI
211 384 winston
.loop3:
212 49 winston
        ld a, (hl)              ; What are we looking at?
213
        cp '.'                  ; DNS string field separator?
214 384 winston
        jr z, .dot3
215 49 winston
        and a                   ; Null terminator?
216 384 winston
        jr z, .done3
217 49 winston
        ldi                     ; copy (hl) to (de), incrementing both
218 384 winston
        jr .loop3
219
.dot3:
220 49 winston
        push de                 ; save current destination address
221
        ld a, c                 ; low order of byte counter (255 - bytes)
222
        cpl                     ; turn it into the byte count
223
        ld de, (v_fieldptr)     ; retrieve field pointer
224
        ld (de), a              ; store byte counter
225
        pop de                  ; get current destination address back
226
        ld (v_fieldptr), de     ; save it
227
        inc e                   ; and update pointer to new address
228
        inc hl                  ; address pointer at next character
229 384 winston
        jr .findsep3            ; and get next bit
230
.done3:
231 49 winston
        push de                 ; save current destination address
232
        xor a                   ; put a NULL on the end of the result
233
        ld (de), a
234
        ld a, c                 ; low order of byte count (255 - bytes)
235
        cpl                     ; turn it into a byte count
236
        ld de, (v_fieldptr)     ; retrieve field pointer
237
        ld (de), a              ; save byte count
238
        pop hl                  ; get current address pointer
239
        inc hl                  ; add 1 - hl points at next byte after end
240
        ret                     ; finished.
241
 
242
;==========================================================================
243
; F_getdnsarec
244
; Gets a DNS 'A' record from an answer. The assumption is that the DNS
245
; answer is in buf_message (0x3C00).
246
;
247
; Returns: HL = pointer to IP address
248
; Carry flag is set if no A records were in the answer.
249 384 winston
.globl F_getdnsarec
250
F_getdnsarec:
251 49 winston
        xor a
252
        ld (v_ansprocessed), a  ; set answers processed = 0
253
        ld hl, buf_message + dns_headerlen
254 384 winston
.questionloop4:
255 49 winston
        ld a, (hl)              ; advance to the end of the question record
256
        and a                   ; null terminator?
257
        inc hl
258 384 winston
        jr nz, .questionloop4   ; not null, check the next character
259 49 winston
        inc hl                  ; go past QTYPE
260
        inc hl
261
        inc hl                  ; go past QCLASS
262
        inc hl
263 384 winston
.decodeanswer4:
264 49 winston
        ld a, (hl)              ; Test for a pointer or a label
265
        and 0xC0                ; First two bits are 1 for a pointer
266 384 winston
        jr z, .skiplabel4       ; otherwise it's a label so skip it
267 49 winston
        inc hl
268
        inc hl
269 384 winston
.recordtype4:
270 49 winston
        inc hl                  ; skip MSB
271
        ld a, (hl)              ; what kind of record?
272
        cp dns_Arecord          ; is it an A record?
273 384 winston
        jr nz, .skiprecord4     ; if not, advance HL to next answer
274
.getipaddr4:
275 49 winston
        ld bc, 9                ; The IP address is the 9th byte
276
        add hl, bc              ; further on in an A record response
277
        ret                     ; so return this.
278 384 winston
.skiplabel4:
279 49 winston
        ld a, (hl)
280
        and a                   ; is it null?
281 384 winston
        jr z, .recordtype4      ; yes - process the record type
282 49 winston
        inc hl
283 384 winston
        jr .skiplabel4
284
.skiprecord4:
285 49 winston
        ld a, (buf_message+dns_ancount+1)
286
        ld b, a                 ; number of RR answers in B
287
        ld a, (v_ansprocessed)  ; how many have we processed already?
288
        inc a                   ; pre-increment processed counter
289
        cp b                    ; compare answers processed with total
290 384 winston
        jr z, .baleout4         ; no A records found
291 49 winston
        ld (v_ansprocessed), a
292
        ld bc, 7                ; skip forward
293
        add hl, bc              ; 7 bytes - now pointing at data length
294
        ld b, (hl)              ; big-endian length MSB
295
        inc hl
296
        ld c, (hl)              ; LSB
297
        inc hl
298
        add hl, bc              ; advance hl to the end of the data
299 384 winston
        jr .decodeanswer4       ; decode the next answer
300
.baleout4:
301 49 winston
        scf                     ; set carry flag to indicate error
302
        ret
303
 
304 83 winston
;------------------------------------------------------------------------
305
; F_waitfordnsmsg
306
; Polls for a response from the DNS server to implement a timeout.
307 384 winston
.globl F_waitfordnsmsg
308
F_waitfordnsmsg:
309 83 winston
        ld bc, dns_polltime
310 384 winston
.loop5:
311 83 winston
        ld a, (v_dnsfd)
312 87 winston
        push bc
313 83 winston
        call F_pollfd
314 87 winston
        pop bc
315 83 winston
        ret nz                  ; data ready
316
        dec bc
317
        ld a, b
318
        or c
319 384 winston
        jr nz, .loop5
320 83 winston
        scf                     ; indicate timeout
321
        ret
322
 
323 384 winston
.data
324
query:           defb 0x01,0x00  ; 16 bit flags field - std. recursive query
325
qdcount:         defb 0x00,0x01  ; we only ever ask one question at a time
326
ancount:         defw 0x0000     ; No answers in a query
327
nscount:         defw 0x0000     ; No NS RRs in a query
328
arcount:         defw 0x0000     ; No additional records
329
queryend: