Skip to content

Commit 02665f9

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 02665f9

File tree

3 files changed

+154
-51
lines changed

3 files changed

+154
-51
lines changed

changelog/2556.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: 98 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
//! Socket options as used by `setsockopt` and `getsockopt`.
2-
use super::{GetSockOpt, SetSockOpt};
3-
use crate::errno::Errno;
2+
#[cfg(linux_android)]
3+
use super::SetSockOpt;
4+
#[cfg(linux_android)]
5+
use crate::{errno::Errno, Result};
46
use crate::sys::time::TimeVal;
5-
use crate::Result;
67
use cfg_if::cfg_if;
78
use libc::{self, c_int, c_void, socklen_t};
8-
#[cfg(apple_targets)]
99
use std::ffi::{CStr, CString};
1010
#[cfg(any(target_os = "freebsd", linux_android))]
1111
use std::ffi::{OsStr, OsString};
1212
use std::mem::{self, MaybeUninit};
1313
#[cfg(any(target_os = "freebsd", linux_android))]
1414
use std::os::unix::ffi::OsStrExt;
15-
use std::os::unix::io::{AsFd, AsRawFd};
15+
use std::os::unix::io::AsRawFd;
16+
#[cfg(linux_android)]
17+
use std::os::unix::io::AsFd;
1618

