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}