Subversion Repositories Kolibri OS

Rev

Rev 3704 | Rev 5545 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3704 Rev 5358
1
format MS COFF
1
format MS COFF
2
 
2
 
3
public @EXPORT as 'EXPORTS'
3
public @EXPORT as 'EXPORTS'
4
 
4
 
5
include '../../../struct.inc'
5
include '../../../struct.inc'
6
include '../../../proc32.inc'
6
include '../../../proc32.inc'
7
include '../../../macros.inc'
7
include '../../../macros.inc'
8
purge section,mov,add,sub
8
purge section,mov,add,sub
9
 
9
 
10
include '../../../network.inc'
10
include '../../../network.inc'
11
 
11
 
12
section '.flat' code readable align 16
12
section '.flat' code readable align 16
13
 
13
 
14
;;===========================================================================;;
14
;;===========================================================================;;
15
lib_init: ;//////////////////////////////////////////////////////////////////;;
15
lib_init: ;//////////////////////////////////////////////////////////////////;;
16
;;---------------------------------------------------------------------------;;
16
;;---------------------------------------------------------------------------;;
17
;? Library entry point (called after library load)                           ;;
17
;? Library entry point (called after library load)                           ;;
18
;;---------------------------------------------------------------------------;;
18
;;---------------------------------------------------------------------------;;
19
;> eax = pointer to memory allocation routine                                ;;
19
;> eax = pointer to memory allocation routine                                ;;
20
;> ebx = pointer to memory freeing routine                                   ;;
20
;> ebx = pointer to memory freeing routine                                   ;;
21
;> ecx = pointer to memory reallocation routine                              ;;
21
;> ecx = pointer to memory reallocation routine                              ;;
22
;> edx = pointer to library loading routine                                  ;;
22
;> edx = pointer to library loading routine                                  ;;
23
;;---------------------------------------------------------------------------;;
23
;;---------------------------------------------------------------------------;;
24
;< eax = 1 (fail) / 0 (ok) (library initialization result)                   ;;
24
;< eax = 1 (fail) / 0 (ok) (library initialization result)                   ;;
25
;;===========================================================================;;
25
;;===========================================================================;;
26
        mov     [mem.alloc], eax
26
        mov     [mem.alloc], eax
27
        mov     [mem.free], ebx
27
        mov     [mem.free], ebx
28
        mov     [mem.realloc], ecx
28
        mov     [mem.realloc], ecx
29
        mov     [dll.load], edx
29
        mov     [dll.load], edx
30
        mov     [DNSrequestID], 1
30
        mov     [DNSrequestID], 1
31
        xor     eax, eax
31
        xor     eax, eax
32
        ret
32
        ret
33
 
33
 
34
;;===========================================================================;;
34
;;===========================================================================;;
35
;; in_addr_t __stdcall inet_addr(__in const char* hostname);                 ;;
35
;; in_addr_t __stdcall inet_addr(__in const char* hostname);                 ;;
36
inet_addr:                                                                   ;;
36
inet_addr:                                                                   ;;
37
;;---------------------------------------------------------------------------;;
37
;;---------------------------------------------------------------------------;;
38
;? Convert the string from standard IPv4 dotted notation to integer IP addr. ;;
38
;? Convert the string from standard IPv4 dotted notation to integer IP addr. ;;
39
;;---------------------------------------------------------------------------;;
39
;;---------------------------------------------------------------------------;;
40
;> first parameter = host name                                               ;;
40
;> first parameter = host name                                               ;;
41
;;---------------------------------------------------------------------------;;
41
;;---------------------------------------------------------------------------;;
42
;< eax = IP address on success / -1 on error                                 ;;
42
;< eax = IP address on success / -1 on error                                 ;;
43
;;===========================================================================;;
43
;;===========================================================================;;
44
; 0. Save used registers for __stdcall.
44
; 0. Save used registers for __stdcall.
45
        push    ebx esi edi
45
        push    ebx esi edi
46
        mov     esi, [esp+16]   ; esi = hostname
46
        mov     esi, [esp+16]   ; esi = hostname
47
; 1. Check that only allowed symbols are present.
47
; 1. Check that only allowed symbols are present.
48
; (hex digits, possibly letters 'x'/'X' and up to 3 dots)
48
; (hex digits, possibly letters 'x'/'X' and up to 3 dots)
49
        push    esi
49
        push    esi
50
        xor     ecx, ecx
50
        xor     ecx, ecx
51
.calcdots_loop:
51
.calcdots_loop:
52
; loop for all characters in string
52
; loop for all characters in string
53
        lodsb
53
        lodsb
54
; check for end of string
54
; check for end of string
55
        cmp     al, 0
55
        cmp     al, 0
56
        jz      .calcdots_loop_done
56
        jz      .calcdots_loop_done
57
; check for dot
57
; check for dot
58
        cmp     al, '.'
58
        cmp     al, '.'
59
        jz      .dot
59
        jz      .dot
60
; check for digit
60
; check for digit
61
        sub     al, '0'
61
        sub     al, '0'
62
        cmp     al, 9
62
        cmp     al, 9
63
        jbe     .calcdots_loop
63
        jbe     .calcdots_loop
64
; check for hex letter
64
; check for hex letter
65
        sub     al, 'A' - '0'   ; 'A'-'F' -> 0-5, 'a'-'f' -> 20h-25h
65
        sub     al, 'A' - '0'   ; 'A'-'F' -> 0-5, 'a'-'f' -> 20h-25h
66
        and     al, not 20h
66
        and     al, not 20h
67
        cmp     al, 'F' - 'A'
67
        cmp     al, 'F' - 'A'
68
        jbe     .calcdots_loop
68
        jbe     .calcdots_loop
69
; check for 'x'/'X'
69
; check for 'x'/'X'
70
        cmp     al, 'X' - 'A'
70
        cmp     al, 'X' - 'A'
71
        jz      .calcdots_loop
71
        jz      .calcdots_loop
72
        jmp     .fail.pop
72
        jmp     .fail.pop
73
.dot:
73
.dot:
74
        inc     ecx
74
        inc     ecx
75
        jmp     .calcdots_loop
75
        jmp     .calcdots_loop
76
.calcdots_loop_done:
76
.calcdots_loop_done:
77
        cmp     ecx, 4
77
        cmp     ecx, 4
78
        jae     .fail.pop
78
        jae     .fail.pop
79
; 2. The name can be valid dotted name; try to convert, checking limit
79
; 2. The name can be valid dotted name; try to convert, checking limit
80
        pop     esi
80
        pop     esi
81
        xor     edi, edi        ; edi = address
81
        xor     edi, edi        ; edi = address
82
        push    0xFFFFFFFF
82
        push    0xFFFFFFFF
83
        pop     edx             ; edx = mask for rest of address
83
        pop     edx             ; edx = mask for rest of address
84
; 2a. Convert name except for last group.
84
; 2a. Convert name except for last group.
85
        jecxz   .ip_convert_2b
85
        jecxz   .ip_convert_2b
86
.ip_convert_2a:
86
.ip_convert_2a:
87
        push    ecx
87
        push    ecx
88
        mov     ecx, 0xFF       ; limit for all groups except for last
88
        mov     ecx, 0xFF       ; limit for all groups except for last
89
        call    .get_number
89
        call    .get_number
90
        pop     ecx
90
        pop     ecx
91
        jc      .fail
91
        jc      .fail
92
        cmp     byte [esi-1], '.'
92
        cmp     byte [esi-1], '.'
93
        jnz     .fail
93
        jnz     .fail
94
        shl     edi, 8
94
        shl     edi, 8
95
        shr     edx, 8
95
        shr     edx, 8
96
        add     edi, eax
96
        add     edi, eax
97
        loop    .ip_convert_2a
97
        loop    .ip_convert_2a
98
; 2b. Convert last group.
98
; 2b. Convert last group.
99
.ip_convert_2b:
99
.ip_convert_2b:
100
        mov     ecx, edx
100
        mov     ecx, edx
101
        call    .get_number
101
        call    .get_number
102
        jc      .fail
102
        jc      .fail
103
        cmp     byte [esi-1], 0
103
        cmp     byte [esi-1], 0
104
        jnz     .fail
104
        jnz     .fail
105
@@:
105
@@:
106
        shl     edi, 8
106
        shl     edi, 8
107
        shr     edx, 8
107
        shr     edx, 8
108
        jnz     @b
108
        jnz     @b
109
        add     edi, eax
109
        add     edi, eax
110
; 2c. Convert to network byte order.
110
; 2c. Convert to network byte order.
111
        bswap   edi
111
        bswap   edi
112
; 3. Set return value, restore used registers and return.
112
; 3. Set return value, restore used registers and return.
113
        xchg    eax, edi
113
        xchg    eax, edi
114
.ret:
114
.ret:
115
        pop     edi esi ebx
115
        pop     edi esi ebx
116
        ret     4
116
        ret     4
117
; 4. On error, return -1.
117
; 4. On error, return -1.
118
.fail.pop:
118
.fail.pop:
119
        pop     esi
119
        pop     esi
120
.fail:
120
.fail:
121
        push    -1
121
        push    -1
122
        pop     eax
122
        pop     eax
123
        jmp     .ret
123
        jmp     .ret
124
 
124
 
125
;;===========================================================================;;
125
;;===========================================================================;;
126
;; Internal auxiliary function for IP parsing.                                        ;;
126
;; Internal auxiliary function for IP parsing.                                        ;;
127
.get_number:                                                                 ;;
127
.get_number:                                                                 ;;
128
;;---------------------------------------------------------------------------;;
128
;;---------------------------------------------------------------------------;;
129
;? Converts string to number.                                                ;;
129
;? Converts string to number.                                                ;;
130
;;---------------------------------------------------------------------------;;
130
;;---------------------------------------------------------------------------;;
131
;> esi -> string                                                             ;;
131
;> esi -> string                                                             ;;
132
;> ecx = limit for number                                                    ;;
132
;> ecx = limit for number                                                    ;;
133
;;---------------------------------------------------------------------------;;
133
;;---------------------------------------------------------------------------;;
134
;< eax = number                                                              ;;
134
;< eax = number                                                              ;;
135
;< CF set on error (too big number) / cleared on success                     ;;
135
;< CF set on error (too big number) / cleared on success                     ;;
136
;< esi -> end of number representation                                       ;;
136
;< esi -> end of number representation                                       ;;
137
;;===========================================================================;;
137
;;===========================================================================;;
138
; 0. Save edx, which is used in caller.
138
; 0. Save edx, which is used in caller.
139
        push    edx
139
        push    edx
140
; 1. Initialize number, zero eax so that lodsb gets full dword.
140
; 1. Initialize number, zero eax so that lodsb gets full dword.
141
        xor     eax, eax
141
        xor     eax, eax
142
        xor     edx, edx
142
        xor     edx, edx
143
; 2. Get used numeral system: 0x = hex, otherwise 0 = octal, otherwise decimal
143
; 2. Get used numeral system: 0x = hex, otherwise 0 = octal, otherwise decimal
144
        push    10
144
        push    10
145
        pop     ebx
145
        pop     ebx
146
        lodsb
146
        lodsb
147
        cmp     al, '0'
147
        cmp     al, '0'
148
        jnz     .convert
148
        jnz     .convert
149
        push    8
149
        push    8
150
        pop     ebx
150
        pop     ebx
151
        lodsb
151
        lodsb
152
        cmp     al, 'x'
152
        cmp     al, 'x'
153
        jnz     .convert
153
        jnz     .convert
154
        add     ebx, ebx
154
        add     ebx, ebx
155
; 3. Loop while digits are encountered.
155
; 3. Loop while digits are encountered.
156
.convert:
156
.convert:
157
; 4. Convert digit from text representation to binary value.
157
; 4. Convert digit from text representation to binary value.
158
        or      al, 20h ; '0'-'9' -> '0'-'9', 'A'-'F' -> 'a'-'f'
158
        or      al, 20h ; '0'-'9' -> '0'-'9', 'A'-'F' -> 'a'-'f'
159
        sub     al, '0'
159
        sub     al, '0'
160
        cmp     al, 9
160
        cmp     al, 9
161
        jbe     .digit
161
        jbe     .digit
162
        sub     al, 'a' - '0'
162
        sub     al, 'a' - '0'
163
        cmp     al, 'f' - 'a'
163
        cmp     al, 'f' - 'a'
164
        ja      .convert_done
164
        ja      .convert_done
165
        add     al, 10
165
        add     al, 10
166
.digit:
166
.digit:
167
; 5. Digit must be less than base of numeral system.
167
; 5. Digit must be less than base of numeral system.
168
        cmp     eax, ebx
168
        cmp     eax, ebx
169
        jae     .convert_done
169
        jae     .convert_done
170
; 6. Advance the number.
170
; 6. Advance the number.
171
        imul    edx, ebx
171
        imul    edx, ebx
172
        add     edx, eax
172
        add     edx, eax
173
        cmp     edx, ecx
173
        cmp     edx, ecx
174
        ja      .gn_error
174
        ja      .gn_error
175
; 3b. Continue loop.
175
; 3b. Continue loop.
176
        lodsb
176
        lodsb
177
        jmp     .convert
