Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 2970 → Rev 2971

/kernel/branches/kolibri_pe/network/socket.inc
1,6 → 1,6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; SOCKET.INC ;;
7,8 → 7,6
;; ;;
;; Sockets constants, structures and functions ;;
;; ;;
;; Last revision: 11.11.2006 ;;
;; ;;
;; This file contains the following: ;;
;; is_localport_unused ;;
;; get_free_socket ;;
31,113 → 29,59
 
$Revision$
 
; socket data structure
struct SOCKET
.PrevPtr dd ? ; pointer to previous socket in list
.NextPtr dd ? ; pointer to next socket in list
.Number dd ? ; socket number (unique within single process)
.PID dd ? ; application process id
.LocalIP dd ? ; local IP address
.LocalPort dw ? ; local port
.RemoteIP dd ? ; remote IP address
.RemotePort dw ? ; remote port
.OrigRemoteIP dd ? ; original remote IP address (used to reset to LISTEN state)
.OrigRemotePort dw ? ; original remote port (used to reset to LISTEN state)
.rxDataCount dd ? ; rx data count
.TCBState dd ? ; TCB state
.TCBTimer dd ? ; TCB timer (seconds)
.ISS dd ? ; initial send sequence
.IRS dd ? ; initial receive sequence
.SND_UNA dd ? ; sequence number of unack'ed sent packets
.SND_NXT dd ? ; bext send sequence number to use
.SND_WND dd ? ; send window
.RCV_NXT dd ? ; next receive sequence number to use
.RCV_WND dd ? ; receive window
.SEG_LEN dd ? ; segment length
.SEG_WND dd ? ; segment window
.wndsizeTimer dd ? ; window size timer
.lock dd ? ; lock mutex
.rxData dd ? ; receive data buffer here
ends
 
