Skip to content

Commit a4f9c89

Browse files
authored
Add safe sockopt rules (#284)
I implemented setsockopt in libcc2rs/src/libc_shims/socket.rs because it contains a lot of match arms and some of them are linux specific. It doesn't make sense to have them in the generated code for macos, for example
1 parent 50d4cc3 commit a4f9c89

9 files changed

Lines changed: 332 additions & 0 deletions

File tree

‎libcc2rs/src/libc_shims/socket.rs‎

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,3 +378,104 @@ impl Sockaddr {
378378
out_len.write(ss.len());
379379
}
380380
}
381+
382+
pub fn setsockopt_refcount(fd: i32, level: i32, optname: i32, optval: crate::AnyPtr) -> i32 {
383+
let res = match (level, optname) {
384+
(::libc::IPPROTO_TCP, ::libc::TCP_NODELAY) => {
385+
let v = optval.reinterpret_cast::<i32>().read() != 0;
386+
crate::FdRegistry::with_fd(fd, |borrowed| {
387+
nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::TcpNoDelay, &v)
388+
})
389+
}
390+
(::libc::SOL_SOCKET, ::libc::SO_KEEPALIVE) => {
391+
let v = optval.reinterpret_cast::<i32>().read() != 0;
392+
crate::FdRegistry::with_fd(fd, |borrowed| {
393+
nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::KeepAlive, &v)
394+
})
395+
}
396+
(::libc::IPPROTO_TCP, ::libc::TCP_KEEPINTVL) => {
397+
let v = optval.reinterpret_cast::<u32>().read();
398+
crate::FdRegistry::with_fd(fd, |borrowed| {
399+
nix::sys::socket::setsockopt(
400+
&borrowed,
401+
nix::sys::socket::sockopt::TcpKeepInterval,
402+
&v,
403+
)
404+
})
405+
}
406+
(::libc::IPPROTO_TCP, ::libc::TCP_KEEPCNT) => {
407+
let v = optval.reinterpret_cast::<u32>().read();
408+
crate::FdRegistry::with_fd(fd, |borrowed| {
409+
nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::TcpKeepCount, &v)
410+
})
411+
}
412+
#[cfg(target_os = "linux")]
413+
(::libc::IPPROTO_IP, ::libc::IP_TOS) => {
414+
let v = optval.reinterpret_cast::<i32>().read();
415+
crate::FdRegistry::with_fd(fd, |borrowed| {
416+
nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::Ipv4Tos, &v)
417+
})
418+
}
419+
#[cfg(target_os = "linux")]
420+
(::libc::IPPROTO_IPV6, ::libc::IPV6_TCLASS) => {
421+
let v = optval.reinterpret_cast::<i32>().read();
422+
crate::FdRegistry::with_fd(fd, |borrowed| {
423+
nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::Ipv6TClass, &v)
424+
})
425+
}
426+
#[cfg(target_os = "linux")]
427+
(::libc::IPPROTO_TCP, ::libc::TCP_KEEPIDLE) => {
428+
let v = optval.reinterpret_cast::<u32>().read();
429+
crate::FdRegistry::with_fd(fd, |borrowed| {
430+
nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::TcpKeepIdle, &v)
431+
})
432+
}
433+
#[cfg(target_os = "linux")]
434+
(::libc::SOL_SOCKET, ::libc::SO_BINDTODEVICE) => {
435+
let v = ::std::ffi::OsString::from(optval.reinterpret_cast::<u8>().to_rust_string());
436+
crate::FdRegistry::with_fd(fd, |borrowed| {
437+
nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::BindToDevice, &v)
438+
})
439+
}
440+
#[cfg(target_os = "linux")]
441+
(::libc::IPPROTO_IP, ::libc::IP_BIND_ADDRESS_NO_PORT) => {
442+
let v = optval.reinterpret_cast::<i32>().read() != 0;
443+
crate::FdRegistry::with_fd(fd, |borrowed| {
444+
nix::sys::socket::setsockopt(
445+
&borrowed,
446+
nix::sys::socket::sockopt::IpBindAddressNoPort,
447+
&v,
448+
)
449+
})
450+
}
451+
#[cfg(target_os = "linux")]
452+
(::libc::IPPROTO_TCP, ::libc::TCP_FASTOPEN_CONNECT) => {
453+
let v = optval.reinterpret_cast::<i32>().read() != 0;
454+
crate::FdRegistry::with_fd(fd, |borrowed| {
455+
nix::sys::socket::setsockopt(
456+
&borrowed,
457+
nix::sys::socket::sockopt::TcpFastOpenConnect,
458+
&v,
459+
)
460+
})
461+
}
462+
#[cfg(target_os = "linux")]
463+
(::libc::SOL_SOCKET, ::libc::SO_PRIORITY) => {
464+
let v = optval.reinterpret_cast::<i32>().read();
465+
crate::FdRegistry::with_fd(fd, |borrowed| {
466+
nix::sys::socket::setsockopt(&borrowed, nix::sys::socket::sockopt::Priority, &v)
467+
})
468+
}
469+
(l, o) => panic!(
470+
"setsockopt: unsupported option (level={}, optname={})",
471+
l, o
472+
),
473+
};
474+
match res {
475+
Ok(()) => 0,
476+
Err(e) => {
477+
crate::cpp2rust_errno().write(e as i32);
478+
-1
479+
}
480+
}
481+
}

