Subversion Repositories Kolibri OS

Rev

Rev 3704 | Rev 5545 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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. ;;===========================================================================;;
  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
  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.
  45.         push    ebx esi edi
  46.         mov     esi, [esp+16]   ; esi = hostname
  47. ; 1. Check that only allowed symbols are present.
  48. ; (hex digits, possibly letters 'x'/'X' and up to 3 dots)
  49.         push    esi
  50.         xor     ecx, ecx
  51. .calcdots_loop:
  52. ; loop for all characters in string
  53.         lodsb
  54. ; check for end of string
  55.         cmp     al, 0
  56.         jz      .calcdots_loop_done
  57. ; check for dot
  58.         cmp     al, '.'
  59.         jz      .dot
  60. ; check for digit
  61.         sub     al, '0'
  62.         cmp     al, 9
  63.         jbe     .calcdots_loop
  64. ; check for hex letter
  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
  69. ; check for 'x'/'X'
  70.         cmp     al, 'X' - 'A'
  71.         jz      .calcdots_loop
  72.         jmp     .fail.pop
  73. .dot:
  74.         inc     ecx
  75.         jmp     .calcdots_loop
  76. .calcdots_loop_done:
  77.         cmp     ecx, 4
  78.         jae     .fail.pop
  79. ; 2. The name can be valid dotted name; try to convert, checking limit
  80.         pop     esi
  81.         xor     edi, edi        ; edi = address
  82.         push    0xFFFFFFFF
  83.         pop     edx             ; edx = mask for rest of address
  84. ; 2a. Convert name except for last group.
  85.         jecxz   .ip_convert_2b
  86. .ip_convert_2a:
  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
  98. ; 2b. Convert last group.
  99. .ip_convert_2b:
  100.         mov     ecx, edx
  101.         call    .get_number
  102.         jc      .fail
  103.         cmp     byte [esi-1], 0
  104.         jnz     .fail
  105. @@:
  106.         shl     edi, 8
  107.         shr     edx, 8
  108.         jnz     @b
  109.         add     edi, eax
  110. ; 2c. Convert to network byte order.
  111.         bswap   edi
  112. ; 3. Set return value, restore used registers and return.
  113.         xchg    eax, edi
  114. .ret:
  115.         pop     edi esi ebx
  116.         ret     4
  117. ; 4. On error, return -1.
  118. .fail.pop:
  119.         pop     esi
  120. .fail:
  121.         push    -1
  122.         pop     eax
  123.         jmp     .ret
  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.
  139.         push    edx
  140. ; 1. Initialize number, zero eax so that lodsb gets full dword.
  141.         xor     eax, eax
  142.         xor     edx, edx
  143. ; 2. Get used numeral system: 0x = hex, otherwise 0 = octal, otherwise decimal
  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
  155. ; 3. Loop while digits are encountered.
  156. .convert:
  157. ; 4. Convert digit from text representation to binary value.
  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
  166. .digit:
  167. ; 5. Digit must be less than base of numeral system.
  168.         cmp     eax, ebx
  169.         jae     .convert_done
  170. ; 6. Advance the number.
  171.         imul    edx, ebx
  172.         add     edx, eax
  173.         cmp     edx, ecx
  174.         ja      .gn_error
  175. ; 3b. Continue loop.
  176.         lodsb
  177.         jmp     .convert
  178. .convert_done:
  179. ; 7. Invalid character, number converted, return success.
  180.         xchg    eax, edx
  181.         pop     edx
  182.         clc
  183.         ret
  184. .gn_error:
  185. ; 8. Too big number, return error.
  186.         pop     edx
  187.         stc
  188.         ret
  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.
  201.         push    ebx esi edi
  202.         mov     bl, 0xCD        ; constant for div 10
  203. ; 1. Write octet 4 times.
  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
  215. ; 2. Replace final dot with terminating zero.
  216.         mov     byte [edi-1], 0
  217. ; 3. Restore used registers, set result value and return.
  218.         pop     edi esi ebx
  219.         mov     eax, .buffer
  220.         ret     4
  221.  
  222. .write:
  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
  248. .2digit:
  249.         add     ah, '0'
  250.         mov     byte [edi], ah
  251.         mov     word [edi+1], si
  252.         add     edi, 3
  253.         ret
  254. .1digit:
  255.         mov     word [edi], si
  256.         add     edi, 2
  257.         ret
  258.  
  259. struct __gai_reqdata
  260.         socketnum  dd      ?
  261. ; external code should not look on rest of this structure,
  262. ; it is internal for getaddrinfo_start/process/abort
  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
  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)       ;;
  282. ;> third parameter (optional) = hints for socketnum type                        ;;
  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.
  288.         push    ebx esi edi
  289.         mov     edi, [esp+28]   ; edi = res
  290. ; 1. Create and send DNS packet.
  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
  300. ; 2. Wait for DNS reply.
  301. ; 2a. Ignore all events except network stack.
  302.         mcall   40, EVM_STACK
  303.         push    eax     ; save previous event mask (2)
  304. ; 2b. Get upper limit for wait time. Use timeout = 5 seconds.
  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
  309. .wait:
  310. ; 2c. Wait for event with timeout.
  311.         mcall   23      ; wait for event - must be stack event
  312. ; 2d. Check for timeout.
  313.         test    eax, eax
  314.         lea     eax, [esp+4]    ; pointer to (1)
  315.         jz      .timeout
  316. ; 3. Got packet. Call processing function.
  317.         push    edi     ; second parameter: pointer to result
  318.         push    eax     ; first parameter: pointer to reqdata
  319.         call    getaddrinfo_process
  320. ; 4. Test whether wait loop must be continued.
  321.         test    eax, eax
  322.         jns     .ret.restore
  323. ; 2e. Recalculate timeout value.
  324.         mcall   26, 9
  325.         mov     ebx, esi
  326.         sub     ebx, eax
  327. ; 2f. Check that time is not over; if not, continue wait loop
  328.         cmp     ebx, 500
  329.         jbe     .wait
  330. .timeout:
  331. ; 5. Timeout: abort and return error
  332.         push    eax
  333.         call    getaddrinfo_abort
  334.         and     dword [edi], 0
  335.         push    EAI_AGAIN
  336.         pop     eax
  337. .ret.restore:
  338. ; 6. Restore event mask.
  339.         pop     ebx     ; get event mask (2)
  340.         push    eax     ; save return code (3)
  341.         mcall   40
  342.         pop     eax     ; restore return code (3)
  343. .ret:
  344. ; 7. Restore stack pointer, used registers and return.
  345.         add     esp, sizeof.__gai_reqdata       ; undo (1)
  346.         pop     edi esi ebx
  347.         ret     16
  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.
  376.         push    ebx esi edi
  377.         push    ebp
  378.         mov     ebp, esp
  379. virtual at ebp-8
  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      ?
  388. end virtual
  389.         xor     edi, edi
  390.         push    edi     ; init .recent_page
  391.         push    edi     ; init .recent_restsize
  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.
  394.         mov     eax, [.res]
  395.         test    eax, eax
  396.         jz      @f
  397.         mov     [eax], edi
  398. @@:
  399. ; 1b. Only AI_SUPPORTED flags are supported for hints->ai_flags.
  400.         mov     ecx, [.hints]
  401.         xor     edx, edx
  402.         jecxz   .nohints
  403.         mov     edx, [ecx+addrinfo.ai_flags]
  404. .nohints:
  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
  411. ; 1c. Either hostname or servname must be given. If AI_CANONNAME is set,
  412. ; hostname must also be set.
  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
  421. @@:
  422. ; 1d. Only IPv4 is supported, so hints->ai_family must be either PF_UNSPEC or PF_INET.
  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
  430. @@:
  431. ; 1e. Valid combinations for ai_socktype/ai_protocol: 0/0 for any or
  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]
  438. ; 1f. Test for ai_socktype=0 and ai_protocol=0.
  439.         test    edx, edx
  440.         jnz     .check_socktype
  441.         test    esi, esi
  442.         jz      .socketnum_type_ok
  443. ; 1g. ai_socktype=0, ai_protocol is nonzero.
  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
  452. .ret:
  453. ; Restore saved registers, destroy stack frame and return.
  454.         mov     esp, ebp
  455.         pop     ebp
  456.         pop     edi esi ebx
  457.         ret     20
  458. ; 1h. ai_socktype is nonzero.
  459. .check_socktype:
  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
  471. .check_tcp:
  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
  478. ; 2. Resolve service.
  479. ; 2a. If no name is given, remember value -1.
  480.         push    -1
  481.         pop     edx
  482.         mov     esi, [.servname]
  483.         test    esi, esi
  484.         jz      .service_resolved
  485. ; 2b. Loop for characters of string while digits are encountered.
  486.         xor     edx, edx
  487.         xor     eax, eax
  488. .serv_to_number:
  489.         lodsb
  490.         sub     al, '0'
  491.         cmp     al, 9
  492.         ja      .serv_to_number_done
  493. ; for each digit, set edx = edx*10 + <digit>
  494.         lea     edx, [edx*5]
  495.         lea     edx, [edx*2+eax]
  496. ; check for correctness: service port must fit in word
  497.         cmp     edx, 0x10000
  498.         jae     .service_not_number
  499.         jmp     .serv_to_number
  500. .serv_to_number_done:
  501.         and     edx, 0xFFFF     ; make sure that port fits
  502. ; 2c. If zero character reached, name is resolved;
  503. ; otherwise, return error (no support for symbolic names yet)
  504.         cmp     al, -'0'
  505.         jz      .service_resolved
  506. .service_not_number:
  507.         push    EAI_NONAME
  508.         pop     eax
  509.         jmp     .ret
  510. .service_resolved:
  511. ; 2d. Save result to reqdata.
  512.         mov     [ebx+__gai_reqdata.service], edx
  513. ; 3. Process host name.
  514.         mov     esi, [.hostname]
  515. ; 3a. If hostname is not given,
  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
  521. @@:
  522.         test    esi, esi
  523.         jz      .hostname_is_ip
  524. ; 3b. Check for dotted IPv4 name.
  525.         push    esi
  526.         call    inet_addr
  527.         cmp     eax, -1
  528.         jz      .resolve_hostname
  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.
  532.         mov     ebx, [.reqdata]
  533.         mov     esi, [.res]
  534.         test    esi, esi
  535.         jz      .no_result
  536.         call    getaddrinfo._.generate_data
  537. ; 3d. Check for memory allocation error.
  538. .3d:
  539.         push    EAI_MEMORY
  540.         pop     eax
  541.         test    esi, esi
  542.         jz      .ret
  543. ; 3e. If AI_CANONNAME is set, copy input name.
  544.         test    byte [ebx+__gai_reqdata.flags], AI_CANONNAME
  545.         jz      .no_result
  546. ; 3f. Calculate length of name.
  547.         push    -1
  548.         pop     ecx
  549.         mov     edi, [.hostname]
  550.         xor     eax, eax
  551.         repnz   scasb
  552.         not     ecx
  553. ; 3g. Check whether it fits on one page with main data.
  554.         cmp     ecx, [.recent_restsize]
  555.         jbe     .name_fits
  556. ; 3h. If not, allocate new page.
  557.         push    ecx
  558.         add     ecx, 4  ; first dword contains number of objects on the page
  559.         mcall   68, 12
  560.         pop     ecx
  561. ; 3i. If allocation has failed, free addrinfo and return error.
  562.         test    eax, eax
  563.         jnz     .name_allocated
  564.         push    [.res]
  565.         call    freeaddrinfo
  566.         push    EAI_MEMORY
  567.         pop     eax
  568.         jmp     .ret
  569. .name_allocated:
  570. ; 3j. Otherwise, set edi to allocated memory and continue to 3l.
  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
  576. .name_fits:
  577. ; 3k. Get pointer to free memory in allocated page.
  578.         mov     edi, [.recent_page]
  579.         mov     eax, edi
  580.         and     eax, not 0xFFF
  581.         inc     dword [eax]     ; increase number of objects
  582. .copy_name:
  583. ; 3l. Put pointer to struct addrinfo.
  584.         mov     eax, [.res]
  585.         mov     eax, [eax]
  586.         mov     [eax+addrinfo.ai_canonname], edi
  587. ; 3m. Copy name.
  588.         rep     movsb
  589. .no_result:
  590. ; 3n. Return success.
  591.         xor     eax, eax
  592.         jmp     .ret
  593. ; 4. Host address is not dotted IP. Test whether we are allowed to contact DNS.
  594. ; Return error if no.
  595. .resolve_hostname:
  596.         push    EAI_NONAME
  597.         pop     eax
  598.         mov     ebx, [.reqdata]
  599.         test    byte [ebx+__gai_reqdata.flags], AI_NUMERICHOST
  600.         jnz     .ret
  601. ; Host address is domain name. Contact DNS server.
  602.         mov     esi, [.hostname]
  603. ; 5. Reserve stack place for UDP packet.
  604. ; According to RFC1035, maximum UDP packet size in DNS is 512 bytes.
  605.         sub     esp, 512
  606. ; 6. Create DNS request packet.
  607. ; 6a. Set pointer to start of buffer.
  608.         mov     edi, esp
  609. ; 6b. Get request ID, write it to buffer.
  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
  615. ; 6c. Packed field: QR=0 (query), Opcode=0000 (standard query),
  616. ;       AA=0 (ignored in requests), TC=0 (no truncation),
  617. ;       RD=1 (recursion desired)
  618.         mov     al, 00000001b
  619.         stosb
  620. ; 6d. Packed field: ignored in requests
  621.         mov     al, 0
  622.         stosb
  623. ; 6e. Write questions count = 1 and answers count = 0
  624. ; Note that network byte order is big-endian.
  625.         mov     eax, 0x00000100
  626.         stosd
  627. ; 6f. Write nameservers count = 0 and additional records count = 0
  628.         xor     eax, eax
  629.         stosd
  630. ; 6g. Write request data: name
  631. ; According to RFC1035, maximum length of name is 255 bytes.
  632. ; For correct names, buffer cannot overflow.
  633.         lea     ebx, [esi+256]  ; ebx = limit for name (including terminating zero)
  634. ; translate string "www.yandex.ru" {00} to byte data {03} "www" {06} "yandex" {02} "ru" {00}
  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
  649. .wrongname:
  650.         push    EAI_NONAME
  651.         pop     eax
  652.         jmp     .ret
  653. .labelend:
  654.         test    ecx, ecx        ; null label can be only in the end of name
  655.         jz      .wrongname
  656. .endname:
  657.         cmp     ecx, 63
  658.         ja      .wrongname
  659. ; write length to byte [edi-ecx-1]
  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
  665. ; write terminating zero if not yet
  666.         mov     al, 0
  667.         cmp     byte [edi-1], al
  668.         jz      @f
  669.         stosb
  670. @@:
  671. ; 6h. Write request data:
  672. ;       query type = A (host address) = 1,
  673. ;       query class = IN (internet IPv4 address) = 1
  674. ; Note that network byte order is big-endian.
  675.         mov     eax, 0x01000100
  676.         stosd
  677. ; 7. Get DNS server address.
  678.         mcall   76, API_IPv4 + (1 shl 8) + 4 ; protocol IP=0, device number=0, function=get DNS address
  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
  701. ; 9. Send DNS request packet.
  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
  713. .ret.close:
  714.         mcall   75, 1
  715. .ret.dnserr:
  716.         push    EAI_AGAIN
  717.         pop     eax
  718. .ret.dns:
  719. ; 6. Restore stack pointer and return.
  720.         jmp     .ret
  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.
  735.         push    ebp
  736.         mov     ebp, esp
  737. virtual at ebp-.locals_size
  738. .locals_start:
  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
  746. .locals_size = $ - .locals_start
  747.                 rd      2
  748. .reqdata        dd      ?
  749. .res            dd      ?
  750. end virtual
  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
  758. ; 1. Save used registers for __stdcall.
  759.         push    ebx esi edi
  760.         mov     edi, [.reqdata]
  761. ; 2. Read UDP datagram.
  762.         mov     ecx, [edi+__gai_reqdata.socketnum]
  763.         push    edi
  764.         mcall   75, 7, , , 512, MSG_DONTWAIT
  765.         pop     edi
  766. ; 3. Check for socket errors
  767.         cmp     eax, -1
  768.         jne     @f
  769.         cmp     ebx, EWOULDBLOCK
  770.         je      .ret.more_processing_required
  771.         jmp     .ret.no_recovery
  772.   @@:
  773. ; 4. Sanity check: discard too short packets.
  774.         xchg    ecx, eax        ; save packet length in ecx
  775.         cmp     ecx, 12
  776.         jb      .ret.more_processing_required
  777. ; 5. Discard packets with ID != request ID.
  778.         mov     eax, dword [edi+__gai_reqdata.reqid]
  779.         cmp     ax, [edx]
  780.         jnz     .ret.more_processing_required
  781. ; 6. Sanity check: discard query packets.
  782.         test    byte [edx+2], 80h
  783.         jz      .ret.more_processing_required
  784. ; 7. Sanity check: must be exactly one query (our).
  785.         cmp     word [edx+4], 0x0100    ; note network byte order
  786.         jnz     .ret.more_processing_required
  787. ; 8. Check for errors. Return EAI_NONAME for error code 3 and EAI_FAIL for other.
  788.         mov     al, [edx+3]
  789.         and     al, 0xF
  790.         jz      @f
  791.         cmp     al, 3
  792.         jnz     .ret.no_recovery
  793.         jmp     .ret.no_name
  794. @@:
  795. ; 9. Locate answers section. Exactly 1 query is present in this packet.
  796.         add     ecx, edx        ; ecx = limit
  797.         lea     esi, [edx+12]
  798.         call    .skip_name
  799.         lodsd           ; skip QTYPE and QCLASS field
  800.         cmp     esi, ecx
  801.         ja      .ret.no_recovery
  802. ; 10. Loop through all answers.
  803.         movzx   ebx, word [edx+6]       ; get answers count
  804.         xchg    bl, bh          ; network -> Intel byte order
  805. .answers_loop:
  806.         dec     ebx
  807.         js      .answers_done
  808. ; 10a. Process each record.
  809.         mov     [.name], esi
  810. ; 10b. Skip name field.
  811.         call    .skip_name
  812. ; 10c. Get record information, handle two types for class IN (internet).
  813.         lodsd           ; get type and class
  814.         cmp     esi, ecx
  815.         ja      .ret.no_recovery
  816.         cmp     eax, 0x01000500 ; type=5, class=1?
  817.         jz      .got_cname
  818.         cmp     eax, 0x01000100 ; type=1, class=1?
  819.         jnz     .answers_loop.next
  820. .got_addr:
  821. ; 10d. Process record A, host address.
  822.         add     esi, 10
  823.         cmp     esi, ecx
  824.         ja      .ret.no_recovery
  825.         cmp     word [esi-6], 0x0400    ; RDATA for A records must be 4 bytes long
  826.         jnz     .ret.no_recovery
  827.         mov     eax, [.name]
  828.         mov     [.addrname], eax
  829. ; 10e. Create corresponding record in the answer.
  830.         push    ebx ecx esi
  831.         mov     eax, [esi-4]    ; IP address
  832.         mov     esi, [.res_list_tail]   ; pointer to result
  833.         test    esi, esi
  834.         jz      .no_result      ; do not save if .res is NULL
  835.         mov     ebx, [.reqdata] ; request data
  836.         call    getaddrinfo._.generate_data
  837.         mov     [.res_list_tail], esi
  838.         pop     esi ecx ebx
  839.         cmp     [.res_list_tail], 0
  840.         jnz     .answers_loop
  841. ; 10f. If generate_data failed (this means memory allocation failure), abort
  842.         jmp     .ret.no_memory
  843. .no_result:
  844.         pop     esi ecx ebx
  845.         jmp     .answers_loop
  846. .got_cname:
  847. ; 10g. Process record CNAME, main host name.
  848.         lea     eax, [esi+6]
  849.         mov     [.cname], eax
  850. .answers_loop.next:
  851. ; 10h. Skip other record fields, advance to next record.
  852.         lodsd   ; skip TTL
  853.         xor     eax, eax
  854.         lodsw   ; get length of RDATA field
  855.         xchg    al, ah  ; network -> Intel byte order
  856.         add     esi, eax
  857.         cmp     esi, ecx
  858.         ja      .ret.no_recovery
  859.         jmp     .answers_loop
  860. .answers_done:
  861. ; 11. Check that there is at least 1 answer.
  862.         mov     eax, [.res_list_tail]
  863.         cmp     [.res], eax
  864.         jz      .ret.no_data
  865. ; 12. If canonical name was required, add it now.
  866.         mov     eax, [.reqdata]
  867.         test    byte [eax+__gai_reqdata.flags], AI_CANONNAME
  868.         jz      .no_canon_name
  869. ; 12a. If at least one CNAME record is present, use name from last such record.
  870. ; Otherwise, use name from one of A records.
  871.         mov     esi, [.cname]
  872.         test    esi, esi
  873.         jnz     .has_cname
  874.         mov     esi, [.addrname]
  875. .has_cname:
  876. ; 12b. Calculate name length.
  877.         call    .get_name_length
  878.         jc      .ret.no_recovery
  879. ; 12c. Check that the caller really want to get data.
  880.         cmp     [.res], 0
  881.         jz      .no_canon_name
  882. ; 12d. Allocate memory for name.
  883.         call    getaddrinfo._.memalloc
  884.         test    edi, edi
  885.         jz      .ret.no_memory
  886. ; 12e. Make first entry in .res list point to canonical name.
  887.         mov     eax, [.res]
  888.         mov     eax, [eax]
  889.         mov     [eax+addrinfo.ai_canonname], edi
  890. ; 12f. Decode name.
  891.         call    .decode_name
  892. .no_canon_name:
  893. ; 13. Set status to success.
  894.         xor     eax, eax
  895.         jmp     .ret.close
  896. ; Handle errors.
  897. .ret.more_processing_required:
  898.         push    -1
  899.         pop     eax
  900.         jmp     .ret
  901. .ret.no_recovery:
  902.         push    EAI_FAIL
  903.         pop     eax
  904.         jmp     .ret.destroy
  905. .ret.no_memory:
  906.         push    EAI_MEMORY
  907.         pop     eax
  908.         jmp     .ret.destroy
  909. .ret.no_name:
  910. .ret.no_data:
  911.         push    EAI_NONAME
  912.         pop     eax
  913. .ret.destroy:
  914. ; 14. If an error occured, free memory acquired so far.
  915.         push    eax
  916.         mov     esi, [.res]
  917.         test    esi, esi
  918.         jz      @f
  919.         pushd   [esi]
  920.         call    freeaddrinfo
  921.         and     dword [esi], 0
  922. @@:
  923.         pop     eax
  924. .ret.close:
  925. ; 15. Close socketnum.
  926.         push    eax
  927.         mov     ecx, [.reqdata]
  928.         mov     ecx, [ecx+__gai_reqdata.socketnum]
  929.         mcall   75, 1
  930.         pop     eax
  931. ; 16. Restore used registers, destroy stack frame and return.
  932. .ret:
  933.         pop     edi esi ebx
  934.         mov     esp, ebp
  935.         pop     ebp
  936.         ret     8
  937.  
  938. ;;===========================================================================;;
  939. ;; Internal auxiliary function for skipping names in DNS packet.             ;;
  940. .skip_name:                                                                  ;;
  941. ;;---------------------------------------------------------------------------;;
  942. ;? Skips name in DNS packet.                                                 ;;
  943. ;;---------------------------------------------------------------------------;;
  944. ;> esi -> name                                                               ;;
  945. ;> ecx = end of packet                                                       ;;
  946. ;;---------------------------------------------------------------------------;;
  947. ;< esi -> end of name                                                        ;;
  948. ;;===========================================================================;;
  949.         xor     eax, eax
  950.         cmp     esi, ecx
  951.         jae     .skip_name.done
  952.         lodsb
  953.         test    al, al
  954.         jz      .skip_name.done
  955.         test    al, 0xC0
  956.         jnz     .skip_name.pointer
  957.         add     esi, eax
  958.         jmp     .skip_name
  959. .skip_name.pointer:
  960.         inc     esi
  961. .skip_name.done:
  962.         ret
  963.  
  964. ;;===========================================================================;;
  965. ;; Internal auxiliary function for calculating length of name in DNS packet. ;;
  966. .get_name_length:                                                            ;;
  967. ;;---------------------------------------------------------------------------;;
  968. ;? Calculate length of name (including terminating zero) in DNS packet.      ;;
  969. ;;---------------------------------------------------------------------------;;
  970. ;> edx = start of packet                                                     ;;
  971. ;> esi -> name                                                               ;;
  972. ;> ecx = end of packet                                                       ;;
  973. ;;---------------------------------------------------------------------------;;
  974. ;< eax = length of name                                                      ;;
  975. ;< CF set on error / cleared on success                                      ;;
  976. ;;===========================================================================;;
  977.         xor     ebx, ebx        ; ebx will hold data length
  978. .get_name_length.zero:
  979.         xor     eax, eax
  980. .get_name_length.loop:
  981.         cmp     esi, ecx
  982.         jae     .get_name_length.fail
  983.         lodsb
  984.         test    al, al
  985.         jz      .get_name_length.done
  986.         test    al, 0xC0
  987.         jnz     .get_name_length.pointer
  988.         add     esi, eax
  989.         inc     ebx
  990.         add     ebx, eax
  991.         cmp     ebx, 256
  992.         jbe     .get_name_length.loop
  993. .get_name_length.fail:
  994.         stc
  995.         ret
  996. .get_name_length.pointer:
  997.         and     al, 0x3F
  998.         mov     ah, al
  999.         lodsb
  1000.         lea     esi, [edx+eax]
  1001.         jmp     .get_name_length.zero
  1002. .get_name_length.done:
  1003.         test    ebx, ebx
  1004.         jz      .get_name_length.fail
  1005.         xchg    eax, ebx
  1006.         clc
  1007.         ret
  1008.  
  1009. ;;===========================================================================;;
  1010. ;; Internal auxiliary function for decoding DNS name.                        ;;
  1011. .decode_name:                                                                ;;
  1012. ;;---------------------------------------------------------------------------;;
  1013. ;? Decode name in DNS packet.                                                ;;
  1014. ;;---------------------------------------------------------------------------;;
  1015. ;> edx = start of packet                                                     ;;
  1016. ;> esi -> name in packet                                                     ;;
  1017. ;> edi -> buffer for decoded name                                            ;;
  1018. ;;===========================================================================;;
  1019.         xor     eax, eax
  1020.         lodsb
  1021.         test    al, al
  1022.         jz      .decode_name.done
  1023.         test    al, 0xC0
  1024.         jnz     .decode_name.pointer
  1025.         mov     ecx, eax
  1026.         rep     movsb
  1027.         mov     al, '.'
  1028.         stosb
  1029.         jmp     .decode_name
  1030. .decode_name.pointer:
  1031.         and     al, 0x3F
  1032.         mov     ah, al
  1033.         lodsb
  1034.         lea     esi, [edx+eax]
  1035.         jmp     .decode_name
  1036. .decode_name.done:
  1037.         mov     byte [edi-1], 0
  1038.         ret
  1039.  
  1040. ;;===========================================================================;;
  1041. ;; Internal auxiliary function for allocating memory for getaddrinfo.        ;;
  1042. getaddrinfo._.memalloc:                                                      ;;
  1043. ;;---------------------------------------------------------------------------;;
  1044. ;? Memory allocation.                                                        ;;
  1045. ;;---------------------------------------------------------------------------;;
  1046. ;> eax = size in bytes, must be less than page size.                         ;;
  1047. ;> [ebp-4] = .recent_page = last allocated page                              ;;
  1048. ;> [ebp-8] = .recent_restsize = bytes rest in last allocated page            ;;
  1049. ;;---------------------------------------------------------------------------;;
  1050. ;< edi -> allocated memory / NULL on error                                   ;;
  1051. ;;===========================================================================;;
  1052. ; 1. Set edi to result of function.
  1053.         mov     edi, [ebp-4]
  1054. ; 2. Check whether we need to allocate a new page.
  1055.         cmp     eax, [ebp-8]
  1056.         jbe     .no_new_page
  1057. ; 2. Allocate new page if need. Reset edi to new result.
  1058.         push    eax ebx
  1059.         mcall   68, 12, 0x1000
  1060.         xchg    edi, eax        ; put result to edi
  1061.         pop     ebx eax
  1062. ; 3. Check returned value of allocator. Fail if it failed.
  1063.         test    edi, edi
  1064.         jz      .ret
  1065. ; 4. Update .recent_page and .recent_restsize.
  1066.         add     edi, 4
  1067.         sub     ecx, 4
  1068.         mov     [ebp-4], edi
  1069.         mov     [ebp-8], ecx
  1070. .no_new_page:
  1071. ; 5. Increase number of objects on this page.
  1072.         push    eax
  1073.         mov     eax, edi
  1074.         and     eax, not 0xFFF
  1075.         inc     dword [eax]
  1076.         pop     eax
  1077. ; 6. Advance last allocated pointer, decrease memory size.
  1078.         add     [ebp-4], eax
  1079.         sub     [ebp-8], eax
  1080. ; 7. Return.
  1081. .ret:
  1082.         ret
  1083.  
  1084. ;;===========================================================================;;
  1085. ;; Internal auxiliary function for freeing memory for freeaddrinfo.          ;;
  1086. getaddrinfo._.memfree:                                                       ;;
  1087. ;;---------------------------------------------------------------------------;;
  1088. ;? Free memory.                                                              ;;
  1089. ;;---------------------------------------------------------------------------;;
  1090. ;> eax = pointer                                                             ;;
  1091. ;;===========================================================================;;
  1092. ; 1. Get start of page.
  1093.         mov     ecx, eax
  1094.         and     ecx, not 0xFFF
  1095. ; 2. Decrease number of objects.
  1096.         dec     dword [ecx]
  1097. ; 3. If it goes to zero, free the page.
  1098.         jnz     @f
  1099.         push    ebx
  1100.         mcall   68, 13
  1101.         pop     ebx
  1102. @@:
  1103. ; 4. Done.
  1104.         ret
  1105.  
  1106. ;;===========================================================================;;
  1107. getaddrinfo._.generate_data:                                                 ;;
  1108. ;;---------------------------------------------------------------------------;;
  1109. ;? Generate item(s) of getaddrinfo result list by one IP address.            ;;
  1110. ;;---------------------------------------------------------------------------;;
  1111. ;> eax = IP address                                                          ;;
  1112. ;> ebx = request data                                                        ;;
  1113. ;> esi = pointer to result                                                   ;;
  1114. ;> [ebp-4] = .recent_page = last allocated page                              ;;
  1115. ;> [ebp-8] = .recent_restsize = bytes rest in last allocated page            ;;
  1116. ;;---------------------------------------------------------------------------;;
  1117. ;< esi = pointer to next list item for result / NULL on error                ;;
  1118. ;;===========================================================================;;
  1119. ; 1. If no service is given, append one item with zero port.
  1120. ; append one item with zero socktype/protocol/port.
  1121.         cmp     [ebx+__gai_reqdata.service], -1
  1122.         jnz     .has_service
  1123.         call    .append_item
  1124. ; 1a. If neither protocol nor socktype were specified,
  1125. ;       leave zeroes in socktype and protocol.
  1126.         mov     cl, [ebx+__gai_reqdata.socktype]
  1127.         test    cl, cl
  1128.         jz      .no_socktype
  1129. ; 1b. Otherwise, set socktype and protocol to desired.
  1130.         call    .set_socktype
  1131. .no_socktype:
  1132.         ret
  1133. .has_service:
  1134. ; 2. If TCP is allowed, append item for TCP.
  1135.         cmp     [ebx+__gai_reqdata.socktype], 0
  1136.         jz      .tcp_ok
  1137.         cmp     [ebx+__gai_reqdata.socktype], SOCK_STREAM
  1138.         jnz     .tcp_disallowed
  1139. .tcp_ok:
  1140.         call    .append_item
  1141.         mov     cl, SOCK_STREAM
  1142.         call    .set_socktype
  1143.         call    .set_port
  1144. .tcp_disallowed:
  1145. ; 3. If UDP is allowed, append item for UDP.
  1146.         cmp     [ebx+__gai_reqdata.socktype], 0
  1147.         jz      .udp_ok
  1148.         cmp     [ebx+__gai_reqdata.socktype], SOCK_DGRAM
  1149.         jnz     .udp_disallowed
  1150. .udp_ok:
  1151.         call    .append_item
  1152.         mov     cl, SOCK_DGRAM
  1153.         call    .set_socktype
  1154.         call    .set_port
  1155. .udp_disallowed:
  1156.         ret
  1157.  
  1158. .append_item:
  1159. ; 1. Allocate memory for struct sockaddr_in and struct addrinfo.
  1160.         push    eax
  1161.         push    sizeof.addrinfo + sizeof.sockaddr_in
  1162.         pop     eax
  1163.         call    getaddrinfo._.memalloc
  1164. ; 2. Check for memory allocation fail.
  1165.         test    edi, edi
  1166.         jz      .no_memory
  1167. ; 3. Zero allocated memory.
  1168.         push    (sizeof.addrinfo + sizeof.sockaddr_in) / 4
  1169.         pop     ecx
  1170.         xor     eax, eax
  1171.         push    edi
  1172.         rep     stosd
  1173.         pop     edi
  1174. ; 4. Fill struct addrinfo.
  1175.         mov     eax, [ebx+__gai_reqdata.flags]
  1176.         mov     [edi+addrinfo.ai_flags], eax
  1177.         mov     byte [edi+addrinfo.ai_family], AF_INET4
  1178.         mov     byte [edi+addrinfo.ai_addrlen], sizeof.sockaddr_in
  1179.         lea     ecx, [edi+sizeof.addrinfo]
  1180.         mov     [edi+addrinfo.ai_addr], ecx
  1181. ; 5. Fill struct sockaddr_in.
  1182.         mov     byte [ecx+sockaddr_in.sin_family], AF_INET4
  1183.         pop     eax
  1184.         mov     [ecx+sockaddr_in.sin_addr], eax
  1185. ; 6. Append new item to the list.
  1186.         mov     [esi], edi
  1187.         lea     esi, [edi+addrinfo.ai_next]
  1188. ; 7. Return.
  1189.         ret
  1190. .no_memory:
  1191.         pop     eax
  1192.         xor     esi, esi
  1193.         ret
  1194.  
  1195. .set_socktype:
  1196. ; Set ai_socktype and ai_protocol fields by given socketnum type.
  1197.         mov     byte [edi+addrinfo.ai_socktype], cl
  1198.         dec     cl
  1199.         jnz     .set_udp
  1200. .set_tcp:
  1201.         mov     byte [edi+addrinfo.ai_protocol], IPPROTO_TCP
  1202.         ret
  1203. .set_udp:
  1204.         mov     byte [edi+addrinfo.ai_protocol], IPPROTO_UDP
  1205.         ret
  1206.  
  1207. .set_port:
  1208. ; Just copy port from input __gai_reqdata to output addrinfo.
  1209.         push    edx
  1210.         mov     edx, [ebx+__gai_reqdata.service]
  1211.         xchg    dl, dh  ; convert to network byte order     ;;;;; CHECKME
  1212.         mov     [edi+sizeof.addrinfo+sockaddr_in.sin_port], dx
  1213.         pop     edx
  1214.         ret
  1215.  
  1216. ;;===========================================================================;;
  1217. ;; void __stdcall getaddrinfo_abort(__in struct __gai_reqdata* reqdata);      ;;
  1218. getaddrinfo_abort:                                                           ;;
  1219. ;;---------------------------------------------------------------------------;;
  1220. ;? Abort process started by getaddrinfo_start, free all resources.           ;;
  1221. ;;---------------------------------------------------------------------------;;
  1222. ;> first parameter = pointer to struct __gai_reqdata filled by ..._start     ;;
  1223. ;;===========================================================================;;
  1224. ; 0. Save used registers for __stdcall.
  1225.         push    ebx
  1226. ; 1. Allocated resources: only socketnum, so close it and return.
  1227.         mov     eax, [esp+8]
  1228.         mov     ecx, [eax+__gai_reqdata.socketnum]
  1229.         mcall   75, 1
  1230. ; 2. Restore used registers and return.
  1231.         pop     ebx
  1232.         ret     4
  1233.  
  1234. ;;===========================================================================;;
  1235. ;; void __stdcall freeaddrinfo(__in struct addrinfo* ai);                    ;;
  1236. freeaddrinfo:                                                                ;;
  1237. ;;---------------------------------------------------------------------------;;
  1238. ;? Free one or more addrinfo structures returned by getaddrinfo.             ;;
  1239. ;;---------------------------------------------------------------------------;;
  1240. ;> first parameter = head of list of structures                              ;;
  1241. ;                    (may be arbitrary sublist of original)                  ;;
  1242. ;;===========================================================================;;
  1243. ; 1. Loop for all items in the list.
  1244.         mov     edx, [esp+4]    ; eax = ai
  1245. .loop:
  1246.         test    edx, edx
  1247.         jz      .done
  1248. ; 2. Free each item.
  1249. ; 2a. Free ai_canonname, if allocated.
  1250.         mov     eax, [edx+addrinfo.ai_canonname]
  1251.         test    eax, eax
  1252.         jz      .no_canon_name
  1253.         call    getaddrinfo._.memfree
  1254. .no_canon_name:
  1255. ; 2b. Remember next item
  1256. ;       (after freeing the field ai_next can became unavailable).
  1257.         pushd   [edx+addrinfo.ai_next]
  1258. ; 2c. Free item itself.
  1259.         xchg    eax, edx
  1260.         call    getaddrinfo._.memfree
  1261. ; 2d. Restore pointer to next item and continue loop.
  1262.         pop     edx
  1263.         jmp     .loop
  1264. .done:
  1265. ; 3. Done.
  1266.         ret     4
  1267.  
  1268. ;;===========================================================================;;
  1269. ;;///////////////////////////////////////////////////////////////////////////;;
  1270. ;;===========================================================================;;
  1271. ;! Exported functions section                                                ;;
  1272. ;;===========================================================================;;
  1273. ;;///////////////////////////////////////////////////////////////////////////;;
  1274. ;;===========================================================================;;
  1275.  
  1276.  
  1277. align 4
  1278. @EXPORT:
  1279. export  \
  1280.         lib_init                , 'lib_init'            , \
  1281.         0x00010001              , 'version'             , \
  1282.         inet_addr               , 'inet_addr'           , \
  1283.         inet_ntoa               , 'inet_ntoa'           , \
  1284.         getaddrinfo             , 'getaddrinfo'         , \
  1285.         getaddrinfo_start       , 'getaddrinfo_start'   , \
  1286.         getaddrinfo_process     , 'getaddrinfo_process' , \
  1287.         getaddrinfo_abort       , 'getaddrinfo_abort'   , \
  1288.         freeaddrinfo            , 'freeaddrinfo'
  1289.  
  1290. section '.data' data readable writable align 16
  1291. ; uninitialized data
  1292. mem.alloc   dd ?
  1293. mem.free    dd ?
  1294. mem.realloc dd ?
  1295. dll.load    dd ?
  1296.  
  1297. DNSrequestID    dd      ?
  1298.  
  1299. inet_ntoa.buffer        rb      16      ; static buffer for inet_ntoa
  1300.