Subversion Repositories Kolibri OS

Rev

Rev 6709 | Rev 6723 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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