Browse Source

Merge pull request #5315 from peperronii/master

Expose getpeername() in core:net package as "peer_endpoint"
Jeroen van Rijn 2 months ago
parent
commit
9c9380d158

+ 1 - 0
core/net/common.odin

@@ -64,6 +64,7 @@ Network_Error :: union #shared_nil {
 	UDP_Recv_Error,
 	Shutdown_Error,
 	Interfaces_Error,
+	Socket_Info_Error,
 	Socket_Option_Error,
 	Set_Blocking_Error,
 	Parse_Endpoint_Error,

+ 17 - 0
core/net/errors.odin

@@ -246,6 +246,23 @@ Shutdown_Error :: enum i32 {
 	Unknown,
 }
 
+Socket_Info_Error :: enum i32 {
+	None,
+	// No network connection, or the network stack is not initialized.
+	Network_Unreachable,
+	// Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given.
+	Insufficient_Resources,
+	// Socket is invalid or not connected, or the manner given is invalid.
+	Invalid_Argument,
+	// The socket is valid, but unsupported by this opperation.
+	Unsupported_Socket,
+	// Connection was closed/aborted/shutdown.
+	Connection_Closed,
+
+	// An error unable to be categorized in above categories, `last_platform_error` may have more info.
+	Unknown,
+}
+
 Socket_Option_Error :: enum i32 {
 	None,
 	// No network connection, or the network stack is not initialized.

+ 17 - 0
core/net/errors_darwin.odin

@@ -226,6 +226,23 @@ _shutdown_error :: proc() -> Shutdown_Error {
 	}
 }
 
+_socket_info_error :: proc() -> Socket_Info_Error {
+	#partial switch posix.errno() {
+	case .EBADF, .ENOTSOCK:
+		return .Invalid_Argument
+	case .ENOTCONN:
+		return .Network_Unreachable
+	case .EOPNOTSUPP:
+		return .Unsupported_Socket
+	case .EINVAL:
+		return .Connection_Closed
+	case .ENOBUFS:
+		return .Insufficient_Resources
+	case:
+		return .Unknown
+	}
+}
+
 _socket_option_error :: proc() -> Socket_Option_Error {
 	#partial switch posix.errno() {
 	case .ENOBUFS:

+ 18 - 0
core/net/errors_freebsd.odin

@@ -255,6 +255,24 @@ _shutdown_error :: proc(errno: freebsd.Errno) -> Shutdown_Error {
 	}
 }
 
+_socket_info_error :: proc(errno: freebsd.Errno) -> Socket_Info_Error {
+	assert(errno != nil)
+	_last_error = errno
+
+	#partial switch errno {
+	case .EBADF, .ENOTSOCK, .EINVAL, .EFAULT:
+		return .Invalid_Argument
+	case .ENOTCONN:
+		return .Network_Unreachable
+	case .ECONNRESET:
+		return .Connection_Closed
+	case .ENOBUFS:
+		return .Insufficient_Resources
+	case:
+		return .Unknown
+	}
+}
+
 _socket_option_error :: proc(errno: freebsd.Errno) -> Socket_Option_Error {
 	assert(errno != nil)
 	_last_error = errno

+ 16 - 0
core/net/errors_linux.odin

@@ -258,6 +258,22 @@ _shutdown_error :: proc(errno: linux.Errno) -> Shutdown_Error {
 	}
 }
 
+_socket_info_error :: proc(errno: linux.Errno) -> Socket_Info_Error {
+	assert(errno != nil)
+	_last_error = errno
+
+	#partial switch errno {
+	case .EBADF, .ENOTSOCK, .EFAULT, .EINVAL:
+		return .Invalid_Argument
+	case .ENOTCONN:
+		return .Network_Unreachable
+	case .ENOBUFS:
+		return .Insufficient_Resources
+	case:
+		return .Unknown
+	}
+}
+
 _socket_option_error :: proc(errno: linux.Errno) -> Socket_Option_Error {
 	assert(errno != nil)
 	_last_error = errno

+ 11 - 0
core/net/errors_windows.odin

@@ -234,6 +234,17 @@ _shutdown_error :: proc() -> Shutdown_Error {
 	}
 }
 
