kolibrios/kernel/branches/kolibri-lldw/network/tcp_usreq.inc

237 lines
7.3 KiB
PHP
Raw Permalink Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2019. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; Part of the TCP/IP network stack for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; Based on the code of 4.4BSD ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision$
;-----------------------------------------------------------------;
; ;
; tcp_usrclosed ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_usrclosed:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_usrclosed: %x\n", eax
push ebx
mov ebx, [eax + TCP_SOCKET.t_state]
mov ebx, dword [.switch + ebx*4]
jmp ebx
.switch:
dd .close ; TCPS_CLOSED
dd .close ; TCPS_LISTEN
dd .close ; TCPS_SYN_SENT
dd .wait1 ; TCPS_SYN_RECEIVED
dd .wait1 ; TCPS_ESTABLISHED
dd .last_ack ; TCPS_CLOSE_WAIT
dd .ret ; TCPS_FIN_WAIT_1
dd .ret ; TCPS_CLOSING
dd .ret ; TCPS_LAST_ACK
dd .disc ; TCPS_FIN_WAIT_2
dd .disc ; TCPS_TIMED_WAIT
.close:
mov [eax + TCP_SOCKET.t_state], TCPS_CLOSED
call tcp_close
pop ebx
ret
.wait1:
mov [eax + TCP_SOCKET.t_state], TCPS_FIN_WAIT_1
pop ebx
ret
.last_ack:
mov [eax + TCP_SOCKET.t_state], TCPS_LAST_ACK
pop ebx
ret
.disc:
call socket_is_disconnected
.ret:
pop ebx
ret
;-----------------------------------------------------------------;
; ;
; tcp_connect ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: eax = 0 on success ;
; eax = -1 on error ;
; ebx = error code on error ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_connect:
test [eax + SOCKET.state], SS_ISCONNECTED
jnz .eisconn
push eax edx
lea ecx, [eax + SOCKET.mutex]
call mutex_lock
mov ebx, eax
lea eax, [ebx + STREAM_SOCKET.snd]
call socket_ring_create
test eax, eax
jz .nomem
lea eax, [ebx + STREAM_SOCKET.rcv]
call socket_ring_create
test eax, eax
jz .nomem
pop edx eax
; Fill in remote port and IP
pushw [edx + 2]
pop [eax + TCP_SOCKET.RemotePort]
pushd [edx + 4]
pop [eax + TCP_SOCKET.RemoteIP]
; Find route to host
pusha
push eax
mov ebx, [eax + TCP_SOCKET.device]
mov edx, [eax + TCP_SOCKET.LocalIP]
mov eax, [eax + TCP_SOCKET.RemoteIP]
call ipv4_route
test eax, eax
jz .enoroute
pop eax
mov ebx, [net_device_list + edi]
mov [eax + TCP_SOCKET.device], ebx
mov [eax + TCP_SOCKET.LocalIP], edx
popa
; Find a local port, if user didnt define one
cmp [eax + TCP_SOCKET.LocalPort], 0
jne @f
call socket_find_port
@@:
; Compute window scaling factor
push ecx
xor ecx, ecx
mov ebx, TCP_max_win
@@:
cmp ebx, SOCKET_BUFFER_SIZE
ja @f
shl ebx, 1
inc ecx
cmp ecx, TCP_max_winshift
jb @r
@@:
mov [eax + TCP_SOCKET.request_r_scale], cl
pop ecx
call socket_is_connecting
inc [TCPS_connattempt]
mov [eax + TCP_SOCKET.timer_persist], 0
mov [eax + TCP_SOCKET.t_state], TCPS_SYN_SENT
mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_init
push [TCP_sequence_num]
add [TCP_sequence_num], TCP_ISSINCR/2
pop [eax + TCP_SOCKET.ISS]
tcp_sendseqinit eax
push eax
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
pop eax
; Now send the SYN packet to remote end
push eax
call tcp_output
pop eax
test [eax + SOCKET.options], SO_NONBLOCK
jz .waitforit
xor eax, eax
dec eax
mov ebx, EINPROGRESS
ret
.nomem:
pop edx eax
xor eax, eax
dec eax
mov ebx, ENOMEM
ret
.eisconn:
xor eax, eax
dec eax
mov ebx, EISCONN
ret
.enoroute:
pop eax
popa
xor eax, eax
dec eax
mov ebx, EADDRNOTAVAIL
ret
.waitforit:
push eax
stdcall timer_hs, TCP_time_connect, 0, .timeout, eax
pop ebx
mov [ebx + TCP_SOCKET.timer_connect], eax
mov eax, ebx
.loop:
cmp [eax + SOCKET.errorcode], 0
jne .fail
cmp [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED
je .established
call socket_block
jmp .loop
.timeout:
mov eax, [esp+4]
mov [eax + SOCKET.errorcode], ETIMEDOUT
and [eax + SOCKET.state], not SS_ISCONNECTING
call socket_notify
ret 4
.fail:
mov ebx, [eax + SOCKET.errorcode]
mov [eax + SOCKET.errorcode], 0 ; Clear the error, we only need to send it to the caller once
xor eax, eax
dec eax
ret
.established:
stdcall cancel_timer_hs, [eax + TCP_SOCKET.timer_connect]
xor eax, eax
ret