Subversion Repositories Kolibri OS

Rev

Rev 1155 | Rev 3601 | 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
 
10
include 'network.inc'
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)       ;;
3545 hidnplayr 282
;> third parameter (optional) = hints for socketnum 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
        lea     eax, [esp+4]    ; pointer to (1)
315
        jz      .timeout
1155 clevermous 316
; 3. Got packet. Call processing function.
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
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.
3545 hidnplayr 678
        mcall   76, API_IPv4 + 4 ; protocol IP=0, device number=0, function=get DNS address
679
        cmp     eax, -1
680
        je      .ret.dnserr
681
        mov     esi, eax        ; put server address to esi
682
; 8. Open UDP socketnum to DNS server, port 53.
683
; 8a. Create new socketnum.
684
        mcall   75, 0, AF_INET4, SOCK_DGRAM
685
        cmp     eax, -1 ; error?
686
        jz      .ret.dnserr
687
        mov     ecx, eax        ; put socketnum handle to ecx
688
; 8b. Create sockaddr structure on the stack.
689
        push    0
690
        push    0       ; sin_zero
691
        push    esi     ; sin_addr
692
        push    AF_INET4 + (53 shl 24)
693
                        ; sin_family and sin_port in network byte order
694
; 8c. Connect.
695
        mcall   75, 4, , esp, sizeof.sockaddr_in
696
; 8d. Restore the stack, undo 8b.
697
        add     esp, esi
698
; 8e. Check result.
699
        cmp     eax, -1
700
        jz      .ret.close
1155 clevermous 701
; 9. Send DNS request packet.
3545 hidnplayr 702
        sub     edi, esp        ; get packet length
703
        mov     esi, edi
704
        xor     edi, edi
705
        mcall   75, 6, , esp
706
        cmp     eax, -1
707
        jz      .ret.close
708
        mov     eax, [.reqdata]
709
        mov     [eax+__gai_reqdata.socketnum], ecx
710
        push    -1
711
        pop     eax     ; return status: more processing required
712
        jmp     .ret.dns
1155 clevermous 713
.ret.close:
3545 hidnplayr 714
        mcall   75, 1
1155 clevermous 715
.ret.dnserr:
3545 hidnplayr 716
        push    EAI_AGAIN
717
        pop     eax
1155 clevermous 718
.ret.dns:
719
; 6. Restore stack pointer and return.
3545 hidnplayr 720
        jmp     .ret
1155 clevermous 721
 
722
;;===========================================================================;;
723
;; int __stdcall getaddrinfo_process(__in struct __gai_reqdata* reqdata,     ;;
724
;;                                   __out struct addrinfo** res);           ;;
725
getaddrinfo_process:                                                         ;;
726
;;---------------------------------------------------------------------------;;
727
;? Processes network events from DNS reply                                   ;;
728
;;---------------------------------------------------------------------------;;
729
;> first parameter = pointer to struct __gai_reqdata filled by ..._start     ;;
730
;> second parameter = same as for getaddrinfo                                ;;
731
;;---------------------------------------------------------------------------;;
732
;< eax = -1 if more processing required / 0 on success / >0 = error code     ;;
733
;;===========================================================================;;
734
; 0. Create stack frame.
3545 hidnplayr 735
        push    ebp
736
        mov     ebp, esp
1155 clevermous 737
virtual at ebp-.locals_size
738
.locals_start:
3545 hidnplayr 739
.datagram       rb      512
740
.addrname       dd      ?
741
.name           dd      ?
742
.res_list_tail  dd      ?
743
.cname          dd      ?
744
.recent_restsize dd     ?       ; this is for memory alloc in ._.generate_data
745
.recent_page    dd      ?       ; this is for memory alloc in ._.generate_data
1155 clevermous 746
.locals_size = $ - .locals_start
3545 hidnplayr 747
                rd      2
