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