177
        jmp     .convert
178
.convert_done:
178
.convert_done:
179
; 7. Invalid character, number converted, return success.
179
; 7. Invalid character, number converted, return success.
180
        xchg    eax, edx
180
        xchg    eax, edx
181
        pop     edx
181
        pop     edx
182
        clc
182
        clc
183
        ret
183
        ret
184
.gn_error:
184
.gn_error:
185
; 8. Too big number, return error.
185
; 8. Too big number, return error.
186
        pop     edx
186
        pop     edx
187
        stc
187
        stc
188
        ret
188
        ret
189
 
189
 
190
;;===========================================================================;;
190
;;===========================================================================;;
191
;; char* __stdcall inet_ntoa(struct in_addr in);                             ;;
191
;; char* __stdcall inet_ntoa(struct in_addr in);                             ;;
192
inet_ntoa:                                                                   ;;
192
inet_ntoa:                                                                   ;;
193
;;---------------------------------------------------------------------------;;
193
;;---------------------------------------------------------------------------;;
194
;? Convert the Internet host address to standard IPv4 dotted notation.       ;;
194
;? Convert the Internet host address to standard IPv4 dotted notation.       ;;
195
;;---------------------------------------------------------------------------;;
195
;;---------------------------------------------------------------------------;;
196
;> first parameter = host address                                            ;;
196
;> first parameter = host address                                            ;;
197
;;---------------------------------------------------------------------------;;
197
;;---------------------------------------------------------------------------;;
198
;< eax = pointer to resulting string (in static buffer)                      ;;
198
;< eax = pointer to resulting string (in static buffer)                      ;;
199
;;===========================================================================;;
199
;;===========================================================================;;
200
; 0. Save used registers for __stdcall.
200
; 0. Save used registers for __stdcall.
201
        push    ebx esi edi
201
        push    ebx esi edi
202
        mov     bl, 0xCD        ; constant for div 10
202
        mov     bl, 0xCD        ; constant for div 10
203
; 1. Write octet 4 times.
203
; 1. Write octet 4 times.
204
        mov     edi, .buffer
204
        mov     edi, .buffer
205
        mov     edx, [esp+16]   ; eax = in
205
        mov     edx, [esp+16]   ; eax = in
206
        mov     al, dl
206
        mov     al, dl
207
        call    .write
207
        call    .write
208
        mov     al, dh
208
        mov     al, dh
209
        shr     edx, 16
209
        shr     edx, 16
210
        call    .write
210
        call    .write
211
        mov     al, dl
211
        mov     al, dl
212
        call    .write
212
        call    .write
213
        mov     al, dh
213
        mov     al, dh
214
        call    .write
214
        call    .write
215
; 2. Replace final dot with terminating zero.
215
; 2. Replace final dot with terminating zero.
216
        mov     byte [edi-1], 0
216
        mov     byte [edi-1], 0
217
; 3. Restore used registers, set result value and return.
217
; 3. Restore used registers, set result value and return.
218
        pop     edi esi ebx
218
        pop     edi esi ebx
219
        mov     eax, .buffer
219
        mov     eax, .buffer
220
        ret     4
220
        ret     4
221
 
221
 
222
.write:
222
.write:
223
        movzx   esi, al
223
        movzx   esi, al
224
        mul     bl
224
        mul     bl
225
        add     esi, ('.' shl 8) + '0'
225
        add     esi, ('.' shl 8) + '0'
226
        shr     ah, 3   ; ah = al / 10
226
        shr     ah, 3   ; ah = al / 10
227
        movzx   ecx, ah
227
        movzx   ecx, ah
228
        add     ecx, ecx
228
        add     ecx, ecx
229
        lea     ecx, [ecx*5]
229
        lea     ecx, [ecx*5]
230
        sub     esi, ecx        ; lobyte(esi) = al % 10, hibyte(esi) = '.'
230
        sub     esi, ecx        ; lobyte(esi) = al % 10, hibyte(esi) = '.'
231
        test    ah, ah
231
        test    ah, ah
232
        jz      .1digit
232
        jz      .1digit
233
        cmp     ah, 10
233
        cmp     ah, 10
234
        jb      .2digit
234
        jb      .2digit
235
        cmp     ah, 20
235
        cmp     ah, 20
236
        sbb     cl, cl
236
        sbb     cl, cl
237
        add     cl, '2'
237
        add     cl, '2'
238
        mov     byte [edi], cl
238
        mov     byte [edi], cl
239
        movzx   ecx, cl
239
        movzx   ecx, cl
240
        lea     ecx, [ecx*5]
240
        lea     ecx, [ecx*5]
241
        sub     ah, cl
241
        sub     ah, cl
242
        sub     ah, cl
242
        sub     ah, cl
243
        add     ah, ('0'*11) and 255
243
        add     ah, ('0'*11) and 255
244
        mov     byte [edi+1], ah
244
        mov     byte [edi+1], ah
245
        mov     word [edi+2], si
245
        mov     word [edi+2], si
246
        add     edi, 4
246
        add     edi, 4
247
        ret
247
        ret
248
.2digit:
248
.2digit:
249
        add     ah, '0'
249
        add     ah, '0'
250
        mov     byte [edi], ah
250
        mov     byte [edi], ah
251
        mov     word [edi+1], si
251
        mov     word [edi+1], si
252
        add     edi, 3
252
        add     edi, 3
253
        ret
253
        ret
254
.1digit:
254
.1digit:
255
        mov     word [edi], si
255
        mov     word [edi], si
256
        add     edi, 2
256
        add     edi, 2
257
        ret
257
        ret
258
 
258
 
259
struct __gai_reqdata
259
struct __gai_reqdata
260
        socketnum  dd      ?
260
        socketnum  dd      ?
261
; external code should not look on rest of this structure,
261
; external code should not look on rest of this structure,
262
; it is internal for getaddrinfo_start/process/abort
262
; it is internal for getaddrinfo_start/process/abort
263
        reqid           dw      ?       ; DNS request ID
263
        reqid           dw      ?       ; DNS request ID
264
        socktype        db      ?       ; SOCK_* or 0 for any
264
        socktype        db      ?       ; SOCK_* or 0 for any
265
                        db      ?
265
                        db      ?
266
        service         dd      ?
266
        service         dd      ?
267
        flags           dd      ?
267
        flags           dd      ?
268
        reserved        rb      16
268
        reserved        rb      16
269
ends
269
ends
270
 
270
 
271
;;===========================================================================;;
271
;;===========================================================================;;
272
;; int __stdcall getaddrinfo(__in const char* hostname,                      ;;
272
;; int __stdcall getaddrinfo(__in const char* hostname,                      ;;
273
;;                           __in const char* servname,                      ;;
273
;;                           __in const char* servname,                      ;;
274
;;                           __in const struct addrinfo* hints,              ;;
274
;;                           __in const struct addrinfo* hints,              ;;
275
;;                           __out struct addrinfo **res);                   ;;
275
;;                           __out struct addrinfo **res);                   ;;
276
getaddrinfo:                                                                 ;;
276
getaddrinfo:                                                                 ;;
277
;;---------------------------------------------------------------------------;;
277
;;---------------------------------------------------------------------------;;
278
;? Get a list of IP addresses and port numbers for given host and service    ;;
278
;? Get a list of IP addresses and port numbers for given host and service    ;;
279
;;---------------------------------------------------------------------------;;
279
;;---------------------------------------------------------------------------;;
280
;> first parameter (optional) = host name                                    ;;
280
;> first parameter (optional) = host name                                    ;;
281
;> second parameter (optional) = service name (decimal number for now)       ;;
281
;> second parameter (optional) = service name (decimal number for now)       ;;
282
;> third parameter (optional) = hints for socketnum type                        ;;
282
;> third parameter (optional) = hints for socketnum type                        ;;
283
;> fourth parameter = pointer to result (head of L1-list)                    ;;
283
;> fourth parameter = pointer to result (head of L1-list)                    ;;
284
;;---------------------------------------------------------------------------;;
284
;;---------------------------------------------------------------------------;;
285
;< eax = 0 on success / one of EAI_ codes on error                           ;;
285
;< eax = 0 on success / one of EAI_ codes on error                           ;;
286
;;===========================================================================;;
286
;;===========================================================================;;
287
; 0. Save used registers for __stdcall.
287
; 0. Save used registers for __stdcall.
288
        push    ebx esi edi
288
        push    ebx esi edi
289
        mov     edi, [esp+28]   ; edi = res
289
        mov     edi, [esp+28]   ; edi = res
290
; 1. Create and send DNS packet.
290
; 1. Create and send DNS packet.
291
        sub     esp, sizeof.__gai_reqdata       ; reserve stack place (1)
291
        sub     esp, sizeof.__gai_reqdata       ; reserve stack place (1)
292
        push    esp             ; fifth parameter = pointer to (1)
292
        push    esp             ; fifth parameter = pointer to (1)
293
        push    edi             ; fourth parameter = res
293
        push    edi             ; fourth parameter = res
294
        push    dword [esp+32+sizeof.__gai_reqdata]     ; third parameter = hints
294
        push    dword [esp+32+sizeof.__gai_reqdata]     ; third parameter = hints
295
        push    dword [esp+32+sizeof.__gai_reqdata]     ; second parameter = servname
295
        push    dword [esp+32+sizeof.__gai_reqdata]     ; second parameter = servname
296
        push    dword [esp+32+sizeof.__gai_reqdata]     ; first parameter = hostname
296
        push    dword [esp+32+sizeof.__gai_reqdata]     ; first parameter = hostname
297
        call    getaddrinfo_start
297
        call    getaddrinfo_start
298
        test    eax, eax
298
        test    eax, eax
299
        jns     .ret    ; if name resolved without network activity, return
299
        jns     .ret    ; if name resolved without network activity, return
300
; 2. Wait for DNS reply.
300
; 2. Wait for DNS reply.
301
; 2a. Ignore all events except network stack.
301
; 2a. Ignore all events except network stack.
302
        mcall   40, EVM_STACK
302
        mcall   40, EVM_STACK
303
        push    eax     ; save previous event mask (2)
303
        push    eax     ; save previous event mask (2)
304
; 2b. Get upper limit for wait time. Use timeout = 5 seconds.
304
; 2b. Get upper limit for wait time. Use timeout = 5 seconds.
305
        mcall   26, 9   ; get time stamp
305
        mcall   26, 9   ; get time stamp
306
        xchg    esi, eax        ; save time stamp to esi
306
        xchg    esi, eax        ; save time stamp to esi
307
        mov     ebx, 500        ; start value for timeout
307
        mov     ebx, 500        ; start value for timeout
308
        add     esi, ebx
308
        add     esi, ebx
309
.wait:
309
.wait:
310
; 2c. Wait for event with timeout.
310
; 2c. Wait for event with timeout.
311
        mcall   23      ; wait for event - must be stack event
311
        mcall   23      ; wait for event - must be stack event
312
; 2d. Check for timeout.
312
; 2d. Check for timeout.
313
        test    eax, eax
313
        test    eax, eax
314
        lea     eax, [esp+4]    ; pointer to (1)
314
        lea     eax, [esp+4]    ; pointer to (1)
315
        jz      .timeout
315
        jz      .timeout
316
; 3. Got packet. Call processing function.
316
; 3. Got packet. Call processing function.
317
        push    edi     ; second parameter: pointer to result
317
        push    edi     ; second parameter: pointer to result
318
        push    eax     ; first parameter: pointer to reqdata
318
        push    eax     ; first parameter: pointer to reqdata
319
        call    getaddrinfo_process
319
        call    getaddrinfo_process
320
; 4. Test whether wait loop must be continued.
320
; 4. Test whether wait loop must be continued.
321
        test    eax, eax
321
        test    eax, eax
322
        jns     .ret.restore
322
        jns     .ret.restore
323
; 2e. Recalculate timeout value.
323
; 2e. Recalculate timeout value.
324
        mcall   26, 9
324
        mcall   26, 9
325
        mov     ebx, esi
325
        mov     ebx, esi
326
        sub     ebx, eax
326
        sub     ebx, eax
327
; 2f. Check that time is not over; if not, continue wait loop
327
; 2f. Check that time is not over; if not, continue wait loop
328
        cmp     ebx, 500
328
        cmp     ebx, 500
329
        jbe     .wait
329
        jbe     .wait
330
.timeout:
330
.timeout:
331
; 5. Timeout: abort and return error
331
; 5. Timeout: abort and return error
332
        push    eax
332
        push    eax
333
        call    getaddrinfo_abort
333
        call    getaddrinfo_abort
334
        and     dword [edi], 0
334
        and     dword [edi], 0
335
        push    EAI_AGAIN
335
        push    EAI_AGAIN
336
        pop     eax
336
        pop     eax
337
.ret.restore:
337
.ret.restore:
338
; 6. Restore event mask.
338
; 6. Restore event mask.
339
        pop     ebx     ; get event mask (2)
339
        pop     ebx     ; get event mask (2)
340
        push    eax     ; save return code (3)
340
        push    eax     ; save return code (3)
341
        mcall   40
341
        mcall   40
342
        pop     eax     ; restore return code (3)
342
        pop     eax     ; restore return code (3)
