Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 2313 → Rev 2314

/kernel/branches/net/make.sh
File deleted
Property changes:
Deleted: svn:mergeinfo
/kernel/branches/net/makefile
File deleted
Property changes:
Deleted: svn:mergeinfo
/kernel/branches/net/applications/network_lib/network.asm
File deleted
Property changes:
Deleted: svn:keywords
-Revision
\ No newline at end of property
Deleted: svn:mergeinfo
/kernel/branches/net/applications/icmp_test/icmp.asm
File deleted
/kernel/branches/net/applications/icmp/icmp.asm
0,0 → 1,319
use32
org 0x0
; standard header
db 'MENUET01' ; signature
dd 1 ; header version
dd start ; entry point
dd I_END ; initialized size
dd mem ; required memory
dd mem ; stack pointer
dd 0 ; parameters
dd 0 ; path
 
 
BUFFERSIZE equ 1500
; useful includes
include '../macros.inc'
purge mov,add,sub
include '../proc32.inc'
include '../dll.inc'
 
include '../network.inc'
 
 
 
; ICMP types & codes
 
ICMP_ECHOREPLY equ 0 ; echo reply message
 
ICMP_UNREACH equ 3
ICMP_UNREACH_NET equ 0 ; bad net
ICMP_UNREACH_HOST equ 1 ; bad host
ICMP_UNREACH_PROTOCOL equ 2 ; bad protocol
ICMP_UNREACH_PORT equ 3 ; bad port
ICMP_UNREACH_NEEDFRAG equ 4 ; IP_DF caused drop
ICMP_UNREACH_SRCFAIL equ 5 ; src route failed
ICMP_UNREACH_NET_UNKNOWN equ 6 ; unknown net
ICMP_UNREACH_HOST_UNKNOWN equ 7 ; unknown host
ICMP_UNREACH_ISOLATED equ 8 ; src host isolated
ICMP_UNREACH_NET_PROHIB equ 9 ; prohibited access
ICMP_UNREACH_HOST_PROHIB equ 10 ; ditto
ICMP_UNREACH_TOSNET equ 11 ; bad tos for net
ICMP_UNREACH_TOSHOST equ 12 ; bad tos for host
ICMP_UNREACH_FILTER_PROHIB equ 13 ; admin prohib
ICMP_UNREACH_HOST_PRECEDENCE equ 14 ; host prec vio.
ICMP_UNREACH_PRECEDENCE_CUTOFF equ 15 ; prec cutoff
 
ICMP_SOURCEQUENCH equ 4 ; Packet lost, slow down
 
ICMP_REDIRECT equ 5 ; shorter route, codes:
ICMP_REDIRECT_NET equ 0 ; for network
ICMP_REDIRECT_HOST equ 1 ; for host
ICMP_REDIRECT_TOSNET equ 2 ; for tos and net
ICMP_REDIRECT_TOSHOST equ 3 ; for tos and host
 
ICMP_ALTHOSTADDR equ 6 ; alternate host address
ICMP_ECHO equ 8 ; echo service
ICMP_ROUTERADVERT equ 9 ; router advertisement
ICMP_ROUTERADVERT_NORMAL equ 0 ; normal advertisement
ICMP_ROUTERADVERT_NOROUTE_COMMON equ 16 ; selective routing
 
ICMP_ROUTERSOLICIT equ 10 ; router solicitation
ICMP_TIMXCEED equ 11 ; time exceeded, code:
ICMP_TIMXCEED_INTRANS equ 0 ; ttl==0 in transit
ICMP_TIMXCEED_REASS equ 1 ; ttl==0 in reass
 
ICMP_PARAMPROB equ 12 ; ip header bad
ICMP_PARAMPROB_ERRATPTR equ 0 ; error at param ptr
ICMP_PARAMPROB_OPTABSENT equ 1 ; req. opt. absent
ICMP_PARAMPROB_LENGTH equ 2 ; bad length
 
ICMP_TSTAMP equ 13 ; timestamp request
ICMP_TSTAMPREPLY equ 14 ; timestamp reply
ICMP_IREQ equ 15 ; information request
ICMP_IREQREPLY equ 16 ; information reply
ICMP_MASKREQ equ 17 ; address mask request
ICMP_MASKREPLY equ 18 ; address mask reply
ICMP_TRACEROUTE equ 30 ; traceroute
ICMP_DATACONVERR equ 31 ; data conversion error
ICMP_MOBILE_REDIRECT equ 32 ; mobile host redirect
ICMP_IPV6_WHEREAREYOU equ 33 ; IPv6 where-are-you
ICMP_IPV6_IAMHERE equ 34 ; IPv6 i-am-here
ICMP_MOBILE_REGREQUEST equ 35 ; mobile registration req
ICMP_MOBILE_REGREPLY equ 36 ; mobile registreation reply
ICMP_SKIP equ 39 ; SKIP
 
ICMP_PHOTURIS equ 40 ; Photuris
ICMP_PHOTURIS_UNKNOWN_INDEX equ 1 ; unknown sec index
ICMP_PHOTURIS_AUTH_FAILED equ 2 ; auth failed
ICMP_PHOTURIS_DECRYPT_FAILED equ 3 ; decrypt failed
 
 
 
virtual at 0
ICMP_Packet:
.Type db ?
.Code db ?
.Checksum dw ?
.Identifier dw ?
.SequenceNumber dw ?
.Data:
end virtual
 
 
; entry point
start:
; load libraries
stdcall dll.Load, @IMPORT
test eax, eax
jnz exit
; initialize console
push 1
call [con_start]
push title
push 25
push 80
push 25
push 80
call [con_init]
; main loop
push str1
call [con_write_asciiz]
main:
; write prompt
push str2
call [con_write_asciiz]
; read string
mov esi, s
push 256
push esi
call [con_gets]
; check for exit
test eax, eax
jz done
cmp byte [esi], 10
jz done
; delete terminating '\n'
push esi
@@:
lodsb
test al, al
jnz @b
mov byte [esi-2], al
pop esi
; resolve name
push esp ; reserve stack place
push esp ; fourth parameter
push 0 ; third parameter
push 0 ; second parameter
push esi ; first parameter
call [getaddrinfo]
pop esi
; test for error
test eax, eax
jnz fail
 