748
.reqdata        dd      ?
749
.res            dd      ?
1155 clevermous 750
end virtual
3545 hidnplayr 751
        xor     eax, eax
752
        push    eax     ; initialize .recent_page
753
        push    eax     ; initialize .recent_restsize
754
        push    eax     ; initialize .cname
755
        push    [.res]  ; initialize .res_list_tail
756
        sub     esp, .locals_size-16    ; reserve place for other vars
757
        mov     edx, esp        ; edx -> buffer for datagram
1155 clevermous 758
; 1. Save used registers for __stdcall.
3545 hidnplayr 759
        push    ebx esi edi
760
        mov     edi, [.reqdata]
1155 clevermous 761
; 2. Read UDP datagram.
3545 hidnplayr 762
        mov     ecx, [edi+__gai_reqdata.socketnum]
763
        push    edi
764
        mcall   75, 7, , , 512, 0
765
        pop     edi
766
; 3. Ignore events for other socketnums (return if no data read)
767
        test    eax, eax
768
        jz      .ret.more_processing_required
1155 clevermous 769
; 4. Sanity check: discard too short packets.
3545 hidnplayr 770
        xchg    ecx, eax        ; save packet length in ecx
771
        cmp     ecx, 12
772
        jb      .ret.more_processing_required
1155 clevermous 773
; 5. Discard packets with ID != request ID.
3545 hidnplayr 774
        mov     eax, dword [edi+__gai_reqdata.reqid]
775
        cmp     ax, [edx]
776
        jnz     .ret.more_processing_required
1155 clevermous 777
; 6. Sanity check: discard query packets.
3545 hidnplayr 778
        test    byte [edx+2], 80h
779
        jz      .ret.more_processing_required
1155 clevermous 780
; 7. Sanity check: must be exactly one query (our).
3545 hidnplayr 781
        cmp     word [edx+4], 0x0100    ; note network byte order
782
        jnz     .ret.more_processing_required
1155 clevermous 783
; 8. Check for errors. Return EAI_NONAME for error code 3 and EAI_FAIL for other.
3545 hidnplayr 784
        mov     al, [edx+3]
785
        and     al, 0xF
786
        jz      @f
787
        cmp     al, 3
788
        jnz     .ret.no_recovery
789
        jmp     .ret.no_name
1155 clevermous 790
@@:
791
; 9. Locate answers section. Exactly 1 query is present in this packet.
3545 hidnplayr 792
        add     ecx, edx        ; ecx = limit
793
        lea     esi, [edx+12]
794
        call    .skip_name
795
        lodsd           ; skip QTYPE and QCLASS field
796
        cmp     esi, ecx
797
        ja      .ret.no_recovery
1155 clevermous 798
; 10. Loop through all answers.
3545 hidnplayr 799
        movzx   ebx, word [edx+6]       ; get answers count
800
        xchg    bl, bh          ; network -> Intel byte order
1155 clevermous 801
.answers_loop:
3545 hidnplayr 802
        dec     ebx
803
        js      .answers_done
1155 clevermous 804
; 10a. Process each record.
3545 hidnplayr 805
        mov     [.name], esi
1155 clevermous 806
; 10b. Skip name field.
3545 hidnplayr 807
        call    .skip_name
1155 clevermous 808
; 10c. Get record information, handle two types for class IN (internet).
3545 hidnplayr 809
        lodsd           ; get type and class
810
        cmp     esi, ecx
811
        ja      .ret.no_recovery
812
        cmp     eax, 0x01000500 ; type=5, class=1?
813
        jz      .got_cname
814
        cmp     eax, 0x01000100 ; type=1, class=1?
815
        jnz     .answers_loop.next
1155 clevermous 816
.got_addr:
817
; 10d. Process record A, host address.
3545 hidnplayr 818
        add     esi, 10
819
        cmp     esi, ecx
820
        ja      .ret.no_recovery