343
.ret:
343
.ret:
344
; 7. Restore stack pointer, used registers and return.
344
; 7. Restore stack pointer, used registers and return.
345
        add     esp, sizeof.__gai_reqdata       ; undo (1)
345
        add     esp, sizeof.__gai_reqdata       ; undo (1)
346
        pop     edi esi ebx
346
        pop     edi esi ebx
347
        ret     16
347
        ret     16
348
 
348
 
349
;;===========================================================================;;
349
;;===========================================================================;;
350
;; int __stdcall getaddrinfo_start(__in const char* hostname,                ;;
350
;; int __stdcall getaddrinfo_start(__in const char* hostname,                ;;
351
;;                                 __in const char* servname,                ;;
351
;;                                 __in const char* servname,                ;;
352
;;                                 __in const struct addrinfo* hints,        ;;
352
;;                                 __in const struct addrinfo* hints,        ;;
353
;;                                 __out struct addrinfo **res,              ;;
353
;;                                 __out struct addrinfo **res,              ;;
354
;;                                 __out struct __gai_reqdata* reqdata);     ;;
354
;;                                 __out struct __gai_reqdata* reqdata);     ;;
355
getaddrinfo_start:                                                           ;;
355
getaddrinfo_start:                                                           ;;
356
;;---------------------------------------------------------------------------;;
356
;;---------------------------------------------------------------------------;;
357
;? Initiator for getaddrinfo, sends DNS request                              ;;
357
;? Initiator for getaddrinfo, sends DNS request                              ;;
358
;;---------------------------------------------------------------------------;;
358
;;---------------------------------------------------------------------------;;
359
;> first 4 parameters same as for getaddrinfo                                ;;
359
;> first 4 parameters same as for getaddrinfo                                ;;
360
;> last parameter = pointer to buffer for __gai_reqdata, must be passed to   ;;
360
;> last parameter = pointer to buffer for __gai_reqdata, must be passed to   ;;
361
;>                  getaddrinfo_process as is                                ;;
361
;>                  getaddrinfo_process as is                                ;;
362
;;---------------------------------------------------------------------------;;
362
;;---------------------------------------------------------------------------;;
363
;< eax = <0 if wait loop must be entered / 0 on success / EAI_* on error     ;;
363
;< eax = <0 if wait loop must be entered / 0 on success / EAI_* on error     ;;
364
;;===========================================================================;;
364
;;===========================================================================;;
365
;; Known limitations:                                                        ;;
365
;; Known limitations:                                                        ;;
366
;; 1. No support for TCP connections =>                                      ;;
366
;; 1. No support for TCP connections =>                                      ;;
367
;; 1a. Long replies will be truncated, and not all IP addresses will be got. ;;
367
;; 1a. Long replies will be truncated, and not all IP addresses will be got. ;;
368
;; 2. No support for iterative resolving =>                                  ;;
368
;; 2. No support for iterative resolving =>                                  ;;
369
;; 2a. In theory may fail with some servers.                                 ;;
369
;; 2a. In theory may fail with some servers.                                 ;;
370
;; 3. Assumes that domain for relative names is always root, ".".            ;;
370
;; 3. Assumes that domain for relative names is always root, ".".            ;;
371
;; 4. Does not support lookup of services by name,                           ;;
371
;; 4. Does not support lookup of services by name,                           ;;
372
;;    only decimal representation is supported.                              ;;
372
;;    only decimal representation is supported.                              ;;
373
;; 5. Assumes that IPv4 is always configured, so AI_ADDRCONFIG has no effect.;;
373
;; 5. Assumes that IPv4 is always configured, so AI_ADDRCONFIG has no effect.;;
374
;;===========================================================================;;
374
;;===========================================================================;;
375
; 0. Create stack frame and save used registers for __stdcall.
375
; 0. Create stack frame and save used registers for __stdcall.
376
        push    ebx esi edi
376
        push    ebx esi edi
377
        push    ebp
377
        push    ebp
378
        mov     ebp, esp
378
        mov     ebp, esp
379
virtual at ebp-8
379
virtual at ebp-8
380
.recent_restsize dd     ?       ; this is for memory alloc in ._.generate_data
380
.recent_restsize dd     ?       ; this is for memory alloc in ._.generate_data
381
.recent_page    dd      ?       ; this is for memory alloc in ._.generate_data
381
.recent_page    dd      ?       ; this is for memory alloc in ._.generate_data
382
        rd      5       ; saved regs and return address
382
        rd      5       ; saved regs and return address
383
.hostname       dd      ?
383
.hostname       dd      ?
384
.servname       dd      ?
384
.servname       dd      ?
385
.hints          dd      ?
385
.hints          dd      ?
386
.res            dd      ?
386
.res            dd      ?
387
.reqdata        dd      ?
387
.reqdata        dd      ?
388
end virtual
388
end virtual
389
        xor     edi, edi
389
        xor     edi, edi
390
        push    edi     ; init .recent_page
390
        push    edi     ; init .recent_page
391
        push    edi     ; init .recent_restsize
391
        push    edi     ; init .recent_restsize
392
; 1. Check that parameters are correct and can be handled by this implementation.
392
; 1. Check that parameters are correct and can be handled by this implementation.
393
; 1a. If 'res' pointer is given, set result to zero.
393
; 1a. If 'res' pointer is given, set result to zero.
394
        mov     eax, [.res]
394
        mov     eax, [.res]
395
        test    eax, eax
395
        test    eax, eax
396
        jz      @f
396
        jz      @f
397
        mov     [eax], edi
397
        mov     [eax], edi
398
@@:
398
@@:
399
; 1b. Only AI_SUPPORTED flags are supported for hints->ai_flags.
399
; 1b. Only AI_SUPPORTED flags are supported for hints->ai_flags.
400
        mov     ecx, [.hints]
400
        mov     ecx, [.hints]
401
        xor     edx, edx
401
        xor     edx, edx
402
        jecxz   .nohints
402
        jecxz   .nohints
403
        mov     edx, [ecx+addrinfo.ai_flags]
403
        mov     edx, [ecx+addrinfo.ai_flags]
404
.nohints:
404
.nohints:
405
        mov     ebx, [.reqdata]
405
        mov     ebx, [.reqdata]
406
        mov     [ebx+__gai_reqdata.flags], edx
406
        mov     [ebx+__gai_reqdata.flags], edx
407
        push    EAI_BADFLAGS
407
        push    EAI_BADFLAGS
408
        pop     eax
408
        pop     eax
409
        test    edx, not AI_SUPPORTED
409
        test    edx, not AI_SUPPORTED
410
        jnz     .ret
410
        jnz     .ret
411
; 1c. Either hostname or servname must be given. If AI_CANONNAME is set,
411
; 1c. Either hostname or servname must be given. If AI_CANONNAME is set,
412
; hostname must also be set.
412
; hostname must also be set.
413
        cmp     [.hostname], edi
413
        cmp     [.hostname], edi
414
        jnz     @f
414
        jnz     @f
415
        test    dl, AI_CANONNAME
415
        test    dl, AI_CANONNAME
416
        jnz     .ret
416
        jnz     .ret
417
        push    EAI_NONAME
417
        push    EAI_NONAME
418
        pop     eax
418
        pop     eax
419
        cmp     [.servname], edi
419
        cmp     [.servname], edi
420
        jz      .ret
420
        jz      .ret
421
@@:
421
@@:
422
; 1d. Only IPv4 is supported, so hints->ai_family must be either PF_UNSPEC or PF_INET.
422
; 1d. Only IPv4 is supported, so hints->ai_family must be either PF_UNSPEC or PF_INET.
423
        push    EAI_FAMILY
423
        push    EAI_FAMILY
424
        pop     eax
424
        pop     eax
425
        jecxz   @f
425
        jecxz   @f
426
        cmp     [ecx+addrinfo.ai_family], edi
426
        cmp     [ecx+addrinfo.ai_family], edi
427
        jz      @f
427
        jz      @f
428
        cmp     [ecx+addrinfo.ai_family], AF_INET4
428
        cmp     [ecx+addrinfo.ai_family], AF_INET4
429
        jnz     .ret
429
        jnz     .ret
430
@@:
430
@@:
431
; 1e. Valid combinations for ai_socktype/ai_protocol: 0/0 for any or
431
; 1e. Valid combinations for ai_socktype/ai_protocol: 0/0 for any or
432
;       SOCK_STREAM/IPPROTO_TCP, SOCK_DGRAM/IPPROTO_UDP
432
;       SOCK_STREAM/IPPROTO_TCP, SOCK_DGRAM/IPPROTO_UDP
433
;       (raw socketnums are not yet supported by the kernel)
433
;       (raw socketnums are not yet supported by the kernel)
434
        xor     edx, edx        ; assume 0=any if no hints
434
        xor     edx, edx        ; assume 0=any if no hints
435
        jecxz   .socketnum_type_ok
435
        jecxz   .socketnum_type_ok
436
        mov     edx, [ecx+addrinfo.ai_socktype]
436
        mov     edx, [ecx+addrinfo.ai_socktype]
437
        mov     esi, [ecx+addrinfo.ai_protocol]
437
        mov     esi, [ecx+addrinfo.ai_protocol]
438
; 1f. Test for ai_socktype=0 and ai_protocol=0.
438
; 1f. Test for ai_socktype=0 and ai_protocol=0.
439
        test    edx, edx
439
        test    edx, edx
440
        jnz     .check_socktype
440
        jnz     .check_socktype
441
        test    esi, esi
441
        test    esi, esi
442
        jz      .socketnum_type_ok
442
        jz      .socketnum_type_ok
443
; 1g. ai_socktype=0, ai_protocol is nonzero.
443
; 1g. ai_socktype=0, ai_protocol is nonzero.
444
        push    EAI_SERVICE
444
        push    EAI_SERVICE
445
        pop     eax
445
        pop     eax
446
        inc     edx     ; edx = SOCK_STREAM
446
        inc     edx     ; edx = SOCK_STREAM
447
        cmp     esi, IPPROTO_TCP
447
        cmp     esi, IPPROTO_TCP
448
        jz      .socketnum_type_ok
448
        jz      .socketnum_type_ok
449
        inc     edx     ; edx = SOCK_DGRAM
449
        inc     edx     ; edx = SOCK_DGRAM
450
        cmp     esi, IPPROTO_UDP
450
        cmp     esi, IPPROTO_UDP
451
        jz      .socketnum_type_ok
451
        jz      .socketnum_type_ok
452
.ret:
452
.ret:
453
; Restore saved registers, destroy stack frame and return.
453
; Restore saved registers, destroy stack frame and return.
454
        mov     esp, ebp
454
        mov     esp, ebp
455
        pop     ebp
455
        pop     ebp
456
        pop     edi esi ebx
456
        pop     edi esi ebx
457
        ret     20
457
        ret     20
458
; 1h. ai_socktype is nonzero.
458
; 1h. ai_socktype is nonzero.
459
.check_socktype:
459
.check_socktype:
460
        push    EAI_SOCKTYPE
460
        push    EAI_SOCKTYPE
461
        pop     eax
461
        pop     eax
462
        cmp     edx, SOCK_STREAM
462
        cmp     edx, SOCK_STREAM
463
        jz      .check_tcp
463
        jz      .check_tcp
464
        cmp     edx, SOCK_DGRAM
464
        cmp     edx, SOCK_DGRAM
465
        jnz     .ret
465
        jnz     .ret
466
        test    esi, esi
466
        test    esi, esi
467
        jz      .socketnum_type_ok
467
        jz      .socketnum_type_ok
468
        cmp     esi, IPPROTO_UDP
468
        cmp     esi, IPPROTO_UDP
469
        jz      .socketnum_type_ok
469
        jz      .socketnum_type_ok
470
        jmp     .ret
470
        jmp     .ret
471
.check_tcp:
471
.check_tcp:
472
        test    esi, esi
472
        test    esi, esi
473
        jz      .socketnum_type_ok
473
        jz      .socketnum_type_ok
474
        cmp     esi, IPPROTO_TCP
474
        cmp     esi, IPPROTO_TCP
475
        jnz     .ret
475
        jnz     .ret
476
.socketnum_type_ok:
476
.socketnum_type_ok:
477
        mov     [ebx+__gai_reqdata.socktype], dl
477
        mov     [ebx+__gai_reqdata.socktype], dl
478
; 2. Resolve service.
478
; 2. Resolve service.
479
; 2a. If no name is given, remember value -1.
479
; 2a. If no name is given, remember value -1.
480
        push    -1
480
        push    -1
481
        pop     edx
481
        pop     edx
482
        mov     esi, [.servname]
482
        mov     esi, [.servname]
483
        test    esi, esi
483
        test    esi, esi
484
        jz      .service_resolved
484
        jz      .service_resolved
485
; 2b. Loop for characters of string while digits are encountered.
485
; 2b. Loop for characters of string while digits are encountered.
486
        xor     edx, edx
486
        xor     edx, edx
487
        xor     eax, eax
487
        xor     eax, eax
488
.serv_to_number:
488
.serv_to_number:
489
        lodsb
489
        lodsb
490
        sub     al, '0'
490
        sub     al, '0'
491
        cmp     al, 9
491
        cmp     al, 9