; convert IP address to decimal notation
mov eax, [esi+addrinfo.ai_addr]
mov eax, [eax+sockaddr_in.sin_addr]
mov [sockaddr1.ip], eax
push eax
call [inet_ntoa]
; write result
mov [ip_ptr], eax
 
push eax
 
; free allocated memory
push esi
call [freeaddrinfo]
 
push str4
call [con_write_asciiz]
 
mcall socket, AF_INET4, SOCK_RAW, IPPROTO_ICMP
cmp eax, -1
jz fail2
mov [socketnum], eax
 
mcall connect, [socketnum], sockaddr1, 18
 
mcall 40, 1 shl 7 ; + 7
; call [con_cls]
 
mov [count], 4
 
mainloop:
push str3
call [con_write_asciiz]
push [ip_ptr]
call [con_write_asciiz]
 
mcall 26,9
mov [time_reference], eax
mcall send, [socketnum], icmp_packet, icmp_packet.length, 0
 
mcall 23, 300 ; 3 seconds time-out
mcall 26,9
neg [time_reference]
add [time_reference], eax
 
mcall recv, [socketnum], buffer_ptr, BUFFERSIZE, 0
cmp eax, -1
je .no_response
 
; validate the packet
lea esi, [buffer_ptr + ICMP_Packet.Data]
mov edi, icmp_packet.data
mov ecx, 32/4
repe cmpsd
jne .miscomp
 
push [time_reference]
push str7
call [con_printf]
 
jmp continue
 
.miscomp:
sub edi, icmp_packet.data
push edi
push str9
call [con_printf]
jmp continue
 
.no_response:
push str8
call [con_write_asciiz]
 
continue:
dec [count]
jz done
mcall 5, 100 ; wait a second
inc [icmp_packet.id]
jmp mainloop
 
 
 
done:
push str10
call [con_write_asciiz]
call [con_getch2]
push 1
call [con_exit]
exit:
mcall -1
 
fail:
push str5
call [con_write_asciiz]
jmp done
fail2:
push str6
call [con_write_asciiz]
jmp done
 
 
; data
title db 'ICMP - test application',0
str1 db 'ICMP test application v0.1',10,' for KolibriOS # 1540 or later. ',10,10,0
str2 db '> ',0
str3 db 'Ping to: ',0
str4 db 10,0
str5 db 'Name resolution failed.',10,10,0
str6 db 'Could not open socket',10,10,0
str7 db ' time= %u0ms',10,0
str8 db ' timeout!',10,0
str9 db ' miscompare at offset %u',10,0
str10 db 10,10,'Press any key to exit',0
 
sockaddr1:
dw AF_INET4
.port dw 0
.ip dd 0
rb 10
 
time_reference dd ?
ip_ptr dd ?
count dd ?
 
 
; import
align 4
@IMPORT:
 
library network, 'network.obj', console, 'console.obj'
import network, \
getaddrinfo, 'getaddrinfo', \
freeaddrinfo, 'freeaddrinfo', \
inet_ntoa, 'inet_ntoa'
 
import console, \
con_start, 'START', \
con_init, 'con_init', \
con_write_asciiz, 'con_write_asciiz', \
con_printf, 'con_printf', \
con_exit, 'con_exit', \
con_gets, 'con_gets',\
con_cls, 'con_cls',\
con_getch2, 'con_getch2',\
con_set_cursor_pos, 'con_set_cursor_pos'
 
socketnum dd ?
 
icmp_packet: db 8 ; type
db 0 ; code
dw 0 ;
.id dw 0x0000 ; identifier
.seq dw 0x0001 ; sequence number
.data db 'abcdefghijklmnopqrstuvwxyz012345678'
.length = $ - icmp_packet
 
I_END:
 
buffer_ptr rb BUFFERSIZE
 
s rb 256
align 4
rb 4096 ; stack
mem:
/kernel/branches/net/applications/libraries/network/network.asm
0,0 → 1,1306
format MS COFF
 
public @EXPORT as 'EXPORTS'
 
include '../../struct.inc'
include '../../proc32.inc'
include '../../macros.inc'
purge section,mov,add,sub
 
include '../../network.inc'
 
section '.flat' code readable align 16
 
;;===========================================================================;;
lib_init: ;//////////////////////////////////////////////////////////////////;;
;;---------------------------------------------------------------------------;;
;? Library entry point (called after library load) ;;
;;---------------------------------------------------------------------------;;
;> eax = pointer to memory allocation routine ;;
;> ebx = pointer to memory freeing routine ;;
;> ecx = pointer to memory reallocation routine ;;
;> edx = pointer to library loading routine ;;
;;---------------------------------------------------------------------------;;
;< 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
 
;;===========================================================================;;
;; in_addr_t __stdcall inet_addr(__in const char* hostname); ;;
inet_addr: ;;
;;---------------------------------------------------------------------------;;
;? Convert the string from standard IPv4 dotted notation to integer IP addr. ;;
;;---------------------------------------------------------------------------;;
;> first parameter = host name ;;
;;---------------------------------------------------------------------------;;
;< eax = IP address on success / -1 on error ;;
;;===========================================================================;;
; 0. Save used registers for __stdcall.
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
.calcdots_loop:
; loop for all characters in string
lodsb
; check for end of string
cmp al, 0
jz .calcdots_loop_done
; check for dot
cmp al, '.'
jz .dot
; check for digit
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
; check for 'x'/'X'
cmp al, 'X' - 'A'
jz .calcdots_loop
jmp .fail.pop
.dot:
inc ecx
jmp .calcdots_loop
.calcdots_loop_done:
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
; 2a. Convert name except for last group.
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
; 2b. Convert last group.
.ip_convert_2b:
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
; 2c. Convert to network byte order.
bswap edi
; 3. Set return value, restore used registers and return.
xchg eax, edi
.ret:
pop edi esi ebx
ret 4
; 4. On error, return -1.
.fail.pop:
pop esi
.fail:
push -1
pop eax
jmp .ret
 