821
        cmp     word [esi-6], 0x0400    ; RDATA for A records must be 4 bytes long
822
        jnz     .ret.no_recovery
823
        mov     eax, [.name]
824
        mov     [.addrname], eax
1155 clevermous 825
; 10e. Create corresponding record in the answer.
3545 hidnplayr 826
        push    ebx ecx esi
827
        mov     eax, [esi-4]    ; IP address
828
        mov     esi, [.res_list_tail]   ; pointer to result
829
        test    esi, esi
830
        jz      .no_result      ; do not save if .res is NULL
831
        mov     ebx, [.reqdata] ; request data
832
        call    getaddrinfo._.generate_data
833
        mov     [.res_list_tail], esi
834
        pop     esi ecx ebx
835
        cmp     [.res_list_tail], 0
836
        jnz     .answers_loop
1155 clevermous 837
; 10f. If generate_data failed (this means memory allocation failure), abort
3545 hidnplayr 838
        jmp     .ret.no_memory
1155 clevermous 839
.no_result:
3545 hidnplayr 840
        pop     esi ecx ebx
841
        jmp     .answers_loop
1155 clevermous 842
.got_cname:
843
; 10g. Process record CNAME, main host name.
3545 hidnplayr 844
        lea     eax, [esi+6]
845
        mov     [.cname], eax
1155 clevermous 846
.answers_loop.next:
847
; 10h. Skip other record fields, advance to next record.
3545 hidnplayr 848
        lodsd   ; skip TTL
849
        xor     eax, eax
850
        lodsw   ; get length of RDATA field
851
        xchg    al, ah  ; network -> Intel byte order
852
        add     esi, eax
853
        cmp     esi, ecx
854
        ja      .ret.no_recovery
855
        jmp     .answers_loop
1155 clevermous 856
.answers_done:
857
; 11. Check that there is at least 1 answer.
3545 hidnplayr 858
        mov     eax, [.res_list_tail]
859
        cmp     [.res], eax
860
        jz      .ret.no_data
1155 clevermous 861
; 12. If canonical name was required, add it now.
3545 hidnplayr 862
        mov     eax, [.reqdata]
863
        test    byte [eax+__gai_reqdata.flags], AI_CANONNAME
864
        jz      .no_canon_name
1155 clevermous 865
; 12a. If at least one CNAME record is present, use name from last such record.
866
; Otherwise, use name from one of A records.
3545 hidnplayr 867
        mov     esi, [.cname]
868
        test    esi, esi
869
        jnz     .has_cname
870
        mov     esi, [.addrname]
1155 clevermous 871
.has_cname:
872
; 12b. Calculate name length.
3545 hidnplayr 873
        call    .get_name_length
874
        jc      .ret.no_recovery
1155 clevermous 875
; 12c. Check that the caller really want to get data.
3545 hidnplayr 876
        cmp     [.res], 0
877
        jz      .no_canon_name
1155 clevermous 878
; 12d. Allocate memory for name.
3545 hidnplayr 879
        call    getaddrinfo._.memalloc
880
        test    edi, edi
881
        jz      .ret.no_memory
1155 clevermous 882
; 12e. Make first entry in .res list point to canonical name.
3545 hidnplayr 883
        mov     eax, [.res]
884
        mov     eax, [eax]
885
        mov     [eax+addrinfo.ai_canonname], edi
1155 clevermous 886
; 12f. Decode name.
3545 hidnplayr 887
        call    .decode_name
1155 clevermous 888
.no_canon_name:
889
; 13. Set status to success.
3545 hidnplayr 890
        xor     eax, eax
891
        jmp     .ret.close
1155 clevermous 892
; Handle errors.
893
.ret.more_processing_required:
3545 hidnplayr 894
        push    -1
895
        pop     eax
896
        jmp     .ret
1155 clevermous 897
.ret.no_recovery:
3545 hidnplayr 898
        push    EAI_FAIL