492
        ja      .serv_to_number_done
492
        ja      .serv_to_number_done
493
; for each digit, set edx = edx*10 + 
493
; for each digit, set edx = edx*10 + 
494
        lea     edx, [edx*5]
494
        lea     edx, [edx*5]
495
        lea     edx, [edx*2+eax]
495
        lea     edx, [edx*2+eax]
496
; check for correctness: service port must fit in word
496
; check for correctness: service port must fit in word
497
        cmp     edx, 0x10000
497
        cmp     edx, 0x10000
498
        jae     .service_not_number
498
        jae     .service_not_number
499
        jmp     .serv_to_number
499
        jmp     .serv_to_number
500
.serv_to_number_done:
500
.serv_to_number_done:
501
        and     edx, 0xFFFF     ; make sure that port fits
501
        and     edx, 0xFFFF     ; make sure that port fits
502
; 2c. If zero character reached, name is resolved;
502
; 2c. If zero character reached, name is resolved;
503
; otherwise, return error (no support for symbolic names yet)
503
; otherwise, return error (no support for symbolic names yet)
504
        cmp     al, -'0'
504
        cmp     al, -'0'
505
        jz      .service_resolved
505
        jz      .service_resolved
506
.service_not_number:
506
.service_not_number:
507
        push    EAI_NONAME
507
        push    EAI_NONAME
508
        pop     eax
508
        pop     eax
509
        jmp     .ret
509
        jmp     .ret
510
.service_resolved:
510
.service_resolved:
511
; 2d. Save result to reqdata.
511
; 2d. Save result to reqdata.
512
        mov     [ebx+__gai_reqdata.service], edx
512
        mov     [ebx+__gai_reqdata.service], edx
513
; 3. Process host name.
513
; 3. Process host name.
514
        mov     esi, [.hostname]
514
        mov     esi, [.hostname]
515
; 3a. If hostname is not given,
515
; 3a. If hostname is not given,
516
;       use localhost for active socketnums and INADDR_ANY for passive socketnums.
516
;       use localhost for active socketnums and INADDR_ANY for passive socketnums.
517
        mov     eax, 0x0100007F ; 127.0.0.1 in network byte order
517
        mov     eax, 0x0100007F ; 127.0.0.1 in network byte order
518
        test    byte [ebx+__gai_reqdata.flags], AI_PASSIVE
518
        test    byte [ebx+__gai_reqdata.flags], AI_PASSIVE
519
        jz      @f
519
        jz      @f
520
        xor     eax, eax
520
        xor     eax, eax
521
@@:
521
@@:
522
        test    esi, esi
522
        test    esi, esi
523
        jz      .hostname_is_ip
523
        jz      .hostname_is_ip
524
; 3b. Check for dotted IPv4 name.
524
; 3b. Check for dotted IPv4 name.
525
        push    esi
525
        push    esi
526
        call    inet_addr
526
        call    inet_addr
527
        cmp     eax, -1
527
        cmp     eax, -1
528
        jz      .resolve_hostname
528
        jz      .resolve_hostname
529
.hostname_is_ip:
529
.hostname_is_ip:
530
; 3c. hostname is valid representation of IP address, and we have resolved it.
530
; 3c. hostname is valid representation of IP address, and we have resolved it.
531
; Generate result, if .res pointer is not NULL.
531
; Generate result, if .res pointer is not NULL.
532
        mov     ebx, [.reqdata]
532
        mov     ebx, [.reqdata]
533
        mov     esi, [.res]
533
        mov     esi, [.res]
534
        test    esi, esi
534
        test    esi, esi
535
        jz      .no_result
535
        jz      .no_result
536
        call    getaddrinfo._.generate_data
536
        call    getaddrinfo._.generate_data
537
; 3d. Check for memory allocation error.
537
; 3d. Check for memory allocation error.
538
.3d:
538
.3d:
539
        push    EAI_MEMORY
539
        push    EAI_MEMORY
540
        pop     eax
540
        pop     eax
541
        test    esi, esi
541
        test    esi, esi
542
        jz      .ret
542
        jz      .ret
543
; 3e. If AI_CANONNAME is set, copy input name.
543
; 3e. If AI_CANONNAME is set, copy input name.
544
        test    byte [ebx+__gai_reqdata.flags], AI_CANONNAME
544
        test    byte [ebx+__gai_reqdata.flags], AI_CANONNAME
545
        jz      .no_result
545
        jz      .no_result
546
; 3f. Calculate length of name.
546
; 3f. Calculate length of name.
547
        push    -1
547
        push    -1
548
        pop     ecx
548
        pop     ecx
549
        mov     edi, [.hostname]
549
        mov     edi, [.hostname]
550
        xor     eax, eax
550
        xor     eax, eax
551
        repnz   scasb
551
        repnz   scasb
552
        not     ecx
552
        not     ecx
553
; 3g. Check whether it fits on one page with main data.
553
; 3g. Check whether it fits on one page with main data.
554
        cmp     ecx, [.recent_restsize]
554
        cmp     ecx, [.recent_restsize]
555
        jbe     .name_fits
555
        jbe     .name_fits
556
; 3h. If not, allocate new page.
556
; 3h. If not, allocate new page.
557
        push    ecx
557
        push    ecx
558
        add     ecx, 4  ; first dword contains number of objects on the page
558
        add     ecx, 4  ; first dword contains number of objects on the page
559
        mcall   68, 12
559
        mcall   68, 12
560
        pop     ecx
560
        pop     ecx
561
; 3i. If allocation has failed, free addrinfo and return error.
561
; 3i. If allocation has failed, free addrinfo and return error.
562
        test    eax, eax
562
        test    eax, eax
563
        jnz     .name_allocated
563
        jnz     .name_allocated
564
        push    [.res]
564
        push    [.res]
565
        call    freeaddrinfo
565
        call    freeaddrinfo
566
        push    EAI_MEMORY
566
        push    EAI_MEMORY
567
        pop     eax
567
        pop     eax
568
        jmp     .ret
568
        jmp     .ret
569
.name_allocated:
569
.name_allocated:
570
; 3j. Otherwise, set edi to allocated memory and continue to 3l.
570
; 3j. Otherwise, set edi to allocated memory and continue to 3l.
571
        xchg    edi, eax        ; put result to edi
571
        xchg    edi, eax        ; put result to edi
572
        push    1
572
        push    1
573
        pop     eax
573
        pop     eax
574
        stosd   ; number of objects on the page = 1
574
        stosd   ; number of objects on the page = 1
575
        jmp     .copy_name
575
        jmp     .copy_name
576
.name_fits:
576
.name_fits:
577
; 3k. Get pointer to free memory in allocated page.
577
; 3k. Get pointer to free memory in allocated page.
578
        mov     edi, [.recent_page]
578
        mov     edi, [.recent_page]
579
        mov     eax, edi
579
        mov     eax, edi
580
        and     eax, not 0xFFF
580
        and     eax, not 0xFFF
581
        inc     dword [eax]     ; increase number of objects
581
        inc     dword [eax]     ; increase number of objects
582
.copy_name:
582
.copy_name:
583
; 3l. Put pointer to struct addrinfo.
583
; 3l. Put pointer to struct addrinfo.
584
        mov     eax, [.res]
584
        mov     eax, [.res]
585
        mov     eax, [eax]
585
        mov     eax, [eax]
586
        mov     [eax+addrinfo.ai_canonname], edi
586
        mov     [eax+addrinfo.ai_canonname], edi
587
; 3m. Copy name.
587
; 3m. Copy name.
588
        rep     movsb
588
        rep     movsb
589
.no_result:
589
.no_result:
590
; 3n. Return success.
590
; 3n. Return success.
591
        xor     eax, eax
591
        xor     eax, eax
592
        jmp     .ret
592
        jmp     .ret
593
; 4. Host address is not dotted IP. Test whether we are allowed to contact DNS.
593
; 4. Host address is not dotted IP. Test whether we are allowed to contact DNS.
594
; Return error if no.
594
; Return error if no.
595
.resolve_hostname:
595
.resolve_hostname:
596
        push    EAI_NONAME
596
        push    EAI_NONAME
597
        pop     eax
597
        pop     eax
598
        mov     ebx, [.reqdata]
598
        mov     ebx, [.reqdata]
599
        test    byte [ebx+__gai_reqdata.flags], AI_NUMERICHOST
599
        test    byte [ebx+__gai_reqdata.flags], AI_NUMERICHOST
600
        jnz     .ret
600
        jnz     .ret
601
; Host address is domain name. Contact DNS server.
601
; Host address is domain name. Contact DNS server.
602
        mov     esi, [.hostname]
602
        mov     esi, [.hostname]
603
; 5. Reserve stack place for UDP packet.
603
; 5. Reserve stack place for UDP packet.
604
; According to RFC1035, maximum UDP packet size in DNS is 512 bytes.
604
; According to RFC1035, maximum UDP packet size in DNS is 512 bytes.
605
        sub     esp, 512
605
        sub     esp, 512
606
; 6. Create DNS request packet.
606
; 6. Create DNS request packet.
607
; 6a. Set pointer to start of buffer.
607
; 6a. Set pointer to start of buffer.
608
        mov     edi, esp
608
        mov     edi, esp
609
; 6b. Get request ID, write it to buffer.
609
; 6b. Get request ID, write it to buffer.
610
        push    1
610
        push    1
611
        pop     eax
611
        pop     eax
612
lock    xadd    [DNSrequestID], eax     ; atomically increment ID, get old value
612
lock    xadd    [DNSrequestID], eax     ; atomically increment ID, get old value
613
        stosw
613
        stosw
614
        mov     [ebx+__gai_reqdata.reqid], ax
614
        mov     [ebx+__gai_reqdata.reqid], ax
615
; 6c. Packed field: QR=0 (query), Opcode=0000 (standard query),
615
; 6c. Packed field: QR=0 (query), Opcode=0000 (standard query),
616
;       AA=0 (ignored in requests), TC=0 (no truncation),
616
;       AA=0 (ignored in requests), TC=0 (no truncation),
617
;       RD=1 (recursion desired)
617
;       RD=1 (recursion desired)
618
        mov     al, 00000001b
618
        mov     al, 00000001b
619
        stosb
619
        stosb
620
; 6d. Packed field: ignored in requests
620
; 6d. Packed field: ignored in requests
621
        mov     al, 0
621
        mov     al, 0
622
        stosb
622
        stosb
623
; 6e. Write questions count = 1 and answers count = 0
623
; 6e. Write questions count = 1 and answers count = 0
624
; Note that network byte order is big-endian.
624
; Note that network byte order is big-endian.
625
        mov     eax, 0x00000100
625
        mov     eax, 0x00000100
626
        stosd
626
        stosd
627
; 6f. Write nameservers count = 0 and additional records count = 0
627
; 6f. Write nameservers count = 0 and additional records count = 0
628
        xor     eax, eax
628
        xor     eax, eax
629
        stosd
629
        stosd
630
; 6g. Write request data: name
630
; 6g. Write request data: name
631
; According to RFC1035, maximum length of name is 255 bytes.
631
; According to RFC1035, maximum length of name is 255 bytes.
632
; For correct names, buffer cannot overflow.
632
; For correct names, buffer cannot overflow.
633
        lea     ebx, [esi+256]  ; ebx = limit for name (including terminating zero)
633
        lea     ebx, [esi+256]  ; ebx = limit for name (including terminating zero)
634
; translate string "www.yandex.ru" {00} to byte data {03} "www" {06} "yandex" {02} "ru" {00}
634
; translate string "www.yandex.ru" {00} to byte data {03} "www" {06} "yandex" {02} "ru" {00}
635
.nameloop:      ; here we go in the start of each label: before "www", before "yandex", before "ru"
635
.nameloop:      ; here we go in the start of each label: before "www", before "yandex", before "ru"
636
        xor     ecx, ecx        ; ecx = length of current label
636
        xor     ecx, ecx        ; ecx = length of current label
637
        inc     edi     ; skip length, it will be filled later
637
        inc     edi     ; skip length, it will be filled later
638
.labelloop:     ; here we go for each symbol of name
638
.labelloop:     ; here we go for each symbol of name
639
        lodsb   ; get next character
639
        lodsb   ; get next character
640
        test    al, al  ; terminating zero?
640
        test    al, al  ; terminating zero?
641
        jz      .endname
641
        jz      .endname
642
        cmp     esi, ebx        ; limit exceeded?
642
        cmp     esi, ebx        ; limit exceeded?
643
        jae     .wrongname
643
        jae     .wrongname
644
        cmp     al, '.' ; end of label?
644
        cmp     al, '.' ; end of label?
645
        jz      .labelend
645
        jz      .labelend
646
        stosb   ; put next character
646
        stosb   ; put next character
647
        inc     ecx     ; increment label length
647
        inc     ecx     ; increment label length
648
        jmp     .labelloop
648
        jmp     .labelloop
649
.wrongname:
649
.wrongname:
650
        push    EAI_NONAME
650
        push    EAI_NONAME
651
        pop     eax
651
        pop     eax
652
        jmp     .ret
652
        jmp     .ret
653
.labelend:
653
.labelend:
654
        test    ecx, ecx        ; null label can be only in the end of name
