1 // Copyright (C) 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 
main()36 fn main() {
37     let mut buf = [0; 65535];
38     let mut out = [0; MAX_DATAGRAM_SIZE];
39 
40     let mut args = std::env::args();
41 
42     let cmd = &args.next().unwrap();
43 
44     if args.len() != 1 {
45         println!("Usage: {} URL", cmd);
46         println!("\nSee tools/apps/ for more complete implementations.");
47         return;
48     }
49 
50     let url = url::Url::parse(&args.next().unwrap()).unwrap();
51 
52     // Setup the event loop.
53     let poll = mio::Poll::new().unwrap();
54     let mut events = mio::Events::with_capacity(1024);
55 
56     // Resolve server address.
57     let peer_addr = url.to_socket_addrs().unwrap().next().unwrap();
58 
59     // Bind to INADDR_ANY or IN6ADDR_ANY depending on the IP family of the
60     // server address. This is needed on macOS and BSD variants that don't
61     // support binding to IN6ADDR_ANY for both v4 and v6.
62     let bind_addr = match peer_addr {
63         std::net::SocketAddr::V4(_) => "0.0.0.0:0",
64         std::net::SocketAddr::V6(_) => "[::]:0",
65     };
66 
67     // Create the UDP socket backing the QUIC connection, and register it with
68     // the event loop.
69     let socket = std::net::UdpSocket::bind(bind_addr).unwrap();
70     socket.connect(peer_addr).unwrap();
71 
72     let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
73     poll.register(
74         &socket,
75         mio::Token(0),
76         mio::Ready::readable(),
77         mio::PollOpt::edge(),
78     )
79     .unwrap();
80 
81     // Create the configuration for the QUIC connection.
82     let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
83 
84     // *CAUTION*: this should not be set to `false` in production!!!
85     config.verify_peer(false);
86 
87     config
88         .set_application_protos(quiche::h3::APPLICATION_PROTOCOL)
89         .unwrap();
90 
91     config.set_max_idle_timeout(5000);
92     config.set_max_udp_payload_size(MAX_DATAGRAM_SIZE as u64);
93     config.set_initial_max_data(10_000_000);
94     config.set_initial_max_stream_data_bidi_local(1_000_000);
95     config.set_initial_max_stream_data_bidi_remote(1_000_000);
96     config.set_initial_max_stream_data_uni(1_000_000);
97     config.set_initial_max_streams_bidi(100);
98     config.set_initial_max_streams_uni(100);
99     config.set_disable_active_migration(true);
100 
101     let mut http3_conn = None;
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     // Create a QUIC connection and initiate handshake.
108     let mut conn = quiche::connect(url.domain(), &scid, &mut config).unwrap();
109 
110     info!(
111         "connecting to {:} from {:} with scid {}",
112         peer_addr,
113         socket.local_addr().unwrap(),
114         hex_dump(&scid)
115     );
116 
117     let write = conn.send(&mut out).expect("initial send failed");
118 
119     while let Err(e) = socket.send(&out[..write]) {
120         if e.kind() == std::io::ErrorKind::WouldBlock {
121             debug!("send() would block");
122             continue;
123         }
124 
125         panic!("send() failed: {:?}", e);
126     }
127 
128     debug!("written {}", write);
129 
130     let h3_config = quiche::h3::Config::new().unwrap();
131 
132     // Prepare request.
133     let mut path = String::from(url.path());
134 
135     if let Some(query) = url.query() {
136         path.push('?');
137         path.push_str(query);
138     }
139 
140     let req = vec![
141         quiche::h3::Header::new(":method", "GET"),
142         quiche::h3::Header::new(":scheme", url.scheme()),
143         quiche::h3::Header::new(":authority", url.host_str().unwrap()),
144         quiche::h3::Header::new(":path", &path),
145         quiche::h3::Header::new("user-agent", "quiche"),
146     ];
147 
148     let req_start = std::time::Instant::now();
149 
150     let mut req_sent = false;
151 
152     loop {
153         poll.poll(&mut events, conn.timeout()).unwrap();
154 
155         // Read incoming UDP packets from the socket and feed them to quiche,
156         // until there are no more packets to read.
157         'read: loop {
158             // If the event loop reported no events, it means that the timeout
159             // has expired, so handle it without attempting to read packets. We
160             // will then proceed with the send loop.
161             if events.is_empty() {
162                 debug!("timed out");
163 
164                 conn.on_timeout();
165 
166                 break 'read;
167             }
168 
169             let len = match socket.recv(&mut buf) {
170                 Ok(v) => v,
171 
172                 Err(e) => {
173                     // There are no more UDP packets to read, so end the read
174                     // loop.
175                     if e.kind() == std::io::ErrorKind::WouldBlock {
176                         debug!("recv() would block");
177                         break 'read;
178                     }
179 
180                     panic!("recv() failed: {:?}", e);
181                 },
182             };
183 
184             debug!("got {} bytes", len);
185 
186             // Process potentially coalesced packets.
187             let read = match conn.recv(&mut buf[..len]) {
188                 Ok(v) => v,
189 
190                 Err(e) => {
191                     error!("recv failed: {:?}", e);
192                     continue 'read;
193                 },
194             };
195 
196             debug!("processed {} bytes", read);
197         }
198 
199         debug!("done reading");
200 
201         if conn.is_closed() {
202             info!("connection closed, {:?}", conn.stats());
203             break;
204         }
205 
206         // Create a new HTTP/3 connection once the QUIC connection is established.
207         if conn.is_established() && http3_conn.is_none() {
208             http3_conn = Some(
209                 quiche::h3::Connection::with_transport(&mut conn, &h3_config)
210                     .unwrap(),
211             );
212         }
213 
214         // Send HTTP requests once the QUIC connection is established, and until
215         // all requests have been sent.
216         if let Some(h3_conn) = &mut http3_conn {
217             if !req_sent {
218                 info!("sending HTTP request {:?}", req);
219 
220                 h3_conn.send_request(&mut conn, &req, true).unwrap();
221 
222                 req_sent = true;
223             }
224         }
225 
226         if let Some(http3_conn) = &mut http3_conn {
227             // Process HTTP/3 events.
228             loop {
229                 match http3_conn.poll(&mut conn) {
230                     Ok((stream_id, quiche::h3::Event::Headers { list, .. })) => {
231                         info!(
232                             "got response headers {:?} on stream id {}",
233                             list, stream_id
234                         );
235                     },
236 
237                     Ok((stream_id, quiche::h3::Event::Data)) => {
238                         if let Ok(read) =
239                             http3_conn.recv_body(&mut conn, stream_id, &mut buf)
240                         {
241                             debug!(
242                                 "got {} bytes of response data on stream {}",
243                                 read, stream_id
244                             );
245 
246                             print!("{}", unsafe {
247                                 std::str::from_utf8_unchecked(&buf[..read])
248                             });
249                         }
250                     },
251 
252                     Ok((_stream_id, quiche::h3::Event::Finished)) => {
253                         info!(
254                             "response received in {:?}, closing...",
255                             req_start.elapsed()
256                         );
257 
258                         conn.close(true, 0x00, b"kthxbye").unwrap();
259                     },
260 
261                     Ok((_flow_id, quiche::h3::Event::Datagram)) => (),
262 
263                     Ok((goaway_id, quiche::h3::Event::GoAway)) => {
264                         info!("GOAWAY id={}", goaway_id);
265                     },
266 
267                     Err(quiche::h3::Error::Done) => {
268                         break;
269                     },
270 
271                     Err(e) => {
272                         error!("HTTP/3 processing failed: {:?}", e);
273 
274                         break;
275                     },
276                 }
277             }
278         }
279 
280         // Generate outgoing QUIC packets and send them on the UDP socket, until
281         // quiche reports that there are no more packets to be sent.
282         loop {
283             let write = match conn.send(&mut out) {
284                 Ok(v) => v,
285 
286                 Err(quiche::Error::Done) => {
287                     debug!("done writing");
288                     break;
289                 },
290 
291                 Err(e) => {
292                     error!("send failed: {:?}", e);
293 
294                     conn.close(false, 0x1, b"fail").ok();
295                     break;
296                 },
297             };
298 
299             if let Err(e) = socket.send(&out[..write]) {
300                 if e.kind() == std::io::ErrorKind::WouldBlock {
301                     debug!("send() would block");
302                     break;
303                 }
304 
305                 panic!("send() failed: {:?}", e);
306             }
307 
308             debug!("written {}", write);
309         }
310 
311         if conn.is_closed() {
312             info!("connection closed, {:?}", conn.stats());
313             break;
314         }
315     }
316 }
317 
hex_dump(buf: &[u8]) -> String318 fn hex_dump(buf: &[u8]) -> String {
319     let vec: Vec<String> = buf.iter().map(|b| format!("{:02x}", b)).collect();
320 
321     vec.join("")
322 }
323