Skip to content

Commit 55d0e54

Browse files
committed
feat: add dont_frag option
Signed-off-by: loongtao.zhang <[email protected]>
1 parent 08ae506 commit 55d0e54

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed

src/socket.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,6 +1615,53 @@ impl Socket {
16151615
.map(|recv_tos| recv_tos > 0)
16161616
}
16171617
}
1618+
1619+
/// Set value for `IP_DONTFRAG` option of this socket
1620+
#[cfg(any(
1621+
target_os = "macos",
1622+
target_os = "ios",
1623+
target_os = "linux",
1624+
target_os = "windows",
1625+
))]
1626+
pub fn dont_frag(&self) -> io::Result<bool> {
1627+
unsafe {
1628+
#[cfg(any(target_os = "macos", target_os = "ios",))]
1629+
return getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_DONTFRAG)
1630+
.map(|dont_frag| dont_frag > 0);
1631+
#[cfg(any(target_os = "linux", target_os = "windows",))]
1632+
return getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MTU_DISCOVER)
1633+
.map(|dont_frag| dont_frag == 0);
1634+
}
1635+
}
1636+
/// Set value for `IP_DONTFRAG` option on this socket
1637+
#[cfg(any(
1638+
target_os = "macos",
1639+
target_os = "ios",
1640+
target_os = "linux",
1641+
target_os = "windows",
1642+
))]
1643+
pub fn set_dont_frag(&self, dont_frag: bool) -> io::Result<()> {
1644+
unsafe {
1645+
#[cfg(any(target_os = "macos", target_os = "ios",))]
1646+
return setsockopt(
1647+
self.as_raw(),
1648+
sys::IPPROTO_IP,
1649+
libc::IP_DONTFRAG,
1650+
dont_frag as c_int,
1651+
);
1652+
#[cfg(any(target_os = "linux", target_os = "windows",))]
1653+
return setsockopt(
1654+
self.as_raw(),
1655+
sys::IPPROTO_IP,
1656+
sys::IP_MTU_DISCOVER,
1657+
if dont_frag {
1658+
sys::IP_PMTUDISC_DONT
1659+
} else {
1660+
sys::IP_PMTUDISC_DO
1661+
},
1662+
);
1663+
};
1664+
}
16181665
}
16191666

16201667
/// Socket options for IPv6 sockets, get/set using `IPPROTO_IPV6`.
@@ -2015,6 +2062,54 @@ impl Socket {
20152062
)
20162063
}
20172064
}
2065+
2066+
/// Get value for `IP_DONTFRAG` option on this socket.
2067+
#[cfg(any(
2068+
target_os = "linux",
2069+
target_os = "windows",
2070+
target_os = "macos",
2071+
target_os = "ios",
2072+
))]
2073+
pub fn dont_frag_v6(&self) -> io::Result<bool> {
2074+
unsafe {
2075+
#[cfg(any(target_os = "macos", target_os = "ios",))]
2076+
return getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, libc::IPV6_DONTFRAG)
2077+
.map(|dont_frag| dont_frag > 0);
2078+
#[cfg(any(target_os = "linux", target_os = "windows",))]
2079+
return getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MTU_DISCOVER)
2080+
.map(|dont_frag| dont_frag == sys::IP_PMTUDISC_DONT);
2081+
}
2082+
}
2083+
2084+
/// Set value for `IP_DONTFRAG` option on this socket
2085+
#[cfg(any(
2086+
target_os = "macos",
2087+
target_os = "ios",
2088+
target_os = "linux",
2089+
target_os = "windows",
2090+
))]
2091+
pub fn set_dont_frag_v6(&self, dont_frag: bool) -> io::Result<()> {
2092+
unsafe {
2093+
#[cfg(any(target_os = "macos", target_os = "ios",))]
2094+
return setsockopt(
2095+
self.as_raw(),
2096+
sys::IPPROTO_IPV6,
2097+
libc::IPV6_DONTFRAG,
2098+
dont_frag as c_int,
2099+
);
2100+
#[cfg(any(target_os = "linux", target_os = "windows",))]
2101+
setsockopt(
2102+
self.as_raw(),
2103+
sys::IPPROTO_IPV6,
2104+
sys::IPV6_MTU_DISCOVER,
2105+
if dont_frag {
2106+
sys::IP_PMTUDISC_DONT
2107+
} else {
2108+
sys::IP_PMTUDISC_DO
2109+
},
2110+
)
2111+
}
2112+
}
20182113
}
20192114

20202115
/// Socket options for TCP sockets, get/set using `IPPROTO_TCP`.

src/sys/unix.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ pub(crate) use libc::{
204204
SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF,
205205
SO_SNDTIMEO, SO_TYPE, TCP_NODELAY,
206206
};
207+
208+
#[cfg(target_os = "linux")]
209+
pub(crate) use libc::{IPV6_MTU_DISCOVER, IP_MTU_DISCOVER, IP_PMTUDISC_DO, IP_PMTUDISC_DONT};
210+
207211
#[cfg(not(any(
208212
target_os = "dragonfly",
209213
target_os = "haiku",

src/sys/windows.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ pub(crate) use windows_sys::Win32::Networking::WinSock::{
8484
pub(crate) const IPPROTO_IP: c_int = windows_sys::Win32::Networking::WinSock::IPPROTO_IP as c_int;
8585
pub(crate) const SOL_SOCKET: c_int = windows_sys::Win32::Networking::WinSock::SOL_SOCKET as c_int;
8686

87+
pub(crate) const IPV6_MTU_DISCOVER: c_int =
88+
windows_sys::Win32::Networking::WinSock::IPV6_MTU_DISCOVER as c_int;
89+
pub(crate) const IP_MTU_DISCOVER: c_int =
90+
windows_sys::Win32::Networking::WinSock::IP_MTU_DISCOVER as c_int;
91+
pub(crate) const IP_PMTUDISC_DO: c_int =
92+
windows_sys::Win32::Networking::WinSock::IP_PMTUDISC_DO as c_int;
93+
pub(crate) const IP_PMTUDISC_DONT: c_int =
94+
windows_sys::Win32::Networking::WinSock::IP_PMTUDISC_DONT as c_int;
8795
/// Type used in set/getsockopt to retrieve the `TCP_NODELAY` option.
8896
///
8997
/// NOTE: <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt>

tests/socket.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,18 @@ test!(
13501350
#[cfg(not(target_os = "redox"))]
13511351
test!(out_of_band_inline, set_out_of_band_inline(true));
13521352
test!(reuse_address, set_reuse_address(true));
1353+
1354+
#[cfg(any(
1355+
target_os = "macos",
1356+
target_os = "ios",
1357+
target_os = "linux",
1358+
target_os = "windows",
1359+
))]
1360+
test!(IPv4 dont_frag, set_dont_frag(cfg!(not(target_os = "windows"))));
1361+
// TODO: macos can only set on udp socket.
1362+
#[cfg(any(target_os = "linux", target_os = "windows",))]
1363+
test!(IPv6 dont_frag_v6, set_dont_frag_v6(cfg!(not(target_os = "freebsd"))));
1364+
13531365
#[cfg(all(
13541366
feature = "all",
13551367
not(any(windows, target_os = "solaris", target_os = "illumos"))

0 commit comments

Comments
 (0)