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 //! `ConnDetail` trait and `HttpStream` implementation.
15 
16 use std::ffi::c_void;
17 use std::net::SocketAddr;
18 use std::ops::{Deref, DerefMut};
19 use std::ptr;
20 
21 use libc::{
22     in6_addr, in_addr, sa_family_t, size_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage,
23     socklen_t, AF_INET, AF_INET6,
24 };
25 use ylong_runtime::fastrand::fast_random;
26 use ylong_runtime::time::timeout;
27 
28 use crate::async_impl::connector::ConnInfo;
29 use crate::c_openssl::ssl::verify_server_cert;
30 use crate::runtime::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
31 use crate::util::c_openssl::ssl::Ssl;
32 use crate::{ErrorKind, HttpClientError, TlsConfig};
33 
34 const MAX_DATAGRAM_SIZE: usize = 1350;
35 const UDP_BUF_SIZE: usize = 65535;
36 const MAX_STREAM_DATA: u64 = 1_000_000;
37 const MAX_TOTAL_DATA: u64 = 10_000_000;
38 const MAX_STREAM_NUM: u64 = 100;
39 const MAX_IDLE_TIME: u64 = 5000;
40 
41 pub struct QuicConn {
42     inner: quiche::Connection,
43 }
44 
45 impl QuicConn {
quic_confignull46     fn quic_config() -> Result<quiche::Config, quiche::Error> {
47         let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
48         config.verify_peer(true);
49         config.set_application_protos(quiche::h3::APPLICATION_PROTOCOL)?;
50         config.set_max_idle_timeout(MAX_IDLE_TIME);
51         config.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE);
52         config.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE);
53         config.set_initial_max_data(MAX_TOTAL_DATA);
54         config.set_initial_max_stream_data_bidi_local(MAX_STREAM_DATA);
55         config.set_initial_max_stream_data_bidi_remote(MAX_STREAM_DATA);
56         config.set_initial_max_stream_data_uni(MAX_STREAM_DATA);
57         config.set_initial_max_streams_bidi(MAX_STREAM_NUM);
58         config.set_initial_max_streams_uni(MAX_STREAM_NUM);
59         config.set_disable_active_migration(true);
60         Ok(config)
61     }
62 
63     pub(crate) async fn connect<S>(
64         stream: &mut S,
65         tls_config: &TlsConfig,
66         host: &str,
67     ) -> Result<QuicConn, HttpClientError>
68     where
69         S: AsyncRead + AsyncWrite + ConnInfo + Unpin + Sync + Send + 'static,
70     {
71         let config = Self::quic_config()
72             .map_err(|_| HttpClientError::from_str(ErrorKind::Connect, "Quic init error"))?;
73         // Generate a random source connection ID for the connection.
74         let mut scid = [0; quiche::MAX_CONN_ID_LEN];
75         for byte in scid.iter_mut() {
76             *byte = fast_random() as u8;
77         }
78         let scid = quiche::ConnectionId::from_ref(&scid);
79 
80         let local = stream.conn_detail().local();
81         let peer = stream.conn_detail().peer();
82         let mut c_local: sockaddr_storage = unsafe { std::mem::zeroed() };
83         let c_local_size = Self::std_addr_to_c(&local, &mut c_local);
84         let mut c_peer: sockaddr_storage = unsafe { std::mem::zeroed() };
85         let c_peer_size = Self::std_addr_to_c(&peer, &mut c_peer);
86         let mut new_ssl = tls_config.ssl_new(host).unwrap().into_inner();
87 
88         let conn = unsafe {
89             quiche_conn_new_with_tls(
90                 scid.as_ptr(),
91                 scid.len() as size_t,
92                 ptr::null_mut(),
93                 0,
94                 &c_local as *const _ as *const sockaddr,
95                 c_local_size,
96                 &c_peer as *const _ as *const sockaddr,
97                 c_peer_size,
98                 &config as *const _ as *const c_void,
99                 new_ssl.get_raw_ptr() as *mut c_void,
100                 false,
101             ) as *mut quiche::Connection
102         };
103         let mut conn = QuicConn {
104             inner: unsafe { *Box::from_raw(conn) },
105         };
106         if let Err(e) = conn.connect_inner(stream, &mut new_ssl, tls_config).await {
107             std::mem::forget(new_ssl);
108             return Err(e);
109         }
110         std::mem::forget(new_ssl);
111         if conn.is_established() {
112             Ok(conn)
113         } else {
114             Err(HttpClientError::from_str(
115                 ErrorKind::Connect,
116                 "Quic connect error",
117             ))
118         }
119     }
120 
121     async fn connect_inner<S>(
122         &mut self,
123         stream: &mut S,
124         ssl: &mut Ssl,
125         tls_config: &TlsConfig,
126     ) -> Result<(), HttpClientError>
127     where
128         S: AsyncRead + AsyncWrite + ConnInfo + Unpin + Sync + Send + 'static,
129     {
130         let mut buf = [0; UDP_BUF_SIZE];
131         let mut out = [0; MAX_DATAGRAM_SIZE];
132         let (write, _send_info) = self.send(&mut out).expect("initial send failed");
133         let mut e: Result<(), HttpClientError> = Ok(());
134         stream
135             .write_all(&out[..write])
136             .await
137             .map_err(|e| HttpClientError::from_io_error(crate::ErrorKind::Connect, e))?;
138         loop {
139             self.conn_recv(stream, &mut buf).await?;
140 
141             if self.is_closed() {
142                 break;
143             }
144             if self.is_established() {
145                 let Some(key) = tls_config.pinning_host_match(stream.conn_detail().addr()) else {
146                     break;
147                 };
148 
149                 if verify_server_cert(ssl.get_raw_ptr(), key.as_str()).is_ok() {
150                     return Ok(());
151                 }
152                 e = Err(HttpClientError::from_str(
153                     ErrorKind::Connect,
154                     "verify server cert failed",
155                 ));
156                 if let Err(quiche::Error::Done) =
157                     self.close(false, 0x1, b"verify server cert failed")
158                 {
159                     return e;
160                 }
161             }
162 
163             loop {
164                 let (write, _send_info) = match self.send(&mut out) {
165                     Ok(v) => v,
166                     Err(quiche::Error::Done) => {
167                         break;
168                     }
169                     Err(err) => {
170                         if e.is_ok() {
171                             e = Err(HttpClientError::from_error(ErrorKind::Connect, err));
172                         }
173                         self.close(false, 0x1, b"fail").ok();
174                         break;
175                     }
176                 };
177                 stream
178                     .write_all(&out[..write])
179                     .await
180                     .map_err(|e| HttpClientError::from_io_error(crate::ErrorKind::Connect, e))?;
181             }
182         }
183         e
184     }
185 
186     async fn conn_recv<S>(&mut self, stream: &mut S, buf: &mut [u8]) -> Result<(), HttpClientError>
187     where
188         S: AsyncRead + AsyncWrite + ConnInfo + Unpin + Sync + Send + 'static,
189     {
190         let recv_info = quiche::RecvInfo {
191             to: stream.conn_detail().local(),
192             from: stream.conn_detail().peer(),
193         };
194         let mut recv_size = 0;
195         let mut len = 0;
196         loop {
197             if len != 0 && recv_size != len {
198                 match self.recv(&mut buf[recv_size..len], recv_info) {
199                     Ok(size) => {
200                         recv_size += size;
201                         if recv_size == len {
202                             return Ok(());
203                         } else {
204                             continue;
205                         }
206                     }
207                     Err(quiche::Error::Done) => {
208                         return Ok(());
209                     }
210                     Err(e) => {
211                         return Err(HttpClientError::from_error(ErrorKind::Connect, e));
212                     }
213                 }
214             }
215             len = match self.timeout() {
216                 Some(dur) => {
217                     if let Ok(res) = timeout(dur, stream.read(buf)).await {
218                         res
219                     } else {
220                         self.on_timeout();
221                         return Ok(());
222                     }
223                 }
224                 None => stream.read(buf).await,
225             }
226             .map_err(|e| HttpClientError::from_io_error(crate::ErrorKind::Connect, e))?;
227         }
228     }
229 
std_addr_to_cnull230     fn std_addr_to_c(addr: &SocketAddr, c_addr: &mut sockaddr_storage) -> socklen_t {
231         let sin_port = addr.port().to_be();
232 
233         match addr {
234             SocketAddr::V4(addr) => unsafe {
235                 let sa_len = std::mem::size_of::<sockaddr_in>();
236                 let c_addr_in = c_addr as *mut _ as *mut sockaddr_in;
237                 let s_addr = u32::from_ne_bytes(addr.ip().octets());
238                 let sin_addr = in_addr { s_addr };
239                 *c_addr_in = sockaddr_in {
240                     sin_family: AF_INET as sa_family_t,
241                     sin_addr,
242                     sin_port,
243                     sin_zero: std::mem::zeroed(),
244                 };
245                 sa_len as socklen_t
246             },
247             SocketAddr::V6(addr) => unsafe {
248                 let sa_len = std::mem::size_of::<sockaddr_in6>();
249                 let c_addr_in6 = c_addr as *mut _ as *mut sockaddr_in6;
250                 let sin6_addr = in6_addr {
251                     s6_addr: addr.ip().octets(),
252                 };
253                 *c_addr_in6 = sockaddr_in6 {
254                     sin6_family: AF_INET6 as sa_family_t,
255                     sin6_addr,
256                     sin6_port: sin_port,
257                     sin6_flowinfo: addr.flowinfo(),
258                     sin6_scope_id: addr.scope_id(),
259                 };
260                 sa_len as socklen_t
261             },
262         }
263     }
264 }
265 
266 impl Deref for QuicConn {
267     type Target = quiche::Connection;
268 
derefnull269     fn deref(&self) -> &Self::Target {
270         &self.inner
271     }
272 }
273 
274 impl DerefMut for QuicConn {
deref_mutnull275     fn deref_mut(&mut self) -> &mut Self::Target {
276         &mut self.inner
277     }
278 }
279 
280 extern "C" {
281     pub(crate) fn quiche_conn_new_with_tls(
282         scid: *const u8,
283         scid_len: size_t,
284         odcid: *const u8,
285         odcid_len: size_t,
286         local: *const sockaddr,
287         local_len: socklen_t,
288         peer: *const sockaddr,
289         peer_len: socklen_t,
290         config: *const c_void,
291         ssl: *mut c_void,
292         is_server: bool,
293     ) -> *mut c_void;
294 }
295