linux_io/fd/
sockopt.rs

1//! A safer abstraction for `setsockopt` and `getsockopt`.
2//!
3//! These system calls are very open-ended, supporting a variety of
4//! different operations with different argument and result types. Passing
5//! the wrong kind of value to the wrong command can cause memory corruption.
6//!
7//! To make these a _little_ safer to use, this module provides option
8//! constants that also include information about the argument and result
9//! types, so that the [`super::File::setsockopt`] and
10//! [`super::File::getsockopt`] methods can then provide a type-safe interface
11//! as long as these constants are defined correctly.
12//!
13//! This module defines constants for the main sockets API options.
14//! Protocol-specific options might also be available in other modules,
15//! or potentially in other crates.
16
17use linux_unsafe::int;
18
19/// The sockopt "level" for general socket options that are not protocol-specific.
20pub const SOL_SOCKET: int = 1;
21
22/// Indicates whether or not this socket has been marked to accept connections
23/// e.g. using [`super::File::listen`].
24///
25/// `1` indicates that the socket is listening, and `0` that it is not.
26pub const SO_ACCEPTCONN: DirectSockOptReadOnly<int> = unsafe { sockopt_readonly(SOL_SOCKET, 30) };
27
28/// Returns the protocol/address family for this socket.
29///
30/// The result can be converted to [`linux_unsafe::sa_family_t`] to compare
31/// with the address family constants defined elsewhere in this crate.
32pub const SO_DOMAIN: DirectSockOptReadOnly<int> = unsafe { sockopt_readonly(SOL_SOCKET, 39) };
33
34/// Send only to directly-connected hosts, ignoring any configured gateway.
35///
36/// `1` indicates direct connections only, while `0` allows using gateways.
37pub const SO_DONTROUTE: DirectSockOpt<int> = unsafe { sockopt(SOL_SOCKET, 5) };
38
39/// Send period keepalive messages on connection-oriented sockets.
40///
41/// `1` enables keepalive messages, while `0` disables them.
42pub const SO_KEEPALIVE: DirectSockOpt<int> = unsafe { sockopt(SOL_SOCKET, 9) };
43
44/// Implemented by options that can be used with `setsockopt`.
45///
46/// Safety: Implementers must ensure that they only generate valid combinations
47/// of `setsockopt` level, optname, optval, and optlen.
48pub unsafe trait SetSockOpt<'a> {
49    /// The type that the caller will provide when setting this option.
50    type ExtArg
51    where
52        Self: 'a;
53
54    /// The type that "optval" will be a pointer to in the call.
55    type OptVal;
56
57    /// The type of the result of the `setsockopt` call.
58    type Result;
59
60    /// Prepare the arguments for a `setsockopt` system call. The tuple
61    /// elements of the result are `(level, optname, optval, optlen)`.
62    fn prepare_setsockopt_args(
63        &self,
64        arg: &Self::ExtArg,
65    ) -> (int, int, *const Self::OptVal, linux_unsafe::socklen_t);
66
67    /// Prepare a raw successful result from a `setsockopt` call to be returned.
68    fn prepare_setsockopt_result(&self, raw: int) -> Self::Result;
69}
70
71/// Implemented by options that can be used with `getsockopt`.
72///
73/// Safety: Implementers must ensure that they only generate valid combinations
74/// of `getsockopt` level, optname, optval, and optlen.
75pub unsafe trait GetSockOpt<'a> {
76    /// The type that "optval" will be a pointer to in the call.
77    type OptVal;
78
79    /// The type of the result of the `getsockopt` call.
80    type Result
81    where
82        Self: 'a;
83
84    /// Prepare the arguments for a `getsockopt` system call. The tuple
85    /// elements of the result are `(level, optname, optlen)`.
86    fn prepare_getsockopt_args(&self) -> (int, int);
87
88    /// Prepare a raw successful result from a `getsockopt` call to be returned.
89    fn prepare_getsockopt_result(&self, retval: int, optval: Self::OptVal) -> Self::Result;
90}
91
92/// Constructs a new "simple" socket option whose safe-facing argument
93/// type is the same as its internal type and whose level and option name
94/// are fixed.
95///
96/// Types used with this implementation should typically be `repr(C)` and
97/// designed to exactly match the layout of the option's kernel structure.
98///
99/// Safety: Callers must ensure that the given `level` and `optname` are valid
100/// and that type `T` is the type that the corresponding option expects.
101pub const unsafe fn sockopt<T>(level: int, optname: int) -> DirectSockOpt<T> {
102    DirectSockOpt::<T> {
103        level,
104        optname,
105        _phantom: core::marker::PhantomData,
106    }
107}
108
109/// Constructs a new "simple" socket option that is read-only.
110///
111/// Aside from the result only supporting `getsockopt`, this is the same
112/// as [`sockopt`].
113pub const unsafe fn sockopt_readonly<T>(level: int, optname: int) -> DirectSockOptReadOnly<T> {
114    DirectSockOptReadOnly(sockopt::<T>(level, optname))
115}
116
117/// Implementation of both [`SetSockOpt`] and [`GetSockOpt`] with fixed `level`
118/// and `optname` values, passing the arg type directly through to the
119/// underlying system calls.
120pub struct DirectSockOpt<T> {
121    level: int,
122    optname: int,
123    _phantom: core::marker::PhantomData<T>,
124}
125
126/// Implementation of just [`GetSockOpt`] with fixed `level` and `optname`
127/// values, similar to [`DirectSockOpt`] but for read-only options.
128#[repr(transparent)]
129pub struct DirectSockOptReadOnly<T>(DirectSockOpt<T>);
130
131unsafe impl<'a, T: 'a> SetSockOpt<'a> for DirectSockOpt<T> {
132    type ExtArg = T;
133    type OptVal = T;
134    type Result = int;
135
136    fn prepare_setsockopt_args(
137        &self,
138        arg: &Self::ExtArg,
139    ) -> (int, int, *const Self::OptVal, linux_unsafe::socklen_t) {
140        (
141            self.level,
142            self.optname,
143            arg as *const Self::OptVal,
144            core::mem::size_of::<Self::OptVal>() as linux_unsafe::socklen_t,
145        )
146    }
147
148    fn prepare_setsockopt_result(&self, raw: int) -> Self::Result {
149        raw
150    }
151}
152
153unsafe impl<'a, T: 'a> GetSockOpt<'a> for DirectSockOpt<T> {
154    type OptVal = T;
155    type Result = T;
156
157    fn prepare_getsockopt_args(&self) -> (int, int) {
158        (self.level, self.optname)
159    }
160
161    fn prepare_getsockopt_result(&self, _: int, optval: T) -> Self::Result {
162        optval
163    }
164}
165
166unsafe impl<'a, T: 'a> GetSockOpt<'a> for DirectSockOptReadOnly<T> {
167    type OptVal = T;
168    type Result = T;
169
170    fn prepare_getsockopt_args(&self) -> (int, int) {
171        self.0.prepare_getsockopt_args()
172    }
173
174    fn prepare_getsockopt_result(&self, ret: int, optval: T) -> Self::Result {
175        self.0.prepare_getsockopt_result(ret, optval)
176    }
177}