examples: remove command-line parsing support

Now that we have proper apps we don't need the examples to be
configurable. This removes docopt as dependency of the examples which
should hopefully speed up builds a bit.
diff --git a/Cargo.toml b/Cargo.toml
index 94a67af..ef56963 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -69,7 +69,6 @@
 [dev-dependencies]
 mio = "0.6"
 url = "1"
-docopt = "1"
 env_logger = "0.6"
 
 [profile.bench]
diff --git a/examples/client.rs b/examples/client.rs
index 2972be8..b27a0c6 100644
--- a/examples/client.rs
+++ b/examples/client.rs
@@ -29,28 +29,12 @@
 
 use std::net::ToSocketAddrs;
 
-use std::io::prelude::*;
-
 use ring::rand::*;
 
 const MAX_DATAGRAM_SIZE: usize = 1350;
 
 const HTTP_REQ_STREAM_ID: u64 = 4;
 
-const USAGE: &str = "Usage:
-  client [options] URL
-  client -h | --help
-
-Options:
-  --max-data BYTES         Connection-wide flow control limit [default: 10000000].
-  --max-stream-data BYTES  Per-stream flow control limit [default: 1000000].
-  --wire-version VERSION   The version number to send to the server [default: babababa].
-  --dump-packets PATH      Dump the incoming packets as files in the given directory.
-  --no-verify              Don't verify server's certificate.
-  --cc-algorithm NAME      Set client congestion control algorithm [default: reno].
-  -h --help                Show this screen.
-";
-
 fn main() {
     let mut buf = [0; 65535];
     let mut out = [0; MAX_DATAGRAM_SIZE];
@@ -59,26 +43,17 @@
         .default_format_timestamp_nanos(true)
         .init();
 
-    let args = docopt::Docopt::new(USAGE)
-        .and_then(|dopt| dopt.parse())
-        .unwrap_or_else(|e| e.exit());
+    let mut args = std::env::args();
 
-    let max_data = args.get_str("--max-data");
-    let max_data = u64::from_str_radix(max_data, 10).unwrap();
+    let cmd = &args.next().unwrap();
 
-    let max_stream_data = args.get_str("--max-stream-data");
-    let max_stream_data = u64::from_str_radix(max_stream_data, 10).unwrap();
+    if args.len() != 1 {
+        println!("Usage: {} URL", cmd);
+        println!("\nSee tools/apps/ for more complete implementations.");
+        return;
+    }
 
-    let version = args.get_str("--wire-version");
-    let version = u32::from_str_radix(version, 16).unwrap();
-
-    let dump_path = if args.get_str("--dump-packets") != "" {
-        Some(args.get_str("--dump-packets"))
-    } else {
-        None
-    };
-
-    let url = url::Url::parse(args.get_str("URL")).unwrap();
+    let url = url::Url::parse(&args.next().unwrap()).unwrap();
 
     // Setup the event loop.
     let poll = mio::Poll::new().unwrap();
@@ -110,9 +85,10 @@
     .unwrap();
 
     // Create the configuration for the QUIC connection.
-    let mut config = quiche::Config::new(version).unwrap();
+    let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
 
-    config.verify_peer(true);
+    // *CAUTION*: this should not be set to `false` in production!!!
+    config.verify_peer(false);
 
     config
         .set_application_protos(b"\x05hq-25\x05hq-24\x05hq-23\x08http/0.9")
@@ -120,25 +96,13 @@
 
     config.set_max_idle_timeout(5000);
     config.set_max_packet_size(MAX_DATAGRAM_SIZE as u64);
-    config.set_initial_max_data(max_data);
-    config.set_initial_max_stream_data_bidi_local(max_stream_data);
-    config.set_initial_max_stream_data_bidi_remote(max_stream_data);
+    config.set_initial_max_data(10_000_000);
+    config.set_initial_max_stream_data_bidi_local(1_000_000);
+    config.set_initial_max_stream_data_bidi_remote(1_000_000);
     config.set_initial_max_streams_bidi(100);
     config.set_initial_max_streams_uni(100);
     config.set_disable_active_migration(true);
 
-    if args.get_bool("--no-verify") {
-        config.verify_peer(false);
-    }
-
-    if std::env::var_os("SSLKEYLOGFILE").is_some() {
-        config.log_keys();
-    }
-
-    config
-        .set_cc_algorithm_name(args.get_str("--cc-algorithm"))
-        .unwrap();
-
     // Generate a random source connection ID for the connection.
     let mut scid = [0; quiche::MAX_CONN_ID_LEN];
     SystemRandom::new().fill(&mut scid[..]).unwrap();
@@ -170,8 +134,6 @@
 
     let mut req_sent = false;
 
-    let mut pkt_count = 0;
-
     loop {
         poll.poll(&mut events, conn.timeout()).unwrap();
 
@@ -205,17 +167,6 @@
 
             debug!("got {} bytes", len);
 
-            if let Some(target_path) = dump_path {
-                let path = format!("{}/{}.pkt", target_path, pkt_count);
-
-                if let Ok(f) = std::fs::File::create(&path) {
-                    let mut f = std::io::BufWriter::new(f);
-                    f.write_all(&buf[..len]).ok();
-                }
-            }
-
-            pkt_count += 1;
-
             // Process potentially coalesced packets.
             let read = match conn.recv(&mut buf[..len]) {
                 Ok(v) => v,
diff --git a/examples/http3-client.rs b/examples/http3-client.rs
index 81aca6d..b9c5f5d 100644
--- a/examples/http3-client.rs
+++ b/examples/http3-client.rs
@@ -33,24 +33,6 @@
 
 const MAX_DATAGRAM_SIZE: usize = 1350;
 
-const USAGE: &str = "Usage:
-  http3-client [options] URL
-  http3-client -h | --help
-
-Options:
-  --method METHOD          Use the given HTTP request method [default: GET].
-  --body FILE              Send the given file as request body.
-  --max-data BYTES         Connection-wide flow control limit [default: 10000000].
-  --max-stream-data BYTES  Per-stream flow control limit [default: 1000000].
-  --wire-version VERSION   The version number to send to the server [default: babababa].
-  --no-verify              Don't verify server's certificate.
-  --no-grease              Don't send GREASE.
-  --cc-algorithm NAME      Set client congestion control algorithm [default: reno].
-  -H --header HEADER ...   Add a request header.
-  -n --requests REQUESTS   Send the given number of identical requests [default: 1].
-  -h --help                Show this screen.
-";
-
 fn main() {
     let mut buf = [0; 65535];
     let mut out = [0; MAX_DATAGRAM_SIZE];
@@ -59,28 +41,17 @@
         .default_format_timestamp_nanos(true)
         .init();
 
-    let args = docopt::Docopt::new(USAGE)
-        .and_then(|dopt| dopt.parse())
-        .unwrap_or_else(|e| e.exit());
+    let mut args = std::env::args();
 
-    let max_data = args.get_str("--max-data");
-    let max_data = u64::from_str_radix(max_data, 10).unwrap();
+    let cmd = &args.next().unwrap();
 
-    let max_stream_data = args.get_str("--max-stream-data");
-    let max_stream_data = u64::from_str_radix(max_stream_data, 10).unwrap();
+    if args.len() != 1 {
+        println!("Usage: {} URL", cmd);
+        println!("\nSee tools/apps/ for more complete implementations.");
+        return;
+    }
 
-    let version = args.get_str("--wire-version");
-    let version = u32::from_str_radix(version, 16).unwrap();
-
-    let url = url::Url::parse(args.get_str("URL")).unwrap();
-
-    // Request headers (can be multiple).
-    let req_headers = args.get_vec("--header");
-
-    let reqs_count = args.get_str("--requests");
-    let reqs_count = u64::from_str_radix(reqs_count, 10).unwrap();
-
-    let mut reqs_complete = 0;
+    let url = url::Url::parse(&args.next().unwrap()).unwrap();
 
     // Setup the event loop.
     let poll = mio::Poll::new().unwrap();
@@ -112,9 +83,10 @@
     .unwrap();
 
     // Create the configuration for the QUIC connection.
-    let mut config = quiche::Config::new(version).unwrap();
+    let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
 
-    config.verify_peer(true);
+    // *CAUTION*: this should not be set to `false` in production!!!
+    config.verify_peer(false);
 
     config
         .set_application_protos(quiche::h3::APPLICATION_PROTOCOL)
@@ -122,32 +94,16 @@
 
     config.set_max_idle_timeout(5000);
     config.set_max_packet_size(MAX_DATAGRAM_SIZE as u64);
-    config.set_initial_max_data(max_data);
-    config.set_initial_max_stream_data_bidi_local(max_stream_data);
-    config.set_initial_max_stream_data_bidi_remote(max_stream_data);
-    config.set_initial_max_stream_data_uni(max_stream_data);
+    config.set_initial_max_data(10_000_000);
+    config.set_initial_max_stream_data_bidi_local(1_000_000);
+    config.set_initial_max_stream_data_bidi_remote(1_000_000);
+    config.set_initial_max_stream_data_uni(1_000_000);
     config.set_initial_max_streams_bidi(100);
     config.set_initial_max_streams_uni(100);
     config.set_disable_active_migration(true);
 
     let mut http3_conn = None;
 
-    if args.get_bool("--no-verify") {
-        config.verify_peer(false);
-    }
-
-    if args.get_bool("--no-grease") {
-        config.grease(false);
-    }
-
-    if std::env::var_os("SSLKEYLOGFILE").is_some() {
-        config.log_keys();
-    }
-
-    config
-        .set_cc_algorithm_name(args.get_str("--cc-algorithm"))
-        .unwrap();
-
     // Generate a random source connection ID for the connection.
     let mut scid = [0; quiche::MAX_CONN_ID_LEN];
     SystemRandom::new().fill(&mut scid[..]).unwrap();
@@ -185,41 +141,18 @@
         path.push_str(query);
     }
 
-    let mut req = vec![
-        quiche::h3::Header::new(":method", args.get_str("--method")),
+    let req = vec![
+        quiche::h3::Header::new(":method", "GET"),
         quiche::h3::Header::new(":scheme", url.scheme()),
         quiche::h3::Header::new(":authority", url.host_str().unwrap()),
         quiche::h3::Header::new(":path", &path),
         quiche::h3::Header::new("user-agent", "quiche"),
     ];
 
-    // Add custom headers to the request.
-    for header in &req_headers {
-        let header_split: Vec<&str> = header.splitn(2, ": ").collect();
-        if header_split.len() != 2 {
-            panic!("malformed header provided - \"{}\"", header);
-        }
-
-        req.push(quiche::h3::Header::new(header_split[0], header_split[1]));
-    }
-
-    let body = if args.get_bool("--body") {
-        std::fs::read(args.get_str("--body")).ok()
-    } else {
-        None
-    };
-
-    if body.is_some() {
-        req.push(quiche::h3::Header::new(
-            "content-length",
-            &body.as_ref().unwrap().len().to_string(),
-        ));
-    }
-
-    let mut reqs_sent = 0;
-
     let req_start = std::time::Instant::now();
 
+    let mut req_sent = false;
+
     loop {
         poll.poll(&mut events, conn.timeout()).unwrap();
 
@@ -274,12 +207,6 @@
 
         if conn.is_closed() {
             info!("connection closed, {:?}", conn.stats());
-
-            if reqs_complete != reqs_count {
-                error!("connection timed out after {:?} and only completed {}/{} requests",
-                       req_start.elapsed(), reqs_complete, reqs_count);
-            }
-
             break;
         }
 
@@ -294,39 +221,13 @@
         // Send HTTP requests once the QUIC connection is established, and until
         // all requests have been sent.
         if let Some(h3_conn) = &mut http3_conn {
-            let mut reqs_done = 0;
-
-            for _ in reqs_sent..reqs_count {
+            if !req_sent {
                 info!("sending HTTP request {:?}", req);
 
-                let s =
-                    match h3_conn.send_request(&mut conn, &req, body.is_none()) {
-                        Ok(v) => v,
+                h3_conn.send_request(&mut conn, &req, true).unwrap();
 
-                        Err(quiche::h3::Error::TransportError(
-                            quiche::Error::StreamLimit,
-                        )) => {
-                            debug!("not enough stream credits, retry later...");
-                            break;
-                        },
-
-                        Err(e) => {
-                            error!("failed to send request {:?}", e);
-                            break;
-                        },
-                    };
-
-                if let Some(body) = &body {
-                    if let Err(e) = h3_conn.send_body(&mut conn, s, body, true) {
-                        error!("failed to send request body {:?}", e);
-                        break;
-                    }
-                }
-
-                reqs_done += 1;
+                req_sent = true;
             }
-
-            reqs_sent += reqs_done;
         }
 
         if let Some(http3_conn) = &mut http3_conn {
@@ -356,30 +257,12 @@
                     },
 
                     Ok((_stream_id, quiche::h3::Event::Finished)) => {
-                        reqs_complete += 1;
-
-                        debug!(
-                            "{}/{} responses received",
-                            reqs_complete, reqs_count
+                        info!(
+                            "response received in {:?}, closing...",
+                            req_start.elapsed()
                         );
 
-                        if reqs_complete == reqs_count {
-                            info!(
-                                "{}/{} response(s) received in {:?}, closing...",
-                                reqs_complete,
-                                reqs_count,
-                                req_start.elapsed()
-                            );
-
-                            match conn.close(true, 0x00, b"kthxbye") {
-                                // Already closed.
-                                Ok(_) | Err(quiche::Error::Done) => (),
-
-                                Err(e) => panic!("error closing conn: {:?}", e),
-                            }
-
-                            break;
-                        }
+                        conn.close(true, 0x00, b"kthxbye").unwrap();
                     },
 
                     Err(quiche::h3::Error::Done) => {
@@ -428,12 +311,6 @@
 
         if conn.is_closed() {
             info!("connection closed, {:?}", conn.stats());
-
-            if reqs_complete != reqs_count {
-                error!("connection timed out after {:?} and only completed {}/{} requests",
-                       req_start.elapsed(), reqs_complete, reqs_count);
-            }
-
             break;
         }
     }
diff --git a/examples/http3-server.rs b/examples/http3-server.rs
index bcf52ca..f6cbc93 100644
--- a/examples/http3-server.rs
+++ b/examples/http3-server.rs
@@ -35,27 +35,6 @@
 
 const MAX_DATAGRAM_SIZE: usize = 1350;
 
-const USAGE: &str = "Usage:
-  http3-server [options]
-  http3-server -h | --help
-
-Options:
-  --listen <addr>             Listen on the given IP:port [default: 127.0.0.1:4433]
-  --cert <file>               TLS certificate path [default: examples/cert.crt]
-  --key <file>                TLS certificate key path [default: examples/cert.key]
-  --root <dir>                Root directory [default: examples/root/]
-  --name <str>                Name of the server [default: quic.tech]
-  --max-data BYTES            Connection-wide flow control limit [default: 10000000].
-  --max-stream-data BYTES     Per-stream flow control limit [default: 1000000].
-  --max-streams-bidi STREAMS  Number of allowed concurrent streams [default: 100].
-  --max-streams-uni STREAMS   Number of allowed concurrent streams [default: 100].
-  --early-data                Enables receiving early data.
-  --no-retry                  Disable stateless retry.
-  --no-grease                 Don't send GREASE.
-  --cc-algorithm NAME         Set server congestion control algorithm [default: reno].
-  -h --help                   Show this screen.
-";
-
 struct PartialResponse {
     body: Vec<u8>,
 
@@ -80,28 +59,22 @@
         .default_format_timestamp_nanos(true)
         .init();
 
-    let args = docopt::Docopt::new(USAGE)
-        .and_then(|dopt| dopt.parse())
-        .unwrap_or_else(|e| e.exit());
+    let mut args = std::env::args();
 
-    let max_data = args.get_str("--max-data");
-    let max_data = u64::from_str_radix(max_data, 10).unwrap();
+    let cmd = &args.next().unwrap();
 
-    let max_stream_data = args.get_str("--max-stream-data");
-    let max_stream_data = u64::from_str_radix(max_stream_data, 10).unwrap();
-
-    let max_streams_bidi = args.get_str("--max-streams-bidi");
-    let max_streams_bidi = u64::from_str_radix(max_streams_bidi, 10).unwrap();
-
-    let max_streams_uni = args.get_str("--max-streams-uni");
-    let max_streams_uni = u64::from_str_radix(max_streams_uni, 10).unwrap();
+    if args.len() != 0 {
+        println!("Usage: {}", cmd);
+        println!("\nSee tools/apps/ for more complete implementations.");
+        return;
+    }
 
     // Setup the event loop.
     let poll = mio::Poll::new().unwrap();
     let mut events = mio::Events::with_capacity(1024);
 
     // Create the UDP listening socket, and register it with the event loop.
-    let socket = net::UdpSocket::bind(args.get_str("--listen")).unwrap();
+    let socket = net::UdpSocket::bind("127.0.0.1:4433").unwrap();
 
     let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
     poll.register(
@@ -116,10 +89,10 @@
     let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
 
     config
-        .load_cert_chain_from_pem_file(args.get_str("--cert"))
+        .load_cert_chain_from_pem_file("examples/cert.crt")
         .unwrap();
     config
-        .load_priv_key_from_pem_file(args.get_str("--key"))
+        .load_priv_key_from_pem_file("examples/cert.key")
         .unwrap();
 
     config
@@ -128,29 +101,14 @@
 
     config.set_max_idle_timeout(5000);
     config.set_max_packet_size(MAX_DATAGRAM_SIZE as u64);
-    config.set_initial_max_data(max_data);
-    config.set_initial_max_stream_data_bidi_local(max_stream_data);
-    config.set_initial_max_stream_data_bidi_remote(max_stream_data);
-    config.set_initial_max_stream_data_uni(max_stream_data);
-    config.set_initial_max_streams_bidi(max_streams_bidi);
-    config.set_initial_max_streams_uni(max_streams_uni);
+    config.set_initial_max_data(10_000_000);
+    config.set_initial_max_stream_data_bidi_local(1_000_000);
+    config.set_initial_max_stream_data_bidi_remote(1_000_000);
+    config.set_initial_max_stream_data_uni(1_000_000);
+    config.set_initial_max_streams_bidi(100);
+    config.set_initial_max_streams_uni(100);
     config.set_disable_active_migration(true);
-
-    if args.get_bool("--early-data") {
-        config.enable_early_data();
-    }
-
-    if args.get_bool("--no-grease") {
-        config.grease(false);
-    }
-
-    if std::env::var_os("SSLKEYLOGFILE").is_some() {
-        config.log_keys();
-    }
-
-    config
-        .set_cc_algorithm_name(args.get_str("--cc-algorithm"))
-        .unwrap();
+    config.enable_early_data();
 
     let h3_config = quiche::h3::Config::new().unwrap();
 
@@ -253,54 +211,50 @@
                 let mut scid = [0; quiche::MAX_CONN_ID_LEN];
                 scid.copy_from_slice(&conn_id);
 
-                let mut odcid = None;
+                // Token is always present in Initial packets.
+                let token = hdr.token.as_ref().unwrap();
 
-                if !args.get_bool("--no-retry") {
-                    // Token is always present in Initial packets.
-                    let token = hdr.token.as_ref().unwrap();
+                // Do stateless retry if the client didn't send a token.
+                if token.is_empty() {
+                    warn!("Doing stateless retry");
 
-                    // Do stateless retry if the client didn't send a token.
-                    if token.is_empty() {
-                        warn!("Doing stateless retry");
+                    let new_token = mint_token(&hdr, &src);
 
-                        let new_token = mint_token(&hdr, &src);
+                    let len = quiche::retry(
+                        &hdr.scid, &hdr.dcid, &scid, &new_token, &mut out,
+                    )
+                    .unwrap();
+                    let out = &out[..len];
 
-                        let len = quiche::retry(
-                            &hdr.scid, &hdr.dcid, &scid, &new_token, &mut out,
-                        )
-                        .unwrap();
-                        let out = &out[..len];
-
-                        if let Err(e) = socket.send_to(out, &src) {
-                            if e.kind() == std::io::ErrorKind::WouldBlock {
-                                debug!("send() would block");
-                                break;
-                            }
-
-                            panic!("send() failed: {:?}", e);
+                    if let Err(e) = socket.send_to(out, &src) {
+                        if e.kind() == std::io::ErrorKind::WouldBlock {
+                            debug!("send() would block");
+                            break;
                         }
-                        continue;
+
+                        panic!("send() failed: {:?}", e);
                     }
-
-                    odcid = validate_token(&src, token);
-
-                    // The token was not valid, meaning the retry failed, so
-                    // drop the packet.
-                    if odcid == None {
-                        error!("Invalid address validation token");
-                        continue;
-                    }
-
-                    if scid.len() != hdr.dcid.len() {
-                        error!("Invalid destination connection ID");
-                        continue;
-                    }
-
-                    // Reuse the source connection ID we sent in the Retry
-                    // packet, instead of changing it again.
-                    scid.copy_from_slice(&hdr.dcid);
+                    continue;
                 }
 
+                let odcid = validate_token(&src, token);
+
+                // The token was not valid, meaning the retry failed, so
+                // drop the packet.
+                if odcid == None {
+                    error!("Invalid address validation token");
+                    continue;
+                }
+
+                if scid.len() != hdr.dcid.len() {
+                    error!("Invalid destination connection ID");
+                    continue;
+                }
+
+                // Reuse the source connection ID we sent in the Retry
+                // packet, instead of changing it again.
+                scid.copy_from_slice(&hdr.dcid);
+
                 debug!(
                     "New connection: dcid={} scid={}",
                     hex_dump(&hdr.dcid),
@@ -388,7 +342,7 @@
                                 client,
                                 stream_id,
                                 &list,
-                                args.get_str("--root"),
+                                "examples/root",
                             );
                         },
 
diff --git a/examples/qpack-decode.rs b/examples/qpack-decode.rs
index 6a2714b..9eef8ea 100644
--- a/examples/qpack-decode.rs
+++ b/examples/qpack-decode.rs
@@ -33,24 +33,21 @@
 
 use quiche::h3::qpack;
 
-const USAGE: &str = "Usage:
-  qpack-decode [options] FILE
-  qpack-decode -h | --help
-
-Options:
-  -h --help  Show this screen.
-";
-
 fn main() {
     env_logger::init();
 
-    let args = docopt::Docopt::new(USAGE)
-        .and_then(|dopt| dopt.parse())
-        .unwrap_or_else(|e| e.exit());
-
     // TODO: parse params from file name.
 
-    let mut file = File::open(args.get_str("FILE")).unwrap();
+    let mut args = std::env::args();
+
+    let cmd = &args.next().unwrap();
+
+    if args.len() != 1 {
+        println!("Usage: {} FILE", cmd);
+        return;
+    }
+
+    let mut file = File::open(&args.next().unwrap()).unwrap();
 
     let mut dec = qpack::Decoder::new();
 
diff --git a/examples/qpack-encode.rs b/examples/qpack-encode.rs
index 4b1e50d..57bb536 100644
--- a/examples/qpack-encode.rs
+++ b/examples/qpack-encode.rs
@@ -34,22 +34,19 @@
 
 use quiche::h3;
 
-const USAGE: &str = "Usage:
-  qpack-encode [options] FILE
-  qpack-encode -h | --help
-
-Options:
-  -h --help  Show this screen.
-";
-
 fn main() {
     env_logger::init();
 
-    let args = docopt::Docopt::new(USAGE)
-        .and_then(|dopt| dopt.parse())
-        .unwrap_or_else(|e| e.exit());
+    let mut args = std::env::args();
 
-    let file = File::open(args.get_str("FILE")).unwrap();
+    let cmd = &args.next().unwrap();
+
+    if args.len() != 1 {
+        println!("Usage: {} FILE", cmd);
+        return;
+    }
+
+    let file = File::open(&args.next().unwrap()).unwrap();
     let file = BufReader::new(&file);
 
     let mut enc = h3::qpack::Encoder::new();
diff --git a/examples/server.rs b/examples/server.rs
index 668684d..e07297d 100644
--- a/examples/server.rs
+++ b/examples/server.rs
@@ -29,35 +29,12 @@
 
 use std::net;
 
-use std::io::prelude::*;
-
 use std::collections::HashMap;
 
 use ring::rand::*;
 
 const MAX_DATAGRAM_SIZE: usize = 1350;
 
-const USAGE: &str = "Usage:
-  server [options]
-  server -h | --help
-
-Options:
-  --listen <addr>             Listen on the given IP:port [default: 127.0.0.1:4433]
-  --cert <file>               TLS certificate path [default: examples/cert.crt]
-  --key <file>                TLS certificate key path [default: examples/cert.key]
-  --root <dir>                Root directory [default: examples/root/]
-  --name <str>                Name of the server [default: quic.tech]
-  --max-data BYTES            Connection-wide flow control limit [default: 10000000].
-  --max-stream-data BYTES     Per-stream flow control limit [default: 1000000].
-  --max-streams-bidi STREAMS  Number of allowed concurrent streams [default: 100].
-  --max-streams-uni STREAMS   Number of allowed concurrent streams [default: 100].
-  --dump-packets PATH         Dump the incoming packets as files in the given directory.
-  --early-data                Enables receiving early data.
-  --no-retry                  Disable stateless retry.
-  --cc-algorithm NAME         Set server congestion control algorithm [default: reno].
-  -h --help                   Show this screen.
-";
-
 struct PartialResponse {
     body: Vec<u8>,
 
@@ -80,34 +57,22 @@
         .default_format_timestamp_nanos(true)
         .init();
 
-    let args = docopt::Docopt::new(USAGE)
-        .and_then(|dopt| dopt.parse())
-        .unwrap_or_else(|e| e.exit());
+    let mut args = std::env::args();
 
-    let max_data = args.get_str("--max-data");
-    let max_data = u64::from_str_radix(max_data, 10).unwrap();
+    let cmd = &args.next().unwrap();
 
-    let max_stream_data = args.get_str("--max-stream-data");
-    let max_stream_data = u64::from_str_radix(max_stream_data, 10).unwrap();
-
-    let max_streams_bidi = args.get_str("--max-streams-bidi");
-    let max_streams_bidi = u64::from_str_radix(max_streams_bidi, 10).unwrap();
-
-    let max_streams_uni = args.get_str("--max-streams-uni");
-    let max_streams_uni = u64::from_str_radix(max_streams_uni, 10).unwrap();
-
-    let dump_path = if args.get_str("--dump-packets") != "" {
-        Some(args.get_str("--dump-packets"))
-    } else {
-        None
-    };
+    if args.len() != 0 {
+        println!("Usage: {}", cmd);
+        println!("\nSee tools/apps/ for more complete implementations.");
+        return;
+    }
 
     // Setup the event loop.
     let poll = mio::Poll::new().unwrap();
     let mut events = mio::Events::with_capacity(1024);
 
     // Create the UDP listening socket, and register it with the event loop.
-    let socket = net::UdpSocket::bind(args.get_str("--listen")).unwrap();
+    let socket = net::UdpSocket::bind("127.0.0.1:4433").unwrap();
 
     let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
     poll.register(
@@ -122,10 +87,10 @@
     let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
 
     config
-        .load_cert_chain_from_pem_file(args.get_str("--cert"))
+        .load_cert_chain_from_pem_file("examples/cert.crt")
         .unwrap();
     config
-        .load_priv_key_from_pem_file(args.get_str("--key"))
+        .load_priv_key_from_pem_file("examples/cert.key")
         .unwrap();
 
     config
@@ -134,25 +99,14 @@
 
     config.set_max_idle_timeout(5000);
     config.set_max_packet_size(MAX_DATAGRAM_SIZE as u64);
-    config.set_initial_max_data(max_data);
-    config.set_initial_max_stream_data_bidi_local(max_stream_data);
-    config.set_initial_max_stream_data_bidi_remote(max_stream_data);
-    config.set_initial_max_stream_data_uni(max_stream_data);
-    config.set_initial_max_streams_bidi(max_streams_bidi);
-    config.set_initial_max_streams_uni(max_streams_uni);
+    config.set_initial_max_data(10_000_000);
+    config.set_initial_max_stream_data_bidi_local(1_000_000);
+    config.set_initial_max_stream_data_bidi_remote(1_000_000);
+    config.set_initial_max_stream_data_uni(1_000_000);
+    config.set_initial_max_streams_bidi(100);
+    config.set_initial_max_streams_uni(100);
     config.set_disable_active_migration(true);
-
-    if args.get_bool("--early-data") {
-        config.enable_early_data();
-    }
-
-    if std::env::var_os("SSLKEYLOGFILE").is_some() {
-        config.log_keys();
-    }
-
-    config
-        .set_cc_algorithm_name(args.get_str("--cc-algorithm"))
-        .unwrap();
+    config.enable_early_data();
 
     let rng = SystemRandom::new();
     let conn_id_seed =
@@ -160,8 +114,6 @@
 
     let mut clients = ClientMap::new();
 
-    let mut pkt_count = 0;
-
     loop {
         // Find the shorter timeout from all the active connections.
         //
@@ -204,17 +156,6 @@
 
             let pkt_buf = &mut buf[..len];
 
-            if let Some(target_path) = dump_path {
-                let path = format!("{}/{}.pkt", target_path, pkt_count);
-
-                if let Ok(f) = std::fs::File::create(&path) {
-                    let mut f = std::io::BufWriter::new(f);
-                    f.write_all(pkt_buf).ok();
-                }
-            }
-
-            pkt_count += 1;
-
             // Parse the QUIC packet's header.
             let hdr = match quiche::Header::from_slice(
                 pkt_buf,
@@ -266,55 +207,51 @@
                 let mut scid = [0; quiche::MAX_CONN_ID_LEN];
                 scid.copy_from_slice(&conn_id);
 
-                let mut odcid = None;
+                // Token is always present in Initial packets.
+                let token = hdr.token.as_ref().unwrap();
 
-                if !args.get_bool("--no-retry") {
-                    // Token is always present in Initial packets.
-                    let token = hdr.token.as_ref().unwrap();
+                // Do stateless retry if the client didn't send a token.
+                if token.is_empty() {
+                    warn!("Doing stateless retry");
 
-                    // Do stateless retry if the client didn't send a token.
-                    if token.is_empty() {
-                        warn!("Doing stateless retry");
+                    let new_token = mint_token(&hdr, &src);
 
-                        let new_token = mint_token(&hdr, &src);
+                    let len = quiche::retry(
+                        &hdr.scid, &hdr.dcid, &scid, &new_token, &mut out,
+                    )
+                    .unwrap();
 
-                        let len = quiche::retry(
-                            &hdr.scid, &hdr.dcid, &scid, &new_token, &mut out,
-                        )
-                        .unwrap();
+                    let out = &out[..len];
 
-                        let out = &out[..len];
-
-                        if let Err(e) = socket.send_to(out, &src) {
-                            if e.kind() == std::io::ErrorKind::WouldBlock {
-                                debug!("send() would block");
-                                break;
-                            }
-
-                            panic!("send() failed: {:?}", e);
+                    if let Err(e) = socket.send_to(out, &src) {
+                        if e.kind() == std::io::ErrorKind::WouldBlock {
+                            debug!("send() would block");
+                            break;
                         }
-                        continue;
+
+                        panic!("send() failed: {:?}", e);
                     }
-
-                    odcid = validate_token(&src, token);
-
-                    // The token was not valid, meaning the retry failed, so
-                    // drop the packet.
-                    if odcid == None {
-                        error!("Invalid address validation token");
-                        continue;
-                    }
-
-                    if scid.len() != hdr.dcid.len() {
-                        error!("Invalid destination connection ID");
-                        continue;
-                    }
-
-                    // Reuse the source connection ID we sent in the Retry
-                    // packet, instead of changing it again.
-                    scid.copy_from_slice(&hdr.dcid);
+                    continue;
                 }
 
+                let odcid = validate_token(&src, token);
+
+                // The token was not valid, meaning the retry failed, so
+                // drop the packet.
+                if odcid == None {
+                    error!("Invalid address validation token");
+                    continue;
+                }
+
+                if scid.len() != hdr.dcid.len() {
+                    error!("Invalid destination connection ID");
+                    continue;
+                }
+
+                // Reuse the source connection ID we sent in the Retry
+                // packet, instead of changing it again.
+                scid.copy_from_slice(&hdr.dcid);
+
                 debug!(
                     "New connection: dcid={} scid={}",
                     hex_dump(&hdr.dcid),
@@ -383,12 +320,7 @@
                             fin
                         );
 
-                        handle_stream(
-                            client,
-                            s,
-                            stream_buf,
-                            args.get_str("--root"),
-                        );
+                        handle_stream(client, s, stream_buf, "examples/root");
                     }
                 }
             }