• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::io;
15 use std::mem::{self, size_of, MaybeUninit};
16 use std::net::{self, SocketAddr};
17 use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
18 use std::time::Duration;
19 
20 use libc::{
21     c_int, c_void, linger, socklen_t, AF_INET, AF_INET6, SOCK_CLOEXEC, SOCK_NONBLOCK, SOCK_STREAM,
22     SOL_SOCKET, SO_LINGER, SO_REUSEADDR,
23 };
24 
25 use super::super::socket_addr::socket_addr_trans;
26 use super::{TcpListener, TcpStream};
27 use crate::source::Fd;
28 
29 pub(crate) struct TcpSocket {
30     socket: c_int,
31 }
32 
33 impl TcpSocket {
new_socket(addr: SocketAddr) -> io::Result<TcpSocket>34     pub(crate) fn new_socket(addr: SocketAddr) -> io::Result<TcpSocket> {
35         if addr.is_ipv4() {
36             TcpSocket::create_socket(AF_INET, SOCK_STREAM)
37         } else {
38             TcpSocket::create_socket(AF_INET6, SOCK_STREAM)
39         }
40     }
41 
create_socket(domain: c_int, socket_type: c_int) -> io::Result<TcpSocket>42     pub(crate) fn create_socket(domain: c_int, socket_type: c_int) -> io::Result<TcpSocket> {
43         let socket_type = socket_type | SOCK_NONBLOCK | SOCK_CLOEXEC;
44         match syscall!(socket(domain, socket_type, 0)) {
45             Ok(socket) => Ok(TcpSocket {
46                 socket: socket as c_int,
47             }),
48             Err(err) => Err(err),
49         }
50     }
51 
set_reuse(&self, is_reuse: bool) -> io::Result<()>52     pub(crate) fn set_reuse(&self, is_reuse: bool) -> io::Result<()> {
53         let set_value: c_int = i32::from(is_reuse);
54 
55         match syscall!(setsockopt(
56             self.socket,
57             SOL_SOCKET,
58             SO_REUSEADDR,
59             &set_value as *const c_int as *const c_void,
60             size_of::<c_int>() as socklen_t
61         )) {
62             Err(err) => Err(err),
63             Ok(_) => Ok(()),
64         }
65     }
66 
bind(&self, addr: SocketAddr) -> io::Result<()>67     pub(crate) fn bind(&self, addr: SocketAddr) -> io::Result<()> {
68         let (raw_addr, addr_length) = socket_addr_trans(&addr);
69         match syscall!(bind(self.socket, raw_addr.as_ptr(), addr_length)) {
70             Err(err) => Err(err),
71             Ok(_) => Ok(()),
72         }
73     }
74 
listen(self, max_connect: c_int) -> io::Result<TcpListener>75     pub(crate) fn listen(self, max_connect: c_int) -> io::Result<TcpListener> {
76         syscall!(listen(self.socket, max_connect))?;
77 
78         let tcp_listener = Ok(TcpListener {
79             inner: unsafe { net::TcpListener::from_raw_fd(self.socket) },
80         });
81 
82         mem::forget(self);
83 
84         tcp_listener
85     }
86 
connect(self, addr: SocketAddr) -> io::Result<TcpStream>87     pub(crate) fn connect(self, addr: SocketAddr) -> io::Result<TcpStream> {
88         let (raw_addr, addr_length) = socket_addr_trans(&addr);
89         match syscall!(connect(self.socket, raw_addr.as_ptr(), addr_length)) {
90             Err(err) if err.raw_os_error() != Some(libc::EINPROGRESS) => Err(err),
91             _ => {
92                 let tcp_stream = Ok(TcpStream {
93                     inner: unsafe { net::TcpStream::from_raw_fd(self.socket) },
94                 });
95                 mem::forget(self);
96                 tcp_stream
97             }
98         }
99     }
100 
close(&self)101     pub(crate) fn close(&self) {
102         let _ = unsafe { net::TcpStream::from_raw_fd(self.socket) };
103     }
104 }
105 
106 impl AsRawFd for TcpSocket {
as_raw_fd(&self) -> RawFd107     fn as_raw_fd(&self) -> RawFd {
108         self.socket
109     }
110 }
111 
112 impl FromRawFd for TcpSocket {
from_raw_fd(fd: RawFd) -> TcpSocket113     unsafe fn from_raw_fd(fd: RawFd) -> TcpSocket {
114         TcpSocket { socket: fd }
115     }
116 }
117 
118 impl Drop for TcpSocket {
drop(&mut self)119     fn drop(&mut self) {
120         self.close();
121     }
122 }
123 
get_sock_linger(fd: Fd) -> io::Result<Option<Duration>>124 pub(crate) fn get_sock_linger(fd: Fd) -> io::Result<Option<Duration>> {
125     let mut payload: MaybeUninit<linger> = MaybeUninit::uninit();
126     let mut len = mem::size_of::<linger>() as libc::socklen_t;
127 
128     syscall!(getsockopt(
129         fd as c_int,
130         SOL_SOCKET,
131         SO_LINGER,
132         payload.as_mut_ptr().cast(),
133         &mut len,
134     ))
135     .map(|_| {
136         let linger = unsafe { payload.assume_init() };
137         from_linger(linger)
138     })
139 }
140 
set_sock_linger(fd: Fd, duration: Option<Duration>) -> io::Result<()>141 pub(crate) fn set_sock_linger(fd: Fd, duration: Option<Duration>) -> io::Result<()> {
142     let payload = into_linger(duration);
143     syscall!(setsockopt(
144         fd as c_int,
145         SOL_SOCKET,
146         SO_LINGER,
147         &payload as *const linger as *const c_void,
148         mem::size_of::<linger>() as libc::socklen_t,
149     ))
150     .map(|_| ())
151 }
152 
from_linger(linger: linger) -> Option<Duration>153 fn from_linger(linger: linger) -> Option<Duration> {
154     if linger.l_onoff == 0 {
155         None
156     } else {
157         Some(Duration::from_secs(linger.l_linger as u64))
158     }
159 }
160 
into_linger(duration: Option<Duration>) -> linger161 fn into_linger(duration: Option<Duration>) -> linger {
162     match duration {
163         None => linger {
164             l_onoff: 0,
165             l_linger: 0,
166         },
167         Some(dur) => linger {
168             l_onoff: 1,
169             l_linger: dur.as_secs() as _,
170         },
171     }
172 }
173