Skip to content

Commit d4adba7

Browse files
committed
Make sockopt_impl! public
This allows users to define their own sockopts, instead of needing to make a PR to Nix for every single one. Fixes #577
1 parent f9ed9f0 commit d4adba7

File tree

3 files changed

+148
-51
lines changed

3 files changed

+148
-51
lines changed

changelog/2557.added.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Added `sockopt_impl!` to the public API. It's now possible for users to define
2+
their own sockopts without needing to make a PR to Nix.

src/sys/socket/sockopt.rs

Lines changed: 92 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
//! Socket options as used by `setsockopt` and `getsockopt`.
2-
use super::{GetSockOpt, SetSockOpt};
3-
use crate::errno::Errno;
42
use crate::sys::time::TimeVal;
5-
use crate::Result;
63
use cfg_if::cfg_if;
74
use libc::{self, c_int, c_void, socklen_t};
8-
#[cfg(apple_targets)]
95
use std::ffi::{CStr, CString};
106
#[cfg(any(target_os = "freebsd", linux_android))]
117
use std::ffi::{OsStr, OsString};
128
use std::mem::{self, MaybeUninit};
139
#[cfg(any(target_os = "freebsd", linux_android))]
1410
use std::os::unix::ffi::OsStrExt;
15-
use std::os::unix::io::{AsFd, AsRawFd};
11+
use std::os::unix::io::AsRawFd;
1612