654
        test    ecx, ecx        ; null label can be only in the end of name
655
        jz      .wrongname
655
        jz      .wrongname
656
.endname:
656
.endname:
657
        cmp     ecx, 63
657
        cmp     ecx, 63
658
        ja      .wrongname
658
        ja      .wrongname
659
; write length to byte [edi-ecx-1]
659
; write length to byte [edi-ecx-1]
660
        mov     eax, ecx
660
        mov     eax, ecx
661
        neg     eax
661
        neg     eax
662
        mov     byte [edi+eax-1], cl
662
        mov     byte [edi+eax-1], cl
663
        cmp     byte [esi-1], 0 ; that was last label in the name?
663
        cmp     byte [esi-1], 0 ; that was last label in the name?
664
        jnz     .nameloop
664
        jnz     .nameloop
665
; write terminating zero if not yet
665
; write terminating zero if not yet
666
        mov     al, 0
666
        mov     al, 0
667
        cmp     byte [edi-1], al
667
        cmp     byte [edi-1], al
668
        jz      @f
668
        jz      @f
669
        stosb
669
        stosb
670
@@:
670
@@:
671
; 6h. Write request data:
671
; 6h. Write request data:
672
;       query type = A (host address) = 1,
672
;       query type = A (host address) = 1,
673
;       query class = IN (internet IPv4 address) = 1
673
;       query class = IN (internet IPv4 address) = 1
674
; Note that network byte order is big-endian.
674
; Note that network byte order is big-endian.
675
        mov     eax, 0x01000100
675
        mov     eax, 0x01000100
676
        stosd
676
        stosd
677
; 7. Get DNS server address.
677
; 7. Get DNS server address.
678
        mcall   76, API_IPv4 + (1 shl 8) + 4 ; protocol IP=0, device number=0, function=get DNS address
678
        mcall   76, API_IPv4 + (1 shl 8) + 4 ; protocol IP=0, device number=0, function=get DNS address
679
        cmp     eax, -1
679
        cmp     eax, -1
680
        je      .ret.dnserr
680
        je      .ret.dnserr
681
        mov     esi, eax        ; put server address to esi
681
        mov     esi, eax        ; put server address to esi
682
; 8. Open UDP socketnum to DNS server, port 53.
682
; 8. Open UDP socketnum to DNS server, port 53.
683
; 8a. Create new socketnum.
683
; 8a. Create new socketnum.
684
        mcall   75, 0, AF_INET4, SOCK_DGRAM
684
        mcall   75, 0, AF_INET4, SOCK_DGRAM
685
        cmp     eax, -1 ; error?
685
        cmp     eax, -1 ; error?
686
        jz      .ret.dnserr
686
        jz      .ret.dnserr
687
        mov     ecx, eax        ; put socketnum handle to ecx
687
        mov     ecx, eax        ; put socketnum handle to ecx
688
; 8b. Create sockaddr structure on the stack.
688
; 8b. Create sockaddr structure on the stack.
689
        push    0
689
        push    0
690
        push    0       ; sin_zero
690
        push    0       ; sin_zero
691
        push    esi     ; sin_addr
691
        push    esi     ; sin_addr
692
        push    AF_INET4 + (53 shl 24)
692
        push    AF_INET4 + (53 shl 24)
693
                        ; sin_family and sin_port in network byte order
693
                        ; sin_family and sin_port in network byte order
694
; 8c. Connect.
694
; 8c. Connect.
695
        mcall   75, 4, , esp, sizeof.sockaddr_in
695
        mcall   75, 4, , esp, sizeof.sockaddr_in
696
; 8d. Restore the stack, undo 8b.
696
; 8d. Restore the stack, undo 8b.
697
        add     esp, esi
697
        add     esp, esi
698
; 8e. Check result.
698
; 8e. Check result.
699
        cmp     eax, -1
699
        cmp     eax, -1
700
        jz      .ret.close
700
        jz      .ret.close
701
; 9. Send DNS request packet.
701
; 9. Send DNS request packet.
702
        sub     edi, esp        ; get packet length
702
        sub     edi, esp        ; get packet length
703
        mov     esi, edi
703
        mov     esi, edi
704
        xor     edi, edi
704
        xor     edi, edi
705
        mcall   75, 6, , esp
705
        mcall   75, 6, , esp
706
        cmp     eax, -1
706
        cmp     eax, -1
707
        jz      .ret.close
707
        jz      .ret.close
708
        mov     eax, [.reqdata]
708
        mov     eax, [.reqdata]
709
        mov     [eax+__gai_reqdata.socketnum], ecx
709
        mov     [eax+__gai_reqdata.socketnum], ecx
710
        push    -1
710
        push    -1
711
        pop     eax     ; return status: more processing required
711
        pop     eax     ; return status: more processing required
712
        jmp     .ret.dns
712
        jmp     .ret.dns
713
.ret.close:
713
.ret.close:
714
        mcall   75, 1
714
        mcall   75, 1
715
.ret.dnserr:
715
.ret.dnserr:
716
        push    EAI_AGAIN
716
        push    EAI_AGAIN
717
        pop     eax
717
        pop     eax
718
.ret.dns:
718
.ret.dns:
719
; 6. Restore stack pointer and return.
719
; 6. Restore stack pointer and return.
720
        jmp     .ret
720
        jmp     .ret
721
 
721
 
722
;;===========================================================================;;
722
;;===========================================================================;;
723
;; int __stdcall getaddrinfo_process(__in struct __gai_reqdata* reqdata,     ;;
723
;; int __stdcall getaddrinfo_process(__in struct __gai_reqdata* reqdata,     ;;
724
;;                                   __out struct addrinfo** res);           ;;
724
;;                                   __out struct addrinfo** res);           ;;
725
getaddrinfo_process:                                                         ;;
725
getaddrinfo_process:                                                         ;;
726
;;---------------------------------------------------------------------------;;
726
;;---------------------------------------------------------------------------;;
727
;? Processes network events from DNS reply                                   ;;
727
;? Processes network events from DNS reply                                   ;;
728
;;---------------------------------------------------------------------------;;
728
;;---------------------------------------------------------------------------;;
729
;> first parameter = pointer to struct __gai_reqdata filled by ..._start     ;;
729
;> first parameter = pointer to struct __gai_reqdata filled by ..._start     ;;
730
;> second parameter = same as for getaddrinfo                                ;;
730
;> second parameter = same as for getaddrinfo                                ;;
731
;;---------------------------------------------------------------------------;;
731
;;---------------------------------------------------------------------------;;
732
;< eax = -1 if more processing required / 0 on success / >0 = error code     ;;
732
;< eax = -1 if more processing required / 0 on success / >0 = error code     ;;
733
;;===========================================================================;;
733
;;===========================================================================;;
734
; 0. Create stack frame.
734
; 0. Create stack frame.
735
        push    ebp
735
        push    ebp
736
        mov     ebp, esp
736
        mov     ebp, esp
737
virtual at ebp-.locals_size
737
virtual at ebp-.locals_size
738
.locals_start:
738
.locals_start:
739
.datagram       rb      512
739
.datagram       rb      512
740
.addrname       dd      ?
740
.addrname       dd      ?
741
.name           dd      ?
741
.name           dd      ?
742
.res_list_tail  dd      ?
742
.res_list_tail  dd      ?
743
.cname          dd      ?
743
.cname          dd      ?
744
.recent_restsize dd     ?       ; this is for memory alloc in ._.generate_data
744
.recent_restsize dd     ?       ; this is for memory alloc in ._.generate_data
745
.recent_page    dd      ?       ; this is for memory alloc in ._.generate_data
745
.recent_page    dd      ?       ; this is for memory alloc in ._.generate_data
746
.locals_size = $ - .locals_start
746
.locals_size = $ - .locals_start
747
                rd      2
747
                rd      2
748
.reqdata        dd      ?
748
.reqdata        dd      ?
749
.res            dd      ?
749
.res            dd      ?
750
end virtual
750
end virtual
751
        xor     eax, eax
751
        xor     eax, eax
752
        push    eax     ; initialize .recent_page
752
        push    eax     ; initialize .recent_page
753
        push    eax     ; initialize .recent_restsize
753
        push    eax     ; initialize .recent_restsize
754
        push    eax     ; initialize .cname
754
        push    eax     ; initialize .cname
755
        push    [.res]  ; initialize .res_list_tail
755
        push    [.res]  ; initialize .res_list_tail
756
        sub     esp, .locals_size-16    ; reserve place for other vars
756
        sub     esp, .locals_size-16    ; reserve place for other vars
757
        mov     edx, esp        ; edx -> buffer for datagram
757
        mov     edx, esp        ; edx -> buffer for datagram
758
; 1. Save used registers for __stdcall.
758
; 1. Save used registers for __stdcall.
759
        push    ebx esi edi
759
        push    ebx esi edi
760
        mov     edi, [.reqdata]
760
        mov     edi, [.reqdata]
761
; 2. Read UDP datagram.
761
; 2. Read UDP datagram.
762
        mov     ecx, [edi+__gai_reqdata.socketnum]
762
        mov     ecx, [edi+__gai_reqdata.socketnum]
763
        push    edi
763
        push    edi
764
        mcall   75, 7, , , 512, MSG_DONTWAIT
764
        mcall   75, 7, , , 512, MSG_DONTWAIT
765
        pop     edi
765
        pop     edi
766
; 3. Ignore events for other socketnums (return if no data read)
766
; 3. Check for socket errors
767
        test    eax, eax
767
        cmp     eax, -1
-
 
768
        jne     @f
-
 
769
        cmp     ebx, EWOULDBLOCK
768
        jz      .ret.more_processing_required
770
        je      .ret.more_processing_required
-
 
771
        jmp     .ret.no_recovery
-
 
772
  @@:
769
; 4. Sanity check: discard too short packets.
773
; 4. Sanity check: discard too short packets.
770
        xchg    ecx, eax        ; save packet length in ecx
774
        xchg    ecx, eax        ; save packet length in ecx
771
        cmp     ecx, 12
775
        cmp     ecx, 12
772
        jb      .ret.more_processing_required
776
        jb      .ret.more_processing_required
773
; 5. Discard packets with ID != request ID.
777
; 5. Discard packets with ID != request ID.
774
        mov     eax, dword [edi+__gai_reqdata.reqid]
778
        mov     eax, dword [edi+__gai_reqdata.reqid]
775
        cmp     ax, [edx]
779
        cmp     ax, [edx]
776
        jnz     .ret.more_processing_required
780
        jnz     .ret.more_processing_required
777
; 6. Sanity check: discard query packets.
781
; 6. Sanity check: discard query packets.
778
        test    byte [edx+2], 80h
782
        test    byte [edx+2], 80h
779
        jz      .ret.more_processing_required
783
        jz      .ret.more_processing_required
780
; 7. Sanity check: must be exactly one query (our).
784
; 7. Sanity check: must be exactly one query (our).
781
        cmp     word [edx+4], 0x0100    ; note network byte order
785
        cmp     word [edx+4], 0x0100    ; note network byte order
782
        jnz     .ret.more_processing_required
786
        jnz     .ret.more_processing_required
783
; 8. Check for errors. Return EAI_NONAME for error code 3 and EAI_FAIL for other.
787
; 8. Check for errors. Return EAI_NONAME for error code 3 and EAI_FAIL for other.
784
        mov     al, [edx+3]
788
        mov     al, [edx+3]
785
        and     al, 0xF
789
        and     al, 0xF
786
        jz      @f
790
        jz      @f
787
        cmp     al, 3
791
        cmp     al, 3
788
        jnz     .ret.no_recovery
792
        jnz     .ret.no_recovery
789
        jmp     .ret.no_name
793
        jmp     .ret.no_name
790
@@:
794
@@:
791
; 9. Locate answers section. Exactly 1 query is present in this packet.
795
; 9. Locate answers section. Exactly 1 query is present in this packet.
792
        add     ecx, edx        ; ecx = limit
796
        add     ecx, edx        ; ecx = limit
793
        lea     esi, [edx+12]
797
        lea     esi, [edx+12]
794
        call    .skip_name
798
        call    .skip_name
795
        lodsd           ; skip QTYPE and QCLASS field
799
        lodsd           ; skip QTYPE and QCLASS field
796
        cmp     esi, ecx
800
        cmp     esi, ecx
797
        ja      .ret.no_recovery
801
        ja      .ret.no_recovery
798
; 10. Loop through all answers.
802
; 10. Loop through all answers.
799
        movzx   ebx, word [edx+6]       ; get answers count
803
        movzx   ebx, word [edx+6]       ; get answers count
800
        xchg    bl, bh          ; network -> Intel byte order
804
        xchg    bl, bh          ; network -> Intel byte order
801
.answers_loop:
805
.answers_loop:
802
        dec     ebx
806
        dec     ebx
803
        js      .answers_done
807
        js      .answers_done
804
; 10a. Process each record.
808
; 10a. Process each record.
805
        mov     [.name], esi
809
        mov     [.name], esi
806
; 10b. Skip name field.
810
; 10b. Skip name field.
807
        call    .skip_name
811
        call    .skip_name
