diff --git a/libcc2rs/src/libc_shims/socket.rs b/libcc2rs/src/libc_shims/socket.rs index 3b15500a..c2391558 100644 --- a/libcc2rs/src/libc_shims/socket.rs +++ b/libcc2rs/src/libc_shims/socket.rs @@ -378,3 +378,104 @@ impl Sockaddr { out_len.write(ss.len()); } } + +pub fn setsockopt_refcount(fd: i32, level: i32, optname: i32, optval: crate::AnyPtr) -> i32 { + let res = match (level, optname) { + (::libc::IPPROTO_TCP, ::libc::TCP_NODELAY) => { + let v = optval.reinterpret_cast::().read() != 0; + crate::FdRegistry::with_fd(fd, |borrowed| { + nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::TcpNoDelay, &v) + }) + } + (::libc::SOL_SOCKET, ::libc::SO_KEEPALIVE) => { + let v = optval.reinterpret_cast::().read() != 0; + crate::FdRegistry::with_fd(fd, |borrowed| { + nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::KeepAlive, &v) + }) + } + (::libc::IPPROTO_TCP, ::libc::TCP_KEEPINTVL) => { + let v = optval.reinterpret_cast::().read(); + crate::FdRegistry::with_fd(fd, |borrowed| { + nix::sys::socket::setsockopt( + &borrowed, + nix::sys::socket::sockopt::TcpKeepInterval, + &v, + ) + }) + } + (::libc::IPPROTO_TCP, ::libc::TCP_KEEPCNT) => { + let v = optval.reinterpret_cast::().read(); + crate::FdRegistry::with_fd(fd, |borrowed| { + nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::TcpKeepCount, &v) + }) + } + #[cfg(target_os = "linux")] + (::libc::IPPROTO_IP, ::libc::IP_TOS) => { + let v = optval.reinterpret_cast::().read(); + crate::FdRegistry::with_fd(fd, |borrowed| { + nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::Ipv4Tos, &v) + }) + } + #[cfg(target_os = "linux")] + (::libc::IPPROTO_IPV6, ::libc::IPV6_TCLASS) => { + let v = optval.reinterpret_cast::().read(); + crate::FdRegistry::with_fd(fd, |borrowed| { + nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::Ipv6TClass, &v) + }) + } + #[cfg(target_os = "linux")] + (::libc::IPPROTO_TCP, ::libc::TCP_KEEPIDLE) => { + let v = optval.reinterpret_cast::().read(); + crate::FdRegistry::with_fd(fd, |borrowed| { + nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::TcpKeepIdle, &v) + }) + } + #[cfg(target_os = "linux")] + (::libc::SOL_SOCKET, ::libc::SO_BINDTODEVICE) => { + let v = ::std::ffi::OsString::from(optval.reinterpret_cast::().to_rust_string()); + crate::FdRegistry::with_fd(fd, |borrowed| { + nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::BindToDevice, &v) + }) + } + #[cfg(target_os = "linux")] + (::libc::IPPROTO_IP, ::libc::IP_BIND_ADDRESS_NO_PORT) => { + let v = optval.reinterpret_cast::().read() != 0; + crate::FdRegistry::with_fd(fd, |borrowed| { + nix::sys::socket::setsockopt( + &borrowed, + nix::sys::socket::sockopt::IpBindAddressNoPort, + &v, + ) + }) + } + #[cfg(target_os = "linux")] + (::libc::IPPROTO_TCP, ::libc::TCP_FASTOPEN_CONNECT) => { + let v = optval.reinterpret_cast::().read() != 0; + crate::FdRegistry::with_fd(fd, |borrowed| { + nix::sys::socket::setsockopt( + &borrowed, + nix::sys::socket::sockopt::TcpFastOpenConnect, + &v, + ) + }) + } + #[cfg(target_os = "linux")] + (::libc::SOL_SOCKET, ::libc::SO_PRIORITY) => { + let v = optval.reinterpret_cast::().read(); + crate::FdRegistry::with_fd(fd, |borrowed| { + nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::Priority, &v) + }) + } + (l, o) => panic!( + "setsockopt: unsupported option (level={}, optname={})", + l, o + ), + }; + match res { + Ok(()) => 0, + Err(e) => { + crate::cpp2rust_errno().write(e as i32); + -1 + } + } +} diff --git a/rules/ip/src.cpp b/rules/ip/src.cpp index ca5b4a4b..3b44b4e3 100644 --- a/rules/ip/src.cpp +++ b/rules/ip/src.cpp @@ -1,4 +1,5 @@ #include +#include typedef struct sockaddr_in t1; typedef struct in_addr t2; @@ -26,3 +27,7 @@ int f5() { return IPPROTO_MPTCP; } #endif + +int f6() { + return TCP_NODELAY; +} diff --git a/rules/ip/tgt_unsafe.rs b/rules/ip/tgt_unsafe.rs index 7dd3988a..caba50fa 100644 --- a/rules/ip/tgt_unsafe.rs +++ b/rules/ip/tgt_unsafe.rs @@ -34,3 +34,7 @@ unsafe fn f4() -> i32 { unsafe fn f5() -> i32 { libc::IPPROTO_MPTCP } + +unsafe fn f6() -> i32 { + libc::TCP_NODELAY +} diff --git a/rules/socket/src.c b/rules/socket/src.c index 95f63fd1..19c9ca8d 100644 --- a/rules/socket/src.c +++ b/rules/socket/src.c @@ -96,3 +96,15 @@ int f20() { int f21() { return AF_INET6; } + +int f22() { + return SOL_SOCKET; +} + +int f23() { + return SO_KEEPALIVE; +} + +int f24() { + return SO_ERROR; +} diff --git a/rules/socket/tgt_refcount.rs b/rules/socket/tgt_refcount.rs index 69bda802..b1d1722c 100644 --- a/rules/socket/tgt_refcount.rs +++ b/rules/socket/tgt_refcount.rs @@ -218,3 +218,35 @@ fn f17(a0: i32, a1: i32) -> i32 { } } } + +fn f7(a0: i32, a1: i32, a2: i32, a3: AnyPtr, a4: u32) -> i32 { + let __a0 = a0; + let __a1 = a1; + let __a2 = a2; + let __a3 = a3; + libcc2rs::setsockopt_refcount(__a0, __a1, __a2, __a3) +} + +fn f8(a0: i32, a1: i32, a2: i32, a3: AnyPtr, a4: Ptr) -> i32 { + match (a1, a2) { + (::libc::SOL_SOCKET, ::libc::SO_ERROR) => { + match FdRegistry::with_fd(a0, |__fd| { + nix::sys::socket::getsockopt(&__fd, nix::sys::socket::sockopt::SocketError) + }) { + Ok(__err) => { + a3.reinterpret_cast::().write(__err); + a4.write(::std::mem::size_of::() as u32); + 0 + } + Err(__e) => { + libcc2rs::cpp2rust_errno().write(__e as i32); + -1 + } + } + } + (__l, __o) => panic!( + "getsockopt: unsupported option (level={}, optname={})", + __l, __o + ), + } +} diff --git a/rules/socket/tgt_unsafe.rs b/rules/socket/tgt_unsafe.rs index 1af2d775..402a1782 100644 --- a/rules/socket/tgt_unsafe.rs +++ b/rules/socket/tgt_unsafe.rs @@ -110,3 +110,15 @@ unsafe fn f20() -> i32 { unsafe fn f21() -> i32 { libc::AF_INET6 } + +unsafe fn f22() -> i32 { + libc::SOL_SOCKET +} + +unsafe fn f23() -> i32 { + libc::SO_KEEPALIVE +} + +unsafe fn f24() -> i32 { + libc::SO_ERROR +} diff --git a/tests/unit/out/refcount/sockopt.rs b/tests/unit/out/refcount/sockopt.rs new file mode 100644 index 00000000..1afb88fa --- /dev/null +++ b/tests/unit/out/refcount/sockopt.rs @@ -0,0 +1,94 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let s: Value = Rc::new(RefCell::new({ + let __family = match libc::AF_INET { + ::libc::AF_INET => nix::sys::socket::AddressFamily::Inet, + ::libc::AF_INET6 => nix::sys::socket::AddressFamily::Inet6, + ::libc::AF_UNIX => nix::sys::socket::AddressFamily::Unix, + __d => panic!("socket: unsupported domain {__d}"), + }; + let __flags = nix::sys::socket::SockFlag::from_bits_truncate(libc::SOCK_STREAM); + let __ty = match libc::SOCK_STREAM & !nix::sys::socket::SockFlag::all().bits() { + ::libc::SOCK_STREAM => nix::sys::socket::SockType::Stream, + ::libc::SOCK_DGRAM => nix::sys::socket::SockType::Datagram, + __t => panic!("socket: unsupported type {__t}"), + }; + let __proto = match 0 { + 0 => None, + ::libc::IPPROTO_TCP => Some(nix::sys::socket::SockProtocol::Tcp), + ::libc::IPPROTO_UDP => Some(nix::sys::socket::SockProtocol::Udp), + __p => panic!("socket: unsupported protocol {__p}"), + }; + match nix::sys::socket::socket(__family, __ty, __flags, __proto) { + Ok(__ofd) => FdRegistry::register(__ofd), + Err(__e) => { + libcc2rs::cpp2rust_errno().write(__e as i32); + -1 + } + } + })); + assert!(((((*s.borrow()) >= 0) as i32) != 0)); + let on: Value = Rc::new(RefCell::new(1)); + assert!( + ((({ + let __a0 = (*s.borrow()); + let __a1 = libc::SOL_SOCKET; + let __a2 = libc::SO_KEEPALIVE; + let __a3 = ((on.as_pointer()) as Ptr).to_any(); + libcc2rs::setsockopt_refcount(__a0, __a1, __a2, __a3) + } == 0) as i32) + != 0) + ); + assert!( + ((({ + let __a0 = (*s.borrow()); + let __a1 = libc::IPPROTO_TCP; + let __a2 = libc::TCP_NODELAY; + let __a3 = ((on.as_pointer()) as Ptr).to_any(); + libcc2rs::setsockopt_refcount(__a0, __a1, __a2, __a3) + } == 0) as i32) + != 0) + ); + let err: Value = Rc::new(RefCell::new(-1_i32)); + let len: Value = Rc::new(RefCell::new((::std::mem::size_of::() as u32))); + assert!( + (((match (libc::SOL_SOCKET, libc::SO_ERROR) { + (::libc::SOL_SOCKET, ::libc::SO_ERROR) => { + match FdRegistry::with_fd((*s.borrow()), |__fd| { + nix::sys::socket::getsockopt(&__fd, nix::sys::socket::sockopt::SocketError) + }) { + Ok(__err) => { + ((err.as_pointer()) as Ptr) + .to_any() + .reinterpret_cast::() + .write(__err); + (len.as_pointer()).write(::std::mem::size_of::() as u32); + 0 + } + Err(__e) => { + libcc2rs::cpp2rust_errno().write(__e as i32); + -1 + } + } + } + (__l, __o) => panic!( + "getsockopt: unsupported option (level={}, optname={})", + __l, __o + ), + } == 0) as i32) + != 0) + ); + assert!(((((*err.borrow()) == 0) as i32) != 0)); + assert!((((FdRegistry::close((*s.borrow())) == 0) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/unsafe/sockopt.rs b/tests/unit/out/unsafe/sockopt.rs new file mode 100644 index 00000000..354dbf5f --- /dev/null +++ b/tests/unit/out/unsafe/sockopt.rs @@ -0,0 +1,53 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut s: i32 = libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0); + assert!(((((s) >= (0)) as i32) != 0)); + let mut on: i32 = 1; + assert!( + ((((libc::setsockopt( + s, + libc::SOL_SOCKET, + libc::SO_KEEPALIVE, + ((&mut on as *mut i32) as *const i32 as *const ::libc::c_void), + (::std::mem::size_of::() as u32) + )) == (0)) as i32) + != 0) + ); + assert!( + ((((libc::setsockopt( + s, + libc::IPPROTO_TCP, + libc::TCP_NODELAY, + ((&mut on as *mut i32) as *const i32 as *const ::libc::c_void), + (::std::mem::size_of::() as u32) + )) == (0)) as i32) + != 0) + ); + let mut err: i32 = -1_i32; + let mut len: u32 = (::std::mem::size_of::() as u32); + assert!( + ((((libc::getsockopt( + s, + libc::SOL_SOCKET, + libc::SO_ERROR, + ((&mut err as *mut i32) as *mut i32 as *mut ::libc::c_void), + (&mut len as *mut u32) + )) == (0)) as i32) + != 0) + ); + assert!(((((err) == (0)) as i32) != 0)); + assert!(((((libc::close(s)) == (0)) as i32) != 0)); + return 0; +} diff --git a/tests/unit/sockopt.c b/tests/unit/sockopt.c new file mode 100644 index 00000000..b5d31d2d --- /dev/null +++ b/tests/unit/sockopt.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + +int main(void) { + int s = socket(AF_INET, SOCK_STREAM, 0); + assert(s >= 0); + int on = 1; + assert(setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == 0); + assert(setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == 0); + int err = -1; + socklen_t len = sizeof(err); + assert(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) == 0); + assert(err == 0); + assert(close(s) == 0); + return 0; +}