diff --git a/kernel/branches/net/applications/libraries/network/network.asm b/kernel/branches/net/applications/libraries/network/network.asm index cee889e74b..c1a0ba1560 100644 --- a/kernel/branches/net/applications/libraries/network/network.asm +++ b/kernel/branches/net/applications/libraries/network/network.asm @@ -23,18 +23,18 @@ lib_init: ;//////////////////////////////////////////////////////////////////;; ;;---------------------------------------------------------------------------;; ;< eax = 1 (fail) / 0 (ok) (library initialization result) ;; ;;===========================================================================;; - mov [mem.alloc], eax - mov [mem.free], ebx - mov [mem.realloc], ecx - mov [dll.load], edx - mov [DNSrequestID], 1 - stdcall edx, @IMPORT - xor eax, eax - ret + mov [mem.alloc], eax + mov [mem.free], ebx + mov [mem.realloc], ecx + mov [dll.load], edx + mov [DNSrequestID], 1 + stdcall edx, @IMPORT + xor eax, eax + ret ;;===========================================================================;; ;; in_addr_t __stdcall inet_addr(__in const char* hostname); ;; -inet_addr: ;; +inet_addr: ;; ;;---------------------------------------------------------------------------;; ;? Convert the string from standard IPv4 dotted notation to integer IP addr. ;; ;;---------------------------------------------------------------------------;; @@ -43,89 +43,89 @@ inet_addr: ;; ;< eax = IP address on success / -1 on error ;; ;;===========================================================================;; ; 0. Save used registers for __stdcall. - push ebx esi edi - mov esi, [esp+16] ; esi = hostname + push ebx esi edi + mov esi, [esp+16] ; esi = hostname ; 1. Check that only allowed symbols are present. ; (hex digits, possibly letters 'x'/'X' and up to 3 dots) - push esi - xor ecx, ecx + push esi + xor ecx, ecx .calcdots_loop: ; loop for all characters in string - lodsb + lodsb ; check for end of string - cmp al, 0 - jz .calcdots_loop_done + cmp al, 0 + jz .calcdots_loop_done ; check for dot - cmp al, '.' - jz .dot + cmp al, '.' + jz .dot ; check for digit - sub al, '0' - cmp al, 9 - jbe .calcdots_loop + sub al, '0' + cmp al, 9 + jbe .calcdots_loop ; check for hex letter - sub al, 'A' - '0' ; 'A'-'F' -> 0-5, 'a'-'f' -> 20h-25h - and al, not 20h - cmp al, 'F' - 'A' - jbe .calcdots_loop + sub al, 'A' - '0' ; 'A'-'F' -> 0-5, 'a'-'f' -> 20h-25h + and al, not 20h + cmp al, 'F' - 'A' + jbe .calcdots_loop ; check for 'x'/'X' - cmp al, 'X' - 'A' - jz .calcdots_loop - jmp .fail.pop + cmp al, 'X' - 'A' + jz .calcdots_loop + jmp .fail.pop .dot: - inc ecx - jmp .calcdots_loop + inc ecx + jmp .calcdots_loop .calcdots_loop_done: - cmp ecx, 4 - jae .fail.pop + cmp ecx, 4 + jae .fail.pop ; 2. The name can be valid dotted name; try to convert, checking limit - pop esi - xor edi, edi ; edi = address - push 0xFFFFFFFF - pop edx ; edx = mask for rest of address + pop esi + xor edi, edi ; edi = address + push 0xFFFFFFFF + pop edx ; edx = mask for rest of address ; 2a. Convert name except for last group. - jecxz .ip_convert_2b + jecxz .ip_convert_2b .ip_convert_2a: - push ecx - mov ecx, 0xFF ; limit for all groups except for last - call .get_number - pop ecx - jc .fail - cmp byte [esi-1], '.' - jnz .fail - shl edi, 8 - shr edx, 8 - add edi, eax - loop .ip_convert_2a + push ecx + mov ecx, 0xFF ; limit for all groups except for last + call .get_number + pop ecx + jc .fail + cmp byte [esi-1], '.' + jnz .fail + shl edi, 8 + shr edx, 8 + add edi, eax + loop .ip_convert_2a ; 2b. Convert last group. .ip_convert_2b: - mov ecx, edx - call .get_number - jc .fail - cmp byte [esi-1], 0 - jnz .fail + mov ecx, edx + call .get_number + jc .fail + cmp byte [esi-1], 0 + jnz .fail @@: - shl edi, 8 - shr edx, 8 - jnz @b - add edi, eax + shl edi, 8 + shr edx, 8 + jnz @b + add edi, eax ; 2c. Convert to network byte order. - bswap edi + bswap edi ; 3. Set return value, restore used registers and return. - xchg eax, edi + xchg eax, edi .ret: - pop edi esi ebx - ret 4 + pop edi esi ebx + ret 4 ; 4. On error, return -1. .fail.pop: - pop esi + pop esi .fail: - push -1 - pop eax - jmp .ret + push -1 + pop eax + jmp .ret ;;===========================================================================;; ;; Internal auxiliary function for IP parsing. ;; -.get_number: ;; +.get_number: ;; ;;---------------------------------------------------------------------------;; ;? Converts string to number. ;; ;;---------------------------------------------------------------------------;; @@ -137,60 +137,60 @@ inet_addr: ;; ;< esi -> end of number representation ;; ;;===========================================================================;; ; 0. Save edx, which is used in caller. - push edx + push edx ; 1. Initialize number, zero eax so that lodsb gets full dword. - xor eax, eax - xor edx, edx + xor eax, eax + xor edx, edx ; 2. Get used numeral system: 0x = hex, otherwise 0 = octal, otherwise decimal - push 10 - pop ebx - lodsb - cmp al, '0' - jnz .convert - push 8 - pop ebx - lodsb - cmp al, 'x' - jnz .convert - add ebx, ebx + push 10 + pop ebx + lodsb + cmp al, '0' + jnz .convert + push 8 + pop ebx + lodsb + cmp al, 'x' + jnz .convert + add ebx, ebx ; 3. Loop while digits are encountered. .convert: ; 4. Convert digit from text representation to binary value. - or al, 20h ; '0'-'9' -> '0'-'9', 'A'-'F' -> 'a'-'f' - sub al, '0' - cmp al, 9 - jbe .digit - sub al, 'a' - '0' - cmp al, 'f' - 'a' - ja .convert_done - add al, 10 + or al, 20h ; '0'-'9' -> '0'-'9', 'A'-'F' -> 'a'-'f' + sub al, '0' + cmp al, 9 + jbe .digit + sub al, 'a' - '0' + cmp al, 'f' - 'a' + ja .convert_done + add al, 10 .digit: ; 5. Digit must be less than base of numeral system. - cmp eax, ebx - jae .convert_done + cmp eax, ebx + jae .convert_done ; 6. Advance the number. - imul edx, ebx - add edx, eax - cmp edx, ecx - ja .gn_error + imul edx, ebx + add edx, eax + cmp edx, ecx + ja .gn_error ; 3b. Continue loop. - lodsb - jmp .convert + lodsb + jmp .convert .convert_done: ; 7. Invalid character, number converted, return success. - xchg eax, edx - pop edx - clc - ret + xchg eax, edx + pop edx + clc + ret .gn_error: ; 8. Too big number, return error. - pop edx - stc - ret + pop edx + stc + ret ;;===========================================================================;; ;; char* __stdcall inet_ntoa(struct in_addr in); ;; -inet_ntoa: ;; +inet_ntoa: ;; ;;---------------------------------------------------------------------------;; ;? Convert the Internet host address to standard IPv4 dotted notation. ;; ;;---------------------------------------------------------------------------;; @@ -199,74 +199,74 @@ inet_ntoa: ;; ;< eax = pointer to resulting string (in static buffer) ;; ;;===========================================================================;; ; 0. Save used registers for __stdcall. - push ebx esi edi - mov bl, 0xCD ; constant for div 10 + push ebx esi edi + mov bl, 0xCD ; constant for div 10 ; 1. Write octet 4 times. - mov edi, .buffer - mov edx, [esp+16] ; eax = in - mov al, dl - call .write - mov al, dh - shr edx, 16 - call .write - mov al, dl - call .write - mov al, dh - call .write + mov edi, .buffer + mov edx, [esp+16] ; eax = in + mov al, dl + call .write + mov al, dh + shr edx, 16 + call .write + mov al, dl + call .write + mov al, dh + call .write ; 2. Replace final dot with terminating zero. - mov byte [edi-1], 0 + mov byte [edi-1], 0 ; 3. Restore used registers, set result value and return. - pop edi esi ebx - mov eax, .buffer - ret 4 + pop edi esi ebx + mov eax, .buffer + ret 4 .write: - movzx esi, al - mul bl - add esi, ('.' shl 8) + '0' - shr ah, 3 ; ah = al / 10 - movzx ecx, ah - add ecx, ecx - lea ecx, [ecx*5] - sub esi, ecx ; lobyte(esi) = al % 10, hibyte(esi) = '.' - test ah, ah - jz .1digit - cmp ah, 10 - jb .2digit - cmp ah, 20 - sbb cl, cl - add cl, '2' - mov byte [edi], cl - movzx ecx, cl - lea ecx, [ecx*5] - sub ah, cl - sub ah, cl - add ah, ('0'*11) and 255 - mov byte [edi+1], ah - mov word [edi+2], si - add edi, 4 - ret + movzx esi, al + mul bl + add esi, ('.' shl 8) + '0' + shr ah, 3 ; ah = al / 10 + movzx ecx, ah + add ecx, ecx + lea ecx, [ecx*5] + sub esi, ecx ; lobyte(esi) = al % 10, hibyte(esi) = '.' + test ah, ah + jz .1digit + cmp ah, 10 + jb .2digit + cmp ah, 20 + sbb cl, cl + add cl, '2' + mov byte [edi], cl + movzx ecx, cl + lea ecx, [ecx*5] + sub ah, cl + sub ah, cl + add ah, ('0'*11) and 255 + mov byte [edi+1], ah + mov word [edi+2], si + add edi, 4 + ret .2digit: - add ah, '0' - mov byte [edi], ah - mov word [edi+1], si - add edi, 3 - ret + add ah, '0' + mov byte [edi], ah + mov word [edi+1], si + add edi, 3 + ret .1digit: - mov word [edi], si - add edi, 2 - ret + mov word [edi], si + add edi, 2 + ret struct __gai_reqdata - socketnum dd ? + socketnum dd ? ; external code should not look on rest of this structure, ; it is internal for getaddrinfo_start/process/abort - reqid dw ? ; DNS request ID - socktype db ? ; SOCK_* or 0 for any - db ? - service dd ? - flags dd ? - reserved rb 16 + reqid dw ? ; DNS request ID + socktype db ? ; SOCK_* or 0 for any + db ? + service dd ? + flags dd ? + reserved rb 16 ends ;;===========================================================================;; @@ -274,7 +274,7 @@ ends ;; __in const char* servname, ;; ;; __in const struct addrinfo* hints, ;; ;; __out struct addrinfo **res); ;; -getaddrinfo: ;; +getaddrinfo: ;; ;;---------------------------------------------------------------------------;; ;? Get a list of IP addresses and port numbers for given host and service ;; ;;---------------------------------------------------------------------------;; @@ -286,66 +286,66 @@ getaddrinfo: ;; ;< eax = 0 on success / one of EAI_ codes on error ;; ;;===========================================================================;; ; 0. Save used registers for __stdcall. - push ebx esi edi - mov edi, [esp+28] ; edi = res + push ebx esi edi + mov edi, [esp+28] ; edi = res ; 1. Create and send DNS packet. - sub esp, sizeof.__gai_reqdata ; reserve stack place (1) - push esp ; fifth parameter = pointer to (1) - push edi ; fourth parameter = res - push dword [esp+32+sizeof.__gai_reqdata] ; third parameter = hints - push dword [esp+32+sizeof.__gai_reqdata] ; second parameter = servname - push dword [esp+32+sizeof.__gai_reqdata] ; first parameter = hostname - call getaddrinfo_start - test eax, eax - jns .ret ; if name resolved without network activity, return + sub esp, sizeof.__gai_reqdata ; reserve stack place (1) + push esp ; fifth parameter = pointer to (1) + push edi ; fourth parameter = res + push dword [esp+32+sizeof.__gai_reqdata] ; third parameter = hints + push dword [esp+32+sizeof.__gai_reqdata] ; second parameter = servname + push dword [esp+32+sizeof.__gai_reqdata] ; first parameter = hostname + call getaddrinfo_start + test eax, eax + jns .ret ; if name resolved without network activity, return ; 2. Wait for DNS reply. ; 2a. Ignore all events except network stack. - mcall 40, EVM_STACK - push eax ; save previous event mask (2) + mcall 40, EVM_STACK + push eax ; save previous event mask (2) ; 2b. Get upper limit for wait time. Use timeout = 5 seconds. - mcall 26, 9 ; get time stamp - xchg esi, eax ; save time stamp to esi - mov ebx, 500 ; start value for timeout - add esi, ebx + mcall 26, 9 ; get time stamp + xchg esi, eax ; save time stamp to esi + mov ebx, 500 ; start value for timeout + add esi, ebx .wait: ; 2c. Wait for event with timeout. - mcall 23 ; wait for event - must be stack event + mcall 23 ; wait for event - must be stack event ; 2d. Check for timeout. - test eax, eax - lea eax, [esp+4] ; pointer to (1) - jz .timeout + test eax, eax + lea eax, [esp+4] ; pointer to (1) + jz .timeout ; 3. Got packet. Call processing function. - push edi ; second parameter: pointer to result - push eax ; first parameter: pointer to reqdata - call getaddrinfo_process + push edi ; second parameter: pointer to result + push eax ; first parameter: pointer to reqdata + call getaddrinfo_process ; 4. Test whether wait loop must be continued. - test eax, eax - jns .ret.restore + test eax, eax + jns .ret.restore ; 2e. Recalculate timeout value. - mcall 26, 9 - mov ebx, esi - sub ebx, eax + mcall 26, 9 + mov ebx, esi + sub ebx, eax ; 2f. Check that time is not over; if not, continue wait loop - cmp ebx, 500 - jbe .wait + cmp ebx, 500 + jbe .wait .timeout: ; 5. Timeout: abort and return error - push eax - call getaddrinfo_abort - and dword [edi], 0 - push EAI_AGAIN - pop eax + push eax + call getaddrinfo_abort + and dword [edi], 0 + push EAI_AGAIN + pop eax .ret.restore: ; 6. Restore event mask. - pop ebx ; get event mask (2) - push eax ; save return code (3) - mcall 40 - pop eax ; restore return code (3) + pop ebx ; get event mask (2) + push eax ; save return code (3) + mcall 40 + pop eax ; restore return code (3) .ret: ; 7. Restore stack pointer, used registers and return. - add esp, sizeof.__gai_reqdata ; undo (1) - pop edi esi ebx - ret 16 + add esp, sizeof.__gai_reqdata ; undo (1) + pop edi esi ebx + ret 16 ;;===========================================================================;; ;; int __stdcall getaddrinfo_start(__in const char* hostname, ;; @@ -353,7 +353,7 @@ getaddrinfo: ;; ;; __in const struct addrinfo* hints, ;; ;; __out struct addrinfo **res, ;; ;; __out struct __gai_reqdata* reqdata); ;; -getaddrinfo_start: ;; +getaddrinfo_start: ;; ;;---------------------------------------------------------------------------;; ;? Initiator for getaddrinfo, sends DNS request ;; ;;---------------------------------------------------------------------------;; @@ -374,356 +374,356 @@ getaddrinfo_start: ;; ;; 5. Assumes that IPv4 is always configured, so AI_ADDRCONFIG has no effect.;; ;;===========================================================================;; ; 0. Create stack frame and save used registers for __stdcall. - push ebx esi edi - push ebp - mov ebp, esp + push ebx esi edi + push ebp + mov ebp, esp virtual at ebp-8 -.recent_restsize dd ? ; this is for memory alloc in ._.generate_data -.recent_page dd ? ; this is for memory alloc in ._.generate_data - rd 5 ; saved regs and return address -.hostname dd ? -.servname dd ? -.hints dd ? -.res dd ? -.reqdata dd ? +.recent_restsize dd ? ; this is for memory alloc in ._.generate_data +.recent_page dd ? ; this is for memory alloc in ._.generate_data + rd 5 ; saved regs and return address +.hostname dd ? +.servname dd ? +.hints dd ? +.res dd ? +.reqdata dd ? end virtual - xor edi, edi - push edi ; init .recent_page - push edi ; init .recent_restsize + xor edi, edi + push edi ; init .recent_page + push edi ; init .recent_restsize ; 1. Check that parameters are correct and can be handled by this implementation. ; 1a. If 'res' pointer is given, set result to zero. - mov eax, [.res] - test eax, eax - jz @f - mov [eax], edi + mov eax, [.res] + test eax, eax + jz @f + mov [eax], edi @@: ; 1b. Only AI_SUPPORTED flags are supported for hints->ai_flags. - mov ecx, [.hints] - xor edx, edx - jecxz .nohints - mov edx, [ecx+addrinfo.ai_flags] + mov ecx, [.hints] + xor edx, edx + jecxz .nohints + mov edx, [ecx+addrinfo.ai_flags] .nohints: - mov ebx, [.reqdata] - mov [ebx+__gai_reqdata.flags], edx - push EAI_BADFLAGS - pop eax - test edx, not AI_SUPPORTED - jnz .ret + mov ebx, [.reqdata] + mov [ebx+__gai_reqdata.flags], edx + push EAI_BADFLAGS + pop eax + test edx, not AI_SUPPORTED + jnz .ret ; 1c. Either hostname or servname must be given. If AI_CANONNAME is set, ; hostname must also be set. - cmp [.hostname], edi - jnz @f - test dl, AI_CANONNAME - jnz .ret - push EAI_NONAME - pop eax - cmp [.servname], edi - jz .ret + cmp [.hostname], edi + jnz @f + test dl, AI_CANONNAME + jnz .ret + push EAI_NONAME + pop eax + cmp [.servname], edi + jz .ret @@: ; 1d. Only IPv4 is supported, so hints->ai_family must be either PF_UNSPEC or PF_INET. - push EAI_FAMILY - pop eax - jecxz @f - cmp [ecx+addrinfo.ai_family], edi - jz @f - cmp [ecx+addrinfo.ai_family], AF_INET4 - jnz .ret + push EAI_FAMILY + pop eax + jecxz @f + cmp [ecx+addrinfo.ai_family], edi + jz @f + cmp [ecx+addrinfo.ai_family], AF_INET4 + jnz .ret @@: ; 1e. Valid combinations for ai_socktype/ai_protocol: 0/0 for any or ; SOCK_STREAM/IPPROTO_TCP, SOCK_DGRAM/IPPROTO_UDP ; (raw socketnums are not yet supported by the kernel) - xor edx, edx ; assume 0=any if no hints - jecxz .socketnum_type_ok - mov edx, [ecx+addrinfo.ai_socktype] - mov esi, [ecx+addrinfo.ai_protocol] + xor edx, edx ; assume 0=any if no hints + jecxz .socketnum_type_ok + mov edx, [ecx+addrinfo.ai_socktype] + mov esi, [ecx+addrinfo.ai_protocol] ; 1f. Test for ai_socktype=0 and ai_protocol=0. - test edx, edx - jnz .check_socktype - test esi, esi - jz .socketnum_type_ok + test edx, edx + jnz .check_socktype + test esi, esi + jz .socketnum_type_ok ; 1g. ai_socktype=0, ai_protocol is nonzero. - push EAI_SERVICE - pop eax - inc edx ; edx = SOCK_STREAM - cmp esi, IPPROTO_TCP - jz .socketnum_type_ok - inc edx ; edx = SOCK_DGRAM - cmp esi, IPPROTO_UDP - jz .socketnum_type_ok + push EAI_SERVICE + pop eax + inc edx ; edx = SOCK_STREAM + cmp esi, IPPROTO_TCP + jz .socketnum_type_ok + inc edx ; edx = SOCK_DGRAM + cmp esi, IPPROTO_UDP + jz .socketnum_type_ok .ret: ; Restore saved registers, destroy stack frame and return. - mov esp, ebp - pop ebp - pop edi esi ebx - ret 20 + mov esp, ebp + pop ebp + pop edi esi ebx + ret 20 ; 1h. ai_socktype is nonzero. .check_socktype: - push EAI_SOCKTYPE - pop eax - cmp edx, SOCK_STREAM - jz .check_tcp - cmp edx, SOCK_DGRAM - jnz .ret - test esi, esi - jz .socketnum_type_ok - cmp esi, IPPROTO_UDP - jz .socketnum_type_ok - jmp .ret + push EAI_SOCKTYPE + pop eax + cmp edx, SOCK_STREAM + jz .check_tcp + cmp edx, SOCK_DGRAM + jnz .ret + test esi, esi + jz .socketnum_type_ok + cmp esi, IPPROTO_UDP + jz .socketnum_type_ok + jmp .ret .check_tcp: - test esi, esi - jz .socketnum_type_ok - cmp esi, IPPROTO_TCP - jnz .ret + test esi, esi + jz .socketnum_type_ok + cmp esi, IPPROTO_TCP + jnz .ret .socketnum_type_ok: - mov [ebx+__gai_reqdata.socktype], dl + mov [ebx+__gai_reqdata.socktype], dl ; 2. Resolve service. ; 2a. If no name is given, remember value -1. - push -1 - pop edx - mov esi, [.servname] - test esi, esi - jz .service_resolved + push -1 + pop edx + mov esi, [.servname] + test esi, esi + jz .service_resolved ; 2b. Loop for characters of string while digits are encountered. - xor edx, edx - xor eax, eax + xor edx, edx + xor eax, eax .serv_to_number: - lodsb - sub al, '0' - cmp al, 9 - ja .serv_to_number_done + lodsb + sub al, '0' + cmp al, 9 + ja .serv_to_number_done ; for each digit, set edx = edx*10 + - lea edx, [edx*5] - lea edx, [edx*2+eax] + lea edx, [edx*5] + lea edx, [edx*2+eax] ; check for correctness: service port must fit in word - cmp edx, 0x10000 - jae .service_not_number - jmp .serv_to_number + cmp edx, 0x10000 + jae .service_not_number + jmp .serv_to_number .serv_to_number_done: - and edx, 0xFFFF ; make sure that port fits + and edx, 0xFFFF ; make sure that port fits ; 2c. If zero character reached, name is resolved; ; otherwise, return error (no support for symbolic names yet) - cmp al, -'0' - jz .service_resolved + cmp al, -'0' + jz .service_resolved .service_not_number: - push EAI_NONAME - pop eax - jmp .ret + push EAI_NONAME + pop eax + jmp .ret .service_resolved: ; 2d. Save result to reqdata. - mov [ebx+__gai_reqdata.service], edx + mov [ebx+__gai_reqdata.service], edx ; 3. Process host name. - mov esi, [.hostname] + mov esi, [.hostname] ; 3a. If hostname is not given, ; use localhost for active socketnums and INADDR_ANY for passive socketnums. - mov eax, 0x0100007F ; 127.0.0.1 in network byte order - test byte [ebx+__gai_reqdata.flags], AI_PASSIVE - jz @f - xor eax, eax + mov eax, 0x0100007F ; 127.0.0.1 in network byte order + test byte [ebx+__gai_reqdata.flags], AI_PASSIVE + jz @f + xor eax, eax @@: - test esi, esi - jz .hostname_is_ip + test esi, esi + jz .hostname_is_ip ; 3b. Check for dotted IPv4 name. - push esi - call inet_addr - cmp eax, -1 - jz .resolve_hostname + push esi + call inet_addr + cmp eax, -1 + jz .resolve_hostname .hostname_is_ip: ; 3c. hostname is valid representation of IP address, and we have resolved it. ; Generate result, if .res pointer is not NULL. - mov ebx, [.reqdata] - mov esi, [.res] - test esi, esi - jz .no_result - call getaddrinfo._.generate_data + mov ebx, [.reqdata] + mov esi, [.res] + test esi, esi + jz .no_result + call getaddrinfo._.generate_data ; 3d. Check for memory allocation error. .3d: - push EAI_MEMORY - pop eax - test esi, esi - jz .ret + push EAI_MEMORY + pop eax + test esi, esi + jz .ret ; 3e. If AI_CANONNAME is set, copy input name. - test byte [ebx+__gai_reqdata.flags], AI_CANONNAME - jz .no_result + test byte [ebx+__gai_reqdata.flags], AI_CANONNAME + jz .no_result ; 3f. Calculate length of name. - push -1 - pop ecx - mov edi, [.hostname] - xor eax, eax - repnz scasb - not ecx + push -1 + pop ecx + mov edi, [.hostname] + xor eax, eax + repnz scasb + not ecx ; 3g. Check whether it fits on one page with main data. - cmp ecx, [.recent_restsize] - jbe .name_fits + cmp ecx, [.recent_restsize] + jbe .name_fits ; 3h. If not, allocate new page. - push ecx - add ecx, 4 ; first dword contains number of objects on the page - mcall 68, 12 - pop ecx + push ecx + add ecx, 4 ; first dword contains number of objects on the page + mcall 68, 12 + pop ecx ; 3i. If allocation has failed, free addrinfo and return error. - test eax, eax - jnz .name_allocated - push [.res] - call freeaddrinfo - push EAI_MEMORY - pop eax - jmp .ret + test eax, eax + jnz .name_allocated + push [.res] + call freeaddrinfo + push EAI_MEMORY + pop eax + jmp .ret .name_allocated: ; 3j. Otherwise, set edi to allocated memory and continue to 3l. - xchg edi, eax ; put result to edi - push 1 - pop eax - stosd ; number of objects on the page = 1 - jmp .copy_name + xchg edi, eax ; put result to edi + push 1 + pop eax + stosd ; number of objects on the page = 1 + jmp .copy_name .name_fits: ; 3k. Get pointer to free memory in allocated page. - mov edi, [.recent_page] - mov eax, edi - and eax, not 0xFFF - inc dword [eax] ; increase number of objects + mov edi, [.recent_page] + mov eax, edi + and eax, not 0xFFF + inc dword [eax] ; increase number of objects .copy_name: ; 3l. Put pointer to struct addrinfo. - mov eax, [.res] - mov eax, [eax] - mov [eax+addrinfo.ai_canonname], edi + mov eax, [.res] + mov eax, [eax] + mov [eax+addrinfo.ai_canonname], edi ; 3m. Copy name. - rep movsb + rep movsb .no_result: ; 3n. Return success. - xor eax, eax - jmp .ret + xor eax, eax + jmp .ret ; 4. Host address is not dotted IP. Test whether we are allowed to contact DNS. ; Return error if no. .resolve_hostname: - push EAI_NONAME - pop eax - mov ebx, [.reqdata] - test byte [ebx+__gai_reqdata.flags], AI_NUMERICHOST - jnz .ret + push EAI_NONAME + pop eax + mov ebx, [.reqdata] + test byte [ebx+__gai_reqdata.flags], AI_NUMERICHOST + jnz .ret ; Host address is domain name. Contact DNS server. - mov esi, [.hostname] + mov esi, [.hostname] ; 5. Reserve stack place for UDP packet. ; According to RFC1035, maximum UDP packet size in DNS is 512 bytes. - sub esp, 512 + sub esp, 512 ; 6. Create DNS request packet. ; 6a. Set pointer to start of buffer. - mov edi, esp + mov edi, esp ; 6b. Get request ID, write it to buffer. - push 1 - pop eax -lock xadd [DNSrequestID], eax ; atomically increment ID, get old value - stosw - mov [ebx+__gai_reqdata.reqid], ax + push 1 + pop eax +lock xadd [DNSrequestID], eax ; atomically increment ID, get old value + stosw + mov [ebx+__gai_reqdata.reqid], ax ; 6c. Packed field: QR=0 (query), Opcode=0000 (standard query), ; AA=0 (ignored in requests), TC=0 (no truncation), ; RD=1 (recursion desired) - mov al, 00000001b - stosb + mov al, 00000001b + stosb ; 6d. Packed field: ignored in requests - mov al, 0 - stosb + mov al, 0 + stosb ; 6e. Write questions count = 1 and answers count = 0 ; Note that network byte order is big-endian. - mov eax, 0x00000100 - stosd + mov eax, 0x00000100 + stosd ; 6f. Write nameservers count = 0 and additional records count = 0 - xor eax, eax - stosd + xor eax, eax + stosd ; 6g. Write request data: name ; According to RFC1035, maximum length of name is 255 bytes. ; For correct names, buffer cannot overflow. - lea ebx, [esi+256] ; ebx = limit for name (including terminating zero) + lea ebx, [esi+256] ; ebx = limit for name (including terminating zero) ; translate string "www.yandex.ru" {00} to byte data {03} "www" {06} "yandex" {02} "ru" {00} -.nameloop: ; here we go in the start of each label: before "www", before "yandex", before "ru" - xor ecx, ecx ; ecx = length of current label - inc edi ; skip length, it will be filled later -.labelloop: ; here we go for each symbol of name - lodsb ; get next character - test al, al ; terminating zero? - jz .endname - cmp esi, ebx ; limit exceeded? - jae .wrongname - cmp al, '.' ; end of label? - jz .labelend - stosb ; put next character - inc ecx ; increment label length - jmp .labelloop +.nameloop: ; here we go in the start of each label: before "www", before "yandex", before "ru" + xor ecx, ecx ; ecx = length of current label + inc edi ; skip length, it will be filled later +.labelloop: ; here we go for each symbol of name + lodsb ; get next character + test al, al ; terminating zero? + jz .endname + cmp esi, ebx ; limit exceeded? + jae .wrongname + cmp al, '.' ; end of label? + jz .labelend + stosb ; put next character + inc ecx ; increment label length + jmp .labelloop .wrongname: - push EAI_NONAME - pop eax - jmp .ret + push EAI_NONAME + pop eax + jmp .ret .labelend: - test ecx, ecx ; null label can be only in the end of name - jz .wrongname + test ecx, ecx ; null label can be only in the end of name + jz .wrongname .endname: - cmp ecx, 63 - ja .wrongname + cmp ecx, 63 + ja .wrongname ; write length to byte [edi-ecx-1] - mov eax, ecx - neg eax - mov byte [edi+eax-1], cl - cmp byte [esi-1], 0 ; that was last label in the name? - jnz .nameloop + mov eax, ecx + neg eax + mov byte [edi+eax-1], cl + cmp byte [esi-1], 0 ; that was last label in the name? + jnz .nameloop ; write terminating zero if not yet - mov al, 0 - cmp byte [edi-1], al - jz @f - stosb + mov al, 0 + cmp byte [edi-1], al + jz @f + stosb @@: ; 6h. Write request data: ; query type = A (host address) = 1, ; query class = IN (internet IPv4 address) = 1 ; Note that network byte order is big-endian. - mov eax, 0x01000100 - stosd + mov eax, 0x01000100 + stosd ; 7. Get DNS server address. - mcall 76, 0x00000004 ; protocol IP=0, device number=0, function=get DNS address - cmp eax, -1 - je .ret.dnserr - mov esi, eax ; put server address to esi + mcall 76, API_IPv4 + 4 ; protocol IP=0, device number=0, function=get DNS address + cmp eax, -1 + je .ret.dnserr + mov esi, eax ; put server address to esi ; 8. Open UDP socketnum to DNS server, port 53. ; 8a. Create new socketnum. - mcall 75, 0, AF_INET4, SOCK_DGRAM - cmp eax, -1 ; error? - jz .ret.dnserr - mov ecx, eax ; put socketnum handle to ecx + mcall 75, 0, AF_INET4, SOCK_DGRAM + cmp eax, -1 ; error? + jz .ret.dnserr + mov ecx, eax ; put socketnum handle to ecx ; 8b. Create sockaddr structure on the stack. - push 0 - push 0 ; sin_zero - push esi ; sin_addr - push AF_INET4 + (53 shl 16) - ; sin_family and sin_port in network byte order + push 0 + push 0 ; sin_zero + push esi ; sin_addr + push AF_INET4 + (53 shl 16) + ; sin_family and sin_port in network byte order ; 8c. Connect. - mcall 75, 4, , esp, sizeof.sockaddr_in + mcall 75, 4, , esp, sizeof.sockaddr_in ; 8d. Restore the stack, undo 8b. - add esp, esi + add esp, esi ; 8e. Check result. - cmp eax, -1 - jz .ret.close + cmp eax, -1 + jz .ret.close ; 9. Send DNS request packet. - sub edi, esp ; get packet length - mov esi, edi - xor edi, edi - mcall 75, 6, , esp - cmp eax, -1 - jz .ret.close - mov eax, [.reqdata] - mov [eax+__gai_reqdata.socketnum], ecx - push -1 - pop eax ; return status: more processing required - jmp .ret.dns + sub edi, esp ; get packet length + mov esi, edi + xor edi, edi + mcall 75, 6, , esp + cmp eax, -1 + jz .ret.close + mov eax, [.reqdata] + mov [eax+__gai_reqdata.socketnum], ecx + push -1 + pop eax ; return status: more processing required + jmp .ret.dns .ret.close: - mcall 75, 1 + mcall 75, 1 .ret.dnserr: - push EAI_AGAIN - pop eax + push EAI_AGAIN + pop eax .ret.dns: ; 6. Restore stack pointer and return. - jmp .ret + jmp .ret ;;===========================================================================;; ;; int __stdcall getaddrinfo_process(__in struct __gai_reqdata* reqdata, ;; ;; __out struct addrinfo** res); ;; -getaddrinfo_process: ;; +getaddrinfo_process: ;; ;;---------------------------------------------------------------------------;; ;? Processes network events from DNS reply ;; ;;---------------------------------------------------------------------------;; @@ -733,208 +733,208 @@ getaddrinfo_process: ;; ;< eax = -1 if more processing required / 0 on success / >0 = error code ;; ;;===========================================================================;; ; 0. Create stack frame. - push ebp - mov ebp, esp + push ebp + mov ebp, esp virtual at ebp-.locals_size .locals_start: -.datagram rb 512 -.addrname dd ? -.name dd ? -.res_list_tail dd ? -.cname dd ? -.recent_restsize dd ? ; this is for memory alloc in ._.generate_data -.recent_page dd ? ; this is for memory alloc in ._.generate_data +.datagram rb 512 +.addrname dd ? +.name dd ? +.res_list_tail dd ? +.cname dd ? +.recent_restsize dd ? ; this is for memory alloc in ._.generate_data +.recent_page dd ? ; this is for memory alloc in ._.generate_data .locals_size = $ - .locals_start - rd 2 -.reqdata dd ? -.res dd ? + rd 2 +.reqdata dd ? +.res dd ? end virtual - xor eax, eax - push eax ; initialize .recent_page - push eax ; initialize .recent_restsize - push eax ; initialize .cname - push [.res] ; initialize .res_list_tail - sub esp, .locals_size-16 ; reserve place for other vars - mov edx, esp ; edx -> buffer for datagram + xor eax, eax + push eax ; initialize .recent_page + push eax ; initialize .recent_restsize + push eax ; initialize .cname + push [.res] ; initialize .res_list_tail + sub esp, .locals_size-16 ; reserve place for other vars + mov edx, esp ; edx -> buffer for datagram ; 1. Save used registers for __stdcall. - push ebx esi edi - mov edi, [.reqdata] + push ebx esi edi + mov edi, [.reqdata] ; 2. Read UDP datagram. - mov ecx, [edi+__gai_reqdata.socketnum] - push edi - mcall 75, 7, , , 512, 0 - pop edi + mov ecx, [edi+__gai_reqdata.socketnum] + push edi + mcall 75, 7, , , 512, 0 + pop edi ; 3. Ignore events for other socketnums (return if no data read) - test eax, eax - jz .ret.more_processing_required + test eax, eax + jz .ret.more_processing_required ; 4. Sanity check: discard too short packets. - xchg ecx, eax ; save packet length in ecx - cmp ecx, 12 - jb .ret.more_processing_required + xchg ecx, eax ; save packet length in ecx + cmp ecx, 12 + jb .ret.more_processing_required ; 5. Discard packets with ID != request ID. - mov eax, dword [edi+__gai_reqdata.reqid] - cmp ax, [edx] - jnz .ret.more_processing_required + mov eax, dword [edi+__gai_reqdata.reqid] + cmp ax, [edx] + jnz .ret.more_processing_required ; 6. Sanity check: discard query packets. - test byte [edx+2], 80h - jz .ret.more_processing_required + test byte [edx+2], 80h + jz .ret.more_processing_required ; 7. Sanity check: must be exactly one query (our). - cmp word [edx+4], 0x0100 ; note network byte order - jnz .ret.more_processing_required + cmp word [edx+4], 0x0100 ; note network byte order + jnz .ret.more_processing_required ; 8. Check for errors. Return EAI_NONAME for error code 3 and EAI_FAIL for other. - mov al, [edx+3] - and al, 0xF - jz @f - cmp al, 3 - jnz .ret.no_recovery - jmp .ret.no_name + mov al, [edx+3] + and al, 0xF + jz @f + cmp al, 3 + jnz .ret.no_recovery + jmp .ret.no_name @@: ; 9. Locate answers section. Exactly 1 query is present in this packet. - add ecx, edx ; ecx = limit - lea esi, [edx+12] - call .skip_name - lodsd ; skip QTYPE and QCLASS field - cmp esi, ecx - ja .ret.no_recovery + add ecx, edx ; ecx = limit + lea esi, [edx+12] + call .skip_name + lodsd ; skip QTYPE and QCLASS field + cmp esi, ecx + ja .ret.no_recovery ; 10. Loop through all answers. - movzx ebx, word [edx+6] ; get answers count - xchg bl, bh ; network -> Intel byte order + movzx ebx, word [edx+6] ; get answers count + xchg bl, bh ; network -> Intel byte order .answers_loop: - dec ebx - js .answers_done + dec ebx + js .answers_done ; 10a. Process each record. - mov [.name], esi + mov [.name], esi ; 10b. Skip name field. - call .skip_name + call .skip_name ; 10c. Get record information, handle two types for class IN (internet). - lodsd ; get type and class - cmp esi, ecx - ja .ret.no_recovery - cmp eax, 0x01000500 ; type=5, class=1? - jz .got_cname - cmp eax, 0x01000100 ; type=1, class=1? - jnz .answers_loop.next + lodsd ; get type and class + cmp esi, ecx + ja .ret.no_recovery + cmp eax, 0x01000500 ; type=5, class=1? + jz .got_cname + cmp eax, 0x01000100 ; type=1, class=1? + jnz .answers_loop.next .got_addr: ; 10d. Process record A, host address. - add esi, 10 - cmp esi, ecx - ja .ret.no_recovery - cmp word [esi-6], 0x0400 ; RDATA for A records must be 4 bytes long - jnz .ret.no_recovery - mov eax, [.name] - mov [.addrname], eax + add esi, 10 + cmp esi, ecx + ja .ret.no_recovery + cmp word [esi-6], 0x0400 ; RDATA for A records must be 4 bytes long + jnz .ret.no_recovery + mov eax, [.name] + mov [.addrname], eax ; 10e. Create corresponding record in the answer. - push ebx ecx esi - mov eax, [esi-4] ; IP address - mov esi, [.res_list_tail] ; pointer to result - test esi, esi - jz .no_result ; do not save if .res is NULL - mov ebx, [.reqdata] ; request data - call getaddrinfo._.generate_data - mov [.res_list_tail], esi - pop esi ecx ebx - cmp [.res_list_tail], 0 - jnz .answers_loop + push ebx ecx esi + mov eax, [esi-4] ; IP address + mov esi, [.res_list_tail] ; pointer to result + test esi, esi + jz .no_result ; do not save if .res is NULL + mov ebx, [.reqdata] ; request data + call getaddrinfo._.generate_data + mov [.res_list_tail], esi + pop esi ecx ebx + cmp [.res_list_tail], 0 + jnz .answers_loop ; 10f. If generate_data failed (this means memory allocation failure), abort - jmp .ret.no_memory + jmp .ret.no_memory .no_result: - pop esi ecx ebx - jmp .answers_loop + pop esi ecx ebx + jmp .answers_loop .got_cname: ; 10g. Process record CNAME, main host name. - lea eax, [esi+6] - mov [.cname], eax + lea eax, [esi+6] + mov [.cname], eax .answers_loop.next: ; 10h. Skip other record fields, advance to next record. - lodsd ; skip TTL - xor eax, eax - lodsw ; get length of RDATA field - xchg al, ah ; network -> Intel byte order - add esi, eax - cmp esi, ecx - ja .ret.no_recovery - jmp .answers_loop + lodsd ; skip TTL + xor eax, eax + lodsw ; get length of RDATA field + xchg al, ah ; network -> Intel byte order + add esi, eax + cmp esi, ecx + ja .ret.no_recovery + jmp .answers_loop .answers_done: ; 11. Check that there is at least 1 answer. - mov eax, [.res_list_tail] - cmp [.res], eax - jz .ret.no_data + mov eax, [.res_list_tail] + cmp [.res], eax + jz .ret.no_data ; 12. If canonical name was required, add it now. - mov eax, [.reqdata] - test byte [eax+__gai_reqdata.flags], AI_CANONNAME - jz .no_canon_name + mov eax, [.reqdata] + test byte [eax+__gai_reqdata.flags], AI_CANONNAME + jz .no_canon_name ; 12a. If at least one CNAME record is present, use name from last such record. ; Otherwise, use name from one of A records. - mov esi, [.cname] - test esi, esi - jnz .has_cname - mov esi, [.addrname] + mov esi, [.cname] + test esi, esi + jnz .has_cname + mov esi, [.addrname] .has_cname: ; 12b. Calculate name length. - call .get_name_length - jc .ret.no_recovery + call .get_name_length + jc .ret.no_recovery ; 12c. Check that the caller really want to get data. - cmp [.res], 0 - jz .no_canon_name + cmp [.res], 0 + jz .no_canon_name ; 12d. Allocate memory for name. - call getaddrinfo._.memalloc - test edi, edi - jz .ret.no_memory + call getaddrinfo._.memalloc + test edi, edi + jz .ret.no_memory ; 12e. Make first entry in .res list point to canonical name. - mov eax, [.res] - mov eax, [eax] - mov [eax+addrinfo.ai_canonname], edi + mov eax, [.res] + mov eax, [eax] + mov [eax+addrinfo.ai_canonname], edi ; 12f. Decode name. - call .decode_name + call .decode_name .no_canon_name: ; 13. Set status to success. - xor eax, eax - jmp .ret.close + xor eax, eax + jmp .ret.close ; Handle errors. .ret.more_processing_required: - push -1 - pop eax - jmp .ret + push -1 + pop eax + jmp .ret .ret.no_recovery: - push EAI_FAIL - pop eax - jmp .ret.destroy + push EAI_FAIL + pop eax + jmp .ret.destroy .ret.no_memory: - push EAI_MEMORY - pop eax - jmp .ret.destroy + push EAI_MEMORY + pop eax + jmp .ret.destroy .ret.no_name: .ret.no_data: - push EAI_NONAME - pop eax + push EAI_NONAME + pop eax .ret.destroy: ; 14. If an error occured, free memory acquired so far. - push eax - mov esi, [.res] - test esi, esi - jz @f - pushd [esi] - call freeaddrinfo - and dword [esi], 0 + push eax + mov esi, [.res] + test esi, esi + jz @f + pushd [esi] + call freeaddrinfo + and dword [esi], 0 @@: - pop eax + pop eax .ret.close: ; 15. Close socketnum. - push eax - mov ecx, [.reqdata] - mov ecx, [ecx+__gai_reqdata.socketnum] - mcall 75, 1 - pop eax + push eax + mov ecx, [.reqdata] + mov ecx, [ecx+__gai_reqdata.socketnum] + mcall 75, 1 + pop eax ; 16. Restore used registers, destroy stack frame and return. .ret: - pop edi esi ebx - mov esp, ebp - pop ebp - ret 8 + pop edi esi ebx + mov esp, ebp + pop ebp + ret 8 ;;===========================================================================;; ;; Internal auxiliary function for skipping names in DNS packet. ;; -.skip_name: ;; +.skip_name: ;; ;;---------------------------------------------------------------------------;; ;? Skips name in DNS packet. ;; ;;---------------------------------------------------------------------------;; @@ -943,24 +943,24 @@ end virtual ;;---------------------------------------------------------------------------;; ;< esi -> end of name ;; ;;===========================================================================;; - xor eax, eax - cmp esi, ecx - jae .skip_name.done - lodsb - test al, al - jz .skip_name.done - test al, 0xC0 - jnz .skip_name.pointer - add esi, eax - jmp .skip_name + xor eax, eax + cmp esi, ecx + jae .skip_name.done + lodsb + test al, al + jz .skip_name.done + test al, 0xC0 + jnz .skip_name.pointer + add esi, eax + jmp .skip_name .skip_name.pointer: - inc esi + inc esi .skip_name.done: - ret + ret ;;===========================================================================;; ;; Internal auxiliary function for calculating length of name in DNS packet. ;; -.get_name_length: ;; +.get_name_length: ;; ;;---------------------------------------------------------------------------;; ;? Calculate length of name (including terminating zero) in DNS packet. ;; ;;---------------------------------------------------------------------------;; @@ -971,41 +971,41 @@ end virtual ;< eax = length of name ;; ;< CF set on error / cleared on success ;; ;;===========================================================================;; - xor ebx, ebx ; ebx will hold data length + xor ebx, ebx ; ebx will hold data length .get_name_length.zero: - xor eax, eax + xor eax, eax .get_name_length.loop: - cmp esi, ecx - jae .get_name_length.fail - lodsb - test al, al - jz .get_name_length.done - test al, 0xC0 - jnz .get_name_length.pointer - add esi, eax - inc ebx - add ebx, eax - cmp ebx, 256 - jbe .get_name_length.loop + cmp esi, ecx + jae .get_name_length.fail + lodsb + test al, al + jz .get_name_length.done + test al, 0xC0 + jnz .get_name_length.pointer + add esi, eax + inc ebx + add ebx, eax + cmp ebx, 256 + jbe .get_name_length.loop .get_name_length.fail: - stc - ret + stc + ret .get_name_length.pointer: - and al, 0x3F - mov ah, al - lodsb - lea esi, [edx+eax] - jmp .get_name_length.zero + and al, 0x3F + mov ah, al + lodsb + lea esi, [edx+eax] + jmp .get_name_length.zero .get_name_length.done: - test ebx, ebx - jz .get_name_length.fail - xchg eax, ebx - clc - ret + test ebx, ebx + jz .get_name_length.fail + xchg eax, ebx + clc + ret ;;===========================================================================;; ;; Internal auxiliary function for decoding DNS name. ;; -.decode_name: ;; +.decode_name: ;; ;;---------------------------------------------------------------------------;; ;? Decode name in DNS packet. ;; ;;---------------------------------------------------------------------------;; @@ -1013,30 +1013,30 @@ end virtual ;> esi -> name in packet ;; ;> edi -> buffer for decoded name ;; ;;===========================================================================;; - xor eax, eax - lodsb - test al, al - jz .decode_name.done - test al, 0xC0 - jnz .decode_name.pointer - mov ecx, eax - rep movsb - mov al, '.' - stosb - jmp .decode_name + xor eax, eax + lodsb + test al, al + jz .decode_name.done + test al, 0xC0 + jnz .decode_name.pointer + mov ecx, eax + rep movsb + mov al, '.' + stosb + jmp .decode_name .decode_name.pointer: - and al, 0x3F - mov ah, al - lodsb - lea esi, [edx+eax] - jmp .decode_name + and al, 0x3F + mov ah, al + lodsb + lea esi, [edx+eax] + jmp .decode_name .decode_name.done: - mov byte [edi-1], 0 - ret + mov byte [edi-1], 0 + ret ;;===========================================================================;; ;; Internal auxiliary function for allocating memory for getaddrinfo. ;; -getaddrinfo._.memalloc: ;; +getaddrinfo._.memalloc: ;; ;;---------------------------------------------------------------------------;; ;? Memory allocation. ;; ;;---------------------------------------------------------------------------;; @@ -1047,61 +1047,61 @@ getaddrinfo._.memalloc: ;; ;< edi -> allocated memory / NULL on error ;; ;;===========================================================================;; ; 1. Set edi to result of function. - mov edi, [ebp-4] + mov edi, [ebp-4] ; 2. Check whether we need to allocate a new page. - cmp eax, [ebp-8] - jbe .no_new_page + cmp eax, [ebp-8] + jbe .no_new_page ; 2. Allocate new page if need. Reset edi to new result. - push eax ebx - mcall 68, 12, 0x1000 - xchg edi, eax ; put result to edi - pop ebx eax + push eax ebx + mcall 68, 12, 0x1000 + xchg edi, eax ; put result to edi + pop ebx eax ; 3. Check returned value of allocator. Fail if it failed. - test edi, edi - jz .ret + test edi, edi + jz .ret ; 4. Update .recent_page and .recent_restsize. - add edi, 4 - sub ecx, 4 - mov [ebp-4], edi - mov [ebp-8], ecx + add edi, 4 + sub ecx, 4 + mov [ebp-4], edi + mov [ebp-8], ecx .no_new_page: ; 5. Increase number of objects on this page. - push eax - mov eax, edi - and eax, not 0xFFF - inc dword [eax] - pop eax + push eax + mov eax, edi + and eax, not 0xFFF + inc dword [eax] + pop eax ; 6. Advance last allocated pointer, decrease memory size. - add [ebp-4], eax - sub [ebp-8], eax + add [ebp-4], eax + sub [ebp-8], eax ; 7. Return. .ret: - ret + ret ;;===========================================================================;; ;; Internal auxiliary function for freeing memory for freeaddrinfo. ;; -getaddrinfo._.memfree: ;; +getaddrinfo._.memfree: ;; ;;---------------------------------------------------------------------------;; ;? Free memory. ;; ;;---------------------------------------------------------------------------;; ;> eax = pointer ;; ;;===========================================================================;; ; 1. Get start of page. - mov ecx, eax - and ecx, not 0xFFF + mov ecx, eax + and ecx, not 0xFFF ; 2. Decrease number of objects. - dec dword [ecx] + dec dword [ecx] ; 3. If it goes to zero, free the page. - jnz @f - push ebx - mcall 68, 13 - pop ebx + jnz @f + push ebx + mcall 68, 13 + pop ebx @@: ; 4. Done. - ret + ret ;;===========================================================================;; -getaddrinfo._.generate_data: ;; +getaddrinfo._.generate_data: ;; ;;---------------------------------------------------------------------------;; ;? Generate item(s) of getaddrinfo result list by one IP address. ;; ;;---------------------------------------------------------------------------;; @@ -1115,122 +1115,122 @@ getaddrinfo._.generate_data: ;; ;;===========================================================================;; ; 1. If no service is given, append one item with zero port. ; append one item with zero socktype/protocol/port. - cmp [ebx+__gai_reqdata.service], -1 - jnz .has_service - call .append_item + cmp [ebx+__gai_reqdata.service], -1 + jnz .has_service + call .append_item ; 1a. If neither protocol nor socktype were specified, ; leave zeroes in socktype and protocol. - mov cl, [ebx+__gai_reqdata.socktype] - test cl, cl - jz .no_socktype + mov cl, [ebx+__gai_reqdata.socktype] + test cl, cl + jz .no_socktype ; 1b. Otherwise, set socktype and protocol to desired. - call .set_socktype + call .set_socktype .no_socktype: - ret + ret .has_service: ; 2. If TCP is allowed, append item for TCP. - cmp [ebx+__gai_reqdata.socktype], 0 - jz .tcp_ok - cmp [ebx+__gai_reqdata.socktype], SOCK_STREAM - jnz .tcp_disallowed + cmp [ebx+__gai_reqdata.socktype], 0 + jz .tcp_ok + cmp [ebx+__gai_reqdata.socktype], SOCK_STREAM + jnz .tcp_disallowed .tcp_ok: - call .append_item - mov cl, SOCK_STREAM - call .set_socktype - call .set_port + call .append_item + mov cl, SOCK_STREAM + call .set_socktype + call .set_port .tcp_disallowed: ; 3. If UDP is allowed, append item for UDP. - cmp [ebx+__gai_reqdata.socktype], 0 - jz .udp_ok - cmp [ebx+__gai_reqdata.socktype], SOCK_DGRAM - jnz .udp_disallowed + cmp [ebx+__gai_reqdata.socktype], 0 + jz .udp_ok + cmp [ebx+__gai_reqdata.socktype], SOCK_DGRAM + jnz .udp_disallowed .udp_ok: - call .append_item - mov cl, SOCK_DGRAM - call .set_socktype - call .set_port + call .append_item + mov cl, SOCK_DGRAM + call .set_socktype + call .set_port .udp_disallowed: - ret + ret .append_item: ; 1. Allocate memory for struct sockaddr_in and struct addrinfo. - push eax - push sizeof.addrinfo + sizeof.sockaddr_in - pop eax - call getaddrinfo._.memalloc + push eax + push sizeof.addrinfo + sizeof.sockaddr_in + pop eax + call getaddrinfo._.memalloc ; 2. Check for memory allocation fail. - test edi, edi - jz .no_memory + test edi, edi + jz .no_memory ; 3. Zero allocated memory. - push (sizeof.addrinfo + sizeof.sockaddr_in) / 4 - pop ecx - xor eax, eax - push edi - rep stosd - pop edi + push (sizeof.addrinfo + sizeof.sockaddr_in) / 4 + pop ecx + xor eax, eax + push edi + rep stosd + pop edi ; 4. Fill struct addrinfo. - mov eax, [ebx+__gai_reqdata.flags] - mov [edi+addrinfo.ai_flags], eax - mov byte [edi+addrinfo.ai_family], AF_INET4 - mov byte [edi+addrinfo.ai_addrlen], sizeof.sockaddr_in - lea ecx, [edi+sizeof.addrinfo] - mov [edi+addrinfo.ai_addr], ecx + mov eax, [ebx+__gai_reqdata.flags] + mov [edi+addrinfo.ai_flags], eax + mov byte [edi+addrinfo.ai_family], AF_INET4 + mov byte [edi+addrinfo.ai_addrlen], sizeof.sockaddr_in + lea ecx, [edi+sizeof.addrinfo] + mov [edi+addrinfo.ai_addr], ecx ; 5. Fill struct sockaddr_in. - mov byte [ecx+sockaddr_in.sin_family], AF_INET4 - pop eax - mov [ecx+sockaddr_in.sin_addr], eax + mov byte [ecx+sockaddr_in.sin_family], AF_INET4 + pop eax + mov [ecx+sockaddr_in.sin_addr], eax ; 6. Append new item to the list. - mov [esi], edi - lea esi, [edi+addrinfo.ai_next] + mov [esi], edi + lea esi, [edi+addrinfo.ai_next] ; 7. Return. - ret + ret .no_memory: - pop eax - xor esi, esi - ret + pop eax + xor esi, esi + ret .set_socktype: ; Set ai_socktype and ai_protocol fields by given socketnum type. - mov byte [edi+addrinfo.ai_socktype], cl - dec cl - jnz .set_udp + mov byte [edi+addrinfo.ai_socktype], cl + dec cl + jnz .set_udp .set_tcp: - mov byte [edi+addrinfo.ai_protocol], IPPROTO_TCP - ret + mov byte [edi+addrinfo.ai_protocol], IPPROTO_TCP + ret .set_udp: - mov byte [edi+addrinfo.ai_protocol], IPPROTO_UDP - ret + mov byte [edi+addrinfo.ai_protocol], IPPROTO_UDP + ret .set_port: ; Just copy port from input __gai_reqdata to output addrinfo. - push edx - mov edx, [ebx+__gai_reqdata.service] - xchg dl, dh ; convert to network byte order - mov [edi+sizeof.addrinfo+sockaddr_in.sin_port], dx - pop edx - ret + push edx + mov edx, [ebx+__gai_reqdata.service] + xchg dl, dh ; convert to network byte order + mov [edi+sizeof.addrinfo+sockaddr_in.sin_port], dx + pop edx + ret ;;===========================================================================;; ;; void __stdcall getaddrinfo_abort(__in struct __gai_reqdata* reqdata); ;; -getaddrinfo_abort: ;; +getaddrinfo_abort: ;; ;;---------------------------------------------------------------------------;; ;? Abort process started by getaddrinfo_start, free all resources. ;; ;;---------------------------------------------------------------------------;; ;> first parameter = pointer to struct __gai_reqdata filled by ..._start ;; ;;===========================================================================;; ; 0. Save used registers for __stdcall. - push ebx + push ebx ; 1. Allocated resources: only socketnum, so close it and return. - mov eax, [esp+8] - mov ecx, [eax+__gai_reqdata.socketnum] - mcall 75, 1 + mov eax, [esp+8] + mov ecx, [eax+__gai_reqdata.socketnum] + mcall 75, 1 ; 2. Restore used registers and return. - pop ebx - ret 4 + pop ebx + ret 4 ;;===========================================================================;; ;; void __stdcall freeaddrinfo(__in struct addrinfo* ai); ;; -freeaddrinfo: ;; +freeaddrinfo: ;; ;;---------------------------------------------------------------------------;; ;? Free one or more addrinfo structures returned by getaddrinfo. ;; ;;---------------------------------------------------------------------------;; @@ -1238,29 +1238,29 @@ freeaddrinfo: ;; ; (may be arbitrary sublist of original) ;; ;;===========================================================================;; ; 1. Loop for all items in the list. - mov edx, [esp+4] ; eax = ai + mov edx, [esp+4] ; eax = ai .loop: - test edx, edx - jz .done + test edx, edx + jz .done ; 2. Free each item. ; 2a. Free ai_canonname, if allocated. - mov eax, [edx+addrinfo.ai_canonname] - test eax, eax - jz .no_canon_name - call getaddrinfo._.memfree + mov eax, [edx+addrinfo.ai_canonname] + test eax, eax + jz .no_canon_name + call getaddrinfo._.memfree .no_canon_name: ; 2b. Remember next item ; (after freeing the field ai_next can became unavailable). - pushd [edx+addrinfo.ai_next] + pushd [edx+addrinfo.ai_next] ; 2c. Free item itself. - xchg eax, edx - call getaddrinfo._.memfree + xchg eax, edx + call getaddrinfo._.memfree ; 2d. Restore pointer to next item and continue loop. - pop edx - jmp .loop + pop edx + jmp .loop .done: ; 3. Done. - ret 4 + ret 4 ;;===========================================================================;; ;;///////////////////////////////////////////////////////////////////////////;; @@ -1273,25 +1273,25 @@ freeaddrinfo: ;; align 4 @EXPORT: -export \ - lib_init , 'lib_init' , \ - 0x00010001 , 'version' , \ - inet_addr , 'inet_addr' , \ - inet_ntoa , 'inet_ntoa' , \ - getaddrinfo , 'getaddrinfo' , \ - getaddrinfo_start , 'getaddrinfo_start' , \ - getaddrinfo_process , 'getaddrinfo_process' , \ - getaddrinfo_abort , 'getaddrinfo_abort' , \ - freeaddrinfo , 'freeaddrinfo' +export \ + lib_init , 'lib_init' , \ + 0x00010001 , 'version' , \ + inet_addr , 'inet_addr' , \ + inet_ntoa , 'inet_ntoa' , \ + getaddrinfo , 'getaddrinfo' , \ + getaddrinfo_start , 'getaddrinfo_start' , \ + getaddrinfo_process , 'getaddrinfo_process' , \ + getaddrinfo_abort , 'getaddrinfo_abort' , \ + freeaddrinfo , 'freeaddrinfo' ; import from libini align 4 @IMPORT: library libini, 'libini.obj' -import libini, \ - ini.get_str, 'ini_get_str', \ - ini.get_int, 'ini_get_int' +import libini, \ + ini.get_str, 'ini_get_str', \ + ini.get_int, 'ini_get_int' section '.data' data readable writable align 16 @@ -1301,6 +1301,6 @@ mem.free dd ? mem.realloc dd ? dll.load dd ? -DNSrequestID dd ? +DNSrequestID dd ? -inet_ntoa.buffer rb 16 ; static buffer for inet_ntoa +inet_ntoa.buffer rb 16 ; static buffer for inet_ntoa