899
        pop     eax
900
        jmp     .ret.destroy
1155 clevermous 901
.ret.no_memory:
3545 hidnplayr 902
        push    EAI_MEMORY
903
        pop     eax
904
        jmp     .ret.destroy
1155 clevermous 905
.ret.no_name:
906
.ret.no_data:
3545 hidnplayr 907
        push    EAI_NONAME
908
        pop     eax
1155 clevermous 909
.ret.destroy:
910
; 14. If an error occured, free memory acquired so far.
3545 hidnplayr 911
        push    eax
912
        mov     esi, [.res]
913
        test    esi, esi
914
        jz      @f
915
        pushd   [esi]
916
        call    freeaddrinfo
917
        and     dword [esi], 0
1155 clevermous 918
@@:
3545 hidnplayr 919
        pop     eax
1155 clevermous 920
.ret.close:
3545 hidnplayr 921
; 15. Close socketnum.
922
        push    eax
923
        mov     ecx, [.reqdata]
924
        mov     ecx, [ecx+__gai_reqdata.socketnum]
925
        mcall   75, 1
926
        pop     eax
1155 clevermous 927
; 16. Restore used registers, destroy stack frame and return.
928
.ret:
3545 hidnplayr 929
        pop     edi esi ebx
930
        mov     esp, ebp
931
        pop     ebp
932
        ret     8
1155 clevermous 933
 
934
;;===========================================================================;;
935
;; Internal auxiliary function for skipping names in DNS packet.             ;;
936
.skip_name:                                                                  ;;
937
;;---------------------------------------------------------------------------;;
938
;? Skips name in DNS packet.                                                 ;;
939
;;---------------------------------------------------------------------------;;
940
;> esi -> name                                                               ;;
941
;> ecx = end of packet                                                       ;;
942
;;---------------------------------------------------------------------------;;
943
;< esi -> end of name                                                        ;;
944
;;===========================================================================;;
3545 hidnplayr 945
        xor     eax, eax
946
        cmp     esi, ecx
947
        jae     .skip_name.done
948
        lodsb
949
        test    al, al
950
        jz      .skip_name.done
951
        test    al, 0xC0
952
        jnz     .skip_name.pointer
953
        add     esi, eax
954
        jmp     .skip_name
1155 clevermous 955
.skip_name.pointer:
3545 hidnplayr 956
        inc     esi
1155 clevermous 957
.skip_name.done:
3545 hidnplayr 958
        ret
1155 clevermous 959
 
960
;;===========================================================================;;
961
;; Internal auxiliary function for calculating length of name in DNS packet. ;;
962
.get_name_length:                                                            ;;
963
;;---------------------------------------------------------------------------;;
964
;? Calculate length of name (including terminating zero) in DNS packet.      ;;
965
;;---------------------------------------------------------------------------;;
966
;> edx = start of packet                                                     ;;
967
;> esi -> name                                                               ;;
968
;> ecx = end of packet                                                       ;;
969
;;---------------------------------------------------------------------------;;
970
;< eax = length of name                                                      ;;
971
;< CF set on error / cleared on success                                      ;;
972
;;===========================================================================;;
3545 hidnplayr 973
        xor     ebx, ebx        ; ebx will hold data length
1155 clevermous 974
.get_name_length.zero:
3545 hidnplayr 975
        xor     eax, eax
1155 clevermous 976
.get_name_length.loop:
3545 hidnplayr 977
        cmp     esi, ecx
978
        jae     .get_name_length.fail
979
        lodsb
980
        test    al, al
981
        jz      .get_name_length.done
982
        test    al, 0xC0
983
        jnz     .get_name_length.pointer
984
        add     esi, eax
985
        inc     ebx
986
        add     ebx, eax
987
        cmp     ebx, 256
988
        jbe     .get_name_length.loop
1155 clevermous 989
.get_name_length.fail:
3545 hidnplayr 990
        stc
