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>>>>>>0>>>>>>>>> |
1299 | inet_ntoa.buffer rb 16 ; static buffer for inet_ntoa>>>>>>0>>>>>>>>> |