Compare commits

..
Author SHA1 Message Date
Leency 6fc8e7596f kernel/net: send nothing on a connection the peer has reset
Check kernel codestyle / Check kernel codestyle (pull_request) Successful in 33s
Test PR / Build (en_US) (pull_request) Successful in 3m35s
Test PR / Build (es_ES) (pull_request) Successful in 3m32s
Test PR / Build (ru_RU) (pull_request) Successful in 3m6s
2026-09-30 10:14:21 +03:00
Leency 8a4662a4c1 kernel/net: stop the TCP timers when the peer resets the connection 2026-09-30 10:14:21 +03:00
Leency 78d8a28f6c kernel/net: mark a TCP socket disconnected when the peer resets it
.econnreset only set t_state = CLOSED, so SS_CANTSENDMORE stayed clear:
send still succeeded and wiped ECONNRESET. Now it fails with ECONNRESET
and a blocked recv wakes up.
2026-09-30 10:14:20 +03:00
Leency 8d0f70c92d kernel/net: fail socket_send on a connection the peer has closed
socket_send_tcp took the data into the transmit ring, cleared the
socket's errorcode and only then called tcp_output, and it never looked
at SS_CANTSENDMORE. After tcp_drop/tcp_close (a RST or FIN from the
peer) had run socket_is_disconnected, a send therefore "succeeded" until
the ring was full and then returned 0 bytes with errorcode 0 -- byte for
byte the answer a healthy socket gives while the kernel drains the ring.
An application writing a large request never learned the connection was
dead; NetSurf on the 2009 QEMU/slirp sat 20 s per upload at ~100 KB of
25 MB with nothing to distinguish it from a slow uplink.

Return -1 with the error the drop recorded (ECONNRESET, ...), or
ENOTCONN when nothing was recorded, when SS_CANTSENDMORE is set.
2026-09-30 10:14:19 +03:00
4 changed files with 29 additions and 2 deletions

No files matched your search

+15 -1
View File
@@ -226,7 +226,6 @@ macro socket_init {
mov ecx, 5
rep stosd
rdtsc ; seed, differs from boot to boot
@@:
pseudo_random eax
cmp ax, EPHEMERAL_PORT_MIN
@@ -1069,6 +1068,11 @@ socket_send_tcp:
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_send: TCP\n"
; Connection closed or reset by peer?
test [eax + SOCKET.state], SS_CANTSENDMORE
jnz .cantsendmore
push eax
add eax, STREAM_SOCKET.snd
call socket_ring_write
@@ -1083,6 +1087,16 @@ socket_send_tcp:
mov [esp + SYSCALL_STACK.ebx], eax
ret
.cantsendmore:
mov ebx, [eax + SOCKET.errorcode]
test ebx, ebx
jnz @f
mov ebx, ENOTCONN
@@:
mov [esp + SYSCALL_STACK.ebx], ebx
mov dword[esp + SYSCALL_STACK.eax], -1
ret
align 4
socket_send_ip:
-1
View File
@@ -208,7 +208,6 @@ macro tcp_init {
mov ecx, (6*NET_DEVICES_MAX)
rep stosd
rdtsc ; seed, differs from boot to boot
pseudo_random eax
mov [TCP_sequence_num], eax
+4
View File
@@ -864,6 +864,10 @@ endl
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSED
inc [TCPS_drops]
; Stop the timers, wake up the application
mov eax, ebx
call tcp_cancel_timers
call socket_is_disconnected
jmp .drop
+10
View File
@@ -63,6 +63,15 @@ endl
.not_idle:
.again:
; Connection was reset by peer, send nothing
cmp [eax + TCP_SOCKET.t_state], TCPS_CLOSED
jne @f
mov ebx, [eax + SOCKET.state]
and ebx, SS_CANTSENDMORE + SS_ISDISCONNECTING
cmp ebx, SS_CANTSENDMORE
je .nothing_to_send
@@:
mov [temp_bits], 0
; Calculate offset
@@ -306,6 +315,7 @@ endl
;----------------------------
; No reason to send a segment
.nothing_to_send:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: No reason to send a segment\n"
pusha