;;===========================================================================;;
;; Internal auxiliary function for IP parsing. ;;
.get_number: ;;
;;---------------------------------------------------------------------------;;
;? Converts string to number. ;;
;;---------------------------------------------------------------------------;;
;> esi -> string ;;
;> ecx = limit for number ;;
;;---------------------------------------------------------------------------;;
;< eax = number ;;
;< CF set on error (too big number) / cleared on success ;;
;< esi -> end of number representation ;;
;;===========================================================================;;
; 0. Save edx, which is used in caller.
push edx
; 1. Initialize number, zero eax so that lodsb gets full dword.
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
; 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
.digit:
; 5. Digit must be less than base of numeral system.
cmp eax, ebx
jae .convert_done
; 6. Advance the number.
imul edx, ebx
add edx, eax
cmp edx, ecx
ja .gn_error
; 3b. Continue loop.
lodsb
jmp .convert
.convert_done:
; 7. Invalid character, number converted, return success.
xchg eax, edx
pop edx
clc
ret
.gn_error:
; 8. Too big number, return error.
pop edx
stc
ret
 
;;===========================================================================;;
;; char* __stdcall inet_ntoa(struct in_addr in); ;;
inet_ntoa: ;;
;;---------------------------------------------------------------------------;;
;? Convert the Internet host address to standard IPv4 dotted notation. ;;
;;---------------------------------------------------------------------------;;
;> first parameter = host address ;;
;;---------------------------------------------------------------------------;;
;< 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
; 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
; 2. Replace final dot with terminating zero.
mov byte [edi-1], 0
; 3. Restore used registers, set result value and return.
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
.2digit:
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
 
struct __gai_reqdata
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
ends
 
;;===========================================================================;;
;; int __stdcall getaddrinfo(__in const char* hostname, ;;
;; __in const char* servname, ;;
;; __in const struct addrinfo* hints, ;;
;; __out struct addrinfo **res); ;;
getaddrinfo: ;;
;;---------------------------------------------------------------------------;;
;? Get a list of IP addresses and port numbers for given host and service ;;
;;---------------------------------------------------------------------------;;
;> first parameter (optional) = host name ;;
;> second parameter (optional) = service name (decimal number for now) ;;
;> third parameter (optional) = hints for socketnum type ;;
;> fourth parameter = pointer to result (head of L1-list) ;;
;;---------------------------------------------------------------------------;;
;< 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
; 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
; 2. Wait for DNS reply.
; 2a. Ignore all events except network stack.
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
.wait:
; 2c. Wait for event with timeout.
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
; 3. Got packet. Call processing function.
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
; 2e. Recalculate timeout value.
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
.timeout:
; 5. Timeout: abort and return error
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)
.ret:
; 7. Restore stack pointer, used registers and return.
add esp, sizeof.__gai_reqdata ; undo (1)
pop edi esi ebx
ret 16
 
;;===========================================================================;;
;; int __stdcall getaddrinfo_start(__in const char* hostname, ;;
;; __in const char* servname, ;;
;; __in const struct addrinfo* hints, ;;
;; __out struct addrinfo **res, ;;
;; __out struct __gai_reqdata* reqdata); ;;
getaddrinfo_start: ;;
;;---------------------------------------------------------------------------;;
;? Initiator for getaddrinfo, sends DNS request ;;
;;---------------------------------------------------------------------------;;
;> first 4 parameters same as for getaddrinfo ;;
;> last parameter = pointer to buffer for __gai_reqdata, must be passed to ;;
;> getaddrinfo_process as is ;;
;;---------------------------------------------------------------------------;;
;< eax = <0 if wait loop must be entered / 0 on success / EAI_* on error ;;
;;===========================================================================;;
;; Known limitations: ;;
;; 1. No support for TCP connections => ;;
;; 1a. Long replies will be truncated, and not all IP addresses will be got. ;;
;; 2. No support for iterative resolving => ;;
;; 2a. In theory may fail with some servers. ;;
;; 3. Assumes that domain for relative names is always root, ".". ;;
;; 4. Does not support lookup of services by name, ;;
;; only decimal representation is supported. ;;
;; 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
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 ?
end virtual
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
@@:
; 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]
.nohints:
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
@@:
; 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
@@:
; 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]
; 1f. Test for ai_socktype=0 and ai_protocol=0.
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
.ret:
; Restore saved registers, destroy stack frame and return.
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
.check_tcp:
test esi, esi
jz .socketnum_type_ok
cmp esi, IPPROTO_TCP
jnz .ret
.socketnum_type_ok:
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
; 2b. Loop for characters of string while digits are encountered.
xor edx, edx
xor eax, eax
.serv_to_number:
lodsb
sub al, '0'
cmp al, 9
ja .serv_to_number_done
; for each digit, set edx = edx*10 + <digit>
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
.serv_to_number_done:
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
.service_not_number:
push EAI_NONAME
pop eax
jmp .ret
.service_resolved:
; 2d. Save result to reqdata.
mov [ebx+__gai_reqdata.service], edx
; 3. Process host name.
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
@@:
test esi, esi
jz .hostname_is_ip
; 3b. Check for dotted IPv4 name.
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
; 3d. Check for memory allocation error.
.3d:
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
; 3f. Calculate length of name.
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
; 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
; 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
.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
.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
.copy_name:
; 3l. Put pointer to struct addrinfo.
mov eax, [.res]
mov eax, [eax]
mov [eax+addrinfo.ai_canonname], edi
; 3m. Copy name.
rep movsb
.no_result:
; 3n. Return success.
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
; Host address is domain name. Contact DNS server.
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
; 6. Create DNS request packet.
; 6a. Set pointer to start of buffer.
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
; 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
; 6d. Packed field: ignored in requests
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
; 6f. Write nameservers count = 0 and additional records count = 0
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)
; 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
.wrongname:
push EAI_NONAME
pop eax
jmp .ret
.labelend:
test ecx, ecx ; null label can be only in the end of name
jz .wrongname
.endname:
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
; write terminating zero if not yet
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
; 7. Get DNS server address.
mcall 75, 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
; 8. Open UDP socketnum to DNS server, port 53.
; 8a. Create new socketnum.
mcall 74, 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
; 8c. Connect.
mcall 74, 4, , esp, sizeof.sockaddr_in
; 8d. Restore the stack, undo 8b.
add esp, esi
; 8e. Check result.
cmp eax, -1
jz .ret.close
; 9. Send DNS request packet.
sub edi, esp ; get packet length
mov esi, edi
xor edi, edi
mcall 74, 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 74, 1
.ret.dnserr:
push EAI_AGAIN
pop eax
.ret.dns:
; 6. Restore stack pointer and return.
jmp .ret
 