991
        ret
1155 clevermous 992
.get_name_length.pointer:
3545 hidnplayr 993
        and     al, 0x3F
994
        mov     ah, al
995
        lodsb
996
        lea     esi, [edx+eax]
997
        jmp     .get_name_length.zero
1155 clevermous 998
.get_name_length.done:
3545 hidnplayr 999
        test    ebx, ebx
1000
        jz      .get_name_length.fail
1001
        xchg    eax, ebx
1002
        clc
1003
        ret
1155 clevermous 1004
 
1005
;;===========================================================================;;
1006
;; Internal auxiliary function for decoding DNS name.                        ;;
1007
.decode_name:                                                                ;;
1008
;;---------------------------------------------------------------------------;;
1009
;? Decode name in DNS packet.                                                ;;
1010
;;---------------------------------------------------------------------------;;
1011
;> edx = start of packet                                                     ;;
1012
;> esi -> name in packet                                                     ;;
1013
;> edi -> buffer for decoded name                                            ;;
1014
;;===========================================================================;;
3545 hidnplayr 1015
        xor     eax, eax
1016
        lodsb
1017
        test    al, al
1018
        jz      .decode_name.done
1019
        test    al, 0xC0
1020
        jnz     .decode_name.pointer
1021
        mov     ecx, eax
1022
        rep     movsb
1023
        mov     al, '.'
1024
        stosb
1025
        jmp     .decode_name
1155 clevermous 1026
.decode_name.pointer:
3545 hidnplayr 1027
        and     al, 0x3F
1028
        mov     ah, al
1029
        lodsb
1030
        lea     esi, [edx+eax]
1031
        jmp     .decode_name
1155 clevermous 1032
.decode_name.done:
3545 hidnplayr 1033
        mov     byte [edi-1], 0
1034
        ret
1155 clevermous 1035
 
1036
;;===========================================================================;;
1037
;; Internal auxiliary function for allocating memory for getaddrinfo.        ;;
1038
getaddrinfo._.memalloc:                                                      ;;
1039
;;---------------------------------------------------------------------------;;
1040
;? Memory allocation.                                                        ;;
1041
;;---------------------------------------------------------------------------;;
1042
;> eax = size in bytes, must be less than page size.                         ;;
1043
;> [ebp-4] = .recent_page = last allocated page                              ;;
1044
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page            ;;
1045
;;---------------------------------------------------------------------------;;
1046
;< edi -> allocated memory / NULL on error                                   ;;
1047
;;===========================================================================;;
1048
; 1. Set edi to result of function.
3545 hidnplayr 1049
        mov     edi, [ebp-4]
1155 clevermous 1050
; 2. Check whether we need to allocate a new page.
3545 hidnplayr 1051
        cmp     eax, [ebp-8]
1052
        jbe     .no_new_page
1155 clevermous 1053
; 2. Allocate new page if need. Reset edi to new result.
3545 hidnplayr 1054
        push    eax ebx
1055
        mcall   68, 12, 0x1000
1056
        xchg    edi, eax        ; put result to edi
1057
        pop     ebx eax
1155 clevermous 1058
; 3. Check returned value of allocator. Fail if it failed.
3545 hidnplayr 1059
        test    edi, edi
1060
        jz      .ret
1155 clevermous 1061
; 4. Update .recent_page and .recent_restsize.
3545 hidnplayr 1062
        add     edi, 4
1063
        sub     ecx, 4
1064
        mov     [ebp-4], edi
1065
        mov     [ebp-8], ecx
1155 clevermous 1066
.no_new_page:
1067
; 5. Increase number of objects on this page.
3545 hidnplayr 1068
        push    eax
1069
        mov     eax, edi
1070
        and     eax, not 0xFFF
1071
        inc     dword [eax]
1072
        pop     eax
