diff --git a/src/runtime2/stdlib/internet.rs b/src/runtime2/stdlib/internet.rs index 19235bcc6ba9280a75aa6770ad44135da2f89485..d32e849a1b76464ae208cb9e11c18789b56e5ea9 100644 --- a/src/runtime2/stdlib/internet.rs +++ b/src/runtime2/stdlib/internet.rs @@ -26,7 +26,9 @@ enum SocketState { Listening, } -/// TCP connection +const SOCKET_BLOCKING: bool = false; + +/// TCP (client) connection pub struct SocketTcpClient { socket_handle: libc::c_int, is_blocking: bool, @@ -34,19 +36,31 @@ pub struct SocketTcpClient { impl SocketTcpClient { pub fn new(ip: IpAddr, port: u16) -> Result { - const BLOCKING: bool = false; let socket_handle = create_and_connect_socket( libc::SOCK_STREAM, libc::IPPROTO_TCP, ip, port )?; - if !set_socket_blocking(socket_handle, BLOCKING) { + if !set_socket_blocking(socket_handle, SOCKET_BLOCKING) { + unsafe{ libc::close(socket_handle); } + return Err(SocketError::Modifying); + } + + println!(" CREATE [{:04}] client", socket_handle); + return Ok(SocketTcpClient{ + socket_handle, + is_blocking: SOCKET_BLOCKING, + }) + } + + pub(crate) fn new_from_handle(socket_handle: libc::c_int) -> Result { + if !set_socket_blocking(socket_handle, SOCKET_BLOCKING) { unsafe{ libc::close(socket_handle); } return Err(SocketError::Modifying); } return Ok(SocketTcpClient{ socket_handle, - is_blocking: BLOCKING, + is_blocking: SOCKET_BLOCKING, }) } @@ -79,6 +93,7 @@ impl SocketTcpClient { impl Drop for SocketTcpClient { fn drop(&mut self) { + println!("DESTRUCT [{:04}] client", self.socket_handle); debug_assert!(self.socket_handle >= 0); unsafe{ close(self.socket_handle) }; } @@ -90,6 +105,67 @@ impl AsFileDescriptor for SocketTcpClient { } } +/// TCP listener. Yielding new connections +pub struct SocketTcpListener { + socket_handle: libc::c_int, + is_blocking: bool, +} + +impl SocketTcpListener { + pub fn new(ip: IpAddr, port: u16) -> Result { + // Create and bind + let socket_handle = create_and_bind_socket( + libc::SOCK_STREAM, libc::IPPROTO_TCP, ip, port + )?; + if !set_socket_blocking(socket_handle, SOCKET_BLOCKING) { + unsafe{ libc::close(socket_handle); } + return Err(SocketError::Modifying); + } + + // Listen + unsafe { + let result = listen(socket_handle, libc::SOMAXCONN); + if result < 0 { + unsafe{ libc::close(socket_handle); } + return Err(SocketError::Listening); + } + } + + + println!(" CREATE [{:04}] listener", socket_handle); + return Ok(SocketTcpListener{ + socket_handle, + is_blocking: SOCKET_BLOCKING, + }); + } + + pub fn accept(&self) -> Result { + let (mut address, mut address_size) = create_sockaddr_in_empty(); + let address_pointer = &mut address as *mut sockaddr_in; + let socket_handle = unsafe { accept(self.socket_handle, address_pointer.cast(), &mut address_size) }; + if socket_handle < 0 { + return Err(IoError::last_os_error()); + } + + println!(" CREATE [{:04}] client (from listener)", socket_handle); + return Ok(socket_handle); + } +} + +impl Drop for SocketTcpListener { + fn drop(&mut self) { + println!("DESTRUCT [{:04}] listener", self.socket_handle); + debug_assert!(self.socket_handle >= 0); + unsafe{ close(self.socket_handle) }; + } +} + +impl AsFileDescriptor for SocketTcpListener { + fn as_file_descriptor(&self) -> FileDescriptor { + return self.socket_handle; + } +} + /// Raw socket receiver. Essentially a listener that accepts a single connection struct SocketRawRx { listen_handle: c_int, @@ -235,6 +311,18 @@ fn create_and_connect_socket(socket_type: libc::c_int, protocol: libc::c_int, ip } } +#[inline] +fn create_sockaddr_in_empty() -> (sockaddr_in, libc::socklen_t) { + let socket_address = sockaddr_in{ + sin_family: 0, + sin_port: 0, + sin_addr: in_addr { s_addr: 0 }, + sin_zero: [0; 8], + }; + let address_size = size_of::(); + + return (socket_address, address_size as _); +} #[inline] fn create_sockaddr_in_v4(ip: Ipv4Addr, port: u16) -> (sockaddr_in, libc::socklen_t) { let address = unsafe{ @@ -316,4 +404,4 @@ fn socket_family_from_ip(ip: IpAddr) -> libc::c_int { #[inline] fn htons(port: u16) -> u16 { return port.to_be(); -} \ No newline at end of file +}