1713
// Constants
1814
// TCP_CA_NAME_MAX isn't defined in user space include files
@@ -26,8 +22,8 @@ const TCP_CA_NAME_MAX: usize = 16;
2622
/// This macro aims to help implementing `SetSockOpt` for different socket options that accept
2723
/// different kinds of data to be used with `setsockopt`.
2824
///
29-
/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
30-
/// you are implementing represents a simple type.
25+
/// Instead of using this macro directly consider using [`sockopt_impl!`](crate::sockopt_impl),
26+
/// especially if the option you are implementing represents a simple type.
3127
///
3228
/// # Arguments
3329
///
@@ -42,15 +38,22 @@ const TCP_CA_NAME_MAX: usize = 16;
4238
/// * Type of the value that you are going to set.
4339
/// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for
4440
/// `bool`, `SetUsize` for `usize`, etc.).
41+
#[macro_export]
4542
macro_rules! setsockopt_impl {
4643
($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => {
4744
#[allow(deprecated)] // to allow we have deprecated socket option
48-
impl SetSockOpt for $name {
45+
impl $crate::sys::socket::SetSockOpt for $name {
4946
type Val = $ty;
5047

51-
fn set<F: AsFd>(&self, fd: &F, val: &$ty) -> Result<()> {
48+
fn set<F: std::os::unix::io::AsFd>(
49+
&self,
50+
fd: &F,
51+
val: &$ty,
52+
) -> $crate::Result<()> {
53+
use $crate::sys::socket::sockopt::Set;
5254
unsafe {
53-
let setter: $setter = Set::new(val);
55+
let setter: $setter =
56+
$crate::sys::socket::sockopt::Set::new(val);
5457

5558
let res = libc::setsockopt(
5659
fd.as_fd().as_raw_fd(),
@@ -59,7 +62,7 @@ macro_rules! setsockopt_impl {
5962
setter.ffi_ptr(),
6063
setter.ffi_len(),
6164
);
62-
Errno::result(res).map(drop)
65+
$crate::errno::Errno::result(res).map(drop)
6366
}
6467
}
6568
}
@@ -72,8 +75,8 @@ macro_rules! setsockopt_impl {
7275
/// This macro aims to help implementing `GetSockOpt` for different socket options that accept
7376
/// different kinds of data to be use with `getsockopt`.
7477
///
75-
/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
76-
/// you are implementing represents a simple type.
78+
/// Instead of using this macro directly consider using [`sockopt_impl!`](crate::sockopt_impl),
79+
/// especially if the option you are implementing represents a simple type.
7780
///
7881
/// # Arguments
7982
///
@@ -88,15 +91,21 @@ macro_rules! setsockopt_impl {
8891
/// * Type of the value that you are going to get.
8992
/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for
9093
/// `bool`, `GetUsize` for `usize`, etc.).
94+
#[macro_export]
9195
macro_rules! getsockopt_impl {
9296
($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => {
9397
#[allow(deprecated)] // to allow we have deprecated socket option
94-
impl GetSockOpt for $name {
98+
impl $crate::sys::socket::GetSockOpt for $name {
9599
type Val = $ty;
96100

97-
fn get<F: AsFd>(&self, fd: &F) -> Result<$ty> {
101+
fn get<F: std::os::unix::io::AsFd>(
102+
&self,
103+
fd: &F,
104+
) -> $crate::Result<$ty> {
105+
use $crate::sys::socket::sockopt::Get;
98106
unsafe {
99-
let mut getter: $getter = Get::uninit();
107+
let mut getter: $getter =
108+
$crate::sys::socket::sockopt::Get::uninit();
100109

101110
let res = libc::getsockopt(
102111
fd.as_fd().as_raw_fd(),
@@ -105,7 +114,7 @@ macro_rules! getsockopt_impl {
105114
getter.ffi_ptr(),
106115
getter.ffi_len(),
107116
);
108-
Errno::result(res)?;
117+
$crate::errno::Errno::result(res)?;
109118

110119
match <$ty>::try_from(getter.assume_init()) {
111120
// In most `getsockopt_impl!` implementations, `assume_init()`
@@ -122,7 +131,7 @@ macro_rules! getsockopt_impl {
122131
// buffer type for this socket option, see issue:
123132
// https://github.com/nix-rust/nix/issues/1819
124133
#[allow(unreachable_patterns)]
125-
Err(_) => Err(Errno::EINVAL),
134+
Err(_) => Err($crate::errno::Errno::EINVAL),
126135
Ok(r) => Ok(r),
127136
}
128137
}
@@ -158,58 +167,59 @@ macro_rules! getsockopt_impl {
158167
/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`.
159168
// Some targets don't use all rules.
160169
#[allow(unused_macro_rules)]
170+
#[macro_export]
161171
macro_rules! sockopt_impl {
162172
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => {
163173
sockopt_impl!($(#[$attr])*
164-
$name, GetOnly, $level, $flag, bool, GetBool);
174+
$name, GetOnly, $level, $flag, bool, $crate::sys::socket::sockopt::GetBool);
165175
};
166176

167177
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => {
168-
sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, GetU8);
178+
sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, $crate::sys::socket::sockopt::GetU8);
169179
};
170180

171181
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) =>
172182
{
173183
sockopt_impl!($(#[$attr])*
174-
$name, GetOnly, $level, $flag, usize, GetUsize);
184+
$name, GetOnly, $level, $flag, usize, $crate::sys::socket::sockopt::GetUsize);
175185
};
176186

177187
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => {
178188
sockopt_impl!($(#[$attr])*
179-
$name, SetOnly, $level, $flag, bool, SetBool);
189+
$name, SetOnly, $level, $flag, bool, $crate::sys::socket::sockopt::SetBool);
180190
};
181191

182192
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => {
183-
sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, SetU8);
193+
sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, $crate::sys::socket::sockopt::SetU8);
184194
};
185195

186196
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) =>
187197
{
188198
sockopt_impl!($(#[$attr])*
189-
$name, SetOnly, $level, $flag, usize, SetUsize);
199+
$name, SetOnly, $level, $flag, usize, $crate::sys::socket::sockopt::SetUsize);
190200
};
191201

192202
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => {
193203
sockopt_impl!($(#[$attr])*
194-
$name, Both, $level, $flag, bool, GetBool, SetBool);
204+
$name, Both, $level, $flag, bool, $crate::sys::socket::sockopt::GetBool, $crate::sys::socket::sockopt::SetBool);
195205
};
196206

197207
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => {
198208
sockopt_impl!($(#[$attr])*
199-
$name, Both, $level, $flag, u8, GetU8, SetU8);
209+
$name, Both, $level, $flag, u8, $crate::sys::socket::sockopt::GetU8, $crate::sys::socket::sockopt::SetU8);
200210
};
201211

202212
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => {
203213
sockopt_impl!($(#[$attr])*
204-
$name, Both, $level, $flag, usize, GetUsize, SetUsize);
214+
$name, Both, $level, $flag, usize, $crate::sys::socket::sockopt::GetUsize, $crate::sys::socket::sockopt::SetUsize);
205215
};
206216

207217
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path,
208218
OsString<$array:ty>) =>
209219
{
210220
sockopt_impl!($(#[$attr])*
211-
$name, Both, $level, $flag, OsString, GetOsString<$array>,
212-
SetOsString);
221+
$name, Both, $level, $flag, std::ffi::OsString, $crate::sys::socket::sockopt::GetOsString<$array>,
222+
$crate::sys::socket::sockopt::SetOsString);
213223
};
214224

215225
/*
@@ -219,7 +229,7 @@ macro_rules! sockopt_impl {
219229
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) =>
220230
{
221231
sockopt_impl!($(#[$attr])*
222-
$name, GetOnly, $level, $flag, $ty, GetStruct<$ty>);
232+
$name, GetOnly, $level, $flag, $ty, $crate::sys::socket::sockopt::GetStruct<$ty>);
223233
};
224234

225235
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty,
@@ -235,7 +245,7 @@ macro_rules! sockopt_impl {
235245
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) =>
236246
{
237247
sockopt_impl!($(#[$attr])*
238-
$name, SetOnly, $level, $flag, $ty, SetStruct<$ty>);
248+
$name, SetOnly, $level, $flag, $ty, $crate::sys::socket::sockopt::SetStruct<$ty>);
239249
};
240250

241251
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty,
@@ -261,8 +271,8 @@ macro_rules! sockopt_impl {
261271

262272
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => {
263273
sockopt_impl!($(#[$attr])*
264-
$name, Both, $level, $flag, $ty, GetStruct<$ty>,
265-
SetStruct<$ty>);
274+
$name, Both, $level, $flag, $ty, $crate::sys::socket::sockopt::GetStruct<$ty>,
275+
$crate::sys::socket::sockopt::SetStruct<$ty>);
266276
};
267277
}
268278

@@ -1437,7 +1447,9 @@ impl SetSockOpt for TcpTlsRx {
14371447
*/
14381448

14391449
/// Helper trait that describes what is expected from a `GetSockOpt` getter.
1440-
trait Get<T> {
1450+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1451+
#[doc(hidden)]
1452+
pub trait Get<T> {
14411453
/// Returns an uninitialized value.
14421454
fn uninit() -> Self;
14431455
/// Returns a pointer to the stored value. This pointer will be passed to the system's
@@ -1451,7 +1463,9 @@ trait Get<T> {
14511463
}
14521464

14531465
/// Helper trait that describes what is expected from a `SetSockOpt` setter.
1454-
trait Set<'a, T> {
1466+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1467+
#[doc(hidden)]
1468+
pub trait Set<'a, T> {
14551469
/// Initialize the setter with a given value.
14561470
fn new(val: &'a T) -> Self;
14571471
/// Returns a pointer to the stored value. This pointer will be passed to the system's
@@ -1463,7 +1477,10 @@ trait Set<'a, T> {
14631477
}
14641478

14651479
/// Getter for an arbitrary `struct`.
1466-
struct GetStruct<T> {
1480+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1481+
#[doc(hidden)]
1482+
#[derive(Debug)]
1483+
pub struct GetStruct<T> {
14671484
len: socklen_t,
14681485
val: MaybeUninit<T>,
14691486
}
@@ -1495,7 +1512,10 @@ impl<T> Get<T> for GetStruct<T> {
14951512
}
14961513

14971514
/// Setter for an arbitrary `struct`.
1498-
struct SetStruct<'a, T: 'static> {
1515+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1516+
#[doc(hidden)]
1517+
#[derive(Debug)]
1518+
pub struct SetStruct<'a, T: 'static> {
14991519
ptr: &'a T,
15001520
}
15011521

@@ -1514,7 +1534,10 @@ impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
15141534
}
15151535

15161536
/// Getter for a boolean value.
1517-
struct GetBool {
1537+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1538+
#[doc(hidden)]
1539+
#[derive(Clone, Copy, Debug)]
1540+
pub struct GetBool {
15181541
len: socklen_t,
15191542
val: MaybeUninit<c_int>,
15201543
}
@@ -1546,7 +1569,10 @@ impl Get<bool> for GetBool {
15461569
}
15471570

15481571
/// Setter for a boolean value.
1549-
struct SetBool {
1572+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1573+
#[doc(hidden)]
1574+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1575+
pub struct SetBool {
15501576
val: c_int,
15511577
}
15521578

@@ -1568,7 +1594,10 @@ impl<'a> Set<'a, bool> for SetBool {
15681594

15691595
/// Getter for an `u8` value.
15701596
#[cfg(feature = "net")]
1571-
struct GetU8 {
1597+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1598+
#[doc(hidden)]
1599+
#[derive(Clone, Copy, Debug)]
1600+
pub struct GetU8 {
15721601
len: socklen_t,
15731602
val: MaybeUninit<u8>,
15741603
}
@@ -1601,7 +1630,9 @@ impl Get<u8> for GetU8 {
16011630
}
16021631

16031632
/// Setter for an `u8` value.
1604-
#[cfg(feature = "net")]
1633+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1634+
#[doc(hidden)]
1635+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16051636
struct SetU8 {
16061637
val: u8,
16071638
}
@@ -1622,7 +1653,10 @@ impl<'a> Set<'a, u8> for SetU8 {
16221653
}
16231654

16241655
/// Getter for an `usize` value.
1625-
struct GetUsize {
1656+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1657+
#[doc(hidden)]
1658+
#[derive(Clone, Copy, Debug)]
1659+
pub struct GetUsize {
16261660
len: socklen_t,
16271661
val: MaybeUninit<c_int>,
16281662
}
@@ -1654,7 +1688,10 @@ impl Get<usize> for GetUsize {
16541688
}
16551689

16561690
/// Setter for an `usize` value.
1657-
struct SetUsize {
1691+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1692+
#[doc(hidden)]
1693+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1694+
pub struct SetUsize {
16581695
val: c_int,
16591696
}
16601697

@@ -1673,8 +1710,10 @@ impl<'a> Set<'a, usize> for SetUsize {
16731710
}
16741711

16751712
/// Getter for a `OsString` value.
1676-
#[cfg(any(target_os = "freebsd", linux_android))]
1677-
struct GetOsString<T: AsMut<[u8]>> {
1713+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1714+
#[doc(hidden)]
1715+
#[derive(Debug)]
1716+
pub struct GetOsString<T: AsMut<[u8]>> {
16781717
len: socklen_t,
16791718
val: MaybeUninit<T>,
16801719
}
@@ -1704,8 +1743,10 @@ impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
17041743
}
17051744

17061745
/// Setter for a `OsString` value.
1707-
#[cfg(any(target_os = "freebsd", linux_android))]
1708-
struct SetOsString<'a> {
1746+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1747+
#[doc(hidden)]
1748+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1749+
pub struct SetOsString<'a> {
17091750
val: &'a OsStr,
17101751
}
17111752

@@ -1727,14 +1768,14 @@ impl<'a> Set<'a, OsString> for SetOsString<'a> {
17271768
}
17281769

17291770
/// Getter for a `CString` value.
1730-
#[cfg(apple_targets)]
1731-
#[cfg(feature = "net")]
1732-
struct GetCString<T: AsMut<[u8]>> {
1771+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1772+
#[doc(hidden)]
1773+
#[derive(Debug)]
1774+
pub struct GetCString<T: AsMut<[u8]>> {
17331775
len: socklen_t,
17341776
val: MaybeUninit<T>,
17351777
}
17361778

1737-
#[cfg(apple_targets)]
17381779
#[cfg(feature = "net")]
17391780
impl<T: AsMut<[u8]>> Get<CString> for GetCString<T> {
17401781
fn uninit() -> Self {

0 commit comments

Comments
 (0)