diff --git a/.github/workflows/example_0.11.yml b/.github/workflows/example_0.11.yml deleted file mode 100644 index ac2d840b..00000000 --- a/.github/workflows/example_0.11.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: examples 0.11 - -on: - workflow_dispatch: - inputs: - logLevel: - description: 'Log level' - required: true - default: 'info' - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - build: - - runs-on: ubuntu-20.04 - - steps: - - uses: actions/checkout@v2 - - - name: Install apt-get packages - run: | - sudo ACCEPT_EULA=Y apt-get update - sudo ACCEPT_EULA=Y apt-get upgrade - sudo apt-get install wget git curl software-properties-common build-essential - - name: Install Rust target - run: | - rustup target add wasm32-wasi - - name: Install WasmEdge - run: | - VERSION=0.11.2 - curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | sudo bash -s -- -e all --version=$VERSION --tf-version=$VERSION --tf-deps-version=$VERSION --tf-tools-version=$VERSION --image-version=$VERSION -p /usr/local - - # Disable this example due to it relies on wasmedge_http_req, which is a cyclic dependence - # - name: HTTP client example - # run: | - # cd examples/http_client/ - # cargo build --target wasm32-wasi --release - # wasmedge target/wasm32-wasi/release/http_client.wasm - - - name: HTTP async client example - run: | - cd examples/nonblock_http_client/ - cargo build --target wasm32-wasi --release - wasmedge target/wasm32-wasi/release/nonblock_http_client.wasm - - - name: HTTP server example - run: | - cd examples/http_server/ - cargo build --target wasm32-wasi --release - nohup wasmedge target/wasm32-wasi/release/http_server.wasm & - echo $! > wasmedge.pid - wasmedge_pid=$(cat wasmedge.pid) - sleep 5 - echo "fds:" - ls /proc/$wasmedge_pid/fd - resp=$(curl -X POST http://127.0.0.1:1234 -d "name=WasmEdge") - echo "Server response is $resp" - resp=$(curl -X POST http://127.0.0.1:1234 -d "name=WasmEdge") - resp=$(curl -X POST http://127.0.0.1:1234 -d "name=WasmEdge") - resp=$(curl -X POST http://127.0.0.1:1234 -d "name=WasmEdge") - resp=$(curl -X POST http://127.0.0.1:1234 -d "name=WasmEdge") - resp=$(curl -X POST http://127.0.0.1:1234 -d "name=WasmEdge") - echo "after 6 request, fds:" - ls /proc/$wasmedge_pid/fd - kill -9 $wasmedge_pid - rm wasmedge.pid - - - name: UDP Socket Example - run: | - cargo build --target wasm32-wasi --example=udp_socket --release --no-default-features --features=built-in-dns - wasmedge target/wasm32-wasi/release/examples/udp_socket.wasm - - - name: DNS Example - run: | - cargo build --target wasm32-wasi --example=get_addrinfo --release - wasmedge target/wasm32-wasi/release/examples/get_addrinfo.wasm - - - name: ToSocketAddrs Example - run: | - cargo build --target wasm32-wasi --example=socket_addr --release - wasmedge target/wasm32-wasi/release/examples/socket_addr.wasm \ No newline at end of file diff --git a/.github/workflows/example_0.12.yml b/.github/workflows/example_0.12.yml deleted file mode 100644 index 93ace918..00000000 --- a/.github/workflows/example_0.12.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: examples 0.12 - -on: - workflow_dispatch: - inputs: - logLevel: - description: 'Log level' - required: true - default: 'info' - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - build: - - runs-on: ubuntu-20.04 - - steps: - - uses: actions/checkout@v2 - - - name: Install apt-get packages - run: | - sudo ACCEPT_EULA=Y apt-get update - sudo ACCEPT_EULA=Y apt-get upgrade - sudo apt-get install wget git curl software-properties-common build-essential - - name: Install Rust target - run: | - rustup target add wasm32-wasi - - name: Install WasmEdge - run: | - VERSION=0.12.1 - curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | sudo bash -s -- -e all --version=$VERSION --tf-version=$VERSION --tf-deps-version=$VERSION --tf-tools-version=$VERSION --image-version=$VERSION -p /usr/local - - # Disable this example due to it relies on wasmedge_http_req, which is a cyclic dependence - # - name: HTTP client example - # run: | - # cd examples/http_client/ - # cargo build --target wasm32-wasi --release - # wasmedge target/wasm32-wasi/release/http_client.wasm - - - name: HTTP async client example - run: | - cd examples/nonblock_http_client/ - cargo build --target wasm32-wasi --release - wasmedge target/wasm32-wasi/release/nonblock_http_client.wasm - - - name: HTTP server example - run: | - cd examples/http_server/ - cargo build --target wasm32-wasi --release - nohup wasmedge target/wasm32-wasi/release/http_server.wasm & - echo $! > wasmedge.pid - wasmedge_pid=$(cat wasmedge.pid) - sleep 5 - echo "fds:" - ls /proc/$wasmedge_pid/fd - resp=$(curl -X POST http://127.0.0.1:1234 -d "name=WasmEdge") - echo "Server response is $resp" - resp=$(curl -X POST http://127.0.0.1:1234 -d "name=WasmEdge") - resp=$(curl -X POST http://127.0.0.1:1234 -d "name=WasmEdge") - resp=$(curl -X POST http://127.0.0.1:1234 -d "name=WasmEdge") - resp=$(curl -X POST http://127.0.0.1:1234 -d "name=WasmEdge") - resp=$(curl -X POST http://127.0.0.1:1234 -d "name=WasmEdge") - echo "after 6 request, fds:" - ls /proc/$wasmedge_pid/fd - kill -9 $wasmedge_pid - rm wasmedge.pid - - - name: UDP Socket Example - run: | - cargo build --target wasm32-wasi --example=udp_socket --release --no-default-features --features=built-in-dns - wasmedge target/wasm32-wasi/release/examples/udp_socket.wasm - - - name: DNS Example - run: | - cargo build --target wasm32-wasi --example=get_addrinfo --release - wasmedge target/wasm32-wasi/release/examples/get_addrinfo.wasm - - - name: ToSocketAddrs Example - run: | - cargo build --target wasm32-wasi --example=socket_addr --release - wasmedge target/wasm32-wasi/release/examples/socket_addr.wasm \ No newline at end of file diff --git a/.github/workflows/example_0.10.yml b/.github/workflows/example_0.13.yml similarity index 96% rename from .github/workflows/example_0.10.yml rename to .github/workflows/example_0.13.yml index 6adc7ac7..aceba364 100644 --- a/.github/workflows/example_0.10.yml +++ b/.github/workflows/example_0.13.yml @@ -1,4 +1,4 @@ -name: examples 0.10 +name: examples 0.13 on: workflow_dispatch: @@ -30,7 +30,7 @@ jobs: rustup target add wasm32-wasi - name: Install WasmEdge run: | - VERSION=0.10.0 + VERSION=0.13.5 curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | sudo bash -s -- -e all --version=$VERSION --tf-version=$VERSION --tf-deps-version=$VERSION --tf-tools-version=$VERSION --image-version=$VERSION -p /usr/local # Disable this example due to it relies on wasmedge_http_req, which is a cyclic dependence @@ -70,7 +70,7 @@ jobs: - name: UDP Socket Example run: | - cargo build --target wasm32-wasi --example=udp_socket --release --no-default-features --features=built-in-dns + cargo build --target wasm32-wasi --example=udp_socket --release wasmedge target/wasm32-wasi/release/examples/udp_socket.wasm - name: DNS Example diff --git a/Cargo.toml b/Cargo.toml index 4a3f4418..080ad745 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmedge_wasi_socket" -version = "0.5.3" +version = "0.5.4" authors = ["Yi "] edition = "2021" license = "Apache-2.0" @@ -21,8 +21,6 @@ libc = "0.2.3" rand = "0.8.5" [features] -default = ["wasmedge_0_12"] -wasmedge_0_12 = [] -built-in-dns = [] +default = [] wasi_poll = [] epoll = [] diff --git a/src/lib.rs b/src/lib.rs index 5301b288..6edd2d1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -318,8 +318,16 @@ impl AsRawFd for UdpSocket { } } -#[cfg(not(feature = "built-in-dns"))] pub fn nslookup(node: &str, service: &str) -> std::io::Result> { + let dns_server = std::env::var("DNS_SERVER"); + if let Ok(dns_server) = dns_server { + nslookup_with_dns_server(&dns_server, node, service) + } else { + nslookup_with_host(node, service) + } +} + +pub fn nslookup_with_host(node: &str, service: &str) -> std::io::Result> { use socket::WasiAddrinfo; let hints: WasiAddrinfo = WasiAddrinfo::default(); let mut sockaddrs = Vec::new(); @@ -367,11 +375,13 @@ pub fn nslookup(node: &str, service: &str) -> std::io::Result> { Ok(r_addrs) } -#[cfg(feature = "built-in-dns")] -pub fn nslookup(node: &str, _service: &str) -> std::io::Result> { - let dns_server = std::env::var("DNS_SERVER").unwrap_or("8.8.8.8:53".into()); +pub fn nslookup_with_dns_server( + dns_server: &str, + node: &str, + _service: &str, +) -> std::io::Result> { let mut conn = TcpStream::connect(dns_server)?; - let timeout = std::time::Duration::from_secs(1); + let timeout = std::time::Duration::from_secs(5); let _ignore = conn.as_mut().set_send_timeout(Some(timeout)); let _ignore = conn.as_mut().set_recv_timeout(Some(timeout)); diff --git a/src/socket.rs b/src/socket.rs index aa649d5d..7754ef1d 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -101,7 +101,6 @@ impl Default for WasiSockaddr { } } -#[cfg(not(feature = "built-in-dns"))] #[derive(Debug, Clone)] #[repr(C, packed(4))] pub struct WasiAddrinfo { @@ -116,7 +115,6 @@ pub struct WasiAddrinfo { pub ai_next: *mut WasiAddrinfo, } -#[cfg(not(feature = "built-in-dns"))] impl WasiAddrinfo { pub fn default() -> WasiAddrinfo { WasiAddrinfo { @@ -195,6 +193,7 @@ impl WasiAddrinfo { max_reslen as u32, &mut res_len, ); + match return_code { 0 => Ok(wasiaddrinfo_array[..res_len as usize].to_vec()), e => Err(std::io::Error::from_raw_os_error(e as i32)), @@ -209,18 +208,47 @@ pub struct IovecRead { pub size: usize, } +impl From for IovecRead { + fn from(value: libc::iovec) -> Self { + IovecRead { + buf: value.iov_base.cast(), + size: value.iov_len, + } + } +} + #[repr(C)] pub struct IovecWrite { pub buf: *const u8, pub size: usize, } +impl From for IovecWrite { + fn from(value: libc::iovec) -> Self { + IovecWrite { + buf: value.iov_base.cast(), + size: value.iov_len, + } + } +} + #[derive(Copy, Clone, Debug)] #[repr(u8, align(1))] pub enum SocketOptLevel { SolSocket = 0, } +impl TryFrom for SocketOptLevel { + type Error = io::Error; + + fn try_from(value: i32) -> Result { + match value { + 0 => Ok(Self::SolSocket), + _ => Err(io::Error::from_raw_os_error(libc::EINVAL)), + } + } +} + #[derive(Copy, Clone, Debug)] #[repr(u8, align(1))] pub enum SocketOptName { @@ -241,6 +269,37 @@ pub enum SocketOptName { SoBindToDevice = 14, } +impl TryFrom for SocketOptName { + type Error = io::Error; + + fn try_from(value: i32) -> Result { + match value { + 0 => Ok(Self::SoReuseaddr), + 1 => Ok(Self::SoType), + 2 => Ok(Self::SoError), + 3 => Ok(Self::SoDontroute), + 4 => Ok(Self::SoBroadcast), + 5 => Ok(Self::SoSndbuf), + 6 => Ok(Self::SoRcvbuf), + 7 => Ok(Self::SoKeepalive), + 8 => Ok(Self::SoOobinline), + 9 => Ok(Self::SoLinger), + 10 => Ok(Self::SoRcvlowat), + 11 => Ok(Self::SoRcvtimeo), + 12 => Ok(Self::SoSndtimeo), + 13 => Ok(Self::SoAcceptconn), + 14 => Ok(Self::SoBindToDevice), + + _ => Err(io::Error::from_raw_os_error(libc::EINVAL)), + } + } +} + +pub const MSG_PEEK: u16 = 1; // __WASI_RIFLAGS_RECV_PEEK +pub const MSG_WAITALL: u16 = 2; // __WASI_RIFLAGS_RECV_WAITALL + +pub const MSG_TRUNC: u16 = 1; // __WASI_ROFLAGS_RECV_DATA_TRUNCATED + macro_rules! syscall { ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{ #[allow(unused_unsafe)] @@ -253,6 +312,10 @@ macro_rules! syscall { }}; } +fn fcntl_get(fd: RawFd, cmd: i32) -> io::Result { + syscall!(fcntl(fd, cmd)) +} + fn fcntl_add(fd: RawFd, get_cmd: i32, set_cmd: i32, flag: i32) -> io::Result<()> { let previous = syscall!(fcntl(fd, get_cmd))?; let new = previous | flag; @@ -294,17 +357,7 @@ mod wasi_sock { recv_len: *mut usize, oflags: *mut usize, ) -> u32; - #[cfg(not(feature = "wasmedge_0_12"))] - pub fn sock_recv_from( - fd: u32, - buf: *mut IovecRead, - buf_len: u32, - addr: *mut u8, - flags: u16, - recv_len: *mut usize, - oflags: *mut usize, - ) -> u32; - #[cfg(feature = "wasmedge_0_12")] + pub fn sock_recv_from( fd: u32, buf: *mut IovecRead, @@ -534,6 +587,33 @@ impl Socket { } } + pub fn send_vectored(&self, bufs: &[io::IoSlice<'_>], flags: u16) -> io::Result { + unsafe { + let mut send_len: u32 = 0; + + let mut write_bufs = Vec::with_capacity(bufs.len()); + for b in bufs { + write_bufs.push(IovecWrite { + buf: b.as_ptr().cast(), + size: b.len(), + }); + } + + let res = sock_send( + self.as_raw_fd() as u32, + write_bufs.as_ptr(), + write_bufs.len() as u32, + flags, + &mut send_len, + ); + if res == 0 { + Ok(send_len as usize) + } else { + Err(io::Error::from_raw_os_error(res as i32)) + } + } + } + pub fn send_to(&self, buf: &[u8], addr: SocketAddr) -> io::Result { let port = addr.port() as u32; let vaddr = match addr { @@ -570,6 +650,49 @@ impl Socket { } } + pub fn send_to_vectored( + &self, + bufs: &[io::IoSlice<'_>], + addr: SocketAddr, + flags: u16, + ) -> io::Result { + let port = addr.port() as u32; + let vaddr = match addr { + SocketAddr::V4(ipv4) => ipv4.ip().octets().to_vec(), + SocketAddr::V6(ipv6) => ipv6.ip().octets().to_vec(), + }; + let addr = WasiAddress { + buf: vaddr.as_ptr(), + size: vaddr.len(), + }; + + let mut write_bufs = Vec::with_capacity(bufs.len()); + for b in bufs { + write_bufs.push(IovecWrite { + buf: b.as_ptr().cast(), + size: b.len(), + }); + } + + let mut send_len: u32 = 0; + unsafe { + let res = sock_send_to( + self.fd as u32, + write_bufs.as_ptr(), + write_bufs.len() as u32, + &addr as *const WasiAddress as *const u8, + port, + flags, + &mut send_len, + ); + if res == 0 { + Ok(send_len as usize) + } else { + Err(io::Error::from_raw_os_error(res as i32)) + } + } + } + pub fn recv(&self, buf: &mut [u8]) -> io::Result { let flags = 0; let mut recv_len: usize = 0; @@ -596,14 +719,63 @@ impl Socket { } } - #[cfg(not(feature = "wasmedge_0_12"))] + pub fn recv_with_flags( + &self, + buf: &mut [MaybeUninit], + flags: u16, + ) -> io::Result<(usize, usize)> { + let mut recv_len: usize = 0; + let mut oflags: usize = 0; + let mut vec = IovecRead { + buf: buf.as_mut_ptr().cast(), + size: buf.len(), + }; + + unsafe { + let res = sock_recv( + self.as_raw_fd() as u32, + &mut vec, + 1, + flags, + &mut recv_len, + &mut oflags, + ); + if res == 0 { + Ok((recv_len, oflags)) + } else { + Err(io::Error::from_raw_os_error(res as i32)) + } + } + } + + pub fn recv_vectored(&self, bufs: &mut [IovecRead], flags: u16) -> io::Result<(usize, usize)> { + let mut recv_len: usize = 0; + let mut oflags: usize = 0; + + unsafe { + let res = sock_recv( + self.as_raw_fd() as u32, + bufs.as_mut_ptr(), + bufs.len(), + flags, + &mut recv_len, + &mut oflags, + ); + if res == 0 { + Ok((recv_len, oflags)) + } else { + Err(io::Error::from_raw_os_error(res as i32)) + } + } + } + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { let flags = 0; - let addr_buf = [0; 16]; + let addr_buf = [0; 128]; let mut addr = WasiAddress { buf: addr_buf.as_ptr(), - size: 16, + size: 128, }; let mut recv_buf = IovecRead { @@ -613,6 +785,7 @@ impl Socket { let mut recv_len: usize = 0; let mut oflags: usize = 0; + let mut sin_port: u32 = 0; unsafe { let res = sock_recv_from( self.as_raw_fd() as u32, @@ -620,6 +793,7 @@ impl Socket { 1, &mut addr as *mut WasiAddress as *mut u8, flags, + &mut sin_port, &mut recv_len, &mut oflags, ); @@ -627,25 +801,18 @@ impl Socket { let sin_family = { let mut d = [0, 0]; d.clone_from_slice(&addr_buf[0..2]); - u16::from_le_bytes(d) - }; - - let sin_port = { - let mut d = [0, 0]; - d.clone_from_slice(&addr_buf[2..4]); - u16::from_le_bytes(d) + u16::from_le_bytes(d) as u8 }; - - let sin_addr = { - if sin_family == 2 { - let ip_addr = - Ipv4Addr::new(addr_buf[4], addr_buf[5], addr_buf[6], addr_buf[7]); - SocketAddr::V4(SocketAddrV4::new(ip_addr, sin_port)) - } else { - // fixme - let ip_addr = Ipv6Addr::from([0; 16]); - SocketAddr::V6(SocketAddrV6::new(ip_addr, sin_port, 0, 0)) - } + let sin_addr = if sin_family == AddressFamily::Inet4 as u8 { + let ip_addr = Ipv4Addr::new(addr_buf[2], addr_buf[3], addr_buf[4], addr_buf[5]); + SocketAddr::V4(SocketAddrV4::new(ip_addr, sin_port as u16)) + } else if sin_family == AddressFamily::Inet6 as u8 { + let mut ipv6_addr = [0u8; 16]; + ipv6_addr.copy_from_slice(&addr_buf[2..18]); + let ip_addr = Ipv6Addr::from(ipv6_addr); + SocketAddr::V6(SocketAddrV6::new(ip_addr, sin_port as u16, 0, 0)) + } else { + unimplemented!("Address family not supported by protocol"); }; Ok((recv_len, sin_addr)) @@ -655,9 +822,11 @@ impl Socket { } } - #[cfg(feature = "wasmedge_0_12")] - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - let flags = 0; + pub fn recv_from_with_flags( + &self, + buf: &mut [MaybeUninit], + flags: u16, + ) -> io::Result<(usize, SocketAddr, usize)> { let addr_buf = [0; 128]; let mut addr = WasiAddress { @@ -666,7 +835,7 @@ impl Socket { }; let mut recv_buf = IovecRead { - buf: buf.as_mut_ptr(), + buf: buf.as_mut_ptr().cast(), size: buf.len(), }; @@ -702,13 +871,70 @@ impl Socket { unimplemented!("Address family not supported by protocol"); }; - Ok((recv_len, sin_addr)) + Ok((recv_len, sin_addr, oflags)) } else { Err(io::Error::from_raw_os_error(res as i32)) } } } + pub fn recv_from_vectored( + &self, + bufs: &mut [IovecRead], + flags: u16, + ) -> io::Result<(usize, SocketAddr, usize)> { + let addr_buf = [0; 128]; + + let mut addr = WasiAddress { + buf: addr_buf.as_ptr(), + size: 128, + }; + + let mut recv_len: usize = 0; + let mut oflags: usize = 0; + let mut sin_port: u32 = 0; + unsafe { + let res = sock_recv_from( + self.as_raw_fd() as u32, + bufs.as_mut_ptr(), + 1, + &mut addr as *mut WasiAddress as *mut u8, + flags, + &mut sin_port, + &mut recv_len, + &mut oflags, + ); + if res == 0 { + let sin_family = { + let mut d = [0, 0]; + d.clone_from_slice(&addr_buf[0..2]); + u16::from_le_bytes(d) as u8 + }; + let sin_addr = if sin_family == AddressFamily::Inet4 as u8 { + let ip_addr = Ipv4Addr::new(addr_buf[2], addr_buf[3], addr_buf[4], addr_buf[5]); + SocketAddr::V4(SocketAddrV4::new(ip_addr, sin_port as u16)) + } else if sin_family == AddressFamily::Inet6 as u8 { + let mut ipv6_addr = [0u8; 16]; + ipv6_addr.copy_from_slice(&addr_buf[2..18]); + let ip_addr = Ipv6Addr::from(ipv6_addr); + SocketAddr::V6(SocketAddrV6::new(ip_addr, sin_port as u16, 0, 0)) + } else { + unimplemented!("Address family not supported by protocol"); + }; + + Ok((recv_len, sin_addr, oflags)) + } else { + Err(io::Error::from_raw_os_error(res as i32)) + } + } + } + + pub fn nonblocking(&self) -> io::Result { + let fd = self.as_raw_fd(); + let file_status_flags = fcntl_get(fd, libc::F_GETFL)?; + Ok((file_status_flags & libc::O_NONBLOCK) != 0) + } + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let fd = self.as_raw_fd(); if nonblocking { @@ -888,6 +1114,150 @@ impl Socket { } } + pub fn is_listener(&self) -> io::Result { + unsafe { + let fd = self.fd; + let mut val = 0; + let mut len = std::mem::size_of::() as u32; + let res = sock_getsockopt( + fd as u32, + SocketOptLevel::SolSocket as i32, + SocketOptName::SoAcceptconn as i32, + &mut val, + &mut len, + ); + if res != 0 { + Err(io::Error::from_raw_os_error(res as i32)) + } else { + Ok(val != 0) + } + } + } + + pub fn r#type(&self) -> io::Result { + unsafe { + let fd = self.fd; + let mut val = 0; + let mut len = std::mem::size_of::() as u32; + let res = sock_getsockopt( + fd as u32, + SocketOptLevel::SolSocket as i32, + SocketOptName::SoType as i32, + &mut val, + &mut len, + ); + if res != 0 { + Err(io::Error::from_raw_os_error(res as i32)) + } else { + match val { + 1 => Ok(SocketType::Datagram), + 2 => Ok(SocketType::Stream), + _ => Err(io::Error::from_raw_os_error(libc::EINVAL)), + } + } + } + } + + pub fn broadcast(&self) -> io::Result { + unsafe { + let fd = self.fd; + let mut val = 0; + let mut len = std::mem::size_of::() as u32; + let res = sock_getsockopt( + fd as u32, + SocketOptLevel::SolSocket as i32, + SocketOptName::SoBroadcast as i32, + &mut val, + &mut len, + ); + if res != 0 { + Err(io::Error::from_raw_os_error(res as i32)) + } else { + Ok(val != 0) + } + } + } + + pub fn keepalive(&self) -> io::Result { + unsafe { + let fd = self.fd; + let mut val = 0; + let mut len = std::mem::size_of::() as u32; + let res = sock_getsockopt( + fd as u32, + SocketOptLevel::SolSocket as i32, + SocketOptName::SoKeepalive as i32, + &mut val, + &mut len, + ); + if res != 0 { + Err(io::Error::from_raw_os_error(res as i32)) + } else { + Ok(val != 0) + } + } + } + + pub fn recv_buffer_size(&self) -> io::Result { + unsafe { + let fd = self.fd; + let mut val = 0; + let mut len = std::mem::size_of::() as u32; + let res = sock_getsockopt( + fd as u32, + SocketOptLevel::SolSocket as i32, + SocketOptName::SoRcvbuf as i32, + &mut val, + &mut len, + ); + if res != 0 { + Err(io::Error::from_raw_os_error(res as i32)) + } else { + Ok(val as usize) + } + } + } + + pub fn send_buffer_size(&self) -> io::Result { + unsafe { + let fd = self.fd; + let mut val = 0; + let mut len = std::mem::size_of::() as u32; + let res = sock_getsockopt( + fd as u32, + SocketOptLevel::SolSocket as i32, + SocketOptName::SoSndbuf as i32, + &mut val, + &mut len, + ); + if res != 0 { + Err(io::Error::from_raw_os_error(res as i32)) + } else { + Ok(val as usize) + } + } + } + + pub fn reuse_address(&self) -> io::Result { + unsafe { + let fd = self.fd; + let mut val = 0; + let mut len = std::mem::size_of::() as u32; + let res = sock_getsockopt( + fd as u32, + SocketOptLevel::SolSocket as i32, + SocketOptName::SoReuseaddr as i32, + &mut val, + &mut len, + ); + if res != 0 { + Err(io::Error::from_raw_os_error(res as i32)) + } else { + Ok(val != 0) + } + } + } + pub fn setsockopt( &self, level: SocketOptLevel,