mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-19 04:50:29 +00:00
net(docs): recv of 0 bytes with no error is a graceful close
This commit is contained in:
@@ -149,7 +149,8 @@ TCP_Recv_Error :: enum i32 {
|
||||
Invalid_Argument,
|
||||
// The socket is not connected.
|
||||
Not_Connected,
|
||||
// Connection was closed/broken/shutdown while receiving data.
|
||||
// Connection was closed due to an error or shutdown.
|
||||
// NOTE: a graceful close is indicated by a `0, nil` (0 bytes received and no error) return.
|
||||
Connection_Closed,
|
||||
// Timed out before being able to receive any data.
|
||||
Timeout,
|
||||
@@ -170,7 +171,8 @@ UDP_Recv_Error :: enum i32 {
|
||||
Insufficient_Resources,
|
||||
// Invalid socket or buffer given.
|
||||
Invalid_Argument,
|
||||
// "Connection" was refused by remote, or closed/broken/shutdown while receiving data.
|
||||
// "Connection" was refused, or closed due to an error.
|
||||
// NOTE: a graceful close is indicated by a `0, nil` (0 bytes received and no error) return.
|
||||
Connection_Refused,
|
||||
// Timed out before being able to receive any data.
|
||||
Timeout,
|
||||
@@ -193,7 +195,7 @@ TCP_Send_Error :: enum i32 {
|
||||
Insufficient_Resources,
|
||||
// Invalid socket or buffer given.
|
||||
Invalid_Argument,
|
||||
// Connection was closed/broken/shutdown while receiving data.
|
||||
// Connection was closed/broken/shutdown while sending data.
|
||||
Connection_Closed,
|
||||
// The socket is not connected.
|
||||
Not_Connected,
|
||||
|
||||
@@ -193,21 +193,36 @@ close :: proc(socket: Any_Socket) {
|
||||
_close(socket)
|
||||
}
|
||||
|
||||
/*
|
||||
Receive data into a buffer from a TCP socket.
|
||||
|
||||
If no error occurs, `recv_tcp` returns the number of bytes received and `buf` will contain this data received.
|
||||
If the connection has been gracefully closed, the return value is `0, nil` (0 bytes read and no error).
|
||||
*/
|
||||
recv_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_read: int, err: TCP_Recv_Error) {
|
||||
return _recv_tcp(socket, buf)
|
||||
}
|
||||
|
||||
/*
|
||||
Receive data into a buffer from a UDP socket.
|
||||
|
||||
If no error occurs, `recv_udp` returns the number of bytes received and `buf` will contain this data received.
|
||||
If the "connection" has been gracefully closed, the return value is `0, nil` (0 bytes read and no error).
|
||||
*/
|
||||
recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: UDP_Recv_Error) {
|
||||
return _recv_udp(socket, buf)
|
||||
}
|
||||
|
||||
/*
|
||||
Receive data from into a buffer from any socket.
|
||||
Receive data into a buffer from any socket.
|
||||
|
||||
Note: `remote_endpoint` parameter is non-nil only if the socket type is UDP. On TCP sockets it
|
||||
will always return `nil`.
|
||||
|
||||
Errors that can be returned: `TCP_Recv_Error`, or `UDP_Recv_Error`
|
||||
Errors that can be returned: `TCP_Recv_Error`, or `UDP_Recv_Error`.
|
||||
|
||||
If no error occurs, `recv_any` returns the number of bytes received and `buf` will contain this data received.
|
||||
If the connection has been gracefully closed, the return value is `0, nil, nil` (0 bytes read and no error).
|
||||
*/
|
||||
recv_any :: proc(socket: Any_Socket, buf: []byte) -> (
|
||||
bytes_read: int,
|
||||
|
||||
@@ -624,6 +624,41 @@ test_nonblocking_option :: proc(t: ^testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test that when the server closes it's connection, the client's next receive is `0, nil` to indicate a correct close.
|
||||
@(test)
|
||||
test_connection_close :: proc(t: ^testing.T) {
|
||||
server, listen_err := net.listen_tcp({address=net.IP4_Address{127, 0, 0, 1}, port=0})
|
||||
testing.expect_value(t, listen_err, nil)
|
||||
defer net.close(server)
|
||||
|
||||
server_ep, bound_endpoint_err := net.bound_endpoint(server)
|
||||
testing.expect_value(t, bound_endpoint_err, nil)
|
||||
|
||||
client, dial_err := net.dial_tcp(server_ep)
|
||||
testing.expect_value(t, dial_err, nil)
|
||||
defer net.close(client)
|
||||
|
||||
server_client, _, accept_err := net.accept_tcp(server)
|
||||
testing.expect_value(t, accept_err, nil)
|
||||
|
||||
send_buf: [512]byte = 1
|
||||
sent, send_err := net.send(server_client, send_buf[:])
|
||||
testing.expect_value(t, sent, 512)
|
||||
testing.expect_value(t, send_err, nil)
|
||||
net.close(server_client)
|
||||
|
||||
recv_buf: [512]byte = ---
|
||||
received, recv_err := net.recv(client, recv_buf[:])
|
||||
testing.expect_value(t, received, 512)
|
||||
testing.expect_value(t, recv_err, nil)
|
||||
|
||||
testing.expect_value(t, recv_buf, send_buf)
|
||||
|
||||
received, recv_err = net.recv(client, recv_buf[:])
|
||||
testing.expect_value(t, received, 0)
|
||||
testing.expect_value(t, recv_err, nil)
|
||||
}
|
||||
|
||||
@(private)
|
||||
address_to_binstr :: proc(address: net.Address) -> (binstr: string) {
|
||||
switch t in address {
|
||||
|
||||
Reference in New Issue
Block a user