1155 clevermous 1073
; 6. Advance last allocated pointer, decrease memory size.
3545 hidnplayr 1074
        add     [ebp-4], eax
1075
        sub     [ebp-8], eax
1155 clevermous 1076
; 7. Return.
1077
.ret:
3545 hidnplayr 1078
        ret
1155 clevermous 1079
 
1080
;;===========================================================================;;
1081
;; Internal auxiliary function for freeing memory for freeaddrinfo.          ;;
1082
getaddrinfo._.memfree:                                                       ;;
1083
;;---------------------------------------------------------------------------;;
1084
;? Free memory.                                                              ;;
1085
;;---------------------------------------------------------------------------;;
1086
;> eax = pointer                                                             ;;
1087
;;===========================================================================;;
1088
; 1. Get start of page.
3545 hidnplayr 1089
        mov     ecx, eax
1090
        and     ecx, not 0xFFF
1155 clevermous 1091
; 2. Decrease number of objects.
3545 hidnplayr 1092
        dec     dword [ecx]
1155 clevermous 1093
; 3. If it goes to zero, free the page.
3545 hidnplayr 1094
        jnz     @f
1095
        push    ebx
1096
        mcall   68, 13
1097
        pop     ebx
1155 clevermous 1098
@@:
1099
; 4. Done.
3545 hidnplayr 1100
        ret
1155 clevermous 1101
 
1102
;;===========================================================================;;
1103
getaddrinfo._.generate_data:                                                 ;;
1104
;;---------------------------------------------------------------------------;;
1105
;? Generate item(s) of getaddrinfo result list by one IP address.            ;;
1106
;;---------------------------------------------------------------------------;;
1107
;> eax = IP address                                                          ;;
1108
;> ebx = request data                                                        ;;
1109
;> esi = pointer to result                                                   ;;
1110
;> [ebp-4] = .recent_page = last allocated page                              ;;
1111
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page            ;;
1112
;;---------------------------------------------------------------------------;;
1113
;< esi = pointer to next list item for result / NULL on error                ;;
1114
;;===========================================================================;;
1115
; 1. If no service is given, append one item with zero port.
1116
; append one item with zero socktype/protocol/port.
3545 hidnplayr 1117
        cmp     [ebx+__gai_reqdata.service], -1
1118
        jnz     .has_service
1119
        call    .append_item
1155 clevermous 1120
; 1a. If neither protocol nor socktype were specified,
3545 hidnplayr 1121
;       leave zeroes in socktype and protocol.
1122
        mov     cl, [ebx+__gai_reqdata.socktype]
1123
        test    cl, cl
1124
        jz      .no_socktype
1155 clevermous 1125
; 1b. Otherwise, set socktype and protocol to desired.
3545 hidnplayr 1126
        call    .set_socktype
1155 clevermous 1127
.no_socktype:
3545 hidnplayr 1128
        ret
1155 clevermous 1129
.has_service:
1130
; 2. If TCP is allowed, append item for TCP.
3545 hidnplayr 1131
        cmp     [ebx+__gai_reqdata.socktype], 0
1132
        jz      .tcp_ok
1133
        cmp     [ebx+__gai_reqdata.socktype], SOCK_STREAM
1134
        jnz     .tcp_disallowed
1155 clevermous 1135
.tcp_ok:
3545 hidnplayr 1136
        call    .append_item
1137
        mov     cl, SOCK_STREAM
1138
        call    .set_socktype
1139
        call    .set_port
1155 clevermous 1140
.tcp_disallowed:
1141
; 3. If UDP is allowed, append item for UDP.
3545 hidnplayr 1142
        cmp     [ebx+__gai_reqdata.socktype], 0
1143
        jz      .udp_ok
1144
        cmp     [ebx+__gai_reqdata.socktype], SOCK_DGRAM
1145
        jnz     .udp_disallowed
1155 clevermous 1146
.udp_ok:
3545 hidnplayr 1147
        call    .append_item