+_socket_info_error :: proc() -> Socket_Info_Error {
+	#partial switch win.System_Error(win.WSAGetLastError()) {
+	case .WSAEFAULT, .WSAEINPROGRESS, .WSAENOTSOCK, .WSAEINVAL:
+		return .Invalid_Argument
+	case .WSANOTINITIALISED, .WSAENETDOWN, .WSAENOTCONN:
+		return .Network_Unreachable
+	case:
+		return .Unknown
+	}
+}
+
 _socket_option_error :: proc() -> Socket_Option_Error {
 	#partial switch win.System_Error(win.WSAGetLastError()) {
 	case .WSAENETDOWN, .WSANOTINITIALISED:

+ 8 - 1
core/net/socket.odin

@@ -174,10 +174,17 @@ listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (socket: TC
 /*
 	Returns the endpoint that the given socket is listening / bound on.
 */
-bound_endpoint :: proc(socket: Any_Socket) -> (endpoint: Endpoint, err: Listen_Error) {
+bound_endpoint :: proc(socket: Any_Socket) -> (endpoint: Endpoint, err: Socket_Info_Error) {
 	return _bound_endpoint(socket)
 }
 
+/*
+	Returns the endpoint that the given socket is connected to. (Peer's endpoint)
+*/
+peer_endpoint :: proc(socket: Any_Socket) -> (endpoint: Endpoint, err: Socket_Info_Error) {
+	return _peer_endpoint(socket)
+}
+
 accept_tcp :: proc(socket: TCP_Socket, options := DEFAULT_TCP_OPTIONS) -> (client: TCP_Socket, source: Endpoint, err: Accept_Error) {
 	return _accept_tcp(socket, options)
 }

+ 15 - 2
core/net/socket_darwin.odin

@@ -137,11 +137,24 @@ _listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (skt: TCP_
 }
 
 @(private)
-_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Listen_Error) {
+_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) {
 	addr: posix.sockaddr_storage
 	addr_len := posix.socklen_t(size_of(addr))
 	if posix.getsockname(posix.FD(any_socket_to_socket(sock)), (^posix.sockaddr)(&addr), &addr_len) != .OK {
-		err = _listen_error()
+		err = _socket_info_error()
+		return
+	}
+
+	ep = _sockaddr_to_endpoint(&addr)
+	return
+}
+
+@(private)
+_peer_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) {
+	addr: posix.sockaddr_storage
+	addr_len := posix.socklen_t(size_of(addr))
+	if posix.getpeername(posix.FD(any_socket_to_socket(sock)), (^posix.sockaddr)(&addr), &addr_len) != .OK {
+		err = _socket_info_error()
 		return
 	}
 

+ 16 - 2
core/net/socket_freebsd.odin

@@ -140,12 +140,26 @@ _listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (socket: T
 }
 
 @(private)
-_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Listen_Error) {
+_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) {
 	sockaddr: freebsd.Socket_Address_Storage
 
 	errno := freebsd.getsockname(cast(Fd)any_socket_to_socket(sock), &sockaddr)
 	if errno != nil {
-		err = _listen_error(errno)
+		err = _socket_info_error(errno)
+		return
+	}
+
+	ep = _sockaddr_to_endpoint(&sockaddr)
+	return
+}
+
+@(private)
+_peer_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) {
+	sockaddr: freebsd.Socket_Address_Storage
+
+	errno := freebsd.getpeername(cast(Fd)any_socket_to_socket(sock), &sockaddr)
+	if errno != nil {
+		err = _socket_info_error(errno)
 		return
 	}
 

+ 15 - 2
core/net/socket_linux.odin

@@ -218,11 +218,24 @@ _listen_tcp :: proc(endpoint: Endpoint, backlog := 1000) -> (socket: TCP_Socket,
 }
 
 @(private)
-_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Listen_Error) {
+_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) {
 	addr: linux.Sock_Addr_Any
 	errno := linux.getsockname(_unwrap_os_socket(sock), &addr)
 	if errno != .NONE {
-		err = _listen_error(errno)
+		err = _socket_info_error(errno)
+		return
+	}
+
+	ep = _wrap_os_addr(addr)
+	return
+}
+
+@(private)
+_peer_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) {
+	addr: linux.Sock_Addr_Any
+	errno := linux.getpeername(_unwrap_os_socket(sock), &addr)
+	if errno != .NONE {
+		err = _socket_info_error(errno)
 		return
 	}
 

+ 16 - 2
core/net/socket_windows.odin

@@ -177,11 +177,25 @@ _listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (socket: T
 }
 
 @(private)
-_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Listen_Error) {
+_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) {
 	sockaddr: win.SOCKADDR_STORAGE_LH
 	sockaddrlen := c.int(size_of(sockaddr))
 	if win.getsockname(win.SOCKET(any_socket_to_socket(sock)), &sockaddr, &sockaddrlen) == win.SOCKET_ERROR {
-		err = _listen_error()
+		err = _socket_info_error()
+		return
+	}
+
+	ep = _sockaddr_to_endpoint(&sockaddr)
+	return
+}
+
+@(private)
+_peer_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) {
+	sockaddr: win.SOCKADDR_STORAGE_LH
+	sockaddrlen := c.int(size_of(sockaddr))
+	res := win.getpeername(win.SOCKET(any_socket_to_socket(sock)), &sockaddr, &sockaddrlen)
+	if res < 0 {
+		err = _socket_info_error()
 		return
 	}