‎rules/ip/src.cpp‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <netinet/in.h>
2+
#include <netinet/tcp.h>
23

34
typedef struct sockaddr_in t1;
45
typedef struct in_addr t2;
@@ -26,3 +27,7 @@ int f5() {
2627
return IPPROTO_MPTCP;
2728
}
2829
#endif
30+
31+
int f6() {
32+
return TCP_NODELAY;
33+
}

‎rules/ip/tgt_unsafe.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,7 @@ unsafe fn f4() -> i32 {
3434
unsafe fn f5() -> i32 {
3535
libc::IPPROTO_MPTCP
3636
}
37+
38+
unsafe fn f6() -> i32 {
39+
libc::TCP_NODELAY
40+
}

‎rules/socket/src.c‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,15 @@ int f20() {
9696
int f21() {
9797
return AF_INET6;
9898
}
99+
100+
int f22() {
101+
return SOL_SOCKET;
102+
}
103+
104+
int f23() {
105+
return SO_KEEPALIVE;
106+
}
107+
108+
int f24() {
109+
return SO_ERROR;
110+
}

‎rules/socket/tgt_refcount.rs‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,35 @@ fn f17(a0: i32, a1: i32) -> i32 {
218218
}
219219
}
220220
}
221+
222+
fn f7(a0: i32, a1: i32, a2: i32, a3: AnyPtr, a4: u32) -> i32 {
223+
let __a0 = a0;
224+
let __a1 = a1;
225+
let __a2 = a2;
226+
let __a3 = a3;
227+
libcc2rs::setsockopt_refcount(__a0, __a1, __a2, __a3)
228+
}
229+
230+
fn f8(a0: i32, a1: i32, a2: i32, a3: AnyPtr, a4: Ptr<u32>) -> i32 {
231+
match (a1, a2) {
232+
(::libc::SOL_SOCKET, ::libc::SO_ERROR) => {
233+
match FdRegistry::with_fd(a0, |__fd| {
234+
nix::sys::socket::getsockopt(&__fd, nix::sys::socket::sockopt::SocketError)
235+
}) {
236+
Ok(__err) => {
237+
a3.reinterpret_cast::<i32>().write(__err);
238+
a4.write(::std::mem::size_of::<i32>() as u32);
239+
0
240+
}
241+
Err(__e) => {
242+
libcc2rs::cpp2rust_errno().write(__e as i32);
243+
-1
244+
}
245+
}
246+
}
247+
(__l, __o) => panic!(
248+
"getsockopt: unsupported option (level={}, optname={})",
249+
__l, __o
250+
),
251+
}
252+
}