;;===========================================================================;;
;; int __stdcall getaddrinfo_process(__in struct __gai_reqdata* reqdata, ;;
;; __out struct addrinfo** res); ;;
getaddrinfo_process: ;;
;;---------------------------------------------------------------------------;;
;? Processes network events from DNS reply ;;
;;---------------------------------------------------------------------------;;
;> first parameter = pointer to struct __gai_reqdata filled by ..._start ;;
;> second parameter = same as for getaddrinfo ;;
;;---------------------------------------------------------------------------;;
;< eax = -1 if more processing required / 0 on success / >0 = error code ;;
;;===========================================================================;;
; 0. Create stack frame.
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
.locals_size = $ - .locals_start
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
; 1. Save used registers for __stdcall.
push ebx esi edi
mov edi, [.reqdata]
; 2. Read UDP datagram.
mov ecx, [edi+__gai_reqdata.socketnum]
push edi
mcall 74, 7, , , 512, 0
pop edi
; 3. Ignore events for other socketnums (return if no data read)
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
; 5. Discard packets with ID != request ID.
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
; 7. Sanity check: must be exactly one query (our).
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
@@:
; 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
; 10. Loop through all answers.
movzx ebx, word [edx+6] ; get answers count
xchg bl, bh ; network -> Intel byte order
.answers_loop:
dec ebx
js .answers_done
; 10a. Process each record.
mov [.name], esi
; 10b. Skip name field.
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
.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
; 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
; 10f. If generate_data failed (this means memory allocation failure), abort
jmp .ret.no_memory
.no_result:
pop esi ecx ebx
jmp .answers_loop
.got_cname:
; 10g. Process record CNAME, main host name.
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
.answers_done:
; 11. Check that there is at least 1 answer.
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
; 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]
.has_cname:
; 12b. Calculate name length.
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
; 12d. Allocate memory for name.
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
; 12f. Decode name.
call .decode_name
.no_canon_name:
; 13. Set status to success.
xor eax, eax
jmp .ret.close
; Handle errors.
.ret.more_processing_required:
push -1
pop eax
jmp .ret
.ret.no_recovery:
push EAI_FAIL
pop eax
jmp .ret.destroy
.ret.no_memory:
push EAI_MEMORY
pop eax
jmp .ret.destroy
.ret.no_name:
.ret.no_data:
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
@@:
pop eax
.ret.close:
; 15. Close socketnum.
push eax
mov ecx, [.reqdata]
mov ecx, [ecx+__gai_reqdata.socketnum]
mcall 74, 1
pop eax
; 16. Restore used registers, destroy stack frame and return.
.ret:
pop edi esi ebx
mov esp, ebp
pop ebp
ret 8
 
;;===========================================================================;;
;; Internal auxiliary function for skipping names in DNS packet. ;;
.skip_name: ;;
;;---------------------------------------------------------------------------;;
;? Skips name in DNS packet. ;;
;;---------------------------------------------------------------------------;;
;> esi -> name ;;
;> ecx = end of packet ;;
;;---------------------------------------------------------------------------;;
;< 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
.skip_name.pointer:
inc esi
.skip_name.done:
ret
 
;;===========================================================================;;
;; Internal auxiliary function for calculating length of name in DNS packet. ;;
.get_name_length: ;;
;;---------------------------------------------------------------------------;;
;? Calculate length of name (including terminating zero) in DNS packet. ;;
;;---------------------------------------------------------------------------;;
;> edx = start of packet ;;
;> esi -> name ;;
;> ecx = end of packet ;;
;;---------------------------------------------------------------------------;;
;< eax = length of name ;;
;< CF set on error / cleared on success ;;
;;===========================================================================;;
xor ebx, ebx ; ebx will hold data length
.get_name_length.zero:
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
.get_name_length.fail:
stc
ret
.get_name_length.pointer:
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
 
;;===========================================================================;;
;; Internal auxiliary function for decoding DNS name. ;;
.decode_name: ;;
;;---------------------------------------------------------------------------;;
;? Decode name in DNS packet. ;;
;;---------------------------------------------------------------------------;;
;> edx = start of packet ;;
;> 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
.decode_name.pointer:
and al, 0x3F
mov ah, al
lodsb
lea esi, [edx+eax]
jmp .decode_name
.decode_name.done:
mov byte [edi-1], 0
ret
 
;;===========================================================================;;
;; Internal auxiliary function for allocating memory for getaddrinfo. ;;
getaddrinfo._.memalloc: ;;
;;---------------------------------------------------------------------------;;
;? Memory allocation. ;;
;;---------------------------------------------------------------------------;;
;> eax = size in bytes, must be less than page size. ;;
;> [ebp-4] = .recent_page = last allocated page ;;
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page ;;
;;---------------------------------------------------------------------------;;
;< edi -> allocated memory / NULL on error ;;
;;===========================================================================;;
; 1. Set edi to result of function.
mov edi, [ebp-4]
; 2. Check whether we need to allocate a 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
; 3. Check returned value of allocator. Fail if it failed.
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
.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
; 6. Advance last allocated pointer, decrease memory size.
add [ebp-4], eax
sub [ebp-8], eax
; 7. Return.
.ret:
ret
 