1719
// Constants
1820
// TCP_CA_NAME_MAX isn't defined in user space include files
@@ -26,8 +28,8 @@ const TCP_CA_NAME_MAX: usize = 16;
2628
/// This macro aims to help implementing `SetSockOpt` for different socket options that accept
2729
/// different kinds of data to be used with `setsockopt`.
2830
///
29-
/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
30-
/// you are implementing represents a simple type.
31+
/// Instead of using this macro directly consider using [`sockopt_impl!`](crate::sockopt_impl),
32+
/// especially if the option you are implementing represents a simple type.
3133
///
3234
/// # Arguments
3335
///
@@ -42,15 +44,22 @@ const TCP_CA_NAME_MAX: usize = 16;
4244
/// * Type of the value that you are going to set.
4345
/// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for
4446
/// `bool`, `SetUsize` for `usize`, etc.).
47+
#[macro_export]
4548
macro_rules! setsockopt_impl {
4649
($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => {
4750
#[allow(deprecated)] // to allow we have deprecated socket option
48-
impl SetSockOpt for $name {
51+
impl $crate::sys::socket::SetSockOpt for $name {
4952
type Val = $ty;
5053

51-
fn set<F: AsFd>(&self, fd: &F, val: &$ty) -> Result<()> {
54+
fn set<F: std::os::unix::io::AsFd>(
55+
&self,
56+
fd: &F,
57+
val: &$ty,
58+
) -> $crate::Result<()> {
59+
use $crate::sys::socket::sockopt::Set;
5260
unsafe {
53-
let setter: $setter = Set::new(val);
61+
let setter: $setter =
62+
$crate::sys::socket::sockopt::Set::new(val);
5463

5564
let res = libc::setsockopt(
5665
fd.as_fd().as_raw_fd(),
@@ -59,7 +68,7 @@ macro_rules! setsockopt_impl {
5968
setter.ffi_ptr(),
6069
setter.ffi_len(),
6170
);
62-
Errno::result(res).map(drop)
71+
$crate::errno::Errno::result(res).map(drop)
6372
}
6473
}
6574
}
@@ -72,8 +81,8 @@ macro_rules! setsockopt_impl {
7281
/// This macro aims to help implementing `GetSockOpt` for different socket options that accept
7382
/// different kinds of data to be use with `getsockopt`.
7483
///
75-
/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
76-
/// you are implementing represents a simple type.
84+
/// Instead of using this macro directly consider using [`sockopt_impl!`](crate::sockopt_impl),
85+
/// especially if the option you are implementing represents a simple type.
7786
///
7887
/// # Arguments
7988
///
@@ -88,15 +97,21 @@ macro_rules! setsockopt_impl {
8897
/// * Type of the value that you are going to get.
8998
/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for
9099
/// `bool`, `GetUsize` for `usize`, etc.).
100+
#[macro_export]
91101
macro_rules! getsockopt_impl {
92102
($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => {
93103
#[allow(deprecated)] // to allow we have deprecated socket option
94-
impl GetSockOpt for $name {
104+
impl $crate::sys::socket::GetSockOpt for $name {
95105
type Val = $ty;
96106

97-
fn get<F: AsFd>(&self, fd: &F) -> Result<$ty> {
107+
fn get<F: std::os::unix::io::AsFd>(
108+
&self,
109+
fd: &F,
110+
) -> $crate::Result<$ty> {
111+
use $crate::sys::socket::sockopt::Get;
98112
unsafe {
99-
let mut getter: $getter = Get::uninit();
113+
let mut getter: $getter =
114+
$crate::sys::socket::sockopt::Get::uninit();
100115

101116
let res = libc::getsockopt(
102117
fd.as_fd().as_raw_fd(),
@@ -105,7 +120,7 @@ macro_rules! getsockopt_impl {
105120
getter.ffi_ptr(),
106121
getter.ffi_len(),
107122
);
108-
Errno::result(res)?;
123+
$crate::errno::Errno::result(res)?;
109124

110125
match <$ty>::try_from(getter.assume_init()) {
111126
// In most `getsockopt_impl!` implementations, `assume_init()`
@@ -122,7 +137,7 @@ macro_rules! getsockopt_impl {
122137
// buffer type for this socket option, see issue:
123138
// https://github.com/nix-rust/nix/issues/1819
124139
#[allow(unreachable_patterns)]
125-
Err(_) => Err(Errno::EINVAL),
140+
Err(_) => Err($crate::errno::Errno::EINVAL),
126141
Ok(r) => Ok(r),
127142
}
128143
}
@@ -158,58 +173,59 @@ macro_rules! getsockopt_impl {
158173
/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`.
159174
// Some targets don't use all rules.
160175
#[allow(unused_macro_rules)]
176+
#[macro_export]
161177
macro_rules! sockopt_impl {
162178
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => {
163179
sockopt_impl!($(#[$attr])*
164-
$name, GetOnly, $level, $flag, bool, GetBool);
180+
$name, GetOnly, $level, $flag, bool, $crate::sys::socket::sockopt::GetBool);
165181
};
166182

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

171187
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) =>
172188
{
173189
sockopt_impl!($(#[$attr])*
174-
$name, GetOnly, $level, $flag, usize, GetUsize);
190+
$name, GetOnly, $level, $flag, usize, $crate::sys::socket::sockopt::GetUsize);
175191
};
176192

177193
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => {
178194
sockopt_impl!($(#[$attr])*
179-
$name, SetOnly, $level, $flag, bool, SetBool);
195+
$name, SetOnly, $level, $flag, bool, $crate::sys::socket::sockopt::SetBool);
180196
};
181197

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

186202
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) =>
187203
{
188204
sockopt_impl!($(#[$attr])*
189-
$name, SetOnly, $level, $flag, usize, SetUsize);
205+
$name, SetOnly, $level, $flag, usize, $crate::sys::socket::sockopt::SetUsize);
190206
};
191207

192208
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => {
193209
sockopt_impl!($(#[$attr])*
194-
$name, Both, $level, $flag, bool, GetBool, SetBool);
210+
$name, Both, $level, $flag, bool, $crate::sys::socket::sockopt::GetBool, $crate::sys::socket::sockopt::SetBool);
195211
};
196212

197213
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => {
198214
sockopt_impl!($(#[$attr])*
199-
$name, Both, $level, $flag, u8, GetU8, SetU8);
215+
$name, Both, $level, $flag, u8, $crate::sys::socket::sockopt::GetU8, $crate::sys::socket::sockopt::SetU8);
200216
};
201217

202218
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => {
203219
sockopt_impl!($(#[$attr])*
204-
$name, Both, $level, $flag, usize, GetUsize, SetUsize);
220+
$name, Both, $level, $flag, usize, $crate::sys::socket::sockopt::GetUsize, $crate::sys::socket::sockopt::SetUsize);
205221
};
206222

207223
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path,
208224
OsString<$array:ty>) =>
209225
{
210226
sockopt_impl!($(#[$attr])*
211-
$name, Both, $level, $flag, OsString, GetOsString<$array>,
212-
SetOsString);
227+
$name, Both, $level, $flag, std::ffi::OsString, $crate::sys::socket::sockopt::GetOsString<$array>,
228+
$crate::sys::socket::sockopt::SetOsString);
213229
};
214230

215231
/*
@@ -219,7 +235,7 @@ macro_rules! sockopt_impl {
219235
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) =>
220236
{
221237
sockopt_impl!($(#[$attr])*
222-
$name, GetOnly, $level, $flag, $ty, GetStruct<$ty>);
238+
$name, GetOnly, $level, $flag, $ty, $crate::sys::socket::sockopt::GetStruct<$ty>);
223239
};
224240

225241
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty,
@@ -235,7 +251,7 @@ macro_rules! sockopt_impl {
235251
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) =>
236252
{
237253
sockopt_impl!($(#[$attr])*
238-
$name, SetOnly, $level, $flag, $ty, SetStruct<$ty>);
254+
$name, SetOnly, $level, $flag, $ty, $crate::sys::socket::sockopt::SetStruct<$ty>);
239255
};
240256

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

262278
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => {
263279
sockopt_impl!($(#[$attr])*
264-
$name, Both, $level, $flag, $ty, GetStruct<$ty>,
265-
SetStruct<$ty>);
280+
$name, Both, $level, $flag, $ty, $crate::sys::socket::sockopt::GetStruct<$ty>,
281+
$crate::sys::socket::sockopt::SetStruct<$ty>);
266282
};
267283
}
268284

@@ -1437,7 +1453,9 @@ impl SetSockOpt for TcpTlsRx {
14371453
*/
14381454

14391455
/// Helper trait that describes what is expected from a `GetSockOpt` getter.
1440-
trait Get<T> {
1456+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1457+
#[doc(hidden)]
1458+
pub trait Get<T> {
14411459
/// Returns an uninitialized value.
14421460
fn uninit() -> Self;
14431461
/// Returns a pointer to the stored value. This pointer will be passed to the system's
@@ -1451,7 +1469,9 @@ trait Get<T> {
14511469
}
14521470

14531471
/// Helper trait that describes what is expected from a `SetSockOpt` setter.
1454-
trait Set<'a, T> {
1472+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1473+
#[doc(hidden)]
1474+
pub trait Set<'a, T> {
14551475
/// Initialize the setter with a given value.
14561476
fn new(val: &'a T) -> Self;
14571477
/// Returns a pointer to the stored value. This pointer will be passed to the system's
@@ -1463,7 +1483,10 @@ trait Set<'a, T> {
14631483
}
14641484

14651485
/// Getter for an arbitrary `struct`.
1466-
struct GetStruct<T> {
1486+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1487+
#[doc(hidden)]
1488+
#[derive(Debug)]
1489+
pub struct GetStruct<T> {
14671490
len: socklen_t,
14681491
val: MaybeUninit<T>,
14691492
}
@@ -1495,7 +1518,10 @@ impl<T> Get<T> for GetStruct<T> {
14951518
}
14961519

14971520
/// Setter for an arbitrary `struct`.
1498-
struct SetStruct<'a, T: 'static> {
1521+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1522+
#[doc(hidden)]
1523+
#[derive(Debug)]
1524+
pub struct SetStruct<'a, T: 'static> {
14991525
ptr: &'a T,
15001526
}
15011527

@@ -1514,7 +1540,10 @@ impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
15141540
}
15151541

15161542
/// Getter for a boolean value.
1517-
struct GetBool {
1543+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1544+
#[doc(hidden)]
1545+
#[derive(Clone, Copy, Debug)]
1546+
pub struct GetBool {
15181547
len: socklen_t,
15191548
val: MaybeUninit<c_int>,
15201549
}
@@ -1546,7 +1575,10 @@ impl Get<bool> for GetBool {
15461575
}
15471576

15481577
/// Setter for a boolean value.
1549-
struct SetBool {
1578+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1579+
#[doc(hidden)]
1580+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1581+
pub struct SetBool {
15501582
val: c_int,
15511583
}
15521584

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

15691601
/// Getter for an `u8` value.
15701602
#[cfg(feature = "net")]
1571-
struct GetU8 {
1603+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1604+
#[doc(hidden)]
1605+
#[derive(Clone, Copy, Debug)]
1606+
pub struct GetU8 {
15721607
len: socklen_t,
15731608
val: MaybeUninit<u8>,
15741609
}
@@ -1601,7 +1636,9 @@ impl Get<u8> for GetU8 {
16011636
}
16021637

16031638
/// Setter for an `u8` value.
1604-
#[cfg(feature = "net")]
1639+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1640+
#[doc(hidden)]
1641+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16051642
struct SetU8 {
16061643
val: u8,
16071644
}
@@ -1622,7 +1659,10 @@ impl<'a> Set<'a, u8> for SetU8 {
16221659
}
16231660

16241661
/// Getter for an `usize` value.
1625-
struct GetUsize {
1662+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1663+
#[doc(hidden)]
1664+
#[derive(Clone, Copy, Debug)]
1665+
pub struct GetUsize {
16261666
len: socklen_t,
16271667
val: MaybeUninit<c_int>,
16281668
}
@@ -1654,7 +1694,10 @@ impl Get<usize> for GetUsize {
16541694
}
16551695

16561696
/// Setter for an `usize` value.
1657-
struct SetUsize {
1697+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1698+
#[doc(hidden)]
1699+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1700+
pub struct SetUsize {
16581701
val: c_int,
16591702
}
16601703

@@ -1673,8 +1716,10 @@ impl<'a> Set<'a, usize> for SetUsize {
16731716
}
16741717

16751718
/// Getter for a `OsString` value.
1676-
#[cfg(any(target_os = "freebsd", linux_android))]
1677-
struct GetOsString<T: AsMut<[u8]>> {
1719+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1720+
#[doc(hidden)]
1721+
#[derive(Debug)]
1722+
pub struct GetOsString<T: AsMut<[u8]>> {
16781723
len: socklen_t,
16791724
val: MaybeUninit<T>,
16801725
}
@@ -1704,8 +1749,10 @@ impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
17041749
}
17051750

17061751
/// Setter for a `OsString` value.
1707-
#[cfg(any(target_os = "freebsd", linux_android))]
1708-
struct SetOsString<'a> {
1752+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1753+
#[doc(hidden)]
1754+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1755+
pub struct SetOsString<'a> {
17091756
val: &'a OsStr,
17101757
}
17111758

@@ -1727,14 +1774,14 @@ impl<'a> Set<'a, OsString> for SetOsString<'a> {
17271774
}
17281775

17291776
/// Getter for a `CString` value.
1730-
#[cfg(apple_targets)]
1731-
#[cfg(feature = "net")]
1732-
struct GetCString<T: AsMut<[u8]>> {
1777+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1778+
#[doc(hidden)]
1779+
#[derive(Debug)]
1780+
pub struct GetCString<T: AsMut<[u8]>> {
17331781
len: socklen_t,
17341782
val: MaybeUninit<T>,
17351783
}
17361784

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

0 commit comments

Comments
 (0)