1 // Copyright (C) 2018-2019, Cloudflare, Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright notice, 9 // this list of conditions and the following disclaimer. 10 // 11 // * Redistributions in binary form must reproduce the above copyright 12 // notice, this list of conditions and the following disclaimer in the 13 // documentation and/or other materials provided with the distribution. 14 // 15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 17 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 19 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 #[macro_use] 28 extern crate log; 29 30 use std::net::ToSocketAddrs; 31 32 use ring::rand::*; 33 34 const MAX_DATAGRAM_SIZE: usize = 1350; 35 36 const HTTP_REQ_STREAM_ID: u64 = 4; 37 main()38 fn main() { 39 let mut buf = [0; 65535]; 40 let mut out = [0; MAX_DATAGRAM_SIZE]; 41 42 let mut args = std::env::args(); 43 44 let cmd = &args.next().unwrap(); 45 46 if args.len() != 1 { 47 println!("Usage: {cmd} URL"); 48 println!("\nSee tools/apps/ for more complete implementations."); 49 return; 50 } 51 52 let url = url::Url::parse(&args.next().unwrap()).unwrap(); 53 54 // Setup the event loop. 55 let mut poll = mio::Poll::new().unwrap(); 56 let mut events = mio::Events::with_capacity(1024); 57 58 // Resolve server address. 59 let peer_addr = url.to_socket_addrs().unwrap().next().unwrap(); 60 61 // Bind to INADDR_ANY or IN6ADDR_ANY depending on the IP family of the 62 // server address. This is needed on macOS and BSD variants that don't 63 // support binding to IN6ADDR_ANY for both v4 and v6. 64 let bind_addr = match peer_addr { 65 std::net::SocketAddr::V4(_) => "0.0.0.0:0", 66 std::net::SocketAddr::V6(_) => "[::]:0", 67 }; 68 69 // Create the UDP socket backing the QUIC connection, and register it with 70 // the event loop. 71 let mut socket = 72 mio::net::UdpSocket::bind(bind_addr.parse().unwrap()).unwrap(); 73 poll.registry() 74 .register(&mut socket, mio::Token(0), mio::Interest::READABLE) 75 .unwrap(); 76 77 // Create the configuration for the QUIC connection. 78 let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap(); 79 80 // *CAUTION*: this should not be set to `false` in production!!! 81 config.verify_peer(false); 82 83 config 84 .set_application_protos(&[ 85 b"hq-interop", 86 b"hq-29", 87 b"hq-28", 88 b"hq-27", 89 b"http/0.9", 90 ]) 91 .unwrap(); 92 93 config.set_max_idle_timeout(5000); 94 config.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE); 95 config.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE); 96 config.set_initial_max_data(10_000_000); 97 config.set_initial_max_stream_data_bidi_local(1_000_000); 98 config.set_initial_max_stream_data_bidi_remote(1_000_000); 99 config.set_initial_max_streams_bidi(100); 100 config.set_initial_max_streams_uni(100); 101 config.set_disable_active_migration(true); 102 103 // Generate a random source connection ID for the connection. 104 let mut scid = [0; quiche::MAX_CONN_ID_LEN]; 105 SystemRandom::new().fill(&mut scid[..]).unwrap(); 106 107 let scid = quiche::ConnectionId::from_ref(&scid); 108 109 // Get local address. 110 let local_addr = socket.local_addr().unwrap(); 111 112 // Create a QUIC connection and initiate handshake. 113 let mut conn = 114 quiche::connect(url.domain(), &scid, local_addr, peer_addr, &mut config) 115 .unwrap(); 116 117 info!( 118 "connecting to {:} from {:} with scid {}", 119 peer_addr, 120 socket.local_addr().unwrap(), 121 hex_dump(&scid) 122 ); 123 124 let (write, send_info) = conn.send(&mut out).expect("initial send failed"); 125 126 while let Err(e) = socket.send_to(&out[..write], send_info.to) { 127 if e.kind() == std::io::ErrorKind::WouldBlock { 128 debug!("send() would block"); 129 continue; 130 } 131 132 panic!("send() failed: {:?}", e); 133 } 134 135 debug!("written {}", write); 136 137 let req_start = std::time::Instant::now(); 138 139 let mut req_sent = false; 140 141 loop { 142 poll.poll(&mut events, conn.timeout()).unwrap(); 143 144 // Read incoming UDP packets from the socket and feed them to quiche, 145 // until there are no more packets to read. 146 'read: loop { 147 // If the event loop reported no events, it means that the timeout 148 // has expired, so handle it without attempting to read packets. We 149 // will then proceed with the send loop. 150 if events.is_empty() { 151 debug!("timed out"); 152 153 conn.on_timeout(); 154 break 'read; 155 } 156 157 let (len, from) = match socket.recv_from(&mut buf) { 158 Ok(v) => v, 159 160 Err(e) => { 161 // There are no more UDP packets to read, so end the read 162 // loop. 163 if e.kind() == std::io::ErrorKind::WouldBlock { 164 debug!("recv() would block"); 165 break 'read; 166 } 167 168 panic!("recv() failed: {:?}", e); 169 }, 170 }; 171 172 debug!("got {} bytes", len); 173 174 let recv_info = quiche::RecvInfo { 175 to: socket.local_addr().unwrap(), 176 from, 177 }; 178 179 // Process potentially coalesced packets. 180 let read = match conn.recv(&mut buf[..len], recv_info) { 181 Ok(v) => v, 182 183 Err(e) => { 184 error!("recv failed: {:?}", e); 185 continue 'read; 186 }, 187 }; 188 189 debug!("processed {} bytes", read); 190 } 191 192 debug!("done reading"); 193 194 if conn.is_closed() { 195 info!("connection closed, {:?}", conn.stats()); 196 break; 197 } 198 199 // Send an HTTP request as soon as the connection is established. 200 if conn.is_established() && !req_sent { 201 info!("sending HTTP request for {}", url.path()); 202 203 let req = format!("GET {}\r\n", url.path()); 204 conn.stream_send(HTTP_REQ_STREAM_ID, req.as_bytes(), true) 205 .unwrap(); 206 207 req_sent = true; 208 } 209 210 // Process all readable streams. 211 for s in conn.readable() { 212 while let Ok((read, fin)) = conn.stream_recv(s, &mut buf) { 213 debug!("received {} bytes", read); 214 215 let stream_buf = &buf[..read]; 216 217 debug!( 218 "stream {} has {} bytes (fin? {})", 219 s, 220 stream_buf.len(), 221 fin 222 ); 223 224 print!("{}", unsafe { 225 std::str::from_utf8_unchecked(stream_buf) 226 }); 227 228 // The server reported that it has no more data to send, which 229 // we got the full response. Close the connection. 230 if s == HTTP_REQ_STREAM_ID && fin { 231 info!( 232 "response received in {:?}, closing...", 233 req_start.elapsed() 234 ); 235 236 conn.close(true, 0x00, b"kthxbye").unwrap(); 237 } 238 } 239 } 240 241 // Generate outgoing QUIC packets and send them on the UDP socket, until 242 // quiche reports that there are no more packets to be sent. 243 loop { 244 let (write, send_info) = match conn.send(&mut out) { 245 Ok(v) => v, 246 247 Err(quiche::Error::Done) => { 248 debug!("done writing"); 249 break; 250 }, 251 252 Err(e) => { 253 error!("send failed: {:?}", e); 254 255 conn.close(false, 0x1, b"fail").ok(); 256 break; 257 }, 258 }; 259 260 if let Err(e) = socket.send_to(&out[..write], send_info.to) { 261 if e.kind() == std::io::ErrorKind::WouldBlock { 262 debug!("send() would block"); 263 break; 264 } 265 266 panic!("send() failed: {:?}", e); 267 } 268 269 debug!("written {}", write); 270 } 271 272 if conn.is_closed() { 273 info!("connection closed, {:?}", conn.stats()); 274 break; 275 } 276 } 277 } 278 hex_dump(buf: &[u8]) -> String279 fn hex_dump(buf: &[u8]) -> String { 280 let vec: Vec<String> = buf.iter().map(|b| format!("{b:02x}")).collect(); 281 282 vec.join("") 283 } 284