‎rules/socket/tgt_unsafe.rs‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,15 @@ unsafe fn f20() -> i32 {
110110
unsafe fn f21() -> i32 {
111111
libc::AF_INET6
112112
}
113+
114+
unsafe fn f22() -> i32 {
115+
libc::SOL_SOCKET
116+
}
117+
118+
unsafe fn f23() -> i32 {
119+
libc::SO_KEEPALIVE
120+
}
121+
122+
unsafe fn f24() -> i32 {
123+
libc::SO_ERROR
124+
}

‎tests/unit/out/refcount/sockopt.rs‎

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
extern crate libcc2rs;
2+
use libcc2rs::*;
3+
use std::cell::RefCell;
4+
use std::collections::BTreeMap;
5+
use std::io::prelude::*;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::AsFd;
8+
use std::rc::{Rc, Weak};
9+
pub fn main() {
10+
std::process::exit(main_0());
11+
}
12+
fn main_0() -> i32 {
13+
let s: Value<i32> = Rc::new(RefCell::new({
14+
let __family = match libc::AF_INET {
15+
::libc::AF_INET => nix::sys::socket::AddressFamily::Inet,
16+
::libc::AF_INET6 => nix::sys::socket::AddressFamily::Inet6,
17+
::libc::AF_UNIX => nix::sys::socket::AddressFamily::Unix,
18+
__d => panic!("socket: unsupported domain {__d}"),
19+
};
20+
let __flags = nix::sys::socket::SockFlag::from_bits_truncate(libc::SOCK_STREAM);
21+
let __ty = match libc::SOCK_STREAM & !nix::sys::socket::SockFlag::all().bits() {
22+
::libc::SOCK_STREAM => nix::sys::socket::SockType::Stream,
23+
::libc::SOCK_DGRAM => nix::sys::socket::SockType::Datagram,
24+
__t => panic!("socket: unsupported type {__t}"),
25+
};
26+
let __proto = match 0 {
27+
0 => None,
28+
::libc::IPPROTO_TCP => Some(nix::sys::socket::SockProtocol::Tcp),
29+
::libc::IPPROTO_UDP => Some(nix::sys::socket::SockProtocol::Udp),
30+
__p => panic!("socket: unsupported protocol {__p}"),
31+
};
32+
match nix::sys::socket::socket(__family, __ty, __flags, __proto) {
33+
Ok(__ofd) => FdRegistry::register(__ofd),
34+
Err(__e) => {
35+
libcc2rs::cpp2rust_errno().write(__e as i32);
36+
-1
37+
}
38+
}
39+
}));
40+
assert!(((((*s.borrow()) >= 0) as i32) != 0));
41+
let on: Value<i32> = Rc::new(RefCell::new(1));
42+
assert!(
43+
((({
44+
let __a0 = (*s.borrow());
45+
let __a1 = libc::SOL_SOCKET;
46+
let __a2 = libc::SO_KEEPALIVE;
47+
let __a3 = ((on.as_pointer()) as Ptr<i32>).to_any();
48+
libcc2rs::setsockopt_refcount(__a0, __a1, __a2, __a3)
49+
} == 0) as i32)
50+
!= 0)
51+
);
52+
assert!(
53+
((({
54+
let __a0 = (*s.borrow());
55+
let __a1 = libc::IPPROTO_TCP;
56+
let __a2 = libc::TCP_NODELAY;
57+
let __a3 = ((on.as_pointer()) as Ptr<i32>).to_any();
58+
libcc2rs::setsockopt_refcount(__a0, __a1, __a2, __a3)
59+
} == 0) as i32)
60+
!= 0)
61+
);
62+
let err: Value<i32> = Rc::new(RefCell::new(-1_i32));
63+
let len: Value<u32> = Rc::new(RefCell::new((::std::mem::size_of::<i32>() as u32)));
64+
assert!(
65+
(((match (libc::SOL_SOCKET, libc::SO_ERROR) {
66+
(::libc::SOL_SOCKET, ::libc::SO_ERROR) => {
67+
match FdRegistry::with_fd((*s.borrow()), |__fd| {
68+
nix::sys::socket::getsockopt(&__fd, nix::sys::socket::sockopt::SocketError)
69+
}) {
70+
Ok(__err) => {
71+
((err.as_pointer()) as Ptr<i32>)
72+
.to_any()
73+
.reinterpret_cast::<i32>()
74+
.write(__err);
75+
(len.as_pointer()).write(::std::mem::size_of::<i32>() as u32);
76+
0
77+
}
78+
Err(__e) => {
79+
libcc2rs::cpp2rust_errno().write(__e as i32);
80+
-1
81+
}
82+
}
83+
}
84+
(__l, __o) => panic!(
85+
"getsockopt: unsupported option (level={}, optname={})",
86+
__l, __o
87+
),
88+
} == 0) as i32)
89+
!= 0)
90+
);
91+
assert!(((((*err.borrow()) == 0) as i32) != 0));
92+
assert!((((FdRegistry::close((*s.borrow())) == 0) as i32) != 0));
93+
return 0;
94+
}

‎tests/unit/out/unsafe/sockopt.rs‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
extern crate libc;
2+
use libc::*;
3+
extern crate libcc2rs;
4+
use libcc2rs::*;
5+
use std::collections::BTreeMap;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
8+
use std::rc::Rc;
9+
pub fn main() {
10+
unsafe {
11+
std::process::exit(main_0() as i32);
12+
}
13+
}
14+
unsafe fn main_0() -> i32 {
15+
let mut s: i32 = libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0);
16+
assert!(((((s) >= (0)) as i32) != 0));
17+
let mut on: i32 = 1;
18+
assert!(
19+
((((libc::setsockopt(
20+
s,
21+
libc::SOL_SOCKET,
22+
libc::SO_KEEPALIVE,
23+
((&mut on as *mut i32) as *const i32 as *const ::libc::c_void),
24+
(::std::mem::size_of::<i32>() as u32)
25+
)) == (0)) as i32)
26+
!= 0)
27+
);
28+
assert!(
29+
((((libc::setsockopt(
30+
s,
31+
libc::IPPROTO_TCP,
32+
libc::TCP_NODELAY,
33+
((&mut on as *mut i32) as *const i32 as *const ::libc::c_void),
34+
(::std::mem::size_of::<i32>() as u32)
35+
)) == (0)) as i32)
36+
!= 0)
37+
);
38+
let mut err: i32 = -1_i32;
39+
let mut len: u32 = (::std::mem::size_of::<i32>() as u32);
40+
assert!(
41+
((((libc::getsockopt(
42+
s,
43+
libc::SOL_SOCKET,
44+
libc::SO_ERROR,
45+
((&mut err as *mut i32) as *mut i32 as *mut ::libc::c_void),
46+
(&mut len as *mut u32)
47+
)) == (0)) as i32)
48+
!= 0)
49+
);
50+
assert!(((((err) == (0)) as i32) != 0));
51+
assert!(((((libc::close(s)) == (0)) as i32) != 0));
52+
return 0;
53+
}

‎tests/unit/sockopt.c‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <assert.h>
2+
#include <netinet/in.h>
3+
#include <netinet/tcp.h>
4+
#include <sys/socket.h>
5+
#include <unistd.h>
6+
7+
int main(void) {
8+
int s = socket(AF_INET, SOCK_STREAM, 0);
9+
assert(s >= 0);
10+
int on = 1;
11+
assert(setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == 0);
12+
assert(setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == 0);
13+
int err = -1;
14+
socklen_t len = sizeof(err);
15+
assert(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) == 0);
16+
assert(err == 0);
17+
assert(close(s) == 0);
18+
return 0;
19+
}

0 commit comments

Comments
 (0)