From c44f618b7dec82cf80609fd613c93ef91cf6a7ae Mon Sep 17 00:00:00 2001 From: Rickard Andersson Date: Fri, 19 Apr 2024 15:17:21 +0300 Subject: [PATCH 1/4] fix(net): add `NOSIGNAL` to `send` options This is a better default than not having it, since it turns errors that would be signals into error values instead. We could take these as options but given that we currently don't I think this at the very least improves on the status quo. --- core/net/errors_linux.odin | 1 + core/net/socket_linux.odin | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/net/errors_linux.odin b/core/net/errors_linux.odin index 2370dd0d8..5e2c52aea 100644 --- a/core/net/errors_linux.odin +++ b/core/net/errors_linux.odin @@ -136,6 +136,7 @@ TCP_Send_Error :: enum c.int { Interrupted = c.int(linux.Errno.EINTR), // A signal occurred before any data was transmitted. See signal(7). Timeout = c.int(linux.Errno.EWOULDBLOCK), // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout. Not_Socket = c.int(linux.Errno.ENOTSOCK), // The so-called socket is not an open socket. + Broken_Pipe = c.int(linux.Errno.EPIPE), // The peer has disconnected when we are trying to send to it } // TODO diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index ba48959fb..9c4342592 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -258,7 +258,7 @@ _send_tcp :: proc(tcp_sock: TCP_Socket, buf: []byte) -> (int, Network_Error) { for total_written < len(buf) { limit := min(int(max(i32)), len(buf) - total_written) remaining := buf[total_written:][:limit] - res, errno := linux.send(linux.Fd(tcp_sock), remaining, {}) + res, errno := linux.send(linux.Fd(tcp_sock), remaining, {.NOSIGNAL}) if errno != .NONE { return total_written, TCP_Send_Error(errno) } From 7b95562827290258c49e27c7ee8d7be53b7239fe Mon Sep 17 00:00:00 2001 From: Rickard Andersson Date: Fri, 19 Apr 2024 15:29:28 +0300 Subject: [PATCH 2/4] feat(net): turn `EPIPE` into `Connection_Closed` --- core/net/errors_linux.odin | 1 - core/net/socket_linux.odin | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/net/errors_linux.odin b/core/net/errors_linux.odin index 5e2c52aea..2370dd0d8 100644 --- a/core/net/errors_linux.odin +++ b/core/net/errors_linux.odin @@ -136,7 +136,6 @@ TCP_Send_Error :: enum c.int { Interrupted = c.int(linux.Errno.EINTR), // A signal occurred before any data was transmitted. See signal(7). Timeout = c.int(linux.Errno.EWOULDBLOCK), // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout. Not_Socket = c.int(linux.Errno.ENOTSOCK), // The so-called socket is not an open socket. - Broken_Pipe = c.int(linux.Errno.EPIPE), // The peer has disconnected when we are trying to send to it } // TODO diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index 9c4342592..d9b29fb3a 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -259,7 +259,9 @@ _send_tcp :: proc(tcp_sock: TCP_Socket, buf: []byte) -> (int, Network_Error) { limit := min(int(max(i32)), len(buf) - total_written) remaining := buf[total_written:][:limit] res, errno := linux.send(linux.Fd(tcp_sock), remaining, {.NOSIGNAL}) - if errno != .NONE { + if errno == .EPIPE { + return total_written, TCP_Send_Error.Connection_Closed + } else if errno != .NONE { return total_written, TCP_Send_Error(errno) } total_written += int(res) From efc84cd390e6773ee71e35bc851ce4f55f39c34a Mon Sep 17 00:00:00 2001 From: Rickard Andersson Date: Fri, 19 Apr 2024 15:37:20 +0300 Subject: [PATCH 3/4] docs(net): add comment about `EPIPE` -> `Connection_Closed` --- core/net/socket_linux.odin | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index d9b29fb3a..ee3a41927 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -260,7 +260,9 @@ _send_tcp :: proc(tcp_sock: TCP_Socket, buf: []byte) -> (int, Network_Error) { remaining := buf[total_written:][:limit] res, errno := linux.send(linux.Fd(tcp_sock), remaining, {.NOSIGNAL}) if errno == .EPIPE { - return total_written, TCP_Send_Error.Connection_Closed + // If the peer is disconnected when we are trying to send we will get an `EPIPE` error, + // so we turn that into a clearer error + return total_written, .Connection_Closed } else if errno != .NONE { return total_written, TCP_Send_Error(errno) } From 68f663ea8585f0de6ca7d34ecf93031603f22cb6 Mon Sep 17 00:00:00 2001 From: Rickard Andersson Date: Fri, 19 Apr 2024 15:39:04 +0300 Subject: [PATCH 4/4] fix(net): fix return type for `send_tcp` Was `.Connection_Closed` but this is only inferrable if our return type is not a sub-union of another. --- core/net/socket_linux.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index ee3a41927..a4d75b92b 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -262,7 +262,7 @@ _send_tcp :: proc(tcp_sock: TCP_Socket, buf: []byte) -> (int, Network_Error) { if errno == .EPIPE { // If the peer is disconnected when we are trying to send we will get an `EPIPE` error, // so we turn that into a clearer error - return total_written, .Connection_Closed + return total_written, TCP_Send_Error.Connection_Closed } else if errno != .NONE { return total_written, TCP_Send_Error(errno) }