808
; 10c. Get record information, handle two types for class IN (internet).
812
; 10c. Get record information, handle two types for class IN (internet).
809
        lodsd           ; get type and class
813
        lodsd           ; get type and class
810
        cmp     esi, ecx
814
        cmp     esi, ecx
811
        ja      .ret.no_recovery
815
        ja      .ret.no_recovery
812
        cmp     eax, 0x01000500 ; type=5, class=1?
816
        cmp     eax, 0x01000500 ; type=5, class=1?
813
        jz      .got_cname
817
        jz      .got_cname
814
        cmp     eax, 0x01000100 ; type=1, class=1?
818
        cmp     eax, 0x01000100 ; type=1, class=1?
815
        jnz     .answers_loop.next
819
        jnz     .answers_loop.next
816
.got_addr:
820
.got_addr:
817
; 10d. Process record A, host address.
821
; 10d. Process record A, host address.
818
        add     esi, 10
822
        add     esi, 10
819
        cmp     esi, ecx
823
        cmp     esi, ecx
820
        ja      .ret.no_recovery
824
        ja      .ret.no_recovery
821
        cmp     word [esi-6], 0x0400    ; RDATA for A records must be 4 bytes long
825
        cmp     word [esi-6], 0x0400    ; RDATA for A records must be 4 bytes long
822
        jnz     .ret.no_recovery
826
        jnz     .ret.no_recovery
823
        mov     eax, [.name]
827
        mov     eax, [.name]
824
        mov     [.addrname], eax
828
        mov     [.addrname], eax
825
; 10e. Create corresponding record in the answer.
829
; 10e. Create corresponding record in the answer.
826
        push    ebx ecx esi
830
        push    ebx ecx esi
827
        mov     eax, [esi-4]    ; IP address
831
        mov     eax, [esi-4]    ; IP address
828
        mov     esi, [.res_list_tail]   ; pointer to result
832
        mov     esi, [.res_list_tail]   ; pointer to result
829
        test    esi, esi
833
        test    esi, esi
830
        jz      .no_result      ; do not save if .res is NULL
834
        jz      .no_result      ; do not save if .res is NULL
831
        mov     ebx, [.reqdata] ; request data
835
        mov     ebx, [.reqdata] ; request data
832
        call    getaddrinfo._.generate_data
836
        call    getaddrinfo._.generate_data
833
        mov     [.res_list_tail], esi
837
        mov     [.res_list_tail], esi
834
        pop     esi ecx ebx
838
        pop     esi ecx ebx
835
        cmp     [.res_list_tail], 0
839
        cmp     [.res_list_tail], 0
836
        jnz     .answers_loop
840
        jnz     .answers_loop
837
; 10f. If generate_data failed (this means memory allocation failure), abort
841
; 10f. If generate_data failed (this means memory allocation failure), abort
838
        jmp     .ret.no_memory
842
        jmp     .ret.no_memory
839
.no_result:
843
.no_result:
840
        pop     esi ecx ebx
844
        pop     esi ecx ebx
841
        jmp     .answers_loop
845
        jmp     .answers_loop
842
.got_cname:
846
.got_cname:
843
; 10g. Process record CNAME, main host name.
847
; 10g. Process record CNAME, main host name.
844
        lea     eax, [esi+6]
848
        lea     eax, [esi+6]
845
        mov     [.cname], eax
849
        mov     [.cname], eax
846
.answers_loop.next:
850
.answers_loop.next:
847
; 10h. Skip other record fields, advance to next record.
851
; 10h. Skip other record fields, advance to next record.
848
        lodsd   ; skip TTL
852
        lodsd   ; skip TTL
849
        xor     eax, eax
853
        xor     eax, eax
850
        lodsw   ; get length of RDATA field
854
        lodsw   ; get length of RDATA field
851
        xchg    al, ah  ; network -> Intel byte order
855
        xchg    al, ah  ; network -> Intel byte order
852
        add     esi, eax
856
        add     esi, eax
853
        cmp     esi, ecx
857
        cmp     esi, ecx
854
        ja      .ret.no_recovery
858
        ja      .ret.no_recovery
855
        jmp     .answers_loop
859
        jmp     .answers_loop
856
.answers_done:
860
.answers_done:
857
; 11. Check that there is at least 1 answer.
861
; 11. Check that there is at least 1 answer.
858
        mov     eax, [.res_list_tail]
862
        mov     eax, [.res_list_tail]
859
        cmp     [.res], eax
863
        cmp     [.res], eax
860
        jz      .ret.no_data
864
        jz      .ret.no_data
861
; 12. If canonical name was required, add it now.
865
; 12. If canonical name was required, add it now.
862
        mov     eax, [.reqdata]
866
        mov     eax, [.reqdata]
863
        test    byte [eax+__gai_reqdata.flags], AI_CANONNAME
867
        test    byte [eax+__gai_reqdata.flags], AI_CANONNAME
864
        jz      .no_canon_name
868
        jz      .no_canon_name
865
; 12a. If at least one CNAME record is present, use name from last such record.
869
; 12a. If at least one CNAME record is present, use name from last such record.
866
; Otherwise, use name from one of A records.
870
; Otherwise, use name from one of A records.
867
        mov     esi, [.cname]
871
        mov     esi, [.cname]
868
        test    esi, esi
872
        test    esi, esi
869
        jnz     .has_cname
873
        jnz     .has_cname
870
        mov     esi, [.addrname]
874
        mov     esi, [.addrname]
871
.has_cname:
875
.has_cname:
872
; 12b. Calculate name length.
876
; 12b. Calculate name length.
873
        call    .get_name_length
877
        call    .get_name_length
874
        jc      .ret.no_recovery
878
        jc      .ret.no_recovery
875
; 12c. Check that the caller really want to get data.
879
; 12c. Check that the caller really want to get data.
876
        cmp     [.res], 0
880
        cmp     [.res], 0
877
        jz      .no_canon_name
881
        jz      .no_canon_name
878
; 12d. Allocate memory for name.
882
; 12d. Allocate memory for name.
879
        call    getaddrinfo._.memalloc
883
        call    getaddrinfo._.memalloc
880
        test    edi, edi
884
        test    edi, edi
881
        jz      .ret.no_memory
885
        jz      .ret.no_memory
882
; 12e. Make first entry in .res list point to canonical name.
886
; 12e. Make first entry in .res list point to canonical name.
883
        mov     eax, [.res]
887
        mov     eax, [.res]
884
        mov     eax, [eax]
888
        mov     eax, [eax]
885
        mov     [eax+addrinfo.ai_canonname], edi
889
        mov     [eax+addrinfo.ai_canonname], edi
886
; 12f. Decode name.
890
; 12f. Decode name.
887
        call    .decode_name
891
        call    .decode_name
888
.no_canon_name:
892
.no_canon_name:
889
; 13. Set status to success.
893
; 13. Set status to success.
890
        xor     eax, eax
894
        xor     eax, eax
891
        jmp     .ret.close
895
        jmp     .ret.close
892
; Handle errors.
896
; Handle errors.
893
.ret.more_processing_required:
897
.ret.more_processing_required:
894
        push    -1
898
        push    -1
895
        pop     eax
899
        pop     eax
896
        jmp     .ret
900
        jmp     .ret
897
.ret.no_recovery:
901
.ret.no_recovery:
898
        push    EAI_FAIL
902
        push    EAI_FAIL
899
        pop     eax
903
        pop     eax
900
        jmp     .ret.destroy
904
        jmp     .ret.destroy
901
.ret.no_memory:
905
.ret.no_memory:
902
        push    EAI_MEMORY
906
        push    EAI_MEMORY
903
        pop     eax
907
        pop     eax
904
        jmp     .ret.destroy
908
        jmp     .ret.destroy
905
.ret.no_name:
909
.ret.no_name:
906
.ret.no_data:
910
.ret.no_data:
907
        push    EAI_NONAME
911
        push    EAI_NONAME
908
        pop     eax
912
        pop     eax
909
.ret.destroy:
913
.ret.destroy:
910
; 14. If an error occured, free memory acquired so far.
914
; 14. If an error occured, free memory acquired so far.
911
        push    eax
915
        push    eax
912
        mov     esi, [.res]
916
        mov     esi, [.res]
913
        test    esi, esi
917
        test    esi, esi
914
        jz      @f
918
        jz      @f
915
        pushd   [esi]
919
        pushd   [esi]
916
        call    freeaddrinfo
920
        call    freeaddrinfo
917
        and     dword [esi], 0
921
        and     dword [esi], 0
918
@@:
922
@@:
919
        pop     eax
923
        pop     eax
920
.ret.close:
924
.ret.close:
921
; 15. Close socketnum.
925
; 15. Close socketnum.
922
        push    eax
926
        push    eax
923
        mov     ecx, [.reqdata]
927
        mov     ecx, [.reqdata]
924
        mov     ecx, [ecx+__gai_reqdata.socketnum]
928
        mov     ecx, [ecx+__gai_reqdata.socketnum]
925
        mcall   75, 1
929
        mcall   75, 1
926
        pop     eax
930
        pop     eax
927
; 16. Restore used registers, destroy stack frame and return.
931
; 16. Restore used registers, destroy stack frame and return.
928
.ret:
932
.ret:
929
        pop     edi esi ebx
933
        pop     edi esi ebx
930
        mov     esp, ebp
934
        mov     esp, ebp
931
        pop     ebp
935
        pop     ebp
932
        ret     8
936
        ret     8
933
 
937
 
934
;;===========================================================================;;
938
;;===========================================================================;;
935
;; Internal auxiliary function for skipping names in DNS packet.             ;;
939
;; Internal auxiliary function for skipping names in DNS packet.             ;;
936
.skip_name:                                                                  ;;
940
.skip_name:                                                                  ;;
937
;;---------------------------------------------------------------------------;;
941
;;---------------------------------------------------------------------------;;
938
;? Skips name in DNS packet.                                                 ;;
942
;? Skips name in DNS packet.                                                 ;;
939
;;---------------------------------------------------------------------------;;
943
;;---------------------------------------------------------------------------;;
940
;> esi -> name                                                               ;;
944
;> esi -> name                                                               ;;
941
;> ecx = end of packet                                                       ;;
945
;> ecx = end of packet                                                       ;;
942
;;---------------------------------------------------------------------------;;
946
;;---------------------------------------------------------------------------;;
943
;< esi -> end of name                                                        ;;
947
;< esi -> end of name                                                        ;;
944
;;===========================================================================;;
948
;;===========================================================================;;
945
        xor     eax, eax
949
        xor     eax, eax
946
        cmp     esi, ecx
950
        cmp     esi, ecx
947
        jae     .skip_name.done
951
        jae     .skip_name.done
948
        lodsb
952
        lodsb
949
        test    al, al
953
        test    al, al
950
        jz      .skip_name.done
954
        jz      .skip_name.done
951
        test    al, 0xC0
955
        test    al, 0xC0
952
        jnz     .skip_name.pointer
956
        jnz     .skip_name.pointer
953
        add     esi, eax
957
        add     esi, eax
954
        jmp     .skip_name
958
        jmp     .skip_name
955
.skip_name.pointer:
959
.skip_name.pointer:
956
        inc     esi
960
        inc     esi
957
.skip_name.done:
961
.skip_name.done:
958
        ret
962
        ret
959
 
963
 
960
;;===========================================================================;;
964
;;===========================================================================;;
961
;; Internal auxiliary function for calculating length of name in DNS packet. ;;
965
;; Internal auxiliary function for calculating length of name in DNS packet. ;;
962
.get_name_length:                                                            ;;
966
.get_name_length:                                                            ;;
963
;;---------------------------------------------------------------------------;;
967
;;---------------------------------------------------------------------------;;
964
;? Calculate length of name (including terminating zero) in DNS packet.      ;;
968
;? Calculate length of name (including terminating zero) in DNS packet.      ;;
965
;;---------------------------------------------------------------------------;;
969
;;---------------------------------------------------------------------------;;
966
;> edx = start of packet                                                     ;;
970
;> edx = start of packet                                                     ;;
967
;> esi -> name                                                               ;;
971
;> esi -> name                                                               ;;
968
;> ecx = end of packet                                                       ;;
972
;> ecx = end of packet                                                       ;;
969
;;---------------------------------------------------------------------------;;
973
;;---------------------------------------------------------------------------;;
970
;< eax = length of name                                                      ;;
974
;< eax = length of name                                                      ;;
971
;< CF set on error / cleared on success                                      ;;
975
;< CF set on error / cleared on success                                      ;;
972
;;===========================================================================;;
976
;;===========================================================================;;
973
        xor     ebx, ebx        ; ebx will hold data length
977
        xor     ebx, ebx        ; ebx will hold data length
974
.get_name_length.zero:
978
.get_name_length.zero:
975
        xor     eax, eax
979
        xor     eax, eax
976
.get_name_length.loop:
980
.get_name_length.loop:
977
        cmp     esi, ecx
981
        cmp     esi, ecx
978
        jae     .get_name_length.fail
982
        jae     .get_name_length.fail
979
        lodsb
983
        lodsb
980
        test    al, al
984
        test    al, al
981
        jz      .get_name_length.done
985
        jz      .get_name_length.done
982
        test    al, 0xC0
