Some changes in TCP for net branch:

* listening sockets have now a queue of incoming connections
* a mechanism which allows an application to know when sent packet is ACKed
* some fixes


git-svn-id: svn://kolibrios.org@1256 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
CleverMouse 2009-11-09 11:34:51 +00:00
parent 30373c2ee1
commit 1f42f20b6f
3 changed files with 113 additions and 51 deletions

View File

@ -43,6 +43,11 @@ struct TCP_SOCKET
.RemotePort dw ? ; In INET byte order
.backlog dw ? ; Backlog
.backlog_cur dw ? ; current size of queue for un-accept-ed connections
.last_ack_number dd ? ; used only to let application know that ACK has been received
; todo: may be use SND_UNA instead
; todo: may be use events which allow additional information instead
; todo: may be count acknowledged bytes (at least it has obvious sense)
; .OrigRemoteIP dd ? ; original remote IP address (used to reset to LISTEN state)
; .OrigRemotePort dw ? ; original remote port (used to reset to LISTEN state)
.wndsizeTimer dd ? ; window size timer
@ -132,7 +137,7 @@ socket_init:
align 4
sys_socket:
and ebx, 0x000000FF ; should i remove this line ?
cmp bl , 7 ; highest possible number
cmp bl , 8 ; highest possible number
jg s_error
lea ebx, [.table + 4*ebx]
jmp dword [ebx]
@ -146,7 +151,7 @@ sys_socket:
dd socket_accept ; 5
dd socket_send ; 6
dd socket_recv ; 7
; dd socket_get_opt ; 8
dd socket_get_opt ; 8
; dd socket_set_opt ; 9
@ -398,8 +403,8 @@ socket_listen:
jne s_error
cmp edx, MAX_backlog
jl .ok
mov dx , 20
jb .ok
mov dx , MAX_backlog
.ok:
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], dx
@ -448,33 +453,20 @@ socket_accept:
.tcp:
cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], 0
jz s_error
call net_socket_alloc
or eax, eax
jz s_error
mov edi, eax
dec [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog]
mov ecx, (SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end+3)/4
push esi edi
rep movsd
pop edi esi
mov [edi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], 0
; TODO: fill in structure in ecx
mov [esi + SOCKET_head.end + IPv4_SOCKET.RemoteIP], 0
mov [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], 0
stdcall net_socket_addr_to_num, edi
lea ebx, [esi + SOCKET_head.lock]
call wait_mutex
movzx eax, [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
test eax, eax
jz .unlock_err
dec [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
mov eax, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end + (eax-1)*4]
mov [esi + SOCKET_head.lock], 0
stdcall net_socket_addr_to_num, eax
mov [esp+32], eax
ret
.unlock_err:
mov [esi + SOCKET_head.lock], 0
jmp s_error
;-----------------------------------------------
@ -753,6 +745,47 @@ socket_send:
mov [esp+32], eax
ret
;-----------------------------------------------
;
; SOCKET_send
;
;
; IN: socket number in ecx
; edx points to the options:
; dd level, optname, optval, optlen
; OUT: -1 on error
;
; At moment, uses only pseudo-optname -2 for get last_ack_number for TCP.
; TODO: find best way to notify that send()'ed data were acknowledged
;
;-----------------------------------------------
socket_get_opt:
cmp dword [edx], IP_PROTO_TCP
jnz .unknown
cmp dword [edx+4], -2
jnz .unknown
mov eax, [edx+12]
test eax, eax
jz .fail
cmp dword [eax], 4
mov dword [eax], 4
jb .fail
stdcall net_socket_num_to_addr, ecx
test eax, eax
jz .fail
; todo: check that eax is really TCP socket
mov ecx, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.last_ack_number]
mov eax, [edx+8]
test eax, eax
jz @f
mov [eax], ecx
@@:
xor eax, eax
ret
.fail:
.unknown:
or eax, -1
ret
;-----------------------------------------------
@ -872,12 +905,13 @@ socket_internal_receiver:
push ecx ; size
push esi ; data_ptr
mov esi, esp
add_to_queue (eax + 2048), SOCKET_QUEUE_SIZE, 3*4, .full
add_to_queue (eax + 2048), SOCKET_QUEUE_SIZE, 3*4, notify_network_event.full
DEBUGF 1,"Queued packet successfully\n"
add esp, 4*3
mov [eax + SOCKET_head.lock], 0
notify_network_event:
; flag an event to the application
mov edx, [eax + SOCKET_head.PID] ; get socket owner PID
mov ecx, 1
@ -907,7 +941,6 @@ socket_internal_receiver:
; 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).

