]> git.proxmox.com Git - rustc.git/blame - src/vendor/nix/src/sys/socket/sockopt.rs
New upstream version 1.25.0+dfsg1
[rustc.git] / src / vendor / nix / src / sys / socket / sockopt.rs
CommitLineData
abe05a73
XL
1use super::{ffi, consts, GetSockOpt, SetSockOpt};
2use {Errno, Result};
3use sys::time::TimeVal;
4use libc::{c_int, uint8_t, c_void, socklen_t};
5#[cfg(target_os = "linux")]
6use libc::sockaddr_in;
7use std::mem;
8use std::os::unix::io::RawFd;
9
10macro_rules! setsockopt_impl {
11 ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
12 impl SetSockOpt for $name {
13 type Val = $ty;
14
15 fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
16 unsafe {
17 let setter: $setter = Set::new(val);
18
19 let res = ffi::setsockopt(fd, $level, $flag,
20 setter.ffi_ptr(),
21 setter.ffi_len());
22 Errno::result(res).map(drop)
23 }
24 }
25 }
26 }
27}
28
29macro_rules! getsockopt_impl {
30 ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
31 impl GetSockOpt for $name {
32 type Val = $ty;
33
34 fn get(&self, fd: RawFd) -> Result<$ty> {
35 unsafe {
36 let mut getter: $getter = Get::blank();
37
38 let res = ffi::getsockopt(fd, $level, $flag,
39 getter.ffi_ptr(),
40 getter.ffi_len());
41 try!(Errno::result(res));
42
43 Ok(getter.unwrap())
44 }
45 }
46 }
47 }
48}
49
50// Helper to generate the sockopt accessors
51macro_rules! sockopt_impl {
52 (GetOnly, $name:ident, $level:path, $flag:path, bool) => {
53 sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool);
54 };
55
56 (GetOnly, $name:ident, $level:path, $flag:path, u8) => {
57 sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8);
58 };
59
60 (GetOnly, $name:ident, $level:path, $flag:path, usize) => {
61 sockopt_impl!(GetOnly, $name, $level, $flag, usize, GetUsize);
62 };
63
64 (SetOnly, $name:ident, $level:path, $flag:path, bool) => {
65 sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool);
66 };
67
68 (SetOnly, $name:ident, $level:path, $flag:path, u8) => {
69 sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8);
70 };
71
72 (SetOnly, $name:ident, $level:path, $flag:path, usize) => {
73 sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize);
74 };
75
76 (Both, $name:ident, $level:path, $flag:path, bool) => {
77 sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
78 };
79
80 (Both, $name:ident, $level:path, $flag:path, u8) => {
81 sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
82 };
83
84 (Both, $name:ident, $level:path, $flag:path, usize) => {
85 sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize);
86 };
87
88 /*
89 * Matchers with generic getter types must be placed at the end, so
90 * they'll only match _after_ specialized matchers fail
91 */
92 (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
93 sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
94 };
95
96 (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
97 #[derive(Copy, Clone, Debug)]
98 pub struct $name;
99
100 getsockopt_impl!($name, $level, $flag, $ty, $getter);
101 };
102
103 (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
104 sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
105 };
106
107 (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
108 #[derive(Copy, Clone, Debug)]
109 pub struct $name;
110
111 setsockopt_impl!($name, $level, $flag, $ty, $setter);
112 };
113
114 (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
115 #[derive(Copy, Clone, Debug)]
116 pub struct $name;
117
118 setsockopt_impl!($name, $level, $flag, $ty, $setter);
119 getsockopt_impl!($name, $level, $flag, $ty, $getter);
120 };
121
122 (Both, $name:ident, $level:path, $flag:path, $ty:ty) => {
123 sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>);
124 };
125}
126
127/*
128 *
129 * ===== Define sockopts =====
130 *
131 */
132
133sockopt_impl!(Both, ReuseAddr, consts::SOL_SOCKET, consts::SO_REUSEADDR, bool);
134sockopt_impl!(Both, ReusePort, consts::SOL_SOCKET, consts::SO_REUSEPORT, bool);
135sockopt_impl!(Both, TcpNoDelay, consts::IPPROTO_TCP, consts::TCP_NODELAY, bool);
136sockopt_impl!(Both, Linger, consts::SOL_SOCKET, consts::SO_LINGER, super::linger);
137sockopt_impl!(SetOnly, IpAddMembership, consts::IPPROTO_IP, consts::IP_ADD_MEMBERSHIP, super::ip_mreq);
138sockopt_impl!(SetOnly, IpDropMembership, consts::IPPROTO_IP, consts::IP_DROP_MEMBERSHIP, super::ip_mreq);
139#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd")))]
140sockopt_impl!(SetOnly, Ipv6AddMembership, consts::IPPROTO_IPV6, consts::IPV6_ADD_MEMBERSHIP, super::ipv6_mreq);
141#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd")))]
142sockopt_impl!(SetOnly, Ipv6DropMembership, consts::IPPROTO_IPV6, consts::IPV6_DROP_MEMBERSHIP, super::ipv6_mreq);
143#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))]
144sockopt_impl!(SetOnly, Ipv6AddMembership, consts::IPPROTO_IPV6, consts::IPV6_JOIN_GROUP, super::ipv6_mreq);
145#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))]
146sockopt_impl!(SetOnly, Ipv6DropMembership, consts::IPPROTO_IPV6, consts::IPV6_LEAVE_GROUP, super::ipv6_mreq);
147sockopt_impl!(Both, IpMulticastTtl, consts::IPPROTO_IP, consts::IP_MULTICAST_TTL, u8);
148sockopt_impl!(Both, IpMulticastLoop, consts::IPPROTO_IP, consts::IP_MULTICAST_LOOP, bool);
149sockopt_impl!(Both, ReceiveTimeout, consts::SOL_SOCKET, consts::SO_RCVTIMEO, TimeVal);
150sockopt_impl!(Both, SendTimeout, consts::SOL_SOCKET, consts::SO_SNDTIMEO, TimeVal);
151sockopt_impl!(Both, Broadcast, consts::SOL_SOCKET, consts::SO_BROADCAST, bool);
152sockopt_impl!(Both, OobInline, consts::SOL_SOCKET, consts::SO_OOBINLINE, bool);
153sockopt_impl!(GetOnly, SocketError, consts::SOL_SOCKET, consts::SO_ERROR, i32);
154sockopt_impl!(Both, KeepAlive, consts::SOL_SOCKET, consts::SO_KEEPALIVE, bool);
155#[cfg(target_os = "linux")]
156sockopt_impl!(GetOnly, PeerCredentials, consts::SOL_SOCKET, consts::SO_PEERCRED, super::ucred);
157#[cfg(any(target_os = "macos",
158 target_os = "ios"))]
159sockopt_impl!(Both, TcpKeepAlive, consts::IPPROTO_TCP, consts::TCP_KEEPALIVE, u32);
160#[cfg(any(target_os = "freebsd",
161 target_os = "dragonfly",
162 target_os = "linux",
163 target_os = "android",
164 target_os = "nacl"))]
165sockopt_impl!(Both, TcpKeepIdle, consts::IPPROTO_TCP, consts::TCP_KEEPIDLE, u32);
166sockopt_impl!(Both, RcvBuf, consts::SOL_SOCKET, consts::SO_RCVBUF, usize);
167sockopt_impl!(Both, SndBuf, consts::SOL_SOCKET, consts::SO_SNDBUF, usize);
168#[cfg(target_os = "linux")]
169sockopt_impl!(SetOnly, RcvBufForce, consts::SOL_SOCKET, consts::SO_RCVBUFFORCE, usize);
170#[cfg(target_os = "linux")]
171sockopt_impl!(SetOnly, SndBufForce, consts::SOL_SOCKET, consts::SO_SNDBUFFORCE, usize);
172sockopt_impl!(GetOnly, SockType, consts::SOL_SOCKET, consts::SO_TYPE, super::SockType);
173#[cfg(any(target_os = "freebsd",
174 target_os = "linux",
175 target_os = "nacl"))]
176sockopt_impl!(GetOnly, AcceptConn, consts::SOL_SOCKET, consts::SO_ACCEPTCONN, bool);
177#[cfg(target_os = "linux")]
178sockopt_impl!(GetOnly, OriginalDst, consts::SOL_IP, consts::SO_ORIGINAL_DST, sockaddr_in);
179
180/*
181 *
182 * ===== Accessor helpers =====
183 *
184 */
185
186trait Get<T> {
187 unsafe fn blank() -> Self;
188 unsafe fn ffi_ptr(&mut self) -> *mut c_void;
189 unsafe fn ffi_len(&mut self) -> *mut socklen_t;
190 unsafe fn unwrap(self) -> T;
191}
192
193trait Set<'a, T> {
194 fn new(val: &'a T) -> Self;
195 unsafe fn ffi_ptr(&self) -> *const c_void;
196 unsafe fn ffi_len(&self) -> socklen_t;
197}
198
199struct GetStruct<T> {
200 len: socklen_t,
201 val: T,
202}
203
204impl<T> Get<T> for GetStruct<T> {
205 unsafe fn blank() -> Self {
206 GetStruct {
207 len: mem::size_of::<T>() as socklen_t,
208 val: mem::zeroed(),
209 }
210 }
211
212 unsafe fn ffi_ptr(&mut self) -> *mut c_void {
213 mem::transmute(&mut self.val)
214 }
215
216 unsafe fn ffi_len(&mut self) -> *mut socklen_t {
217 mem::transmute(&mut self.len)
218 }
219
220 unsafe fn unwrap(self) -> T {
221 assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation");
222 self.val
223 }
224}
225
226struct SetStruct<'a, T: 'static> {
227 ptr: &'a T,
228}
229
230impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
231 fn new(ptr: &'a T) -> SetStruct<'a, T> {
232 SetStruct { ptr: ptr }
233 }
234
235 unsafe fn ffi_ptr(&self) -> *const c_void {
236 mem::transmute(self.ptr)
237 }
238
239 unsafe fn ffi_len(&self) -> socklen_t {
240 mem::size_of::<T>() as socklen_t
241 }
242}
243
244struct GetBool {
245 len: socklen_t,
246 val: c_int,
247}
248
249impl Get<bool> for GetBool {
250 unsafe fn blank() -> Self {
251 GetBool {
252 len: mem::size_of::<c_int>() as socklen_t,
253 val: mem::zeroed(),
254 }
255 }
256
257 unsafe fn ffi_ptr(&mut self) -> *mut c_void {
258 mem::transmute(&mut self.val)
259 }
260
261 unsafe fn ffi_len(&mut self) -> *mut socklen_t {
262 mem::transmute(&mut self.len)
263 }
264
265 unsafe fn unwrap(self) -> bool {
266 assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
267 self.val != 0
268 }
269}
270
271struct SetBool {
272 val: c_int,
273}
274
275impl<'a> Set<'a, bool> for SetBool {
276 fn new(val: &'a bool) -> SetBool {
277 SetBool { val: if *val { 1 } else { 0 } }
278 }
279
280 unsafe fn ffi_ptr(&self) -> *const c_void {
281 mem::transmute(&self.val)
282 }
283
284 unsafe fn ffi_len(&self) -> socklen_t {
285 mem::size_of::<c_int>() as socklen_t
286 }
287}
288
289struct GetU8 {
290 len: socklen_t,
291 val: uint8_t,
292}
293
294impl Get<u8> for GetU8 {
295 unsafe fn blank() -> Self {
296 GetU8 {
297 len: mem::size_of::<uint8_t>() as socklen_t,
298 val: mem::zeroed(),
299 }
300 }
301
302 unsafe fn ffi_ptr(&mut self) -> *mut c_void {
303 mem::transmute(&mut self.val)
304 }
305
306 unsafe fn ffi_len(&mut self) -> *mut socklen_t {
307 mem::transmute(&mut self.len)
308 }
309
310 unsafe fn unwrap(self) -> u8 {
311 assert!(self.len as usize == mem::size_of::<uint8_t>(), "invalid getsockopt implementation");
312 self.val as u8
313 }
314}
315
316struct SetU8 {
317 val: uint8_t,
318}
319
320impl<'a> Set<'a, u8> for SetU8 {
321 fn new(val: &'a u8) -> SetU8 {
322 SetU8 { val: *val as uint8_t }
323 }
324
325 unsafe fn ffi_ptr(&self) -> *const c_void {
326 mem::transmute(&self.val)
327 }
328
329 unsafe fn ffi_len(&self) -> socklen_t {
330 mem::size_of::<c_int>() as socklen_t
331 }
332}
333
334struct GetUsize {
335 len: socklen_t,
336 val: c_int,
337}
338
339impl Get<usize> for GetUsize {
340 unsafe fn blank() -> Self {
341 GetUsize {
342 len: mem::size_of::<c_int>() as socklen_t,
343 val: mem::zeroed(),
344 }
345 }
346
347 unsafe fn ffi_ptr(&mut self) -> *mut c_void {
348 mem::transmute(&mut self.val)
349 }
350
351 unsafe fn ffi_len(&mut self) -> *mut socklen_t {
352 mem::transmute(&mut self.len)
353 }
354
355 unsafe fn unwrap(self) -> usize {
356 assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
357 self.val as usize
358 }
359}
360
361struct SetUsize {
362 val: c_int,
363}
364
365impl<'a> Set<'a, usize> for SetUsize {
366 fn new(val: &'a usize) -> SetUsize {
367 SetUsize { val: *val as c_int }
368 }
369
370 unsafe fn ffi_ptr(&self) -> *const c_void {
371 mem::transmute(&self.val)
372 }
373
374 unsafe fn ffi_len(&self) -> socklen_t {
375 mem::size_of::<c_int>() as socklen_t
376 }
377}
378
379#[cfg(test)]
380mod test {
381 #[cfg(target_os = "linux")]
382 #[test]
383 fn can_get_peercred_on_unix_socket() {
384 use super::super::*;
385
386 let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, 0, SockFlag::empty()).unwrap();
387 let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
388 let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
389 assert_eq!(a_cred, b_cred);
390 assert!(a_cred.pid != 0);
391 }
392
393 #[test]
394 fn is_socket_type_unix() {
395 use super::super::*;
396 use ::unistd::close;
397
398 let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, 0, SockFlag::empty()).unwrap();
399 let a_type = getsockopt(a, super::SockType).unwrap();
400 assert!(a_type == SockType::Stream);
401 close(a).unwrap();
402 close(b).unwrap();
403 }
404
405 #[test]
406 fn is_socket_type_dgram() {
407 use super::super::*;
408 use ::unistd::close;
409
410 let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), 0).unwrap();
411 let s_type = getsockopt(s, super::SockType).unwrap();
412 assert!(s_type == SockType::Datagram);
413 close(s).unwrap();
414 }
415
416 #[cfg(any(target_os = "freebsd",
417 target_os = "linux",
418 target_os = "nacl"))]
419 #[test]
420 fn can_get_listen_on_tcp_socket() {
421 use super::super::*;
422 use ::unistd::close;
423
424 let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), 0).unwrap();
425 let s_listening = getsockopt(s, super::AcceptConn).unwrap();
426 assert!(!s_listening);
427 listen(s, 10).unwrap();
428 let s_listening2 = getsockopt(s, super::AcceptConn).unwrap();
429 assert!(s_listening2);
430 close(s).unwrap();
431 }
432}