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