;;===========================================================================;;
;; Internal auxiliary function for freeing memory for freeaddrinfo. ;;
getaddrinfo._.memfree: ;;
;;---------------------------------------------------------------------------;;
;? Free memory. ;;
;;---------------------------------------------------------------------------;;
;> eax = pointer ;;
;;===========================================================================;;
; 1. Get start of page.
mov ecx, eax
and ecx, not 0xFFF
; 2. Decrease number of objects.
dec dword [ecx]
; 3. If it goes to zero, free the page.
jnz @f
push ebx
mcall 68, 13
pop ebx
@@:
; 4. Done.
ret
 
;;===========================================================================;;
getaddrinfo._.generate_data: ;;
;;---------------------------------------------------------------------------;;
;? Generate item(s) of getaddrinfo result list by one IP address. ;;
;;---------------------------------------------------------------------------;;
;> eax = IP address ;;
;> ebx = request data ;;
;> esi = pointer to result ;;
;> [ebp-4] = .recent_page = last allocated page ;;
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page ;;
;;---------------------------------------------------------------------------;;
;< esi = pointer to next list item for result / NULL on error ;;
;;===========================================================================;;
; 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
; 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
; 1b. Otherwise, set socktype and protocol to desired.
call .set_socktype
.no_socktype:
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
.tcp_ok:
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
.udp_ok:
call .append_item
mov cl, SOCK_DGRAM
call .set_socktype
call .set_port
.udp_disallowed:
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
; 2. Check for memory allocation fail.
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
; 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
; 5. Fill struct sockaddr_in.
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]
; 7. Return.
ret
.no_memory:
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
.set_tcp:
mov byte [edi+addrinfo.ai_protocol], IPPROTO_TCP
ret
.set_udp:
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
 
;;===========================================================================;;
;; void __stdcall getaddrinfo_abort(__in struct __gai_reqdata* reqdata); ;;
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
; 1. Allocated resources: only socketnum, so close it and return.
mov eax, [esp+8]
mov ecx, [eax+__gai_reqdata.socketnum]
mcall 74, 1
; 2. Restore used registers and return.
pop ebx
ret 4
 
;;===========================================================================;;
;; void __stdcall freeaddrinfo(__in struct addrinfo* ai); ;;
freeaddrinfo: ;;
;;---------------------------------------------------------------------------;;
;? Free one or more addrinfo structures returned by getaddrinfo. ;;
;;---------------------------------------------------------------------------;;
;> first parameter = head of list of structures ;;
; (may be arbitrary sublist of original) ;;
;;===========================================================================;;
; 1. Loop for all items in the list.
mov edx, [esp+4] ; eax = ai
.loop:
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
.no_canon_name:
; 2b. Remember next item
; (after freeing the field ai_next can became unavailable).
pushd [edx+addrinfo.ai_next]
; 2c. Free item itself.
xchg eax, edx
call getaddrinfo._.memfree
; 2d. Restore pointer to next item and continue loop.
pop edx
jmp .loop
.done:
; 3. Done.
ret 4
 
;;===========================================================================;;
;;///////////////////////////////////////////////////////////////////////////;;
;;===========================================================================;;
;! Exported functions section ;;
;;===========================================================================;;
;;///////////////////////////////////////////////////////////////////////////;;
;;===========================================================================;;
 
 
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'
 
; import from libini
align 4
@IMPORT:
 
library libini, 'libini.obj'
import libini, \
ini.get_str, 'ini_get_str', \
ini.get_int, 'ini_get_int'
 
 
section '.data' data readable writable align 16
; uninitialized data
mem.alloc dd ?
mem.free dd ?
mem.realloc dd ?
dll.load dd ?
 
DNSrequestID dd ?
 
inet_ntoa.buffer rb 16 ; static buffer for inet_ntoa
/kernel/branches/net/applications/netcfg/drivers.inc
144,4 → 144,45
dd 0x604017F3
dd 0x0
 
db 'i8254x'
dd 0x10008086 ; 82542 (Fiber)
dd 0x10018086 ; 82543GC (Fiber)
dd 0x10048086 ; 82543GC (Copper)
dd 0x10088086 ; 82544EI (Copper)
dd 0x10098086 ; 82544EI (Fiber)
dd 0x100A8086 ; 82540EM
dd 0x100C8086 ; 82544GC (Copper)
dd 0x100D8086 ; 82544GC (LOM)
dd 0x100E8086 ; 82540EM
dd 0x100F8086 ; 82545EM (Copper)
dd 0x10108086 ; 82546EB (Copper)
dd 0x10118086 ; 82545EM (Fiber)
dd 0x10128086 ; 82546EB (Fiber)
dd 0x10138086 ; 82541EI
dd 0x10148086 ; 82541ER
dd 0x10158086 ; 82540EM (LOM)
dd 0x10168086 ; 82540EP (Mobile)
dd 0x10178086 ; 82540EP
dd 0x10188086 ; 82541EI
dd 0x10198086 ; 82547EI
dd 0x101a8086 ; 82547EI (Mobile)
dd 0x101d8086 ; 82546EB
dd 0x101e8086 ; 82540EP (Mobile)
dd 0x10268086 ; 82545GM
dd 0x10278086 ; 82545GM
dd 0x10288086 ; 82545GM
dd 0x105b8086 ; 82546GB (Copper)
dd 0x10758086 ; 82547GI
dd 0x10768086 ; 82541GI
dd 0x10778086 ; 82541GI
dd 0x10788086 ; 82541ER
dd 0x10798086 ; 82546GB
dd 0x107a8086 ; 82546GB
dd 0x107b8086 ; 82546GB
dd 0x107c8086 ; 82541PI
dd 0x10b58086 ; 82546GB (Copper)
dd 0x11078086 ; 82544EI
dd 0x11128086 ; 82544GC
dd 0x0
 