View File

@ -77,23 +77,23 @@ TH_URG equ 1 shl 5
macro inc_INET reg {
inc byte [reg + 3]
add byte [reg + 3], 1
adc byte [reg + 2], 0
adc byte [reg + 1], 0
adc byte [reg + 0], 0
adc byte [reg], 0
}
macro add_INET reg {
add byte [reg + 3], cl
adc byte [reg + 2], ch
adc byte [reg + 1], 0
adc byte [reg], 0
rol ecx, 16
adc byte [reg + 3], ch
adc byte [reg + 2], cl
add byte [reg + 1], cl
adc byte [reg], ch
rol ecx, 16
adc byte [reg + 1], ch
adc byte [reg + 0], cl
}
include "queue.inc"
@ -389,4 +389,4 @@ sys_protocols:
.return:
mov [esp+28+4], eax
ret
ret

View File

@ -360,6 +360,7 @@ TCP_handler :
; add eax, ecx ;
mov eax, [edx + TCP_Packet.AckNumber]
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.last_ack_number], eax
;---------
cmp [TCP_OUT_QUEUE], 0
@ -615,32 +616,58 @@ stateTCB_LISTEN:
; Look at control flags
test [edx + TCP_Packet.Flags], TH_SYN
jz .exit
; Exit if backlog queue is full
mov ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
cmp ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog]
jae .exit
; Allocate new socket
push esi
call net_socket_alloc
pop esi
test eax, eax
jz .exit
; Copy structure from current socket to new, including lock
push esi edi
lea esi, [ebx + SOCKET_head.PID] ; yes, PID must also be copied
lea edi, [eax + SOCKET_head.PID]
mov ecx, ((SOCKET_head.end - SOCKET_head.PID) + IPv4_SOCKET.end + TCP_SOCKET.end + 3)/4
rep movsd
pop edi esi
; Push pointer to new socket to queue
movzx ecx, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
inc [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end + ecx*4], eax
; We have a SYN. update the socket with this IP Packets details,
; And send a response
mov [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP], esi ; IP source address
mov ax, [edx + TCP_Packet.SourcePort]
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], ax
mov eax, [edx + TCP_Packet.SequenceNumber]
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], eax
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax
lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
mov [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], esi ; IP source address
mov cx, [edx + TCP_Packet.SourcePort]
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], cx
mov ecx, [edx + TCP_Packet.SequenceNumber]
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], ecx
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], ecx
lea esi, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
inc_INET esi ; RCV.NXT
mov eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS]
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], eax
mov ecx, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS]
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], ecx
mov [eax + SOCKET_head.lock], 0
mov [ebx + SOCKET_head.lock], 0
push eax
; Now construct the response
mov bl, TH_SYN + TH_ACK
call TCP_send_ack
pop eax
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
call notify_network_event
; increment SND.NXT in socket
lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
lea esi, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
inc_INET esi
ret
.exit:
mov [ebx + SOCKET_head.lock], 0
@ -721,6 +748,8 @@ stateTCB_SYN_RECEIVED:
jz .exit
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
mov eax, ebx
call notify_network_event
.exit:
mov [ebx + SOCKET_head.lock], 0