;
; Socket Descriptor + Buffer
;
; 0 1 2 3
; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
;
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 0| Status ( of this buffer ) |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 4| Application Process ID |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 8| Local IP Address |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 12| Local IP Port | Unused ( set to 0 ) |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 16| Remote IP Address |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 20| Remote IP Port | Unused ( set to 0 ) |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 24| Rx Data Count INTEL format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 28| TCB STATE INTEL format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 32| TCB Timer (seconds) INTEL format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 36| ISS (Inital Sequence # used by this connection ) INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 40| IRS ( Inital Receive Sequence # ) INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 44| SND.UNA Seq # of unack'ed sent packets INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 48| SND.NXT Next send seq # to use INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 52| SND.WND Send window INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 56| RCV.NXT Next expected receive sequence # INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 60| RCV.WND Receive window INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 64| SEG.LEN Segment length INTEL format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 68| SEG.WND Segment window INTEL format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 72| Retransmit queue # NOW WINDOW SIZE TIMER INTEL format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 76| RX Data Buffer |
; +-+-+-.......... -+
; TCP opening modes
SOCKET_PASSIVE = 0
SOCKET_ACTIVE = 1
 
; socket types
SOCK_STREAM = 1
SOCK_DGRAM = 2
 
; so, define struct
struc SOCKET
{
.PrevPtr dd ?
.NextPtr dd ?
.Status dd ? ;+00 - Status ( of this buffer )
.PID dd ? ;+04 - Application Process ID
.LocalIP dd ? ;+08 - Local IP Address
.LocalPort dw ? ;+12 - Local Port
.RemoteIP dd ? ;+16 - Remote IP Address
.RemotePort dw ? ;+20 - Remote Port
.OrigRemoteIP dd ?
.OrigRemotePort dw ?
.rxDataCount dd ? ;+24 - Rx Data Count
.TCBState dd ? ;+28 - TCB STATE
.TCBTimer dd ? ;+32 - TCB Timer (seconds)
.ISS dd ? ;+36 - Initial Send Sequence
.IRS dd ? ;+40 - Initial Receive Sequence
.SND_UNA dd ? ;+44 - Sequence number of unack'ed sent packets
.SND_NXT dd ? ;+48 - Next send sequence number to use
.SND_WND dd ? ;+52 - Send window
.RCV_NXT dd ? ;+56 - Next receive sequence number to use
.RCV_WND dd ? ;+60 - Receive window
.SEG_LEN dd ? ;+64 - Segment length
.SEG_WND dd ? ;+68 - Segment window
.wndsizeTimer dd ? ;+72 - Retransmit queue # NOW WINDOW SIZE TIMER
.rxData dd ? ;+76 - receive data buffer here
}
 
virtual at 0
SOCKET SOCKET
end virtual
 
; simple macro calcing real memory address of SOCKET struct by socket's
;macro Index2RealAddr reg
;{
; shl reg, 12
; add reg, sockets
;}
 
;Constants
; current socket statuses
SOCK_EMPTY = 0 ; socket not in use
SOCK_OPEN = 1 ; open issued, but no data sent
 
; TCP opening modes
SOCKET_PASSIVE equ 0
SOCKET_ACTIVE equ 1
 
;; Allocate memory for socket data and put new socket into the list
; Newly created socket is initialized with calling PID and number and
; put into beginning of list (which is a fastest way).
;
; @return socket structure address in EAX
;;
proc net_socket_alloc stdcall uses ebx ecx edx edi
mov ecx, SOCKETBUFFSIZE
mov edx, PG_SW
call @mem_alloc@8
DEBUGF 1, "K : net_socket_alloc (0x%x)\n", eax
; check if we can allocate needed amount of memory
or eax, eax
jz .exit
 
; zero-initialize allocated memory
push eax
mov edi, eax
mov ecx, SOCKETBUFFSIZE / 4
146,6 → 90,7
rep stosd
pop eax
 
; add socket to the list by changing pointers
mov ebx, net_sockets
push [ebx + SOCKET.NextPtr]
mov [ebx + SOCKET.NextPtr], eax
156,23 → 101,50
jz @f
mov [ebx + SOCKET.PrevPtr], eax
 
@@: mov ebx, [TASK_BASE]
@@: ; set socket owner PID to the one of calling process
mov ebx, [TASK_BASE]
mov ebx, [ebx + TASKDATA.pid]
mov [eax + SOCKET.PID], ebx
 
; find first free socket number and use it
;mov edx, ebx
mov ebx, net_sockets
xor ecx, ecx
.next_socket_number:
inc ecx
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .last_socket_number
cmp [ebx + SOCKET.Number], ecx
jne .next_socket
;cmp [ebx + SOCKET.PID], edx
;jne .next_socket
mov ebx, net_sockets
jmp .next_socket_number
 
.last_socket_number:
mov [eax + SOCKET.Number], ecx
 
.exit:
ret
endp
 
proc net_socket_free stdcall uses ebx ecx edx, sock:DWORD
mov eax, [sock]
;; Free socket data memory and pop socket off the list
;
; @param sockAddr is a socket structure address
;;
proc net_socket_free stdcall uses ebx ecx edx, sockAddr:DWORD
mov eax, [sockAddr]
DEBUGF 1, "K : net_socket_free (0x%x)\n", eax
; check if we got something similar to socket structure address
or eax, eax
jz .error
 
; make sure sockAddr is one of the socket addresses in the list
mov ebx, net_sockets
mov ecx, [TASK_BASE]
mov ecx, [ecx + TASKDATA.pid]
;mov ecx, [TASK_BASE]
;mov ecx, [ecx + TASKDATA.pid]
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
182,6 → 154,8
;cmp [ebx + SOCKET.PID], ecx
;jne .next_socket
 
; okay, we found the correct one
; remove it from the list first, changing pointers
mov ebx, [eax + SOCKET.NextPtr]
mov eax, [eax + SOCKET.PrevPtr]
mov [eax + SOCKET.NextPtr], ebx
199,20 → 173,35
ret
endp
 
proc net_socket_num_to_addr stdcall uses ebx ecx, x:DWORD
; FIXME: do real transform
mov eax, [x]
;; Get socket structure address by its number
; Scan through sockets list to find the socket with specified number.
; This proc uses SOCKET.PID indirectly to check if socket is owned by
; calling process.
;
; @param sockNum is a socket number
; @return socket structure address or 0 (not found) in EAX
;;
proc net_socket_num_to_addr stdcall uses ebx ecx, sockNum:DWORD
mov eax, [sockNum]
; check if we got something similar to socket number
or eax, eax
jz .error
 
; scan through sockets list
mov ebx, net_sockets
mov ecx, [TASK_BASE]
mov ecx, [ecx + TASKDATA.pid]
;mov ecx, [TASK_BASE]
;mov ecx, [ecx + TASKDATA.pid]
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .error
cmp ebx, eax
cmp [ebx + SOCKET.Number], eax
jne .next_socket
;cmp [ebx + SOCKET.PID], ecx
;jne .next_socket
 
; okay, we found the correct one
mov eax, ebx
ret
 
.error:
220,12 → 209,24
ret
endp
 
proc net_socket_addr_to_num stdcall uses ebx ecx, x:DWORD
; FIXME: do real transform
mov eax, [x]
;; Get socket number by its structure address
; Scan through sockets list to find the socket with specified address.
; This proc uses SOCKET.PID indirectly to check if socket is owned by
; calling process.
;
; @param sockAddr is a socket structure address
; @return socket number (SOCKET.Number) or 0 (not found) in EAX
;;
proc net_socket_addr_to_num stdcall uses ebx ecx, sockAddr:DWORD
mov eax, [sockAddr]
; check if we got something similar to socket structure address
or eax, eax
jz .error
 
; scan through sockets list
mov ebx, net_sockets
mov ecx, [TASK_BASE]
mov ecx, [ecx + TASKDATA.pid]
;mov ecx, [TASK_BASE]
;mov ecx, [ecx + TASKDATA.pid]
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
234,6 → 235,9
jne .next_socket
;cmp [ebx + SOCKET.PID], ecx
;jne .next_socket
 
; okay, we found the correct one
mov eax, [ebx + SOCKET.Number]
ret
 
.error:
241,23 → 245,22
ret
endp
 
;***************************************************************************
; Function
; is_localport_unused
;; [53.9] Check if local port is used by any socket in the system.
; Scan through sockets list, checking SOCKET.LocalPort.
; Useful when you want a to generate a unique local port number.
; This proc doesn't guarantee that after calling it and trying to use
; the port reported being free in calls to socket_open/socket_open_tcp it'll
; still be free or otherwise it'll still be used if reported being in use.
;
; Description
; scans through all the active sockets , looking to see if the
; port number specified in bx is in use as a localport number.
; This is useful when you want a to generate a unique local port
; number.
; On return, eax = 1 for free, 0 for in use
;
;***************************************************************************
; @param BX is a port number
; @return 1 (port is free) or 0 (port is in use) in EAX
;;
proc is_localport_unused stdcall
 
xchg bl, bh
 
xor eax, eax ; Assume the return value is 'free'
; assume the return value is 'free'
xor eax, eax
inc al
mov edx, net_sockets
 
266,27 → 269,22
or edx, edx
jz .exit
cmp [edx + SOCKET.LocalPort], bx
jne .next_socket ; Return back if the port is not occupied
jne .next_socket
 
dec al ; return 'in use'
; return 'in use'
dec al
 
.exit:
ret
endp
 
 
;***************************************************************************
; Function
; socket_open
;; [53.0] Open DGRAM socket (connectionless, unreliable)
;
; Description
; find a free socket
; local port in ebx
; remote port in ecx
; remote ip in edx
; return socket # in eax, -1 if none available
;
;***************************************************************************
; @param BX is local port number
; @param CX is remote port number
; @param EDX is remote IP address
; @return socket number or -1 (error) in EAX
;;
proc socket_open stdcall
call net_socket_alloc
or eax, eax
296,7 → 294,6
 
push eax
 
mov [eax + SOCKET.Status], SOCK_OPEN
xchg bh, bl
mov [eax + SOCKET.LocalPort], bx
xchg ch, cl
316,21 → 313,14
ret
endp
 
 
;***************************************************************************
; Function
; socket_open_tcp
;; [53.5] Open STREAM socket (connection-based, sequenced, reliable, two-way)
;
; Description
; Opens a TCP socket in PASSIVE or ACTIVE mode
; find a free socket
; local port in ebx ( intel format )
; remote port in ecx ( intel format )
; remote ip in edx ( in Internet byte order )
; Socket open mode in esi ( SOCKET_PASSIVE or SOCKET_ACTIVE )
; return socket # in eax, -1 if none available
;
;***************************************************************************
; @param BX is local port number
; @param CX is remote port number
; @param EDX is remote IP address
; @param ESI is open mode (SOCKET_ACTIVE, SOCKET_PASSIVE)
; @return socket number or -1 (error) in EAX
;;
proc socket_open_tcp stdcall
local sockAddr dd ?
 
369,7 → 359,6
mov [sockAddr], eax
 
; TODO - check this works!
;xxx: already 0 (intialized by net_socket_alloc)
;mov [eax + SOCKET.wndsizeTimer], 0 ; Reset the window timer.
 
xchg bh, bl
423,10 → 412,8
call inc_inet_esi
 
.exit:
mov ebx, [sockAddr]
mov [ebx + SOCKET.Status], SOCK_OPEN
;pop eax ; Get the socket number back, so we can return it
stdcall net_socket_addr_to_num, ebx
; Get the socket number back, so we can return it
stdcall net_socket_addr_to_num, [sockAddr]
ret
 
.error:
435,16 → 422,11
ret
endp
 
 
;***************************************************************************
; Function
; socket_close
;; [53.1] Close DGRAM socket
;
; Description
; socket # in ebx
; returns 0 for ok, -1 for socket not open (fail)
;
;***************************************************************************
; @param EBX is socket number
; @return 0 (closed successfully) or -1 (error) in EAX
;;
proc socket_close stdcall
DEBUGF 1, "K : socket_close (0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx
451,16 → 433,7
or eax, eax
jz .error
 
cmp [eax + SOCKET.Status], dword SOCK_EMPTY
jz .error
 
; Clear the socket varaibles
stdcall net_socket_free, eax
; mov edi, eax
; xor eax, eax
; mov ecx, SOCKETHEADERSIZE
; cld
; rep stosb
 
xor eax, eax
ret
471,16 → 444,13
ret
endp
 
 
;***************************************************************************
; Function
; socket_close_tcp
;; [53.8] Close STREAM socket
; Closing TCP sockets takes time, so when you get successful return code
; from this function doesn't always mean that socket is actually closed.
;
; Description
; socket # in ebx
; returns 0 for ok, -1 for socket not open (fail)
;
;***************************************************************************
; @param EBX is socket number
; @return 0 (closed successfully) or -1 (error) in EAX
;;
proc socket_close_tcp stdcall
local sockAddr dd ?
DEBUGF 1, "K : socket_close_tcp (0x%x)\n", ebx
493,7 → 463,6
.next_resendq:
cmp ecx, NUMRESENDENTRIES
je .last_resendq ; None left
;cmp [esi], bl ; XTODO: bl -> ebx
cmp [esi + 4], ebx
je @f ; found one
inc ecx
500,7 → 469,6
add esi, 8
jmp .next_resendq
 
;@@: mov byte[esi], 0xff ; XTODO: 0xff -> 0
@@: mov dword[esi + 4], 0
inc ecx
add esi, 8
515,13 → 483,11
 
mov ebx, eax
mov [sockAddr], eax
cmp [ebx + SOCKET.Status], SOCK_EMPTY
je .error
 
cmp [ebx + SOCKET.TCBState], TCB_LISTEN ;xxx
je .destroy_tcb ;xxx
cmp [ebx + SOCKET.TCBState], TCB_SYN_SENT ;xxx
je .destroy_tcb ;xxx
cmp [ebx + SOCKET.TCBState], TCB_LISTEN
je .destroy_tcb
cmp [ebx + SOCKET.TCBState], TCB_SYN_SENT
je .destroy_tcb
 
; Now construct the response, and queue for sending by IP
mov eax, EMPTY_QUEUE
531,8 → 497,7
 
push eax
 
;xxx mov bl, TH_FIN + TH_ACK
mov bl, TH_FIN ;xxx
mov bl, TH_FIN
xor ecx, ecx
xor esi, esi
stdcall build_tcp_packet, [sockAddr]
545,10 → 510,6
 
; Get the socket state
mov eax, [ebx + SOCKET.TCBState]
;xxx cmp eax, TCB_LISTEN
;xxx je .destroy_tcb
;xxx cmp eax, TCB_SYN_SENT
;xxx je .destroy_tcb
cmp eax, TCB_SYN_RECEIVED
je .fin_wait_1
cmp eax, TCB_ESTABLISHED
556,7 → 517,6
 
; assume CLOSE WAIT
; Send a fin, then enter last-ack state
; TODO: check if it's really a TCB_CLOSE_WAIT
mov [ebx + SOCKET.TCBState], TCB_LAST_ACK
jmp .send
 
580,10 → 540,8
jmp .exit
 
.destroy_tcb:
;xxx pop eax
 
; Clear the socket variables
;xxx stdcall net_socket_free, [sockAddr]
stdcall net_socket_free, ebx
 
.exit:
596,16 → 554,11
ret
endp
 
 
;***************************************************************************
; Function
; socket_poll
;; [53.2] Poll socket
;
; Description
; socket # in ebx
; returns count in eax.
;
;***************************************************************************
; @param EBX is socket number
; @return count or bytes in rx buffer or 0 (error) in EAX
;;
proc socket_poll stdcall
; DEBUGF 1, "socket_poll(0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx
616,21 → 569,15
ret
 
.error:
;or eax, -1
xor eax, eax
ret
endp
 
 
;***************************************************************************
; Function
; socket_status
;; [53.6] Get socket TCB state
;
; Description
; socket # in ebx
; returns TCB state in eax.
;
;***************************************************************************
; @param EBX is socket number
; @return socket TCB state or 0 (error) in EAX
;;
proc socket_status stdcall
;; DEBUGF 1, "socket_status(0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx
641,26 → 588,19
ret
 
.error:
;or eax, -1
xor eax, eax
ret
endp
 
; Index2RealAddr ebx
; mov eax, [ebx + SOCKET.TCBState]
;; [53.3] Get one byte from rx buffer
; This function can return 0 in two cases: if there's one byte read and
; non left, and if an error occured. Behavior should be changed and function
; shouldn't be used for now. Consider using [53.11] instead.
;
; ret
 
 
;***************************************************************************
; Function
; socket_read
;
; Description
; socket # in ebx
; returns # of bytes remaining in eax, data in bl
;
;***************************************************************************
; @param EBX is socket number
; @return number of bytes left in rx buffer or 0 (error) in EAX
; @return byte read in BL
;;
proc socket_read stdcall
; DEBUGF 1, "socket_read(0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx
667,47 → 607,53
or eax, eax
jz .error
 
lea ebx, [eax + SOCKET.lock]
call wait_mutex
 
mov ebx, eax
mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes
test eax, eax
jz .error
jz .error_release
 
dec eax
mov esi, ebx ; esi is address of socket
mov [ebx + SOCKET.rxDataCount], eax ; store new count
;movzx ebx, byte[ebx + SOCKET.rxData] ; get the byte
movzx ebx, byte[ebx + SOCKETHEADERSIZE] ; get the byte
add esi, SOCKETHEADERSIZE
mov edi, esi
inc esi
movzx eax, byte[ebx + SOCKET.rxData] ; get the byte
 
mov ecx, (SOCKETBUFFSIZE - SOCKETHEADERSIZE) / 4
lea edi, [ebx + SOCKETHEADERSIZE]
mov ecx, SOCKETBUFFSIZE - SOCKET.rxData - 1
lea edi, [esi + SOCKET.rxData]
lea esi, [edi + 1]
cld
push ecx
shr ecx, 2
rep movsd
pop ecx
and ecx, 3
rep movsb
 
mov [ebx + SOCKET.lock], 0
mov ebx, eax
 
ret
 
.error_release:
mov [ebx + SOCKET.lock], 0
.error:
;or eax, -1
xor eax, eax
xor ebx, ebx
ret
endp
 
 
;***************************************************************************
; Function
; socket_read_packet
;; [53.11] Get specified number of bytes from rx buffer
; Number of bytes in rx buffer can be less than requested size. In this case,
; only available number of bytes is read.
; This function can return 0 in two cases: if there's no data to read, and if
; an error occured. Behavior should be changed.
;
; Description
; socket # in ebx
; datapointer # in ecx
; buffer size in edx
; returns # of bytes copied in eax
;
;***************************************************************************
; @param EBX is socket number
; @param ECX is pointer to application buffer
; @param EDX is application buffer size (number of bytes to read)
; @return number of bytes read or 0 (error) in EAX
;;
proc socket_read_packet stdcall
; DEBUGF 1, "socket_read_packet(0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx ; get real socket address
714,6 → 660,9
or eax, eax
jz .error
 
lea ebx, [eax + SOCKET.lock]
call wait_mutex
 
mov ebx, eax
mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes
test eax, eax ; if count of bytes is zero..
731,7 → 680,7
call .start_copy ; copy to the application
 
mov esi, ebx ; now we're going to copy the remaining bytes to the beginning
add esi, SOCKETHEADERSIZE ; we dont need to copy the header
add esi, SOCKET.rxData ; we dont need to copy the header
mov edi, esi ; edi is where we're going to copy to
add esi, edx ; esi is from where we copy
pop ecx ; count of bytes we have left
744,10 → 693,10
rep movsb ; copy remaining bytes
 
.exit:
mov [ebx + SOCKET.lock], 0
ret ; at last, exit
 
.error:
;or eax, -1
xor eax, eax
ret
 
755,12 → 704,13
xor esi, esi
mov [ebx + SOCKET.rxDataCount], esi ; store new count (zero)
call .start_copy
mov [ebx + SOCKET.lock], 0
ret
 
.start_copy:
mov edi, ecx
mov esi, ebx
add esi, SOCKETHEADERSIZE ; we dont need to copy the header
add esi, SOCKET.rxData ; we dont need to copy the header
mov ecx, eax ; eax is count of bytes
push ecx
shr ecx, 2 ; divide eax by 4
772,19 → 722,13
retn ; exit, or go back to shift remaining bytes if any
endp
 
 
;***************************************************************************
; Function
; socket_write
;; [53.4] Send data through DGRAM socket
;
; Description
; socket in ebx
; # of bytes to write in ecx
; pointer to data in edx
; returns 0 in eax ok, -1 == failed ( invalid socket, or
; could not queue IP packet )
;
;***************************************************************************
; @param EBX is socket number
; @param ECX is application data size (number of bytes to send)
; @param EDX is pointer to application data buffer
; @return 0 (sent successfully) or -1 (error) in EAX
;;
proc socket_write stdcall
; DEBUGF 1, "socket_write(0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx ; get real socket address
793,10 → 737,6
 
mov ebx, eax
 
; If the socket is invalid, return with an error code
cmp [ebx + SOCKET.Status], SOCK_EMPTY
je .error
 
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
940,19 → 880,13
ret
endp
 
 
;***************************************************************************
; Function
; socket_write_tcp
;; [53.7] Send data through STREAM socket
;
; Description
; socket in ebx
; # of bytes to write in ecx
; pointer to data in edx
; returns 0 in eax ok, -1 == failed ( invalid socket, or
; could not queue IP packet )
;
;***************************************************************************
; @param EBX is socket number
; @param ECX is application data size (number of bytes to send)
; @param EDX is pointer to application data buffer
; @return 0 (sent successfully) or -1 (error) in EAX
;;
proc socket_write_tcp stdcall
local sockAddr dd ?
 
964,12 → 898,7
mov ebx, eax
mov [sockAddr], ebx
 
; If the socket is invalid, return with an error code
cmp [ebx + SOCKET.Status], SOCK_EMPTY
je .error
 
; If the sockets window timer is nonzero, do not queue packet
; TODO - done
cmp [ebx + SOCKET.wndsizeTimer], 0
jne .error
 
999,8 → 928,8
 
pop ebx
push ecx
 
mov eax, NET1OUT_QUEUE
 
mov edx, [stack_ip]
mov ecx, [sockAddr]
cmp edx, [ecx + SOCKET.RemoteIP]
1031,7 → 960,6
.next_resendq:
cmp ecx, NUMRESENDENTRIES
je .exit ; None found
;cmp byte[esi], 0xff ; XTODO: 0xff -> 0
cmp dword[esi + 4], 0
je @f ; found one
inc ecx
1049,7 → 977,6
; fill IP buffer associated with this descriptor
 
stdcall net_socket_addr_to_num, [sockAddr]
;mov [esi], al ; XTODO: al -> eax
mov [esi + 4], eax
mov byte[esi + 1], TCP_RETRIES
mov word[esi + 2], TCP_TIMEOUT