1148
        mov     cl, SOCK_DGRAM
1149
        call    .set_socktype
1150
        call    .set_port
1155 clevermous 1151
.udp_disallowed:
3545 hidnplayr 1152
        ret
1155 clevermous 1153
 
1154
.append_item:
1155
; 1. Allocate memory for struct sockaddr_in and struct addrinfo.
3545 hidnplayr 1156
        push    eax
1157
        push    sizeof.addrinfo + sizeof.sockaddr_in
1158
        pop     eax
1159
        call    getaddrinfo._.memalloc
1155 clevermous 1160
; 2. Check for memory allocation fail.
3545 hidnplayr 1161
        test    edi, edi
1162
        jz      .no_memory
1155 clevermous 1163
; 3. Zero allocated memory.
3545 hidnplayr 1164
        push    (sizeof.addrinfo + sizeof.sockaddr_in) / 4
1165
        pop     ecx
1166
        xor     eax, eax
1167
        push    edi
1168
        rep     stosd
1169
        pop     edi
1155 clevermous 1170
; 4. Fill struct addrinfo.
3545 hidnplayr 1171
        mov     eax, [ebx+__gai_reqdata.flags]
1172
        mov     [edi+addrinfo.ai_flags], eax
1173
        mov     byte [edi+addrinfo.ai_family], AF_INET4
1174
        mov     byte [edi+addrinfo.ai_addrlen], sizeof.sockaddr_in
1175
        lea     ecx, [edi+sizeof.addrinfo]
1176
        mov     [edi+addrinfo.ai_addr], ecx
1155 clevermous 1177
; 5. Fill struct sockaddr_in.
3545 hidnplayr 1178
        mov     byte [ecx+sockaddr_in.sin_family], AF_INET4
1179
        pop     eax
1180
        mov     [ecx+sockaddr_in.sin_addr], eax
1155 clevermous 1181
; 6. Append new item to the list.
3545 hidnplayr 1182
        mov     [esi], edi
1183
        lea     esi, [edi+addrinfo.ai_next]
1155 clevermous 1184
; 7. Return.
3545 hidnplayr 1185
        ret
1155 clevermous 1186
.no_memory:
3545 hidnplayr 1187
        pop     eax
1188
        xor     esi, esi
1189
        ret
1155 clevermous 1190
 
1191
.set_socktype:
3545 hidnplayr 1192
; Set ai_socktype and ai_protocol fields by given socketnum type.
1193
        mov     byte [edi+addrinfo.ai_socktype], cl
1194
        dec     cl
1195
        jnz     .set_udp
1155 clevermous 1196
.set_tcp:
3545 hidnplayr 1197
        mov     byte [edi+addrinfo.ai_protocol], IPPROTO_TCP
1198
        ret
1155 clevermous 1199
.set_udp:
3545 hidnplayr 1200
        mov     byte [edi+addrinfo.ai_protocol], IPPROTO_UDP
1201
        ret
1155 clevermous 1202
 
1203
.set_port:
1204
; Just copy port from input __gai_reqdata to output addrinfo.
3545 hidnplayr 1205
        push    edx
1206
        mov     edx, [ebx+__gai_reqdata.service]
1207
        xchg    dl, dh  ; convert to network byte order     ;;;;; CHECKME
1208
        mov     [edi+sizeof.addrinfo+sockaddr_in.sin_port], dx
1209
        pop     edx
1210
        ret
1155 clevermous 1211
 
1212
;;===========================================================================;;
1213
;; void __stdcall getaddrinfo_abort(__in struct __gai_reqdata* reqdata);      ;;
1214
getaddrinfo_abort:                                                           ;;
1215
;;---------------------------------------------------------------------------;;
1216
;? Abort process started by getaddrinfo_start, free all resources.           ;;
1217
;;---------------------------------------------------------------------------;;
1218
;> first parameter = pointer to struct __gai_reqdata filled by ..._start     ;;
1219
;;===========================================================================;;
1220
; 0. Save used registers for __stdcall.
3545 hidnplayr 1221
        push    ebx
