Subversion Repositories Kolibri OS

Rev

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