Skip to content

Commit 089a07a

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 089a07a

File tree

3 files changed

+149
-54
lines changed

3 files changed

+149
-54
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: 99 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
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};
10-
#[cfg(any(target_os = "freebsd", linux_android))]
1110
use std::ffi::{OsStr, OsString};
1211
use std::mem::{self, MaybeUninit};
1312
#[cfg(any(target_os = "freebsd", linux_android))]
1413
use std::os::unix::ffi::OsStrExt;
15-
use std::os::unix::io::{AsFd, AsRawFd};
14+
use std::os::unix::io::AsRawFd;
15+
#[cfg(linux_android)]
16+
use std::os::unix::io::AsFd;
1617

1718
// Constants
1819
// TCP_CA_NAME_MAX isn't defined in user space include files
@@ -26,8 +27,8 @@ const TCP_CA_NAME_MAX: usize = 16;
2627
/// This macro aims to help implementing `SetSockOpt` for different socket options that accept
2728
/// different kinds of data to be used with `setsockopt`.
2829
///
29-
/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
30-
/// you are implementing represents a simple type.
30+
/// Instead of using this macro directly consider using [`sockopt_impl!`](crate::sockopt_impl),
31+
/// especially if the option you are implementing represents a simple type.
3132
///
3233
/// # Arguments
3334
///
@@ -42,15 +43,22 @@ const TCP_CA_NAME_MAX: usize = 16;
4243
/// * Type of the value that you are going to set.
4344
/// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for
4445
/// `bool`, `SetUsize` for `usize`, etc.).
46+
#[macro_export]
4547
macro_rules! setsockopt_impl {
4648
($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => {
4749
#[allow(deprecated)] // to allow we have deprecated socket option
48-
impl SetSockOpt for $name {
50+
impl $crate::sys::socket::SetSockOpt for $name {
4951
type Val = $ty;
5052

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

5563
let res = libc::setsockopt(
5664
fd.as_fd().as_raw_fd(),
@@ -59,7 +67,7 @@ macro_rules! setsockopt_impl {
5967
setter.ffi_ptr(),
6068
setter.ffi_len(),
6169
);
62-
Errno::result(res).map(drop)
70+
$crate::errno::Errno::result(res).map(drop)
6371
}
6472
}
6573
}
@@ -72,8 +80,8 @@ macro_rules! setsockopt_impl {
7280
/// This macro aims to help implementing `GetSockOpt` for different socket options that accept
7381
/// different kinds of data to be use with `getsockopt`.
7482
///
75-
/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
76-
/// you are implementing represents a simple type.
83+
/// Instead of using this macro directly consider using [`sockopt_impl!`](crate::sockopt_impl),
84+
/// especially if the option you are implementing represents a simple type.
7785
///
7886
/// # Arguments
7987
///
@@ -88,15 +96,21 @@ macro_rules! setsockopt_impl {
8896
/// * Type of the value that you are going to get.
8997
/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for
9098
/// `bool`, `GetUsize` for `usize`, etc.).
99+
#[macro_export]
91100
macro_rules! getsockopt_impl {
92101
($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => {
93102
#[allow(deprecated)] // to allow we have deprecated socket option
94-
impl GetSockOpt for $name {
103+
impl $crate::sys::socket::GetSockOpt for $name {
95104
type Val = $ty;
96105

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

101115
let res = libc::getsockopt(
102116
fd.as_fd().as_raw_fd(),
@@ -105,7 +119,7 @@ macro_rules! getsockopt_impl {
105119
getter.ffi_ptr(),
106120
getter.ffi_len(),
107121
);
108-
Errno::result(res)?;
122+
$crate::errno::Errno::result(res)?;
109123

110124
match <$ty>::try_from(getter.assume_init()) {
111125
// In most `getsockopt_impl!` implementations, `assume_init()`
@@ -122,7 +136,7 @@ macro_rules! getsockopt_impl {
122136
// buffer type for this socket option, see issue:
123137
// https://github.com/nix-rust/nix/issues/1819
124138
#[allow(unreachable_patterns)]
125-
Err(_) => Err(Errno::EINVAL),
139+
Err(_) => Err($crate::errno::Errno::EINVAL),
126140
Ok(r) => Ok(r),
127141
}
128142
}
@@ -158,58 +172,59 @@ macro_rules! getsockopt_impl {
158172
/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`.
159173
// Some targets don't use all rules.
160174
#[allow(unused_macro_rules)]
175+
#[macro_export]
161176
macro_rules! sockopt_impl {
162177
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => {
163178
sockopt_impl!($(#[$attr])*
164-
$name, GetOnly, $level, $flag, bool, GetBool);
179+
$name, GetOnly, $level, $flag, bool, $crate::sys::socket::sockopt::GetBool);
165180
};
166181

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

171186
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) =>
172187
{
173188
sockopt_impl!($(#[$attr])*
174-
$name, GetOnly, $level, $flag, usize, GetUsize);
189+
$name, GetOnly, $level, $flag, usize, $crate::sys::socket::sockopt::GetUsize);
175190
};
176191

177192
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => {
178193
sockopt_impl!($(#[$attr])*
179-
$name, SetOnly, $level, $flag, bool, SetBool);
194+
$name, SetOnly, $level, $flag, bool, $crate::sys::socket::sockopt::SetBool);
180195
};
181196

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

186201
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) =>
187202
{
188203
sockopt_impl!($(#[$attr])*
189-
$name, SetOnly, $level, $flag, usize, SetUsize);
204+
$name, SetOnly, $level, $flag, usize, $crate::sys::socket::sockopt::SetUsize);
190205
};
191206

192207
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => {
193208
sockopt_impl!($(#[$attr])*
194-
$name, Both, $level, $flag, bool, GetBool, SetBool);
209+
$name, Both, $level, $flag, bool, $crate::sys::socket::sockopt::GetBool, $crate::sys::socket::sockopt::SetBool);
195210
};
196211

197212
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => {
198213
sockopt_impl!($(#[$attr])*
199-
$name, Both, $level, $flag, u8, GetU8, SetU8);
214+
$name, Both, $level, $flag, u8, $crate::sys::socket::sockopt::GetU8, $crate::sys::socket::sockopt::SetU8);
200215
};
201216

202217
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => {
203218
sockopt_impl!($(#[$attr])*
204-
$name, Both, $level, $flag, usize, GetUsize, SetUsize);
219+
$name, Both, $level, $flag, usize, $crate::sys::socket::sockopt::GetUsize, $crate::sys::socket::sockopt::SetUsize);
205220
};
206221

207222
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path,
208223
OsString<$array:ty>) =>
209224
{
210225
sockopt_impl!($(#[$attr])*
211-
$name, Both, $level, $flag, OsString, GetOsString<$array>,
212-
SetOsString);
226+
$name, Both, $level, $flag, std::ffi::OsString, $crate::sys::socket::sockopt::GetOsString<$array>,
227+
$crate::sys::socket::sockopt::SetOsString);
213228
};
214229

215230
/*
@@ -219,7 +234,7 @@ macro_rules! sockopt_impl {
219234
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) =>
220235
{
221236
sockopt_impl!($(#[$attr])*
222-
$name, GetOnly, $level, $flag, $ty, GetStruct<$ty>);
237+
$name, GetOnly, $level, $flag, $ty, $crate::sys::socket::sockopt::GetStruct<$ty>);
223238
};
224239

225240
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty,
@@ -235,7 +250,7 @@ macro_rules! sockopt_impl {
235250
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) =>
236251
{
237252
sockopt_impl!($(#[$attr])*
238-
$name, SetOnly, $level, $flag, $ty, SetStruct<$ty>);
253+
$name, SetOnly, $level, $flag, $ty, $crate::sys::socket::sockopt::SetStruct<$ty>);
239254
};
240255

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

262277
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => {
263278
sockopt_impl!($(#[$attr])*
264-
$name, Both, $level, $flag, $ty, GetStruct<$ty>,
265-
SetStruct<$ty>);
279+
$name, Both, $level, $flag, $ty, $crate::sys::socket::sockopt::GetStruct<$ty>,
280+
$crate::sys::socket::sockopt::SetStruct<$ty>);
266281
};
267282
}
268283

@@ -1437,7 +1452,9 @@ impl SetSockOpt for TcpTlsRx {
14371452
*/
14381453

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

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

14651484
/// Getter for an arbitrary `struct`.
1466-
struct GetStruct<T> {
1485+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1486+
#[doc(hidden)]
1487+
#[derive(Debug)]
1488+
pub struct GetStruct<T> {
14671489
len: socklen_t,
14681490
val: MaybeUninit<T>,
14691491
}
@@ -1495,7 +1517,10 @@ impl<T> Get<T> for GetStruct<T> {
14951517
}
14961518

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

@@ -1514,7 +1539,10 @@ impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
15141539
}
15151540

15161541
/// Getter for a boolean value.
1517-
struct GetBool {
1542+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1543+
#[doc(hidden)]
1544+
#[derive(Clone, Copy, Debug)]
1545+
pub struct GetBool {
15181546
len: socklen_t,
15191547
val: MaybeUninit<c_int>,
15201548
}
@@ -1546,7 +1574,10 @@ impl Get<bool> for GetBool {
15461574
}
15471575

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

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

15691600
/// Getter for an `u8` value.
15701601
#[cfg(feature = "net")]
1571-
struct GetU8 {
1602+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1603+
#[doc(hidden)]
1604+
#[derive(Clone, Copy, Debug)]
1605+
pub struct GetU8 {
15721606
len: socklen_t,
15731607
val: MaybeUninit<u8>,
15741608
}
@@ -1601,8 +1635,10 @@ impl Get<u8> for GetU8 {
16011635
}
16021636

16031637
/// Setter for an `u8` value.
1604-
#[cfg(feature = "net")]
1605-
struct SetU8 {
1638+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1639+
#[doc(hidden)]
1640+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1641+
pub struct SetU8 {
16061642
val: u8,
16071643
}
16081644

@@ -1622,7 +1658,10 @@ impl<'a> Set<'a, u8> for SetU8 {
16221658
}
16231659

16241660
/// Getter for an `usize` value.
1625-
struct GetUsize {
1661+
// Hide the docs, because it's an implementation detail of `sockopt_impl!`
1662+
#[doc(hidden)]
1663+
#[derive(Clone, Copy, Debug)]
1664+
pub struct GetUsize {
16261665
len: socklen_t,
16271666
val: MaybeUninit<c_int>,
16281667
}
@@ -1654,7 +1693,10 @@ impl Get<usize> for GetUsize {
16541693
}
16551694

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

@@ -1673,8 +1715,10 @@ impl<'a> Set<'a, usize> for SetUsize {
16731715
}
16741716

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

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

@@ -1727,15 +1773,14 @@ impl<'a> Set<'a, OsString> for SetOsString<'a> {
17271773
}
17281774

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

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

0 commit comments

Comments
 (0)