1222
; 1. Allocated resources: only socketnum, so close it and return.
1223
        mov     eax, [esp+8]
1224
        mov     ecx, [eax+__gai_reqdata.socketnum]
1225
        mcall   75, 1
1155 clevermous 1226
; 2. Restore used registers and return.
3545 hidnplayr 1227
        pop     ebx
1228
        ret     4
1155 clevermous 1229
 
1230
;;===========================================================================;;
1231
;; void __stdcall freeaddrinfo(__in struct addrinfo* ai);                    ;;
1232
freeaddrinfo:                                                                ;;
1233
;;---------------------------------------------------------------------------;;
1234
;? Free one or more addrinfo structures returned by getaddrinfo.             ;;
1235
;;---------------------------------------------------------------------------;;
1236
;> first parameter = head of list of structures                              ;;
1237
;                    (may be arbitrary sublist of original)                  ;;
1238
;;===========================================================================;;
1239
; 1. Loop for all items in the list.
3545 hidnplayr 1240
        mov     edx, [esp+4]    ; eax = ai
1155 clevermous 1241
.loop:
3545 hidnplayr 1242
        test    edx, edx
1243
        jz      .done
1155 clevermous 1244
; 2. Free each item.
1245
; 2a. Free ai_canonname, if allocated.
3545 hidnplayr 1246
        mov     eax, [edx+addrinfo.ai_canonname]
1247
        test    eax, eax
1248
        jz      .no_canon_name
1249
        call    getaddrinfo._.memfree
1155 clevermous 1250
.no_canon_name:
1251
; 2b. Remember next item
3545 hidnplayr 1252
;       (after freeing the field ai_next can became unavailable).
1253
        pushd   [edx+addrinfo.ai_next]
1155 clevermous 1254
; 2c. Free item itself.
3545 hidnplayr 1255
        xchg    eax, edx
1256
        call    getaddrinfo._.memfree
1155 clevermous 1257
; 2d. Restore pointer to next item and continue loop.
3545 hidnplayr 1258
        pop     edx
1259
        jmp     .loop
1155 clevermous 1260
.done:
1261
; 3. Done.
3545 hidnplayr 1262
        ret     4
1155 clevermous 1263
 
1264
;;===========================================================================;;
1265
;;///////////////////////////////////////////////////////////////////////////;;
1266
;;===========================================================================;;
1267
;! Exported functions section                                                ;;
1268
;;===========================================================================;;
1269
;;///////////////////////////////////////////////////////////////////////////;;
1270
;;===========================================================================;;
1271
 
1272
 
1273
align 4
1274
@EXPORT:
3545 hidnplayr 1275
export  \
1276
        lib_init                , 'lib_init'            , \
1277
        0x00010001              , 'version'             , \
1278
        inet_addr               , 'inet_addr'           , \
1279
        inet_ntoa               , 'inet_ntoa'           , \
1280
        getaddrinfo             , 'getaddrinfo'         , \
1281
        getaddrinfo_start       , 'getaddrinfo_start'   , \
1282
        getaddrinfo_process     , 'getaddrinfo_process' , \
1283
        getaddrinfo_abort       , 'getaddrinfo_abort'   , \
1284
        freeaddrinfo            , 'freeaddrinfo'
1155 clevermous 1285
 
1286
section '.data' data readable writable align 16
1287
; uninitialized data
1288
mem.alloc   dd ?
1289
mem.free    dd ?
1290
mem.realloc dd ?
1291
dll.load    dd ?
1292
 
3545 hidnplayr 1293
DNSrequestID    dd      ?
1155 clevermous 1294
 
3545 hidnplayr 1295
inet_ntoa.buffer        rb      16      ; static buffer for inet_ntoa