986
        test    al, 0xC0
983
        jnz     .get_name_length.pointer
987
        jnz     .get_name_length.pointer
984
        add     esi, eax
988
        add     esi, eax
985
        inc     ebx
989
        inc     ebx
986
        add     ebx, eax
990
        add     ebx, eax
987
        cmp     ebx, 256
991
        cmp     ebx, 256
988
        jbe     .get_name_length.loop
992
        jbe     .get_name_length.loop
989
.get_name_length.fail:
993
.get_name_length.fail:
990
        stc
994
        stc
991
        ret
995
        ret
992
.get_name_length.pointer:
996
.get_name_length.pointer:
993
        and     al, 0x3F
997
        and     al, 0x3F
994
        mov     ah, al
998
        mov     ah, al
995
        lodsb
999
        lodsb
996
        lea     esi, [edx+eax]
1000
        lea     esi, [edx+eax]
997
        jmp     .get_name_length.zero
1001
        jmp     .get_name_length.zero
998
.get_name_length.done:
1002
.get_name_length.done:
999
        test    ebx, ebx
1003
        test    ebx, ebx
1000
        jz      .get_name_length.fail
1004
        jz      .get_name_length.fail
1001
        xchg    eax, ebx
1005
        xchg    eax, ebx
1002
        clc
1006
        clc
1003
        ret
1007
        ret
1004
 
1008
 
1005
;;===========================================================================;;
1009
;;===========================================================================;;
1006
;; Internal auxiliary function for decoding DNS name.                        ;;
1010
;; Internal auxiliary function for decoding DNS name.                        ;;
1007
.decode_name:                                                                ;;
1011
.decode_name:                                                                ;;
1008
;;---------------------------------------------------------------------------;;
1012
;;---------------------------------------------------------------------------;;
1009
;? Decode name in DNS packet.                                                ;;
1013
;? Decode name in DNS packet.                                                ;;
1010
;;---------------------------------------------------------------------------;;
1014
;;---------------------------------------------------------------------------;;
1011
;> edx = start of packet                                                     ;;
1015
;> edx = start of packet                                                     ;;
1012
;> esi -> name in packet                                                     ;;
1016
;> esi -> name in packet                                                     ;;
1013
;> edi -> buffer for decoded name                                            ;;
1017
;> edi -> buffer for decoded name                                            ;;
1014
;;===========================================================================;;
1018
;;===========================================================================;;
1015
        xor     eax, eax
1019
        xor     eax, eax
1016
        lodsb
1020
        lodsb
1017
        test    al, al
1021
        test    al, al
1018
        jz      .decode_name.done
1022
        jz      .decode_name.done
1019
        test    al, 0xC0
1023
        test    al, 0xC0
1020
        jnz     .decode_name.pointer
1024
        jnz     .decode_name.pointer
1021
        mov     ecx, eax
1025
        mov     ecx, eax
1022
        rep     movsb
1026
        rep     movsb
1023
        mov     al, '.'
1027
        mov     al, '.'
1024
        stosb
1028
        stosb
1025
        jmp     .decode_name
1029
        jmp     .decode_name
1026
.decode_name.pointer:
1030
.decode_name.pointer:
1027
        and     al, 0x3F
1031
        and     al, 0x3F
1028
        mov     ah, al
1032
        mov     ah, al
1029
        lodsb
1033
        lodsb
1030
        lea     esi, [edx+eax]
1034
        lea     esi, [edx+eax]
1031
        jmp     .decode_name
1035
        jmp     .decode_name
1032
.decode_name.done:
1036
.decode_name.done:
1033
        mov     byte [edi-1], 0
1037
        mov     byte [edi-1], 0
1034
        ret
1038
        ret
1035
 
1039
 
1036
;;===========================================================================;;
1040
;;===========================================================================;;
1037
;; Internal auxiliary function for allocating memory for getaddrinfo.        ;;
1041
;; Internal auxiliary function for allocating memory for getaddrinfo.        ;;
1038
getaddrinfo._.memalloc:                                                      ;;
1042
getaddrinfo._.memalloc:                                                      ;;
1039
;;---------------------------------------------------------------------------;;
1043
;;---------------------------------------------------------------------------;;
1040
;? Memory allocation.                                                        ;;
1044
;? Memory allocation.                                                        ;;
1041
;;---------------------------------------------------------------------------;;
1045
;;---------------------------------------------------------------------------;;
1042
;> eax = size in bytes, must be less than page size.                         ;;
1046
;> eax = size in bytes, must be less than page size.                         ;;
1043
;> [ebp-4] = .recent_page = last allocated page                              ;;
1047
;> [ebp-4] = .recent_page = last allocated page                              ;;
1044
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page            ;;
1048
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page            ;;
1045
;;---------------------------------------------------------------------------;;
1049
;;---------------------------------------------------------------------------;;
1046
;< edi -> allocated memory / NULL on error                                   ;;
1050
;< edi -> allocated memory / NULL on error                                   ;;
1047
;;===========================================================================;;
1051
;;===========================================================================;;
1048
; 1. Set edi to result of function.
1052
; 1. Set edi to result of function.
1049
        mov     edi, [ebp-4]
1053
        mov     edi, [ebp-4]
1050
; 2. Check whether we need to allocate a new page.
1054
; 2. Check whether we need to allocate a new page.
1051
        cmp     eax, [ebp-8]
1055
        cmp     eax, [ebp-8]
1052
        jbe     .no_new_page
1056
        jbe     .no_new_page
1053
; 2. Allocate new page if need. Reset edi to new result.
1057
; 2. Allocate new page if need. Reset edi to new result.
1054
        push    eax ebx
1058
        push    eax ebx
1055
        mcall   68, 12, 0x1000
1059
        mcall   68, 12, 0x1000
1056
        xchg    edi, eax        ; put result to edi
1060
        xchg    edi, eax        ; put result to edi
1057
        pop     ebx eax
1061
        pop     ebx eax
1058
; 3. Check returned value of allocator. Fail if it failed.
1062
; 3. Check returned value of allocator. Fail if it failed.
1059
        test    edi, edi
1063
        test    edi, edi
1060
        jz      .ret
1064
        jz      .ret
1061
; 4. Update .recent_page and .recent_restsize.
1065
; 4. Update .recent_page and .recent_restsize.
1062
        add     edi, 4
1066
        add     edi, 4
1063
        sub     ecx, 4
1067
        sub     ecx, 4
1064
        mov     [ebp-4], edi
1068
        mov     [ebp-4], edi
1065
        mov     [ebp-8], ecx
1069
        mov     [ebp-8], ecx
1066
.no_new_page:
1070
.no_new_page:
1067
; 5. Increase number of objects on this page.
1071
; 5. Increase number of objects on this page.
1068
        push    eax
1072
        push    eax
1069
        mov     eax, edi
1073
        mov     eax, edi
1070
        and     eax, not 0xFFF
1074
        and     eax, not 0xFFF
1071
        inc     dword [eax]
1075
        inc     dword [eax]
1072
        pop     eax
1076
        pop     eax
1073
; 6. Advance last allocated pointer, decrease memory size.
1077
; 6. Advance last allocated pointer, decrease memory size.
1074
        add     [ebp-4], eax
1078
        add     [ebp-4], eax
1075
        sub     [ebp-8], eax
1079
        sub     [ebp-8], eax
1076
; 7. Return.
1080
; 7. Return.
1077
.ret:
1081
.ret:
1078
        ret
1082
        ret
1079
 
1083
 
1080
;;===========================================================================;;
1084
;;===========================================================================;;
1081
;; Internal auxiliary function for freeing memory for freeaddrinfo.          ;;
1085
;; Internal auxiliary function for freeing memory for freeaddrinfo.          ;;
1082
getaddrinfo._.memfree:                                                       ;;
1086
getaddrinfo._.memfree:                                                       ;;
1083
;;---------------------------------------------------------------------------;;
1087
;;---------------------------------------------------------------------------;;
1084
;? Free memory.                                                              ;;
1088
;? Free memory.                                                              ;;
1085
;;---------------------------------------------------------------------------;;
1089
;;---------------------------------------------------------------------------;;
1086
;> eax = pointer                                                             ;;
1090
;> eax = pointer                                                             ;;
1087
;;===========================================================================;;
1091
;;===========================================================================;;
1088
; 1. Get start of page.
1092
; 1. Get start of page.
1089
        mov     ecx, eax
1093
        mov     ecx, eax
1090
        and     ecx, not 0xFFF
1094
        and     ecx, not 0xFFF
1091
; 2. Decrease number of objects.
1095
; 2. Decrease number of objects.
1092
        dec     dword [ecx]
1096
        dec     dword [ecx]
1093
; 3. If it goes to zero, free the page.
1097
; 3. If it goes to zero, free the page.
1094
        jnz     @f
1098
        jnz     @f
1095
        push    ebx
1099
        push    ebx
1096
        mcall   68, 13
1100
        mcall   68, 13
1097
        pop     ebx
1101
        pop     ebx
1098
@@:
1102
@@:
1099
; 4. Done.
1103
; 4. Done.
1100
        ret
1104
        ret
1101
 
1105
 
1102
;;===========================================================================;;
1106
;;===========================================================================;;
1103
getaddrinfo._.generate_data:                                                 ;;
1107
getaddrinfo._.generate_data:                                                 ;;
1104
;;---------------------------------------------------------------------------;;
1108
;;---------------------------------------------------------------------------;;
1105
;? Generate item(s) of getaddrinfo result list by one IP address.            ;;
1109
;? Generate item(s) of getaddrinfo result list by one IP address.            ;;
1106
;;---------------------------------------------------------------------------;;
1110
;;---------------------------------------------------------------------------;;
1107
;> eax = IP address                                                          ;;
1111
;> eax = IP address                                                          ;;
1108
;> ebx = request data                                                        ;;
1112
;> ebx = request data                                                        ;;
1109
;> esi = pointer to result                                                   ;;
1113
;> esi = pointer to result                                                   ;;
1110
;> [ebp-4] = .recent_page = last allocated page                              ;;
1114
;> [ebp-4] = .recent_page = last allocated page                              ;;
1111
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page            ;;
1115
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page            ;;
1112
;;---------------------------------------------------------------------------;;
1116
;;---------------------------------------------------------------------------;;
1113
;< esi = pointer to next list item for result / NULL on error                ;;
1117
;< esi = pointer to next list item for result / NULL on error                ;;
1114
;;===========================================================================;;
1118
;;===========================================================================;;
1115
; 1. If no service is given, append one item with zero port.
1119
; 1. If no service is given, append one item with zero port.
1116
; append one item with zero socktype/protocol/port.
1120
; append one item with zero socktype/protocol/port.
1117
        cmp     [ebx+__gai_reqdata.service], -1
1121
        cmp     [ebx+__gai_reqdata.service], -1
1118
        jnz     .has_service
1122
        jnz     .has_service
1119
        call    .append_item
1123
        call    .append_item
1120
; 1a. If neither protocol nor socktype were specified,
1124
; 1a. If neither protocol nor socktype were specified,
1121
;       leave zeroes in socktype and protocol.
1125
;       leave zeroes in socktype and protocol.
1122
        mov     cl, [ebx+__gai_reqdata.socktype]
1126
        mov     cl, [ebx+__gai_reqdata.socktype]
1123
        test    cl, cl
1127
        test    cl, cl
1124
        jz      .no_socktype
1128
        jz      .no_socktype
1125
; 1b. Otherwise, set socktype and protocol to desired.
1129
; 1b. Otherwise, set socktype and protocol to desired.
1126
        call    .set_socktype
1130
        call    .set_socktype
1127
.no_socktype:
1131
.no_socktype:
1128
        ret
1132
        ret
1129
.has_service:
1133
.has_service:
1130
; 2. If TCP is allowed, append item for TCP.
1134
; 2. If TCP is allowed, append item for TCP.
1131
        cmp     [ebx+__gai_reqdata.socktype], 0
1135
        cmp     [ebx+__gai_reqdata.socktype], 0
1132
        jz      .tcp_ok
1136
        jz      .tcp_ok
1133
        cmp     [ebx+__gai_reqdata.socktype], SOCK_STREAM
1137
        cmp     [ebx+__gai_reqdata.socktype], SOCK_STREAM
1134
        jnz     .tcp_disallowed
1138
        jnz     .tcp_disallowed
1135
.tcp_ok:
1139
.tcp_ok:
1136
        call    .append_item
1140
        call    .append_item
1137
        mov     cl, SOCK_STREAM
1141
        mov     cl, SOCK_STREAM
1138
        call    .set_socktype
1142
        call    .set_socktype
1139
        call    .set_port
1143
        call    .set_port
1140
.tcp_disallowed:
1144
.tcp_disallowed:
1141
; 3. If UDP is allowed, append item for UDP.
1145
; 3. If UDP is allowed, append item for UDP.
1142
        cmp     [ebx+__gai_reqdata.socktype], 0
1146
        cmp     [ebx+__gai_reqdata.socktype], 0
1143
        jz      .udp_ok
1147
        jz      .udp_ok
1144
        cmp     [ebx+__gai_reqdata.socktype], SOCK_DGRAM