dd 0x0 ; driverlist end
/kernel/branches/net/applications/telnet/telnet.asm
10,7 → 10,7
dd 0 ; path
 
 
BUFFERSIZE equ 1500
BUFFERSIZE equ 4096
; useful includes
include '../macros.inc'
purge mov,add,sub
116,40 → 116,56
je mainloop
 
mov esi, buffer_ptr
mov byte [esi + eax], 0
lea edi, [esi + eax]
mov byte [edi], 0
 
@@:
.scan_cmd:
cmp byte [esi], 0xff ; Interpret As Command
jne @f
jne .no_cmd
; TODO: parse options, for now, we will reply with 'WONT' to everything
mov byte [esi + 1], 252 ; WONT
add esi, 3 ; a command is always 3 bytes
jmp @r
jmp .scan_cmd
.no_cmd:
 
push esi
 
cmp esi, buffer_ptr
je .print_it
 
push edi
mov edx, buffer_ptr
sub esi, buffer_ptr
xor edi, edi
mcall send, [socketnum]
pop edi
 
.print_it:
mov esi, [esp]
 
@@:
cmp esi, edi
jge .last_print
 
cmp byte [esi], 0x1b ; escape character
inc esi
jne @f
cmp word [esi+1], 0x485b ; move cursor to beginning
cmp word [esi], 0x485b ; move cursor to beginning
jne @f
 
mov byte [esi - 1], 0
call [con_write_asciiz]
push 0
push 0
call [con_set_cursor_pos]
add esi, 3
 
 
@@:
inc esi
inc esi
push esi
jmp @r
 
cmp esi, buffer_ptr
je .nocommands
 
mov edx, buffer_ptr
sub esi, buffer_ptr
xor edi, edi
mcall send, [socketnum]
 
.nocommands:
.last_print:
call [con_write_asciiz]
jmp mainloop
 
221,7 → 237,7
i_end:
 
socketnum dd ?
buffer_ptr rb BUFFERSIZE
buffer_ptr rb BUFFERSIZE+1
send_data rb 100
 
s rb 256
/kernel/branches/net/applications/tftpc/TFTP.asm
File deleted
\ No newline at end of file
/kernel/branches/net/applications/tftpc/tftpc.asm
0,0 → 1,561
use32
org 0x0
 
db 'MENUET01'
dd 0x1
dd START
dd I_END
dd IM_END
dd IM_END
dd 0, 0
 
include '../proc32.inc'
include '../macros.inc'
include '../libio.inc'
include '../dll.inc'
include 'editbox_ex.mac'
 
include '../network.inc'
 
 
filebuffer_size equ 4*4096 ; 16kb (dont try to change it yet..)
TIMEOUT equ 100
buffer_len equ 1500
 
AF_INET4 equ 2
IP_PROTO_UDP equ 17
 
opcode_rrq equ 1
opcode_wrq equ 2
opcode_data equ 3
opcode_ack equ 4
opcode_error equ 5
 
; read/write request packet
;
; 2 bytes string 1 byte string 1 byte
; ------------------------------------------------
; | Opcode | Filename | 0 | Mode | 0 |
; ------------------------------------------------
 
; data packet
;
; 2 bytes 2 bytes n bytes
; ----------------------------------
; | Opcode | Block # | Data |
; ----------------------------------
 
; acknowledgement packet
;
; 2 bytes 2 bytes
; ---------------------
; | Opcode | Block # |
; ---------------------
 
; error packet
;
; 2 bytes 2 bytes string 1 byte
; ----------------------------------------
; | Opcode | ErrorCode | ErrMsg | 0 |
; ----------------------------------------
 
 
START:
 
mcall 68, 11
 
stdcall dll.Load, @IMPORT
or eax, eax
jnz exit
 
stop_transfer:
mcall 40, 00100111b
 
red_win:
call draw_window
 
align 4
still:
mcall 10
 
dec eax
jz red_win
 
dec eax
jz key
 
dec eax
jz button
 
push dword edit1
call [edit_box_mouse]
 
push dword edit2
call [edit_box_mouse]
 
push dword edit3
call [edit_box_mouse]
 
push dword edit4
call [edit_box_mouse]
 
push dword Option_boxs1
call [option_box_mouse]
 
push dword Option_boxs2
call [option_box_mouse]
 
jmp still
 
button:
mcall 17
 
cmp ah,0x10
je start_transfer
 
 
test ah , ah
jz still
 
exit: mcall -1
key:
mcall 2
 
push dword edit1
call [edit_box_key]
 
push dword edit2
call [edit_box_key]
 
push dword edit3
call [edit_box_key]
 
push dword edit4
call [edit_box_key]
 
jmp still
 
 
align 4
draw_window:
mcall 12,1
mcall 0,(50*65536+400),(30*65536+180),0x34AABBCC,0x085080DD,str_title
 
mcall 4,35*65536+10,0x80000000, str_server
 
mov ebx,5*65536+ 30
mov edx, str_source
mcall
 
mov ebx,11*65536+ 50
mov edx, str_destination
mcall
 
mov ebx,47*65536+72
mov edx, str_mode
mcall
 
mov ebx,160*65536+72
mov edx, str_method
mcall
 
mov ebx,270*65536+72
mov edx, str_blocksize
mcall
 
push dword edit1
call [edit_box_draw]
 
push dword edit2
call [edit_box_draw]
 
push dword edit3
call [edit_box_draw]
 
push dword edit4
call [edit_box_draw]
 
push dword Option_boxs1
call [option_box_draw]
 
push dword Option_boxs2
call [option_box_draw]
 
mcall 8,210*65536+170, 105*65536+16,0x00000010,0x085080DD
 
mcall 4,260*65536+110, 0x80000000, str_transfer
 
