• 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 //! `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::c_openssl::ssl::{verify_server_cert, verify_server_root_cert};
29 use crate::runtime::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
30 use crate::util::c_openssl::ssl::Ssl;
31 use crate::util::ConnInfo;
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_config() -> Result<quiche::Config, quiche::Error>46     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 
connect<S>( stream: &mut S, tls_config: &TlsConfig, host: &str, ) -> Result<QuicConn, HttpClientError> where S: AsyncRead + AsyncWrite + ConnInfo + Unpin + Sync + Send + 'static,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_data().detail().local();
81         let peer = stream.conn_data().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 
connect_inner<S>( &mut self, stream: &mut S, ssl: &mut Ssl, tls_config: &TlsConfig, ) -> Result<(), HttpClientError> where S: AsyncRead + AsyncWrite + ConnInfo + Unpin + Sync + Send + 'static,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(pins_info) =
146                     tls_config.pinning_host_match(stream.conn_data().detail().addr())
147                 else {
148                     break;
149                 };
150 
151                 // cert pins verify
152                 let verify_result = if pins_info.is_root() {
153                     verify_server_root_cert(ssl.get_raw_ptr(), pins_info.get_digest())
154                 } else {
155                     verify_server_cert(ssl.get_raw_ptr(), pins_info.get_digest())
156                 };
157                 if verify_result.is_ok() {
158                     return Ok(());
159                 }
160 
161                 e = Err(HttpClientError::from_str(
162                     ErrorKind::Connect,
163                     "verify server cert failed",
164                 ));
165                 if let Err(quiche::Error::Done) =
166                     self.close(false, 0x1, b"verify server cert failed")
167                 {
168                     return e;
169                 }
170             }
171 
172             loop {
173                 let (write, _send_info) = match self.send(&mut out) {
174                     Ok(v) => v,
175                     Err(quiche::Error::Done) => {
176                         break;
177                     }
178                     Err(err) => {
179                         if e.is_ok() {
180                             e = Err(HttpClientError::from_error(ErrorKind::Connect, err));
181                         }
182                         self.close(false, 0x1, b"fail").ok();
183                         break;
184                     }
185                 };
186                 stream
187                     .write_all(&out[..write])
188                     .await
189                     .map_err(|e| HttpClientError::from_io_error(crate::ErrorKind::Connect, e))?;
190             }
191         }
192         e
193     }
194 
conn_recv<S>(&mut self, stream: &mut S, buf: &mut [u8]) -> Result<(), HttpClientError> where S: AsyncRead + AsyncWrite + ConnInfo + Unpin + Sync + Send + 'static,195     async fn conn_recv<S>(&mut self, stream: &mut S, buf: &mut [u8]) -> Result<(), HttpClientError>
196     where
197         S: AsyncRead + AsyncWrite + ConnInfo + Unpin + Sync + Send + 'static,
198     {
199         let recv_info = quiche::RecvInfo {
200             to: stream.conn_data().detail().local(),
201             from: stream.conn_data().detail().peer(),
202         };
203         let mut recv_size = 0;
204         let mut len = 0;
205         loop {
206             if len != 0 && recv_size != len {
207                 match self.recv(&mut buf[recv_size..len], recv_info) {
208                     Ok(size) => {
209                         recv_size += size;
210                         if recv_size == len {
211                             return Ok(());
212                         } else {
213                             continue;
214                         }
215                     }
216                     Err(quiche::Error::Done) => {
217                         return Ok(());
218                     }
219                     Err(e) => {
220                         return Err(HttpClientError::from_error(ErrorKind::Connect, e));
221                     }
222                 }
223             }
224             len = match self.timeout() {
225                 Some(dur) => {
226                     if let Ok(res) = timeout(dur, stream.read(buf)).await {
227                         res
228                     } else {
229                         self.on_timeout();
230                         return Ok(());
231                     }
232                 }
233                 None => stream.read(buf).await,
234             }
235             .map_err(|e| HttpClientError::from_io_error(crate::ErrorKind::Connect, e))?;
236         }
237     }
238 
std_addr_to_c(addr: &SocketAddr, c_addr: &mut sockaddr_storage) -> socklen_t239     fn std_addr_to_c(addr: &SocketAddr, c_addr: &mut sockaddr_storage) -> socklen_t {
240         let sin_port = addr.port().to_be();
241 
242         match addr {
243             SocketAddr::V4(addr) => unsafe {
244                 let sa_len = std::mem::size_of::<sockaddr_in>();
245                 let c_addr_in = c_addr as *mut _ as *mut sockaddr_in;
246                 let s_addr = u32::from_ne_bytes(addr.ip().octets());
247                 let sin_addr = in_addr { s_addr };
248                 *c_addr_in = sockaddr_in {
249                     sin_family: AF_INET as sa_family_t,
250                     sin_addr,
251                     sin_port,
252                     sin_zero: std::mem::zeroed(),
253                 };
254                 sa_len as socklen_t
255             },
256             SocketAddr::V6(addr) => unsafe {
257                 let sa_len = std::mem::size_of::<sockaddr_in6>();
258                 let c_addr_in6 = c_addr as *mut _ as *mut sockaddr_in6;
259                 let sin6_addr = in6_addr {
260                     s6_addr: addr.ip().octets(),
261                 };
262                 *c_addr_in6 = sockaddr_in6 {
263                     sin6_family: AF_INET6 as sa_family_t,
264                     sin6_addr,
265                     sin6_port: sin_port,
266                     sin6_flowinfo: addr.flowinfo(),
267                     sin6_scope_id: addr.scope_id(),
268                 };
269                 sa_len as socklen_t
270             },
271         }
272     }
273 }
274 
275 impl Deref for QuicConn {
276     type Target = quiche::Connection;
277 
deref(&self) -> &Self::Target278     fn deref(&self) -> &Self::Target {
279         &self.inner
280     }
281 }
282 
283 impl DerefMut for QuicConn {
deref_mut(&mut self) -> &mut Self::Target284     fn deref_mut(&mut self) -> &mut Self::Target {
285         &mut self.inner
286     }
287 }
288 
289 extern "C" {
quiche_conn_new_with_tls( scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t, local: *const sockaddr, local_len: socklen_t, peer: *const sockaddr, peer_len: socklen_t, config: *const c_void, ssl: *mut c_void, is_server: bool, ) -> *mut c_void290     pub(crate) fn quiche_conn_new_with_tls(
291         scid: *const u8,
292         scid_len: size_t,
293         odcid: *const u8,
294         odcid_len: size_t,
295         local: *const sockaddr,
296         local_len: socklen_t,
297         peer: *const sockaddr,
298         peer_len: socklen_t,
299         config: *const c_void,
300         ssl: *mut c_void,
301         is_server: bool,
302     ) -> *mut c_void;
303 }
304