1148
        cmp     [ebx+__gai_reqdata.socktype], SOCK_DGRAM
1145
        jnz     .udp_disallowed
1149
        jnz     .udp_disallowed
1146
.udp_ok:
1150
.udp_ok:
1147
        call    .append_item
1151
        call    .append_item
1148
        mov     cl, SOCK_DGRAM
1152
        mov     cl, SOCK_DGRAM
1149
        call    .set_socktype
1153
        call    .set_socktype
1150
        call    .set_port
1154
        call    .set_port
1151
.udp_disallowed:
1155
.udp_disallowed:
1152
        ret
1156
        ret
1153
 
1157
 
1154
.append_item:
1158
.append_item:
1155
; 1. Allocate memory for struct sockaddr_in and struct addrinfo.
1159
; 1. Allocate memory for struct sockaddr_in and struct addrinfo.
1156
        push    eax
1160
        push    eax
1157
        push    sizeof.addrinfo + sizeof.sockaddr_in
1161
        push    sizeof.addrinfo + sizeof.sockaddr_in
1158
        pop     eax
1162
        pop     eax
1159
        call    getaddrinfo._.memalloc
1163
        call    getaddrinfo._.memalloc
1160
; 2. Check for memory allocation fail.
1164
; 2. Check for memory allocation fail.
1161
        test    edi, edi
1165
        test    edi, edi
1162
        jz      .no_memory
1166
        jz      .no_memory
1163
; 3. Zero allocated memory.
1167
; 3. Zero allocated memory.
1164
        push    (sizeof.addrinfo + sizeof.sockaddr_in) / 4
1168
        push    (sizeof.addrinfo + sizeof.sockaddr_in) / 4
1165
        pop     ecx
1169
        pop     ecx
1166
        xor     eax, eax
1170
        xor     eax, eax
1167
        push    edi
1171
        push    edi
1168
        rep     stosd
1172
        rep     stosd
1169
        pop     edi
1173
        pop     edi
1170
; 4. Fill struct addrinfo.
1174
; 4. Fill struct addrinfo.
1171
        mov     eax, [ebx+__gai_reqdata.flags]
1175
        mov     eax, [ebx+__gai_reqdata.flags]
1172
        mov     [edi+addrinfo.ai_flags], eax
1176
        mov     [edi+addrinfo.ai_flags], eax
1173
        mov     byte [edi+addrinfo.ai_family], AF_INET4
1177
        mov     byte [edi+addrinfo.ai_family], AF_INET4
1174
        mov     byte [edi+addrinfo.ai_addrlen], sizeof.sockaddr_in
1178
        mov     byte [edi+addrinfo.ai_addrlen], sizeof.sockaddr_in
1175
        lea     ecx, [edi+sizeof.addrinfo]
1179
        lea     ecx, [edi+sizeof.addrinfo]
1176
        mov     [edi+addrinfo.ai_addr], ecx
1180
        mov     [edi+addrinfo.ai_addr], ecx
1177
; 5. Fill struct sockaddr_in.
1181
; 5. Fill struct sockaddr_in.
1178
        mov     byte [ecx+sockaddr_in.sin_family], AF_INET4
1182
        mov     byte [ecx+sockaddr_in.sin_family], AF_INET4
1179
        pop     eax
1183
        pop     eax
1180
        mov     [ecx+sockaddr_in.sin_addr], eax
1184
        mov     [ecx+sockaddr_in.sin_addr], eax
1181
; 6. Append new item to the list.
1185
; 6. Append new item to the list.
1182
        mov     [esi], edi
1186
        mov     [esi], edi
1183
        lea     esi, [edi+addrinfo.ai_next]
1187
        lea     esi, [edi+addrinfo.ai_next]
1184
; 7. Return.
1188
; 7. Return.
1185
        ret
1189
        ret
1186
.no_memory:
1190
.no_memory:
1187
        pop     eax
1191
        pop     eax
1188
        xor     esi, esi
1192
        xor     esi, esi
1189
        ret
1193
        ret
1190
 
1194
 
1191
.set_socktype:
1195
.set_socktype:
1192
; Set ai_socktype and ai_protocol fields by given socketnum type.
1196
; Set ai_socktype and ai_protocol fields by given socketnum type.
1193
        mov     byte [edi+addrinfo.ai_socktype], cl
1197
        mov     byte [edi+addrinfo.ai_socktype], cl
1194
        dec     cl
1198
        dec     cl
1195
        jnz     .set_udp
1199
        jnz     .set_udp
1196
.set_tcp:
1200
.set_tcp:
1197
        mov     byte [edi+addrinfo.ai_protocol], IPPROTO_TCP
1201
        mov     byte [edi+addrinfo.ai_protocol], IPPROTO_TCP
1198
        ret
1202
        ret
1199
.set_udp:
1203
.set_udp:
1200
        mov     byte [edi+addrinfo.ai_protocol], IPPROTO_UDP
1204
        mov     byte [edi+addrinfo.ai_protocol], IPPROTO_UDP
1201
        ret
1205
        ret
1202
 
1206
 
1203
.set_port:
1207
.set_port:
1204
; Just copy port from input __gai_reqdata to output addrinfo.
1208
; Just copy port from input __gai_reqdata to output addrinfo.
1205
        push    edx
1209
        push    edx
1206
        mov     edx, [ebx+__gai_reqdata.service]
1210
        mov     edx, [ebx+__gai_reqdata.service]
1207
        xchg    dl, dh  ; convert to network byte order     ;;;;; CHECKME
1211
        xchg    dl, dh  ; convert to network byte order     ;;;;; CHECKME
1208
        mov     [edi+sizeof.addrinfo+sockaddr_in.sin_port], dx
1212
        mov     [edi+sizeof.addrinfo+sockaddr_in.sin_port], dx
1209
        pop     edx
1213
        pop     edx
1210
        ret
1214
        ret
1211
 
1215
 
1212
;;===========================================================================;;
1216
;;===========================================================================;;
1213
;; void __stdcall getaddrinfo_abort(__in struct __gai_reqdata* reqdata);      ;;
1217
;; void __stdcall getaddrinfo_abort(__in struct __gai_reqdata* reqdata);      ;;
1214
getaddrinfo_abort:                                                           ;;
1218
getaddrinfo_abort:                                                           ;;
1215
;;---------------------------------------------------------------------------;;
1219
;;---------------------------------------------------------------------------;;
1216
;? Abort process started by getaddrinfo_start, free all resources.           ;;
1220
;? Abort process started by getaddrinfo_start, free all resources.           ;;
1217
;;---------------------------------------------------------------------------;;
1221
;;---------------------------------------------------------------------------;;
1218
;> first parameter = pointer to struct __gai_reqdata filled by ..._start     ;;
1222
;> first parameter = pointer to struct __gai_reqdata filled by ..._start     ;;
1219
;;===========================================================================;;
1223
;;===========================================================================;;
1220
; 0. Save used registers for __stdcall.
1224
; 0. Save used registers for __stdcall.
1221
        push    ebx
1225
        push    ebx
1222
; 1. Allocated resources: only socketnum, so close it and return.
1226
; 1. Allocated resources: only socketnum, so close it and return.
1223
        mov     eax, [esp+8]
1227
        mov     eax, [esp+8]
1224
        mov     ecx, [eax+__gai_reqdata.socketnum]
1228
        mov     ecx, [eax+__gai_reqdata.socketnum]
1225
        mcall   75, 1
1229
        mcall   75, 1
1226
; 2. Restore used registers and return.
1230
; 2. Restore used registers and return.
1227
        pop     ebx
1231
        pop     ebx
1228
        ret     4
1232
        ret     4
1229
 
1233
 
1230
;;===========================================================================;;
1234
;;===========================================================================;;
1231
;; void __stdcall freeaddrinfo(__in struct addrinfo* ai);                    ;;
1235
;; void __stdcall freeaddrinfo(__in struct addrinfo* ai);                    ;;
1232
freeaddrinfo:                                                                ;;
1236
freeaddrinfo:                                                                ;;
1233
;;---------------------------------------------------------------------------;;
1237
;;---------------------------------------------------------------------------;;
1234
;? Free one or more addrinfo structures returned by getaddrinfo.             ;;
1238
;? Free one or more addrinfo structures returned by getaddrinfo.             ;;
1235
;;---------------------------------------------------------------------------;;
1239
;;---------------------------------------------------------------------------;;
1236
;> first parameter = head of list of structures                              ;;
1240
;> first parameter = head of list of structures                              ;;
1237
;                    (may be arbitrary sublist of original)                  ;;
1241
;                    (may be arbitrary sublist of original)                  ;;
1238
;;===========================================================================;;
1242
;;===========================================================================;;
1239
; 1. Loop for all items in the list.
1243
; 1. Loop for all items in the list.
1240
        mov     edx, [esp+4]    ; eax = ai
1244
        mov     edx, [esp+4]    ; eax = ai
1241
.loop:
1245
.loop:
1242
        test    edx, edx
1246
        test    edx, edx
1243
        jz      .done
1247
        jz      .done
1244
; 2. Free each item.
1248
; 2. Free each item.
1245
; 2a. Free ai_canonname, if allocated.
1249
; 2a. Free ai_canonname, if allocated.
1246
        mov     eax, [edx+addrinfo.ai_canonname]
1250
        mov     eax, [edx+addrinfo.ai_canonname]
1247
        test    eax, eax
1251
        test    eax, eax
1248
        jz      .no_canon_name
1252
        jz      .no_canon_name
1249
        call    getaddrinfo._.memfree
1253
        call    getaddrinfo._.memfree
1250
.no_canon_name:
1254
.no_canon_name:
1251
; 2b. Remember next item
1255
; 2b. Remember next item
1252
;       (after freeing the field ai_next can became unavailable).
1256
;       (after freeing the field ai_next can became unavailable).
1253
        pushd   [edx+addrinfo.ai_next]
1257
        pushd   [edx+addrinfo.ai_next]
1254
; 2c. Free item itself.
1258
; 2c. Free item itself.
1255
        xchg    eax, edx
1259
        xchg    eax, edx
1256
        call    getaddrinfo._.memfree
1260
        call    getaddrinfo._.memfree
1257
; 2d. Restore pointer to next item and continue loop.
1261
; 2d. Restore pointer to next item and continue loop.
1258
        pop     edx
1262
        pop     edx
1259
        jmp     .loop
1263
        jmp     .loop
1260
.done:
1264
.done:
1261
; 3. Done.
1265
; 3. Done.
1262
        ret     4
1266
        ret     4
1263
 
1267
 
1264
;;===========================================================================;;
1268
;;===========================================================================;;
1265
;;///////////////////////////////////////////////////////////////////////////;;
1269
;;///////////////////////////////////////////////////////////////////////////;;
1266
;;===========================================================================;;
1270
;;===========================================================================;;
1267
;! Exported functions section                                                ;;
1271
;! Exported functions section                                                ;;
1268
;;===========================================================================;;
1272
;;===========================================================================;;
1269
;;///////////////////////////////////////////////////////////////////////////;;
1273
;;///////////////////////////////////////////////////////////////////////////;;
1270
;;===========================================================================;;
1274
;;===========================================================================;;
1271
 
1275
 
1272
 
1276
 
1273
align 4
1277
align 4
1274
@EXPORT:
1278
@EXPORT:
1275
export  \
1279
export  \
1276
        lib_init                , 'lib_init'            , \
1280
        lib_init                , 'lib_init'            , \
1277
        0x00010001              , 'version'             , \
1281
        0x00010001              , 'version'             , \
1278
        inet_addr               , 'inet_addr'           , \
1282
        inet_addr               , 'inet_addr'           , \
1279
        inet_ntoa               , 'inet_ntoa'           , \
1283
        inet_ntoa               , 'inet_ntoa'           , \
1280
        getaddrinfo             , 'getaddrinfo'         , \
1284
        getaddrinfo             , 'getaddrinfo'         , \
1281
        getaddrinfo_start       , 'getaddrinfo_start'   , \
1285
        getaddrinfo_start       , 'getaddrinfo_start'   , \
1282
        getaddrinfo_process     , 'getaddrinfo_process' , \
1286
        getaddrinfo_process     , 'getaddrinfo_process' , \
1283
        getaddrinfo_abort       , 'getaddrinfo_abort'   , \
1287
        getaddrinfo_abort       , 'getaddrinfo_abort'   , \
1284
        freeaddrinfo            , 'freeaddrinfo'
1288
        freeaddrinfo            , 'freeaddrinfo'
1285
 
1289
 
1286
section '.data' data readable writable align 16
1290
section '.data' data readable writable align 16
1287
; uninitialized data
1291
; uninitialized data
1288
mem.alloc   dd ?
1292
mem.alloc   dd ?
1289
mem.free    dd ?
1293
mem.free    dd ?
1290
mem.realloc dd ?
1294
mem.realloc dd ?
1291
dll.load    dd ?
1295
dll.load    dd ?
1292
 
1296
 
1293
DNSrequestID    dd      ?
1297
DNSrequestID    dd      ?
1294
 
1298
 
1295
inet_ntoa.buffer        rb      16      ; static buffer for inet_ntoa
1299
inet_ntoa.buffer        rb      16      ; static buffer for inet_ntoa