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: {} URL", cmd);
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 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 socket = std::net::UdpSocket::bind(bind_addr).unwrap();
72
73 let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
74 poll.register(
75 &socket,
76 mio::Token(0),
77 mio::Ready::readable(),
78 mio::PollOpt::edge(),
79 )
80 .unwrap();
81
82 // Create the configuration for the QUIC connection.
83 let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
84
85 // *CAUTION*: this should not be set to `false` in production!!!
86 config.verify_peer(false);
87
88 config
89 .set_application_protos(
90 b"\x0ahq-interop\x05hq-29\x05hq-28\x05hq-27\x08http/0.9",
91 )
92 .unwrap();
93
94 config.set_max_idle_timeout(5000);
95 config.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE);
96 config.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE);
97 config.set_initial_max_data(10_000_000);
98 config.set_initial_max_stream_data_bidi_local(1_000_000);
99 config.set_initial_max_stream_data_bidi_remote(1_000_000);
100 config.set_initial_max_streams_bidi(100);
101 config.set_initial_max_streams_uni(100);
102 config.set_disable_active_migration(true);
103
104 // Generate a random source connection ID for the connection.
105 let mut scid = [0; quiche::MAX_CONN_ID_LEN];
106 SystemRandom::new().fill(&mut scid[..]).unwrap();
107
108 let scid = quiche::ConnectionId::from_ref(&scid);
109
110 // Create a QUIC connection and initiate handshake.
111 let mut conn =
112 quiche::connect(url.domain(), &scid, peer_addr, &mut config).unwrap();
113
114 info!(
115 "connecting to {:} from {:} with scid {}",
116 peer_addr,
117 socket.local_addr().unwrap(),
118 hex_dump(&scid)
119 );
120
121 let (write, send_info) = conn.send(&mut out).expect("initial send failed");
122
123 while let Err(e) = socket.send_to(&out[..write], &send_info.to) {
124 if e.kind() == std::io::ErrorKind::WouldBlock {
125 debug!("send() would block");
126 continue;
127 }
128
129 panic!("send() failed: {:?}", e);
130 }
131
132 debug!("written {}", write);
133
134 let req_start = std::time::Instant::now();
135
136 let mut req_sent = false;
137
138 loop {
139 poll.poll(&mut events, conn.timeout()).unwrap();
140
141 // Read incoming UDP packets from the socket and feed them to quiche,
142 // until there are no more packets to read.
143 'read: loop {
144 // If the event loop reported no events, it means that the timeout
145 // has expired, so handle it without attempting to read packets. We
146 // will then proceed with the send loop.
147 if events.is_empty() {
148 debug!("timed out");
149
150 conn.on_timeout();
151 break 'read;
152 }
153
154 let (len, from) = match socket.recv_from(&mut buf) {
155 Ok(v) => v,
156
157 Err(e) => {
158 // There are no more UDP packets to read, so end the read
159 // loop.
160 if e.kind() == std::io::ErrorKind::WouldBlock {
161 debug!("recv() would block");
162 break 'read;
163 }
164
165 panic!("recv() failed: {:?}", e);
166 },
167 };
168
169 debug!("got {} bytes", len);
170
171 let recv_info = quiche::RecvInfo { from };
172
173 // Process potentially coalesced packets.
174 let read = match conn.recv(&mut buf[..len], recv_info) {
175 Ok(v) => v,
176
177 Err(e) => {
178 error!("recv failed: {:?}", e);
179 continue 'read;
180 },
181 };
182
183 debug!("processed {} bytes", read);
184 }
185
186 debug!("done reading");
187
188 if conn.is_closed() {
189 info!("connection closed, {:?}", conn.stats());
190 break;
191 }
192
193 // Send an HTTP request as soon as the connection is established.
194 if conn.is_established() && !req_sent {
195 info!("sending HTTP request for {}", url.path());
196
197 let req = format!("GET {}\r\n", url.path());
198 conn.stream_send(HTTP_REQ_STREAM_ID, req.as_bytes(), true)
199 .unwrap();
200
201 req_sent = true;
202 }
203
204 // Process all readable streams.
205 for s in conn.readable() {
206 while let Ok((read, fin)) = conn.stream_recv(s, &mut buf) {
207 debug!("received {} bytes", read);
208
209 let stream_buf = &buf[..read];
210
211 debug!(
212 "stream {} has {} bytes (fin? {})",
213 s,
214 stream_buf.len(),
215 fin
216 );
217
218 print!("{}", unsafe {
219 std::str::from_utf8_unchecked(&stream_buf)
220 });
221
222 // The server reported that it has no more data to send, which
223 // we got the full response. Close the connection.
224 if s == HTTP_REQ_STREAM_ID && fin {
225 info!(
226 "response received in {:?}, closing...",
227 req_start.elapsed()
228 );
229
230 conn.close(true, 0x00, b"kthxbye").unwrap();
231 }
232 }
233 }
234
235 // Generate outgoing QUIC packets and send them on the UDP socket, until
236 // quiche reports that there are no more packets to be sent.
237 loop {
238 let (write, send_info) = match conn.send(&mut out) {
239 Ok(v) => v,
240
241 Err(quiche::Error::Done) => {
242 debug!("done writing");
243 break;
244 },
245
246 Err(e) => {
247 error!("send failed: {:?}", e);
248
249 conn.close(false, 0x1, b"fail").ok();
250 break;
251 },
252 };
253
254 if let Err(e) = socket.send_to(&out[..write], &send_info.to) {
255 if e.kind() == std::io::ErrorKind::WouldBlock {
256 debug!("send() would block");
257 break;
258 }
259
260 panic!("send() failed: {:?}", e);
261 }
262
263 debug!("written {}", write);
264 }
265
266 if conn.is_closed() {
267 info!("connection closed, {:?}", conn.stats());
268 break;
269 }
270 }
271 }
272
hex_dump(buf: &[u8]) -> String273 fn hex_dump(buf: &[u8]) -> String {
274 let vec: Vec<String> = buf.iter().map(|b| format!("{:02x}", b)).collect();
275
276 vec.join("")
277 }
278