mcall 38,10*65536+380, 130*65536+130,0x00000000
 
mcall 4,350*65536+137, 0x80000000, str_kb_s
 
mcall 47,1 shl 31 + 7 shl 16 + 1,kbps,305*65536+137,0x00000000
 
mcall 4,50*65536+137, 0x80000000, str_complete
 
mcall 47,1 shl 31 + 3 shl 16 + 1,done,25*65536+137,0x00000000
 
mcall 12,2
 
ret
 
 
 
 
 
 
start_transfer:
 
; first, resolve the hostname
 
push esp ; reserve stack place
 
push esp ; fourth parameter
push 0 ; third parameter
push 0 ; second parameter
push dword SRV ; first parameter
call [getaddrinfo]
 
pop esi
 
; test for error
test eax, eax
jnz still
 
mov esi, [esi]
mov esi, [esi + sockaddr_in.sin_addr]
mov dword [IP], esi
 
mcall socket, AF_INET4, SOCK_DGRAM, 0 ; socket_open
cmp eax, -1
je still
 
mov [socketnum], eax
 
mcall connect, [socketnum], sockaddr, sockaddr_len ; socket_connect
cmp eax, -1
je still
 
mov word [I_END], opcode_rrq
cmp [option_group2],op3
je @f
mov word [I_END], opcode_wrq
@@:
 
xor al , al
mov edi, remote_addr
mov ecx, 250
repnz scasb
sub edi, remote_addr-1
mov ecx, edi
mov edi, I_END+2
mov esi, remote_addr
rep movsb
 
cmp [option_group1], op1
je .ascii
 
mov esi, octet
movsd
movsb
 
jmp .send_request
 
.ascii:
 
mov esi, netascii
movsd
movsd
 
.send_request:
 
xor al, al
stosb
 
sub edi, I_END
mov esi, edi
mcall send, [socketnum], I_END
 
mcall 40, 10000101b
 
mov [last_ack], 0
 
 
 
 
 
 
receive_data_loop:
 
mcall 23, TIMEOUT
 
dec eax
jz .red
 
dec eax
jz .key
 
 
mcall recv, [socketnum], buffer, buffer_len, 0 ; receive data
 
cmp word[buffer], opcode_data
jne .error
 
mov bx, [last_ack]
cmp word [buffer + 2], bx
jne .packet_got_lost
inc [last_ack]
 
cmp eax, 4+512
je .continue
 
; last packet, or something else
.error:
 
.packet_got_lost:
 
 
 
.continue:
 
mov word[buffer], opcode_ack ; send ack
mcall send, [socketnum], buffer, 4, 0
 
jmp receive_data_loop
 
.red:
 
call draw_window
 
jmp receive_data_loop
 
 
.key:
mcall 2
cmp ah, 2
jz exit
 
; close socket ?
 
jmp receive_data_loop
 
 
 
 
 
 
;--------------------------------
 
 
send_:
 
invoke file_open, local_addr, O_READ
or eax, eax
jz .exit
mov [fh], eax
 
stdcall mem.Alloc, filebuffer_size
or eax, eax
jz .exit
mov [fb], eax
 
mov [last_ack], 0
mov [fo], 0
 
.read_chunk:
 
invoke file_seek, [fh], [fo], SEEK_END
cmp eax, -1
je .exit
invoke file_read, [fh], [fb], filebuffer_size
cmp eax, -1
je .exit
add [fo], filebuffer_size
cmp eax, filebuffer_size
je .packet
 
; ijhidfhfdsndsfqk
 
.packet:
 
movzx esi, [last_ack]
and esi, 0x000000001f ; last five bits BUFFER SIZE MUST BE 16 kb for this to work !!!
shl esi, 9 ; = * 512
add esi, [fb]
mov edi, buffer
mov ax, opcode_data
stosw
mov ax, [last_ack]
stosw
mov ecx, 512/4
rep movsd
 
mcall send, [socketnum], buffer, 4+512, 0 ; send data
 
 
.loop:
 
mcall 23, TIMEOUT
 
dec eax
jz .red
 
dec eax
jz .key
 
mcall recv, [socketnum], buffer, buffer_len, 0 ; receive ack
 
cmp word[buffer], opcode_ack
jne .exit
 
mov ax, [last_ack]
cmp word[buffer+2], ax
jne .packet
inc [last_ack]
test [last_ack],0x001f
jz .read_chunk
jmp .packet
 
 
.red:
 
call draw_window
 
jmp .loop
 
 
.key:
mcall 2
cmp ah, 2
jz exit
 
; close socket ?
 
jmp .loop
 
.exit:
invoke file_close, [fh]
jmp still
 
 
 
 
 
;-------------------------
; DATA
 
socketnum dd 0
kbps dd 0
done dd 0
 
sockaddr:
dw AF_INET4
dw 69
IP db 192,168,1,115
sockaddr_len = $ - sockaddr
 
align 16
@IMPORT:
 
library box_lib , 'box_lib.obj'
library io_lib , 'libio.obj'
library network , 'network.obj'
 
import box_lib ,\
edit_box_draw ,'edit_box' ,\
edit_box_key ,'edit_box_key' ,\
edit_box_mouse ,'edit_box_mouse' ,\
version_ed ,'version_ed' ,\
check_box_draw ,'check_box_draw' ,\
check_box_mouse ,'check_box_mouse' ,\
version_ch ,'version_ch' ,\
option_box_draw ,'option_box_draw' ,\
option_box_mouse ,'option_box_mouse' ,\
version_op ,'version_op'
 
import io_lib ,\
file_find_first , 'file_find_first' ,\
file_find_next , 'file_find_next' ,\
file_find_close , 'file_find_close' ,\
file_size , 'file_size' ,\
file_open , 'file_open' ,\
file_read , 'file_read' ,\
file_write , 'file_write' ,\
file_seek , 'file_seek' ,\
file_tell , 'file_tell' ,\
file_eof? , 'file_iseof' ,\
file_seteof , 'file_seteof' ,\
file_truncate , 'file_truncate' ,\
file_close , 'file_close'
 
import network ,\
inet_ntoa , 'inet_ntoa' ,\
getaddrinfo , 'getaddrinfo' ,\
freeaddrinfo , 'freeaddrinfo'
 
 
edit1 edit_box 300,80,5 ,0xffffff,0x6f9480,0,0,0,99 ,SRV,ed_focus, 11,11
edit2 edit_box 300,80,25,0xffffff,0x6a9480,0,0,0,99 ,remote_addr,ed_figure_only, 10,10
edit3 edit_box 300,80,45,0xffffff,0x6a9480,0,0,0,99 ,local_addr,ed_figure_only, 27,27
edit4 edit_box 40,340,68,0xffffff,0x6a9480,0,0,0,5 ,BLK,ed_figure_only, 3,3
 
op1 option_box option_group1,80,68,6,12,0xffffff,0,0,netascii,octet-netascii
op2 option_box option_group1,80,85,6,12,0xFFFFFF,0,0,octet,get-octet
 
op3 option_box option_group2,210,68,6,12,0xffffff,0,0,get,put-get
op4 option_box option_group2,210,85,6,12,0xFFFFFF,0,0,put,BLK-put
 
option_group1 dd op1
option_group2 dd op3
Option_boxs1 dd op1,op2,0
Option_boxs2 dd op3,op4,0
 
str_title db 'TFTP client for KolibriOS',0
str_server db 'Server:',0
str_source db 'Remote file:',0
str_destination db 'Local file:',0
str_mode db 'Mode:',0
str_method db 'Method:',0
str_blocksize db 'Blocksize:',0
str_kb_s db 'kb/s',0
str_complete db '% complete',0
str_transfer db 'Transfer',0
 
str_error:
._0 db 'Not defined, see error message (if any).',0
._1 db 'File not found.',0
._2 db 'Access violation.',0
._3 db 'Disk full or allocation exceeded.',0
._4 db 'Illegal TFTP operation.',0
._5 db 'Unknown transfer ID.',0
._6 db 'File already exists.',0
._7 db 'No such user.',0
 
 
netascii db 'NetASCII'
octet db 'Octet'
get db 'GET'
put db 'PUT'
 
BLK db "512",0,0,0
 
last_ack dw ?
 
fh dd ? ; file handle
fo dd ? ; file offset
fb dd ? ; file buffer
 
SRV db "192.168.1.115",0
rb (SRV + 256 - $)
 
remote_addr db "IMG00",0
rb (remote_addr + 256 - $)
 
local_addr db "/hd0/1/KolibriOS/kernel.mnt",0
rb (local_addr + 256 - $)
 
I_END:
buffer:
rb buffer_len
 
IM_END:
/kernel/branches/net/build.bat
1,8 → 1,10
@echo off
cls
set languages=en ru ge et
set drivers=sound sis infinity ensoniq ps2mouse com_mouse uart ati2d vmode
set targets=all kernel drivers skins clean
set languages=en
set drivers=3c59x dec21x4x i8255x mtd80x pcnet32 r6040 rtl8029 rtl8139 rtl8169 sis900
set apps=arpcfg icmp netcfg netstat nslookup synergyc tcpserv telnet tftpc zeroconf
set libs=network
set targets=all kernel apps libs drivers clean
 
call :Check_Target %1
for %%a in (all kernel) do if %%a==%target% call :Check_Lang %2
58,11 → 60,40
 
:Target_all
call :Target_kernel
call :Target_apps
call :Target_libs
call :Target_drivers
call :Target_skins
goto :eof
 
 
:Target_apps
echo *** building applications ...
 
if not exist bin\apps mkdir bin\apps
cd applications
for %%a in (%apps%) do (
fasm -m 65536 %%a\%%a.asm ..\bin\apps\%%a
if not %errorlevel%==0 goto :Error_FasmFailed
)
cd ..
 
goto :eof
 
 
:Target_libs
echo *** building libraries ...
 
if not exist bin\lib mkdir bin\lib
cd applications\libraries
for %%a in (%libs%) do (
fasm -m 65536 %%a\%%a.asm ..\..\bin\libs\%%a.obj
if not %errorlevel%==0 goto :Error_FasmFailed
)
cd ..\..
 
goto :eof
 
 
:Target_drivers
echo *** building drivers ...
 
73,7 → 104,6
if not %errorlevel%==0 goto :Error_FasmFailed
)
cd ..
move bin\drivers\vmode.obj bin\drivers\vmode.mdr
 
 
kpack >nul 2>&1
103,17 → 133,6
)
goto :eof
 
 
:Target_skins
echo *** building skins ...
 
if not exist bin\skins mkdir bin\skins
cd skin
fasm -m 65536 default.asm ..\bin\skins\default.skn
if not %errorlevel%==0 goto :Error_FasmFailed
cd ..
goto :eof
 
:Target_clean
echo *** cleaning ...
rmdir /S /Q bin
/kernel/branches/net/drivers/usb/urb.inc
File deleted
Property changes:
Deleted: svn:keywords
-Revision
\ No newline at end of property
/kernel/branches/net/drivers/usb/usb.asm
File deleted
Property changes:
Deleted: svn:keywords
-Revision
\ No newline at end of property
/kernel/branches/net/drivers/sb16/SB16.INC
File deleted
Property changes:
Deleted: svn:keywords
-Revision
\ No newline at end of property
/kernel/branches/net/drivers/sb16/sb16.asm
File deleted
Property changes:
Deleted: svn:keywords
-Revision
\ No newline at end of property
/kernel/branches/net/drivers/sb16/README.TXT
File deleted
\ No newline at end of file
/kernel/branches/net/drivers/sb16/CONFIG.INC
File deleted
Property changes:
Deleted: svn:keywords
-Revision
\ No newline at end of property
/kernel/branches/net
Property changes:
Added: svn:ignore
+bin