1 /*
2 * ngtcp2
3 *
4 * Copyright (c) 2017 ngtcp2 contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #include <chrono>
26 #include <cstdlib>
27 #include <cassert>
28 #include <cstring>
29 #include <iostream>
30 #include <algorithm>
31 #include <memory>
32 #include <fstream>
33 #include <iomanip>
34
35 #include <unistd.h>
36 #include <getopt.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netdb.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <sys/mman.h>
43 #include <netinet/udp.h>
44 #include <net/if.h>
45
46 #include <http-parser/http_parser.h>
47
48 #include "server.h"
49 #include "network.h"
50 #include "debug.h"
51 #include "util.h"
52 #include "shared.h"
53 #include "http.h"
54 #include "template.h"
55
56 using namespace ngtcp2;
57 using namespace std::literals;
58
59 #ifndef NGTCP2_ENABLE_UDP_GSO
60 # ifdef UDP_SEGMENT
61 # define NGTCP2_ENABLE_UDP_GSO 1
62 # else // !UDP_SEGMENT
63 # define NGTCP2_ENABLE_UDP_GSO 0
64 # endif // !UDP_SEGMENT
65 #endif // NGTCP2_ENABLE_UDP_GSO
66
67 namespace {
68 constexpr size_t NGTCP2_SV_SCIDLEN = 18;
69 } // namespace
70
71 namespace {
72 constexpr size_t MAX_DYNBUFLEN = 10 * 1024 * 1024;
73 } // namespace
74
75 namespace {
76 auto randgen = util::make_mt19937();
77 } // namespace
78
79 Config config{};
80
Stream(int64_t stream_id,Handler * handler)81 Stream::Stream(int64_t stream_id, Handler *handler)
82 : stream_id(stream_id),
83 handler(handler),
84 data(nullptr),
85 datalen(0),
86 dynresp(false),
87 dyndataleft(0),
88 dynbuflen(0) {}
89
90 namespace {
91 constexpr char NGTCP2_SERVER[] = "nghttp3/ngtcp2 server";
92 } // namespace
93
94 namespace {
make_status_body(unsigned int status_code)95 std::string make_status_body(unsigned int status_code) {
96 auto status_string = std::to_string(status_code);
97 auto reason_phrase = http::get_reason_phrase(status_code);
98
99 std::string body;
100 body = "<html><head><title>";
101 body += status_string;
102 body += ' ';
103 body += reason_phrase;
104 body += "</title></head><body><h1>";
105 body += status_string;
106 body += ' ';
107 body += reason_phrase;
108 body += "</h1><hr><address>";
109 body += NGTCP2_SERVER;
110 body += " at port ";
111 body += std::to_string(config.port);
112 body += "</address>";
113 body += "</body></html>";
114 return body;
115 }
116 } // namespace
117
118 struct Request {
119 std::string path;
120 struct {
121 int32_t urgency;
122 int inc;
123 } pri;
124 };
125
126 namespace {
request_path(const std::string_view & uri,bool is_connect)127 Request request_path(const std::string_view &uri, bool is_connect) {
128 http_parser_url u;
129 Request req;
130
131 req.pri.urgency = -1;
132 req.pri.inc = -1;
133
134 http_parser_url_init(&u);
135
136 if (auto rv = http_parser_parse_url(uri.data(), uri.size(), is_connect, &u);
137 rv != 0) {
138 return req;
139 }
140
141 if (u.field_set & (1 << UF_PATH)) {
142 req.path = std::string(uri.data() + u.field_data[UF_PATH].off,
143 u.field_data[UF_PATH].len);
144 if (req.path.find('%') != std::string::npos) {
145 req.path = util::percent_decode(std::begin(req.path), std::end(req.path));
146 }
147 if (!req.path.empty() && req.path.back() == '/') {
148 req.path += "index.html";
149 }
150 } else {
151 req.path = "/index.html";
152 }
153
154 req.path = util::normalize_path(req.path);
155 if (req.path == "/") {
156 req.path = "/index.html";
157 }
158
159 if (u.field_set & (1 << UF_QUERY)) {
160 static constexpr char urgency_prefix[] = "u=";
161 static constexpr char inc_prefix[] = "i=";
162 auto q = std::string(uri.data() + u.field_data[UF_QUERY].off,
163 u.field_data[UF_QUERY].len);
164 for (auto p = std::begin(q); p != std::end(q);) {
165 if (util::istarts_with(p, std::end(q), std::begin(urgency_prefix),
166 std::end(urgency_prefix) - 1)) {
167 auto urgency_start = p + sizeof(urgency_prefix) - 1;
168 auto urgency_end = std::find(urgency_start, std::end(q), '&');
169 if (urgency_start + 1 == urgency_end && '0' <= *urgency_start &&
170 *urgency_start <= '7') {
171 req.pri.urgency = *urgency_start - '0';
172 }
173 if (urgency_end == std::end(q)) {
174 break;
175 }
176 p = urgency_end + 1;
177 continue;
178 }
179 if (util::istarts_with(p, std::end(q), std::begin(inc_prefix),
180 std::end(inc_prefix) - 1)) {
181 auto inc_start = p + sizeof(inc_prefix) - 1;
182 auto inc_end = std::find(inc_start, std::end(q), '&');
183 if (inc_start + 1 == inc_end &&
184 (*inc_start == '0' || *inc_start == '1')) {
185 req.pri.inc = *inc_start - '0';
186 }
187 if (inc_end == std::end(q)) {
188 break;
189 }
190 p = inc_end + 1;
191 continue;
192 }
193
194 p = std::find(p, std::end(q), '&');
195 if (p == std::end(q)) {
196 break;
197 }
198 ++p;
199 }
200 }
201 return req;
202 }
203 } // namespace
204
205 enum FileEntryFlag {
206 FILE_ENTRY_TYPE_DIR = 0x1,
207 };
208
209 struct FileEntry {
210 uint64_t len;
211 void *map;
212 int fd;
213 uint8_t flags;
214 };
215
216 namespace {
217 std::unordered_map<std::string, FileEntry> file_cache;
218 } // namespace
219
open_file(const std::string & path)220 std::pair<FileEntry, int> Stream::open_file(const std::string &path) {
221 auto it = file_cache.find(path);
222 if (it != std::end(file_cache)) {
223 return {(*it).second, 0};
224 }
225
226 auto fd = open(path.c_str(), O_RDONLY);
227 if (fd == -1) {
228 return {{}, -1};
229 }
230
231 struct stat st {};
232 if (fstat(fd, &st) != 0) {
233 close(fd);
234 return {{}, -1};
235 }
236
237 FileEntry fe{};
238 if (st.st_mode & S_IFDIR) {
239 fe.flags |= FILE_ENTRY_TYPE_DIR;
240 fe.fd = -1;
241 close(fd);
242 } else {
243 fe.fd = fd;
244 fe.len = st.st_size;
245 fe.map = mmap(nullptr, fe.len, PROT_READ, MAP_SHARED, fd, 0);
246 if (fe.map == MAP_FAILED) {
247 std::cerr << "mmap: " << strerror(errno) << std::endl;
248 close(fd);
249 return {{}, -1};
250 }
251 }
252
253 file_cache.emplace(path, fe);
254
255 return {std::move(fe), 0};
256 }
257
map_file(const FileEntry & fe)258 void Stream::map_file(const FileEntry &fe) {
259 data = static_cast<uint8_t *>(fe.map);
260 datalen = fe.len;
261 }
262
find_dyn_length(const std::string_view & path)263 int64_t Stream::find_dyn_length(const std::string_view &path) {
264 assert(path[0] == '/');
265
266 if (path.size() == 1) {
267 return -1;
268 }
269
270 uint64_t n = 0;
271
272 for (auto it = std::begin(path) + 1; it != std::end(path); ++it) {
273 if (*it < '0' || '9' < *it) {
274 return -1;
275 }
276 auto d = *it - '0';
277 if (n > (((1ull << 62) - 1) - d) / 10) {
278 return -1;
279 }
280 n = n * 10 + d;
281 if (n > config.max_dyn_length) {
282 return -1;
283 }
284 }
285
286 return static_cast<int64_t>(n);
287 }
288
289 namespace {
read_data(nghttp3_conn * conn,int64_t stream_id,nghttp3_vec * vec,size_t veccnt,uint32_t * pflags,void * user_data,void * stream_user_data)290 nghttp3_ssize read_data(nghttp3_conn *conn, int64_t stream_id, nghttp3_vec *vec,
291 size_t veccnt, uint32_t *pflags, void *user_data,
292 void *stream_user_data) {
293 auto stream = static_cast<Stream *>(stream_user_data);
294
295 vec[0].base = stream->data;
296 vec[0].len = stream->datalen;
297 *pflags |= NGHTTP3_DATA_FLAG_EOF;
298 if (config.send_trailers) {
299 *pflags |= NGHTTP3_DATA_FLAG_NO_END_STREAM;
300 }
301
302 return 1;
303 }
304 } // namespace
305
306 auto dyn_buf = std::make_unique<std::array<uint8_t, 16_k>>();
307
308 namespace {
dyn_read_data(nghttp3_conn * conn,int64_t stream_id,nghttp3_vec * vec,size_t veccnt,uint32_t * pflags,void * user_data,void * stream_user_data)309 nghttp3_ssize dyn_read_data(nghttp3_conn *conn, int64_t stream_id,
310 nghttp3_vec *vec, size_t veccnt, uint32_t *pflags,
311 void *user_data, void *stream_user_data) {
312 auto stream = static_cast<Stream *>(stream_user_data);
313
314 if (stream->dynbuflen > MAX_DYNBUFLEN) {
315 return NGHTTP3_ERR_WOULDBLOCK;
316 }
317
318 auto len =
319 std::min(dyn_buf->size(), static_cast<size_t>(stream->dyndataleft));
320
321 vec[0].base = dyn_buf->data();
322 vec[0].len = len;
323
324 stream->dynbuflen += len;
325 stream->dyndataleft -= len;
326
327 if (stream->dyndataleft == 0) {
328 *pflags |= NGHTTP3_DATA_FLAG_EOF;
329 if (config.send_trailers) {
330 *pflags |= NGHTTP3_DATA_FLAG_NO_END_STREAM;
331 auto stream_id_str = std::to_string(stream_id);
332 std::array<nghttp3_nv, 1> trailers{
333 util::make_nv("x-ngtcp2-stream-id", stream_id_str),
334 };
335
336 if (auto rv = nghttp3_conn_submit_trailers(
337 conn, stream_id, trailers.data(), trailers.size());
338 rv != 0) {
339 std::cerr << "nghttp3_conn_submit_trailers: " << nghttp3_strerror(rv)
340 << std::endl;
341 return NGHTTP3_ERR_CALLBACK_FAILURE;
342 }
343 }
344 }
345
346 return 1;
347 }
348 } // namespace
349
http_acked_stream_data(uint64_t datalen)350 void Stream::http_acked_stream_data(uint64_t datalen) {
351 if (!dynresp) {
352 return;
353 }
354
355 assert(dynbuflen >= datalen);
356
357 dynbuflen -= datalen;
358 }
359
send_status_response(nghttp3_conn * httpconn,unsigned int status_code,const std::vector<HTTPHeader> & extra_headers)360 int Stream::send_status_response(nghttp3_conn *httpconn,
361 unsigned int status_code,
362 const std::vector<HTTPHeader> &extra_headers) {
363 status_resp_body = make_status_body(status_code);
364
365 auto status_code_str = std::to_string(status_code);
366 auto content_length_str = std::to_string(status_resp_body.size());
367
368 std::vector<nghttp3_nv> nva(4 + extra_headers.size());
369 nva[0] = util::make_nv(":status", status_code_str);
370 nva[1] = util::make_nv("server", NGTCP2_SERVER);
371 nva[2] = util::make_nv("content-type", "text/html; charset=utf-8");
372 nva[3] = util::make_nv("content-length", content_length_str);
373 for (size_t i = 0; i < extra_headers.size(); ++i) {
374 auto &hdr = extra_headers[i];
375 auto &nv = nva[4 + i];
376 nv = util::make_nv(hdr.name, hdr.value);
377 }
378
379 data = (uint8_t *)status_resp_body.data();
380 datalen = status_resp_body.size();
381
382 nghttp3_data_reader dr{};
383 dr.read_data = read_data;
384
385 if (auto rv = nghttp3_conn_submit_response(httpconn, stream_id, nva.data(),
386 nva.size(), &dr);
387 rv != 0) {
388 std::cerr << "nghttp3_conn_submit_response: " << nghttp3_strerror(rv)
389 << std::endl;
390 return -1;
391 }
392
393 if (config.send_trailers) {
394 auto stream_id_str = std::to_string(stream_id);
395 std::array<nghttp3_nv, 1> trailers{
396 util::make_nv("x-ngtcp2-stream-id", stream_id_str),
397 };
398
399 if (auto rv = nghttp3_conn_submit_trailers(
400 httpconn, stream_id, trailers.data(), trailers.size());
401 rv != 0) {
402 std::cerr << "nghttp3_conn_submit_trailers: " << nghttp3_strerror(rv)
403 << std::endl;
404 return -1;
405 }
406 }
407
408 handler->shutdown_read(stream_id, NGHTTP3_H3_NO_ERROR);
409
410 return 0;
411 }
412
send_redirect_response(nghttp3_conn * httpconn,unsigned int status_code,const std::string_view & path)413 int Stream::send_redirect_response(nghttp3_conn *httpconn,
414 unsigned int status_code,
415 const std::string_view &path) {
416 return send_status_response(httpconn, status_code, {{"location", path}});
417 }
418
start_response(nghttp3_conn * httpconn)419 int Stream::start_response(nghttp3_conn *httpconn) {
420 // TODO This should be handled by nghttp3
421 if (uri.empty() || method.empty()) {
422 return send_status_response(httpconn, 400);
423 }
424
425 auto req = request_path(uri, method == "CONNECT");
426 if (req.path.empty()) {
427 return send_status_response(httpconn, 400);
428 }
429
430 auto dyn_len = find_dyn_length(req.path);
431
432 int64_t content_length = -1;
433 nghttp3_data_reader dr{};
434 std::string content_type = "text/plain";
435
436 if (dyn_len == -1) {
437 auto path = config.htdocs + req.path;
438 auto [fe, rv] = open_file(path);
439 if (rv != 0) {
440 send_status_response(httpconn, 404);
441 return 0;
442 }
443
444 if (fe.flags & FILE_ENTRY_TYPE_DIR) {
445 send_redirect_response(httpconn, 308,
446 path.substr(config.htdocs.size() - 1) + '/');
447 return 0;
448 }
449
450 content_length = fe.len;
451
452 if (method != "HEAD") {
453 map_file(fe);
454 }
455
456 dr.read_data = read_data;
457
458 auto ext = std::end(req.path) - 1;
459 for (; ext != std::begin(req.path) && *ext != '.' && *ext != '/'; --ext)
460 ;
461 if (*ext == '.') {
462 ++ext;
463 auto it = config.mime_types.find(std::string{ext, std::end(req.path)});
464 if (it != std::end(config.mime_types)) {
465 content_type = (*it).second;
466 }
467 }
468 } else {
469 content_length = dyn_len;
470 dynresp = true;
471 dr.read_data = dyn_read_data;
472
473 if (method != "HEAD") {
474 datalen = dyn_len;
475 dyndataleft = dyn_len;
476 }
477
478 content_type = "application/octet-stream";
479 }
480
481 auto content_length_str = std::to_string(content_length);
482
483 std::array<nghttp3_nv, 5> nva{
484 util::make_nv(":status", "200"),
485 util::make_nv("server", NGTCP2_SERVER),
486 util::make_nv("content-type", content_type),
487 util::make_nv("content-length", content_length_str),
488 };
489
490 size_t nvlen = 4;
491
492 std::string prival;
493
494 if (req.pri.urgency != -1 || req.pri.inc != -1) {
495 nghttp3_pri pri;
496
497 if (auto rv = nghttp3_conn_get_stream_priority(httpconn, &pri, stream_id);
498 rv != 0) {
499 std::cerr << "nghttp3_conn_get_stream_priority: " << nghttp3_strerror(rv)
500 << std::endl;
501 return -1;
502 }
503
504 if (req.pri.urgency != -1) {
505 pri.urgency = req.pri.urgency;
506 }
507 if (req.pri.inc != -1) {
508 pri.inc = req.pri.inc;
509 }
510
511 if (auto rv = nghttp3_conn_set_stream_priority(httpconn, stream_id, &pri);
512 rv != 0) {
513 std::cerr << "nghttp3_conn_set_stream_priority: " << nghttp3_strerror(rv)
514 << std::endl;
515 return -1;
516 }
517
518 prival = "u=";
519 prival += pri.urgency + '0';
520 prival += ",i";
521 if (!pri.inc) {
522 prival += "=?0";
523 }
524
525 nva[nvlen++] = util::make_nv("priority", prival);
526 }
527
528 if (!config.quiet) {
529 debug::print_http_response_headers(stream_id, nva.data(), nvlen);
530 }
531
532 if (auto rv = nghttp3_conn_submit_response(httpconn, stream_id, nva.data(),
533 nvlen, &dr);
534 rv != 0) {
535 std::cerr << "nghttp3_conn_submit_response: " << nghttp3_strerror(rv)
536 << std::endl;
537 return -1;
538 }
539
540 if (config.send_trailers && dyn_len == -1) {
541 auto stream_id_str = std::to_string(stream_id);
542 std::array<nghttp3_nv, 1> trailers{
543 util::make_nv("x-ngtcp2-stream-id", stream_id_str),
544 };
545
546 if (auto rv = nghttp3_conn_submit_trailers(
547 httpconn, stream_id, trailers.data(), trailers.size());
548 rv != 0) {
549 std::cerr << "nghttp3_conn_submit_trailers: " << nghttp3_strerror(rv)
550 << std::endl;
551 return -1;
552 }
553 }
554
555 return 0;
556 }
557
558 namespace {
writecb(struct ev_loop * loop,ev_io * w,int revents)559 void writecb(struct ev_loop *loop, ev_io *w, int revents) {
560 ev_io_stop(loop, w);
561
562 auto h = static_cast<Handler *>(w->data);
563 auto s = h->server();
564
565 switch (h->on_write()) {
566 case 0:
567 case NETWORK_ERR_CLOSE_WAIT:
568 return;
569 default:
570 s->remove(h);
571 }
572 }
573 } // namespace
574
575 namespace {
timeoutcb(struct ev_loop * loop,ev_timer * w,int revents)576 void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
577 auto h = static_cast<Handler *>(w->data);
578 auto s = h->server();
579
580 if (ngtcp2_conn_is_in_closing_period(h->conn())) {
581 if (!config.quiet) {
582 std::cerr << "Closing Period is over" << std::endl;
583 }
584
585 s->remove(h);
586 return;
587 }
588 if (h->draining()) {
589 if (!config.quiet) {
590 std::cerr << "Draining Period is over" << std::endl;
591 }
592
593 s->remove(h);
594 return;
595 }
596
597 if (!config.quiet) {
598 std::cerr << "Timeout" << std::endl;
599 }
600
601 h->start_draining_period();
602 }
603 } // namespace
604
605 namespace {
retransmitcb(struct ev_loop * loop,ev_timer * w,int revents)606 void retransmitcb(struct ev_loop *loop, ev_timer *w, int revents) {
607 int rv;
608
609 auto h = static_cast<Handler *>(w->data);
610 auto s = h->server();
611
612 if (!config.quiet) {
613 std::cerr << "Timer expired" << std::endl;
614 }
615
616 rv = h->handle_expiry();
617 if (rv != 0) {
618 goto fail;
619 }
620
621 rv = h->on_write();
622 if (rv != 0) {
623 goto fail;
624 }
625
626 return;
627
628 fail:
629 switch (rv) {
630 case NETWORK_ERR_CLOSE_WAIT:
631 ev_timer_stop(loop, w);
632 return;
633 default:
634 s->remove(h);
635 return;
636 }
637 }
638 } // namespace
639
Handler(struct ev_loop * loop,Server * server)640 Handler::Handler(struct ev_loop *loop, Server *server)
641 : loop_(loop),
642 server_(server),
643 qlog_(nullptr),
644 scid_{},
645 httpconn_{nullptr},
646 nkey_update_(0),
647 draining_(false) {
648 ev_io_init(&wev_, writecb, 0, EV_WRITE);
649 wev_.data = this;
650 ev_timer_init(&timer_, timeoutcb, 0.,
651 static_cast<double>(config.timeout) / NGTCP2_SECONDS);
652 timer_.data = this;
653 ev_timer_init(&rttimer_, retransmitcb, 0., 0.);
654 rttimer_.data = this;
655
__anon50ca2e3d0e02() 656 application_tx_key_cb_ = [this]() { return setup_httpconn(); };
657 }
658
~Handler()659 Handler::~Handler() {
660 if (!config.quiet) {
661 std::cerr << scid_ << " Closing QUIC connection " << std::endl;
662 }
663
664 ev_timer_stop(loop_, &rttimer_);
665 ev_timer_stop(loop_, &timer_);
666 ev_io_stop(loop_, &wev_);
667
668 if (httpconn_) {
669 nghttp3_conn_del(httpconn_);
670 }
671
672 if (qlog_) {
673 fclose(qlog_);
674 }
675 }
676
677 namespace {
handshake_completed(ngtcp2_conn * conn,void * user_data)678 int handshake_completed(ngtcp2_conn *conn, void *user_data) {
679 auto h = static_cast<Handler *>(user_data);
680
681 if (!config.quiet) {
682 debug::handshake_completed(conn, user_data);
683 }
684
685 if (h->handshake_completed() != 0) {
686 return NGTCP2_ERR_CALLBACK_FAILURE;
687 }
688
689 return 0;
690 }
691 } // namespace
692
handshake_completed()693 int Handler::handshake_completed() {
694 if (!config.quiet) {
695 std::cerr << "Negotiated cipher suite is " << tls_session_.get_cipher_name()
696 << std::endl;
697 std::cerr << "Negotiated ALPN is " << tls_session_.get_selected_alpn()
698 << std::endl;
699 }
700
701 if (tls_session_.send_session_ticket() != 0) {
702 std::cerr << "Unable to send session ticket" << std::endl;
703 }
704
705 std::array<uint8_t, NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN> token;
706
707 auto path = ngtcp2_conn_get_path(conn_);
708 auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
709 std::chrono::system_clock::now().time_since_epoch())
710 .count();
711
712 auto tokenlen = ngtcp2_crypto_generate_regular_token(
713 token.data(), config.static_secret.data(), config.static_secret.size(),
714 path->remote.addr, path->remote.addrlen, t);
715 if (tokenlen < 0) {
716 if (!config.quiet) {
717 std::cerr << "Unable to generate token" << std::endl;
718 }
719 return 0;
720 }
721
722 if (auto rv = ngtcp2_conn_submit_new_token(conn_, token.data(), tokenlen);
723 rv != 0) {
724 if (!config.quiet) {
725 std::cerr << "ngtcp2_conn_submit_new_token: " << ngtcp2_strerror(rv)
726 << std::endl;
727 }
728 return -1;
729 }
730
731 return 0;
732 }
733
734 namespace {
do_hp_mask(uint8_t * dest,const ngtcp2_crypto_cipher * hp,const ngtcp2_crypto_cipher_ctx * hp_ctx,const uint8_t * sample)735 int do_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
736 const ngtcp2_crypto_cipher_ctx *hp_ctx, const uint8_t *sample) {
737 if (ngtcp2_crypto_hp_mask(dest, hp, hp_ctx, sample) != 0) {
738 return NGTCP2_ERR_CALLBACK_FAILURE;
739 }
740
741 if (!config.quiet && config.show_secret) {
742 debug::print_hp_mask(dest, NGTCP2_HP_MASKLEN, sample, NGTCP2_HP_SAMPLELEN);
743 }
744
745 return 0;
746 }
747 } // namespace
748
749 namespace {
recv_crypto_data(ngtcp2_conn * conn,ngtcp2_crypto_level crypto_level,uint64_t offset,const uint8_t * data,size_t datalen,void * user_data)750 int recv_crypto_data(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level,
751 uint64_t offset, const uint8_t *data, size_t datalen,
752 void *user_data) {
753 if (!config.quiet && !config.no_quic_dump) {
754 debug::print_crypto_data(crypto_level, data, datalen);
755 }
756
757 return ngtcp2_crypto_recv_crypto_data_cb(conn, crypto_level, offset, data,
758 datalen, user_data);
759 }
760 } // namespace
761
762 namespace {
recv_stream_data(ngtcp2_conn * conn,uint32_t flags,int64_t stream_id,uint64_t offset,const uint8_t * data,size_t datalen,void * user_data,void * stream_user_data)763 int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
764 uint64_t offset, const uint8_t *data, size_t datalen,
765 void *user_data, void *stream_user_data) {
766 auto h = static_cast<Handler *>(user_data);
767
768 if (h->recv_stream_data(flags, stream_id, data, datalen) != 0) {
769 return NGTCP2_ERR_CALLBACK_FAILURE;
770 }
771
772 return 0;
773 }
774 } // namespace
775
776 namespace {
acked_stream_data_offset(ngtcp2_conn * conn,int64_t stream_id,uint64_t offset,uint64_t datalen,void * user_data,void * stream_user_data)777 int acked_stream_data_offset(ngtcp2_conn *conn, int64_t stream_id,
778 uint64_t offset, uint64_t datalen, void *user_data,
779 void *stream_user_data) {
780 auto h = static_cast<Handler *>(user_data);
781 if (h->acked_stream_data_offset(stream_id, datalen) != 0) {
782 return NGTCP2_ERR_CALLBACK_FAILURE;
783 }
784 return 0;
785 }
786 } // namespace
787
acked_stream_data_offset(int64_t stream_id,uint64_t datalen)788 int Handler::acked_stream_data_offset(int64_t stream_id, uint64_t datalen) {
789 if (!httpconn_) {
790 return 0;
791 }
792
793 if (auto rv = nghttp3_conn_add_ack_offset(httpconn_, stream_id, datalen);
794 rv != 0) {
795 std::cerr << "nghttp3_conn_add_ack_offset: " << nghttp3_strerror(rv)
796 << std::endl;
797 return -1;
798 }
799
800 return 0;
801 }
802
803 namespace {
stream_open(ngtcp2_conn * conn,int64_t stream_id,void * user_data)804 int stream_open(ngtcp2_conn *conn, int64_t stream_id, void *user_data) {
805 auto h = static_cast<Handler *>(user_data);
806 h->on_stream_open(stream_id);
807 return 0;
808 }
809 } // namespace
810
on_stream_open(int64_t stream_id)811 void Handler::on_stream_open(int64_t stream_id) {
812 if (!ngtcp2_is_bidi_stream(stream_id)) {
813 return;
814 }
815 auto it = streams_.find(stream_id);
816 (void)it;
817 assert(it == std::end(streams_));
818 streams_.emplace(stream_id, std::make_unique<Stream>(stream_id, this));
819 }
820
821 namespace {
stream_close(ngtcp2_conn * conn,uint32_t flags,int64_t stream_id,uint64_t app_error_code,void * user_data,void * stream_user_data)822 int stream_close(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
823 uint64_t app_error_code, void *user_data,
824 void *stream_user_data) {
825 auto h = static_cast<Handler *>(user_data);
826
827 if (!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) {
828 app_error_code = NGHTTP3_H3_NO_ERROR;
829 }
830
831 if (h->on_stream_close(stream_id, app_error_code) != 0) {
832 return NGTCP2_ERR_CALLBACK_FAILURE;
833 }
834 return 0;
835 }
836 } // namespace
837
838 namespace {
stream_reset(ngtcp2_conn * conn,int64_t stream_id,uint64_t final_size,uint64_t app_error_code,void * user_data,void * stream_user_data)839 int stream_reset(ngtcp2_conn *conn, int64_t stream_id, uint64_t final_size,
840 uint64_t app_error_code, void *user_data,
841 void *stream_user_data) {
842 auto h = static_cast<Handler *>(user_data);
843 if (h->on_stream_reset(stream_id) != 0) {
844 return NGTCP2_ERR_CALLBACK_FAILURE;
845 }
846 return 0;
847 }
848 } // namespace
849
on_stream_reset(int64_t stream_id)850 int Handler::on_stream_reset(int64_t stream_id) {
851 if (httpconn_) {
852 if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id);
853 rv != 0) {
854 std::cerr << "nghttp3_conn_shutdown_stream_read: " << nghttp3_strerror(rv)
855 << std::endl;
856 return -1;
857 }
858 }
859 return 0;
860 }
861
862 namespace {
stream_stop_sending(ngtcp2_conn * conn,int64_t stream_id,uint64_t app_error_code,void * user_data,void * stream_user_data)863 int stream_stop_sending(ngtcp2_conn *conn, int64_t stream_id,
864 uint64_t app_error_code, void *user_data,
865 void *stream_user_data) {
866 auto h = static_cast<Handler *>(user_data);
867 if (h->on_stream_stop_sending(stream_id) != 0) {
868 return NGTCP2_ERR_CALLBACK_FAILURE;
869 }
870 return 0;
871 }
872 } // namespace
873
on_stream_stop_sending(int64_t stream_id)874 int Handler::on_stream_stop_sending(int64_t stream_id) {
875 if (!httpconn_) {
876 return 0;
877 }
878
879 if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id);
880 rv != 0) {
881 std::cerr << "nghttp3_conn_shutdown_stream_read: " << nghttp3_strerror(rv)
882 << std::endl;
883 return -1;
884 }
885
886 return 0;
887 }
888
889 namespace {
rand(uint8_t * dest,size_t destlen,const ngtcp2_rand_ctx * rand_ctx)890 void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) {
891 auto dis = std::uniform_int_distribution<uint8_t>(0, 255);
892 std::generate(dest, dest + destlen, [&dis]() { return dis(randgen); });
893 }
894 } // namespace
895
896 namespace {
get_new_connection_id(ngtcp2_conn * conn,ngtcp2_cid * cid,uint8_t * token,size_t cidlen,void * user_data)897 int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, uint8_t *token,
898 size_t cidlen, void *user_data) {
899 if (util::generate_secure_random(cid->data, cidlen) != 0) {
900 return NGTCP2_ERR_CALLBACK_FAILURE;
901 }
902
903 cid->datalen = cidlen;
904 if (ngtcp2_crypto_generate_stateless_reset_token(
905 token, config.static_secret.data(), config.static_secret.size(),
906 cid) != 0) {
907 return NGTCP2_ERR_CALLBACK_FAILURE;
908 }
909
910 auto h = static_cast<Handler *>(user_data);
911 h->server()->associate_cid(cid, h);
912
913 return 0;
914 }
915 } // namespace
916
917 namespace {
remove_connection_id(ngtcp2_conn * conn,const ngtcp2_cid * cid,void * user_data)918 int remove_connection_id(ngtcp2_conn *conn, const ngtcp2_cid *cid,
919 void *user_data) {
920 auto h = static_cast<Handler *>(user_data);
921 h->server()->dissociate_cid(cid);
922 return 0;
923 }
924 } // namespace
925
926 namespace {
update_key(ngtcp2_conn * conn,uint8_t * rx_secret,uint8_t * tx_secret,ngtcp2_crypto_aead_ctx * rx_aead_ctx,uint8_t * rx_iv,ngtcp2_crypto_aead_ctx * tx_aead_ctx,uint8_t * tx_iv,const uint8_t * current_rx_secret,const uint8_t * current_tx_secret,size_t secretlen,void * user_data)927 int update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
928 ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
929 ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
930 const uint8_t *current_rx_secret,
931 const uint8_t *current_tx_secret, size_t secretlen,
932 void *user_data) {
933 auto h = static_cast<Handler *>(user_data);
934 if (h->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx,
935 tx_iv, current_rx_secret, current_tx_secret,
936 secretlen) != 0) {
937 return NGTCP2_ERR_CALLBACK_FAILURE;
938 }
939 return 0;
940 }
941 } // namespace
942
943 namespace {
path_validation(ngtcp2_conn * conn,uint32_t flags,const ngtcp2_path * path,ngtcp2_path_validation_result res,void * user_data)944 int path_validation(ngtcp2_conn *conn, uint32_t flags, const ngtcp2_path *path,
945 ngtcp2_path_validation_result res, void *user_data) {
946 if (!config.quiet) {
947 debug::path_validation(path, res);
948 }
949 return 0;
950 }
951 } // namespace
952
953 namespace {
extend_max_remote_streams_bidi(ngtcp2_conn * conn,uint64_t max_streams,void * user_data)954 int extend_max_remote_streams_bidi(ngtcp2_conn *conn, uint64_t max_streams,
955 void *user_data) {
956 auto h = static_cast<Handler *>(user_data);
957 h->extend_max_remote_streams_bidi(max_streams);
958 return 0;
959 }
960 } // namespace
961
extend_max_remote_streams_bidi(uint64_t max_streams)962 void Handler::extend_max_remote_streams_bidi(uint64_t max_streams) {
963 if (!httpconn_) {
964 return;
965 }
966
967 nghttp3_conn_set_max_client_streams_bidi(httpconn_, max_streams);
968 }
969
970 namespace {
http_recv_data(nghttp3_conn * conn,int64_t stream_id,const uint8_t * data,size_t datalen,void * user_data,void * stream_user_data)971 int http_recv_data(nghttp3_conn *conn, int64_t stream_id, const uint8_t *data,
972 size_t datalen, void *user_data, void *stream_user_data) {
973 if (!config.quiet && !config.no_http_dump) {
974 debug::print_http_data(stream_id, data, datalen);
975 }
976 auto h = static_cast<Handler *>(user_data);
977 h->http_consume(stream_id, datalen);
978 return 0;
979 }
980 } // namespace
981
982 namespace {
http_deferred_consume(nghttp3_conn * conn,int64_t stream_id,size_t nconsumed,void * user_data,void * stream_user_data)983 int http_deferred_consume(nghttp3_conn *conn, int64_t stream_id,
984 size_t nconsumed, void *user_data,
985 void *stream_user_data) {
986 auto h = static_cast<Handler *>(user_data);
987 h->http_consume(stream_id, nconsumed);
988 return 0;
989 }
990 } // namespace
991
http_consume(int64_t stream_id,size_t nconsumed)992 void Handler::http_consume(int64_t stream_id, size_t nconsumed) {
993 ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, nconsumed);
994 ngtcp2_conn_extend_max_offset(conn_, nconsumed);
995 }
996
997 namespace {
http_begin_request_headers(nghttp3_conn * conn,int64_t stream_id,void * user_data,void * stream_user_data)998 int http_begin_request_headers(nghttp3_conn *conn, int64_t stream_id,
999 void *user_data, void *stream_user_data) {
1000 if (!config.quiet) {
1001 debug::print_http_begin_request_headers(stream_id);
1002 }
1003
1004 auto h = static_cast<Handler *>(user_data);
1005 h->http_begin_request_headers(stream_id);
1006 return 0;
1007 }
1008 } // namespace
1009
http_begin_request_headers(int64_t stream_id)1010 void Handler::http_begin_request_headers(int64_t stream_id) {
1011 auto it = streams_.find(stream_id);
1012 assert(it != std::end(streams_));
1013 auto &stream = (*it).second;
1014
1015 nghttp3_conn_set_stream_user_data(httpconn_, stream_id, stream.get());
1016 }
1017
1018 namespace {
http_recv_request_header(nghttp3_conn * conn,int64_t stream_id,int32_t token,nghttp3_rcbuf * name,nghttp3_rcbuf * value,uint8_t flags,void * user_data,void * stream_user_data)1019 int http_recv_request_header(nghttp3_conn *conn, int64_t stream_id,
1020 int32_t token, nghttp3_rcbuf *name,
1021 nghttp3_rcbuf *value, uint8_t flags,
1022 void *user_data, void *stream_user_data) {
1023 if (!config.quiet) {
1024 debug::print_http_header(stream_id, name, value, flags);
1025 }
1026
1027 auto h = static_cast<Handler *>(user_data);
1028 auto stream = static_cast<Stream *>(stream_user_data);
1029 h->http_recv_request_header(stream, token, name, value);
1030 return 0;
1031 }
1032 } // namespace
1033
http_recv_request_header(Stream * stream,int32_t token,nghttp3_rcbuf * name,nghttp3_rcbuf * value)1034 void Handler::http_recv_request_header(Stream *stream, int32_t token,
1035 nghttp3_rcbuf *name,
1036 nghttp3_rcbuf *value) {
1037 auto v = nghttp3_rcbuf_get_buf(value);
1038
1039 switch (token) {
1040 case NGHTTP3_QPACK_TOKEN__PATH:
1041 stream->uri = std::string{v.base, v.base + v.len};
1042 break;
1043 case NGHTTP3_QPACK_TOKEN__METHOD:
1044 stream->method = std::string{v.base, v.base + v.len};
1045 break;
1046 case NGHTTP3_QPACK_TOKEN__AUTHORITY:
1047 stream->authority = std::string{v.base, v.base + v.len};
1048 break;
1049 }
1050 }
1051
1052 namespace {
http_end_request_headers(nghttp3_conn * conn,int64_t stream_id,void * user_data,void * stream_user_data)1053 int http_end_request_headers(nghttp3_conn *conn, int64_t stream_id,
1054 void *user_data, void *stream_user_data) {
1055 if (!config.quiet) {
1056 debug::print_http_end_headers(stream_id);
1057 }
1058
1059 auto h = static_cast<Handler *>(user_data);
1060 auto stream = static_cast<Stream *>(stream_user_data);
1061 if (h->http_end_request_headers(stream) != 0) {
1062 return NGHTTP3_ERR_CALLBACK_FAILURE;
1063 }
1064 return 0;
1065 }
1066 } // namespace
1067
http_end_request_headers(Stream * stream)1068 int Handler::http_end_request_headers(Stream *stream) {
1069 if (config.early_response) {
1070 if (start_response(stream) != 0) {
1071 return -1;
1072 }
1073
1074 shutdown_read(stream->stream_id, NGHTTP3_H3_NO_ERROR);
1075 }
1076 return 0;
1077 }
1078
1079 namespace {
http_end_stream(nghttp3_conn * conn,int64_t stream_id,void * user_data,void * stream_user_data)1080 int http_end_stream(nghttp3_conn *conn, int64_t stream_id, void *user_data,
1081 void *stream_user_data) {
1082 auto h = static_cast<Handler *>(user_data);
1083 auto stream = static_cast<Stream *>(stream_user_data);
1084 if (h->http_end_stream(stream) != 0) {
1085 return NGHTTP3_ERR_CALLBACK_FAILURE;
1086 }
1087 return 0;
1088 }
1089 } // namespace
1090
http_end_stream(Stream * stream)1091 int Handler::http_end_stream(Stream *stream) {
1092 if (!config.early_response) {
1093 return start_response(stream);
1094 }
1095 return 0;
1096 }
1097
start_response(Stream * stream)1098 int Handler::start_response(Stream *stream) {
1099 return stream->start_response(httpconn_);
1100 }
1101
1102 namespace {
http_acked_stream_data(nghttp3_conn * conn,int64_t stream_id,uint64_t datalen,void * user_data,void * stream_user_data)1103 int http_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
1104 uint64_t datalen, void *user_data,
1105 void *stream_user_data) {
1106 auto h = static_cast<Handler *>(user_data);
1107 auto stream = static_cast<Stream *>(stream_user_data);
1108 h->http_acked_stream_data(stream, datalen);
1109 return 0;
1110 }
1111 } // namespace
1112
http_acked_stream_data(Stream * stream,uint64_t datalen)1113 void Handler::http_acked_stream_data(Stream *stream, uint64_t datalen) {
1114 stream->http_acked_stream_data(datalen);
1115
1116 if (stream->dynresp && stream->dynbuflen < MAX_DYNBUFLEN - 16384) {
1117 if (auto rv = nghttp3_conn_resume_stream(httpconn_, stream->stream_id);
1118 rv != 0) {
1119 // TODO Handle error
1120 std::cerr << "nghttp3_conn_resume_stream: " << nghttp3_strerror(rv)
1121 << std::endl;
1122 }
1123 }
1124 }
1125
1126 namespace {
http_stream_close(nghttp3_conn * conn,int64_t stream_id,uint64_t app_error_code,void * conn_user_data,void * stream_user_data)1127 int http_stream_close(nghttp3_conn *conn, int64_t stream_id,
1128 uint64_t app_error_code, void *conn_user_data,
1129 void *stream_user_data) {
1130 auto h = static_cast<Handler *>(conn_user_data);
1131 h->http_stream_close(stream_id, app_error_code);
1132 return 0;
1133 }
1134 } // namespace
1135
http_stream_close(int64_t stream_id,uint64_t app_error_code)1136 void Handler::http_stream_close(int64_t stream_id, uint64_t app_error_code) {
1137 auto it = streams_.find(stream_id);
1138 if (it == std::end(streams_)) {
1139 return;
1140 }
1141
1142 if (!config.quiet) {
1143 std::cerr << "HTTP stream " << stream_id << " closed with error code "
1144 << app_error_code << std::endl;
1145 }
1146
1147 streams_.erase(it);
1148
1149 if (ngtcp2_is_bidi_stream(stream_id)) {
1150 assert(!ngtcp2_conn_is_local_stream(conn_, stream_id));
1151 ngtcp2_conn_extend_max_streams_bidi(conn_, 1);
1152 }
1153 }
1154
1155 namespace {
http_stop_sending(nghttp3_conn * conn,int64_t stream_id,uint64_t app_error_code,void * user_data,void * stream_user_data)1156 int http_stop_sending(nghttp3_conn *conn, int64_t stream_id,
1157 uint64_t app_error_code, void *user_data,
1158 void *stream_user_data) {
1159 auto h = static_cast<Handler *>(user_data);
1160 if (h->http_stop_sending(stream_id, app_error_code) != 0) {
1161 return NGHTTP3_ERR_CALLBACK_FAILURE;
1162 }
1163 return 0;
1164 }
1165 } // namespace
1166
http_stop_sending(int64_t stream_id,uint64_t app_error_code)1167 int Handler::http_stop_sending(int64_t stream_id, uint64_t app_error_code) {
1168 if (auto rv =
1169 ngtcp2_conn_shutdown_stream_read(conn_, stream_id, app_error_code);
1170 rv != 0) {
1171 std::cerr << "ngtcp2_conn_shutdown_stream_read: " << ngtcp2_strerror(rv)
1172 << std::endl;
1173 if (rv == NGTCP2_ERR_STREAM_NOT_FOUND) {
1174 return 0;
1175 }
1176 return -1;
1177 }
1178 return 0;
1179 }
1180
1181 namespace {
http_reset_stream(nghttp3_conn * conn,int64_t stream_id,uint64_t app_error_code,void * user_data,void * stream_user_data)1182 int http_reset_stream(nghttp3_conn *conn, int64_t stream_id,
1183 uint64_t app_error_code, void *user_data,
1184 void *stream_user_data) {
1185 auto h = static_cast<Handler *>(user_data);
1186 if (h->http_reset_stream(stream_id, app_error_code) != 0) {
1187 return NGHTTP3_ERR_CALLBACK_FAILURE;
1188 }
1189 return 0;
1190 }
1191 } // namespace
1192
http_reset_stream(int64_t stream_id,uint64_t app_error_code)1193 int Handler::http_reset_stream(int64_t stream_id, uint64_t app_error_code) {
1194 if (auto rv =
1195 ngtcp2_conn_shutdown_stream_write(conn_, stream_id, app_error_code);
1196 rv != 0) {
1197 std::cerr << "ngtcp2_conn_shutdown_stream_write: " << ngtcp2_strerror(rv)
1198 << std::endl;
1199 if (rv == NGTCP2_ERR_STREAM_NOT_FOUND) {
1200 return 0;
1201 }
1202 return -1;
1203 }
1204 return 0;
1205 }
1206
setup_httpconn()1207 int Handler::setup_httpconn() {
1208 if (httpconn_) {
1209 return 0;
1210 }
1211
1212 if (ngtcp2_conn_get_max_local_streams_uni(conn_) < 3) {
1213 std::cerr << "peer does not allow at least 3 unidirectional streams."
1214 << std::endl;
1215 return -1;
1216 }
1217
1218 nghttp3_callbacks callbacks{
1219 ::http_acked_stream_data, // acked_stream_data
1220 ::http_stream_close,
1221 ::http_recv_data,
1222 ::http_deferred_consume,
1223 ::http_begin_request_headers,
1224 ::http_recv_request_header,
1225 ::http_end_request_headers,
1226 nullptr, // begin_trailers
1227 nullptr, // recv_trailer
1228 nullptr, // end_trailers
1229 ::http_stop_sending,
1230 ::http_end_stream,
1231 ::http_reset_stream,
1232 };
1233 nghttp3_settings settings;
1234 nghttp3_settings_default(&settings);
1235 settings.qpack_max_table_capacity = 4096;
1236 settings.qpack_blocked_streams = 100;
1237
1238 auto mem = nghttp3_mem_default();
1239
1240 if (auto rv =
1241 nghttp3_conn_server_new(&httpconn_, &callbacks, &settings, mem, this);
1242 rv != 0) {
1243 std::cerr << "nghttp3_conn_server_new: " << nghttp3_strerror(rv)
1244 << std::endl;
1245 return -1;
1246 }
1247
1248 ngtcp2_transport_params params;
1249 ngtcp2_conn_get_local_transport_params(conn_, ¶ms);
1250
1251 nghttp3_conn_set_max_client_streams_bidi(httpconn_,
1252 params.initial_max_streams_bidi);
1253
1254 int64_t ctrl_stream_id;
1255
1256 if (auto rv = ngtcp2_conn_open_uni_stream(conn_, &ctrl_stream_id, nullptr);
1257 rv != 0) {
1258 std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv)
1259 << std::endl;
1260 return -1;
1261 }
1262
1263 if (auto rv = nghttp3_conn_bind_control_stream(httpconn_, ctrl_stream_id);
1264 rv != 0) {
1265 std::cerr << "nghttp3_conn_bind_control_stream: " << nghttp3_strerror(rv)
1266 << std::endl;
1267 return -1;
1268 }
1269
1270 if (!config.quiet) {
1271 fprintf(stderr, "http: control stream=%" PRIx64 "\n", ctrl_stream_id);
1272 }
1273
1274 int64_t qpack_enc_stream_id, qpack_dec_stream_id;
1275
1276 if (auto rv =
1277 ngtcp2_conn_open_uni_stream(conn_, &qpack_enc_stream_id, nullptr);
1278 rv != 0) {
1279 std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv)
1280 << std::endl;
1281 return -1;
1282 }
1283
1284 if (auto rv =
1285 ngtcp2_conn_open_uni_stream(conn_, &qpack_dec_stream_id, nullptr);
1286 rv != 0) {
1287 std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv)
1288 << std::endl;
1289 return -1;
1290 }
1291
1292 if (auto rv = nghttp3_conn_bind_qpack_streams(httpconn_, qpack_enc_stream_id,
1293 qpack_dec_stream_id);
1294 rv != 0) {
1295 std::cerr << "nghttp3_conn_bind_qpack_streams: " << nghttp3_strerror(rv)
1296 << std::endl;
1297 return -1;
1298 }
1299
1300 if (!config.quiet) {
1301 fprintf(stderr,
1302 "http: QPACK streams encoder=%" PRIx64 " decoder=%" PRIx64 "\n",
1303 qpack_enc_stream_id, qpack_dec_stream_id);
1304 }
1305
1306 return 0;
1307 }
1308
1309 namespace {
extend_max_stream_data(ngtcp2_conn * conn,int64_t stream_id,uint64_t max_data,void * user_data,void * stream_user_data)1310 int extend_max_stream_data(ngtcp2_conn *conn, int64_t stream_id,
1311 uint64_t max_data, void *user_data,
1312 void *stream_user_data) {
1313 auto h = static_cast<Handler *>(user_data);
1314 if (h->extend_max_stream_data(stream_id, max_data) != 0) {
1315 return NGTCP2_ERR_CALLBACK_FAILURE;
1316 }
1317 return 0;
1318 }
1319 } // namespace
1320
extend_max_stream_data(int64_t stream_id,uint64_t max_data)1321 int Handler::extend_max_stream_data(int64_t stream_id, uint64_t max_data) {
1322 if (auto rv = nghttp3_conn_unblock_stream(httpconn_, stream_id); rv != 0) {
1323 std::cerr << "nghttp3_conn_unblock_stream: " << nghttp3_strerror(rv)
1324 << std::endl;
1325 return -1;
1326 }
1327 return 0;
1328 }
1329
1330 namespace {
write_qlog(void * user_data,uint32_t flags,const void * data,size_t datalen)1331 void write_qlog(void *user_data, uint32_t flags, const void *data,
1332 size_t datalen) {
1333 auto h = static_cast<Handler *>(user_data);
1334 h->write_qlog(data, datalen);
1335 }
1336 } // namespace
1337
write_qlog(const void * data,size_t datalen)1338 void Handler::write_qlog(const void *data, size_t datalen) {
1339 assert(qlog_);
1340 fwrite(data, 1, datalen, qlog_);
1341 }
1342
init(const Endpoint & ep,const Address & local_addr,const sockaddr * sa,socklen_t salen,const ngtcp2_cid * dcid,const ngtcp2_cid * scid,const ngtcp2_cid * ocid,const uint8_t * token,size_t tokenlen,uint32_t version,const TLSServerContext & tls_ctx)1343 int Handler::init(const Endpoint &ep, const Address &local_addr,
1344 const sockaddr *sa, socklen_t salen, const ngtcp2_cid *dcid,
1345 const ngtcp2_cid *scid, const ngtcp2_cid *ocid,
1346 const uint8_t *token, size_t tokenlen, uint32_t version,
1347 const TLSServerContext &tls_ctx) {
1348 auto callbacks = ngtcp2_callbacks{
1349 nullptr, // client_initial
1350 ngtcp2_crypto_recv_client_initial_cb,
1351 ::recv_crypto_data,
1352 ::handshake_completed,
1353 nullptr, // recv_version_negotiation
1354 ngtcp2_crypto_encrypt_cb,
1355 ngtcp2_crypto_decrypt_cb,
1356 do_hp_mask,
1357 ::recv_stream_data,
1358 ::acked_stream_data_offset,
1359 stream_open,
1360 stream_close,
1361 nullptr, // recv_stateless_reset
1362 nullptr, // recv_retry
1363 nullptr, // extend_max_streams_bidi
1364 nullptr, // extend_max_streams_uni
1365 rand,
1366 get_new_connection_id,
1367 remove_connection_id,
1368 ::update_key,
1369 path_validation,
1370 nullptr, // select_preferred_addr
1371 ::stream_reset,
1372 ::extend_max_remote_streams_bidi,
1373 nullptr, // extend_max_remote_streams_uni
1374 ::extend_max_stream_data,
1375 nullptr, // dcid_status
1376 nullptr, // handshake_confirmed
1377 nullptr, // recv_new_token
1378 ngtcp2_crypto_delete_crypto_aead_ctx_cb,
1379 ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
1380 nullptr, // recv_datagram
1381 nullptr, // ack_datagram
1382 nullptr, // lost_datagram
1383 ngtcp2_crypto_get_path_challenge_data_cb,
1384 stream_stop_sending,
1385 };
1386
1387 scid_.datalen = NGTCP2_SV_SCIDLEN;
1388 if (util::generate_secure_random(scid_.data, scid_.datalen) != 0) {
1389 std::cerr << "Could not generate connection ID" << std::endl;
1390 return -1;
1391 }
1392
1393 ngtcp2_settings settings;
1394 ngtcp2_settings_default(&settings);
1395 settings.log_printf = config.quiet ? nullptr : debug::log_printf;
1396 settings.initial_ts = util::timestamp(loop_);
1397 settings.token = ngtcp2_vec{const_cast<uint8_t *>(token), tokenlen};
1398 settings.cc_algo = config.cc_algo;
1399 settings.initial_rtt = config.initial_rtt;
1400 settings.max_window = config.max_window;
1401 settings.max_stream_window = config.max_stream_window;
1402 if (config.max_udp_payload_size) {
1403 settings.max_udp_payload_size = config.max_udp_payload_size;
1404 settings.no_udp_payload_size_shaping = 1;
1405 } else {
1406 settings.max_udp_payload_size = server_max_udp_payload_size;
1407 settings.assume_symmetric_path = 1;
1408 }
1409 if (!config.qlog_dir.empty()) {
1410 auto path = std::string{config.qlog_dir};
1411 path += '/';
1412 path += util::format_hex(scid_.data, scid_.datalen);
1413 path += ".sqlog";
1414 qlog_ = fopen(path.c_str(), "w");
1415 if (qlog_ == nullptr) {
1416 std::cerr << "Could not open qlog file " << std::quoted(path) << ": "
1417 << strerror(errno) << std::endl;
1418 return -1;
1419 }
1420 settings.qlog.write = ::write_qlog;
1421 settings.qlog.odcid = *scid;
1422 }
1423
1424 ngtcp2_transport_params params;
1425 ngtcp2_transport_params_default(¶ms);
1426 params.initial_max_stream_data_bidi_local = config.max_stream_data_bidi_local;
1427 params.initial_max_stream_data_bidi_remote =
1428 config.max_stream_data_bidi_remote;
1429 params.initial_max_stream_data_uni = config.max_stream_data_uni;
1430 params.initial_max_data = config.max_data;
1431 params.initial_max_streams_bidi = config.max_streams_bidi;
1432 params.initial_max_streams_uni = config.max_streams_uni;
1433 params.max_idle_timeout = config.timeout;
1434 params.stateless_reset_token_present = 1;
1435 params.active_connection_id_limit = 7;
1436
1437 if (ocid) {
1438 params.original_dcid = *ocid;
1439 params.retry_scid = *scid;
1440 params.retry_scid_present = 1;
1441 } else {
1442 params.original_dcid = *scid;
1443 }
1444
1445 if (util::generate_secure_random(params.stateless_reset_token,
1446 sizeof(params.stateless_reset_token)) != 0) {
1447 std::cerr << "Could not generate stateless reset token" << std::endl;
1448 return -1;
1449 }
1450
1451 if (config.preferred_ipv4_addr.len || config.preferred_ipv6_addr.len) {
1452 params.preferred_address_present = 1;
1453 if (config.preferred_ipv4_addr.len) {
1454 auto &dest = params.preferred_address.ipv4_addr;
1455 const auto &addr = config.preferred_ipv4_addr;
1456 assert(sizeof(dest) == sizeof(addr.su.in.sin_addr));
1457 memcpy(&dest, &addr.su.in.sin_addr, sizeof(dest));
1458 params.preferred_address.ipv4_port = htons(addr.su.in.sin_port);
1459 params.preferred_address.ipv4_present = 1;
1460 }
1461 if (config.preferred_ipv6_addr.len) {
1462 auto &dest = params.preferred_address.ipv6_addr;
1463 const auto &addr = config.preferred_ipv6_addr;
1464 assert(sizeof(dest) == sizeof(addr.su.in6.sin6_addr));
1465 memcpy(&dest, &addr.su.in6.sin6_addr, sizeof(dest));
1466 params.preferred_address.ipv6_port = htons(addr.su.in6.sin6_port);
1467 params.preferred_address.ipv6_present = 1;
1468 }
1469
1470 auto &token = params.preferred_address.stateless_reset_token;
1471 if (util::generate_secure_random(token, sizeof(token)) != 0) {
1472 std::cerr << "Could not generate preferred address stateless reset token"
1473 << std::endl;
1474 return -1;
1475 }
1476
1477 params.preferred_address.cid.datalen = NGTCP2_SV_SCIDLEN;
1478 if (util::generate_secure_random(params.preferred_address.cid.data,
1479 params.preferred_address.cid.datalen) !=
1480 0) {
1481 std::cerr << "Could not generate preferred address connection ID"
1482 << std::endl;
1483 return -1;
1484 }
1485 }
1486
1487 auto path = ngtcp2_path{
1488 {
1489 const_cast<sockaddr *>(&local_addr.su.sa),
1490 local_addr.len,
1491 },
1492 {
1493 const_cast<sockaddr *>(sa),
1494 salen,
1495 },
1496 const_cast<Endpoint *>(&ep),
1497 };
1498 if (auto rv =
1499 ngtcp2_conn_server_new(&conn_, dcid, &scid_, &path, version,
1500 &callbacks, &settings, ¶ms, nullptr, this);
1501 rv != 0) {
1502 std::cerr << "ngtcp2_conn_server_new: " << ngtcp2_strerror(rv) << std::endl;
1503 return -1;
1504 }
1505
1506 if (tls_session_.init(tls_ctx, this) != 0) {
1507 return -1;
1508 }
1509
1510 tls_session_.enable_keylog();
1511
1512 ngtcp2_conn_set_tls_native_handle(conn_, tls_session_.get_native_handle());
1513
1514 ev_io_set(&wev_, ep.fd, EV_WRITE);
1515 ev_timer_again(loop_, &timer_);
1516
1517 return 0;
1518 }
1519
feed_data(const Endpoint & ep,const Address & local_addr,const sockaddr * sa,socklen_t salen,const ngtcp2_pkt_info * pi,uint8_t * data,size_t datalen)1520 int Handler::feed_data(const Endpoint &ep, const Address &local_addr,
1521 const sockaddr *sa, socklen_t salen,
1522 const ngtcp2_pkt_info *pi, uint8_t *data,
1523 size_t datalen) {
1524 auto path = ngtcp2_path{
1525 {
1526 const_cast<sockaddr *>(&local_addr.su.sa),
1527 local_addr.len,
1528 },
1529 {
1530 const_cast<sockaddr *>(sa),
1531 salen,
1532 },
1533 const_cast<Endpoint *>(&ep),
1534 };
1535
1536 if (auto rv = ngtcp2_conn_read_pkt(conn_, &path, pi, data, datalen,
1537 util::timestamp(loop_));
1538 rv != 0) {
1539 std::cerr << "ngtcp2_conn_read_pkt: " << ngtcp2_strerror(rv) << std::endl;
1540 switch (rv) {
1541 case NGTCP2_ERR_DRAINING:
1542 start_draining_period();
1543 return NETWORK_ERR_CLOSE_WAIT;
1544 case NGTCP2_ERR_RETRY:
1545 return NETWORK_ERR_RETRY;
1546 case NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM:
1547 case NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM:
1548 case NGTCP2_ERR_TRANSPORT_PARAM:
1549 // If rv indicates transport_parameters related error, we should
1550 // send TRANSPORT_PARAMETER_ERROR even if last_error_.code is
1551 // already set. This is because OpenSSL might set Alert.
1552 last_error_ = quic_err_transport(rv);
1553 break;
1554 case NGTCP2_ERR_DROP_CONN:
1555 return NETWORK_ERR_DROP_CONN;
1556 default:
1557 if (!last_error_.code) {
1558 last_error_ = quic_err_transport(rv);
1559 }
1560 }
1561 return handle_error();
1562 }
1563
1564 return 0;
1565 }
1566
on_read(const Endpoint & ep,const Address & local_addr,const sockaddr * sa,socklen_t salen,const ngtcp2_pkt_info * pi,uint8_t * data,size_t datalen)1567 int Handler::on_read(const Endpoint &ep, const Address &local_addr,
1568 const sockaddr *sa, socklen_t salen,
1569 const ngtcp2_pkt_info *pi, uint8_t *data, size_t datalen) {
1570 if (auto rv = feed_data(ep, local_addr, sa, salen, pi, data, datalen);
1571 rv != 0) {
1572 return rv;
1573 }
1574
1575 reset_idle_timer();
1576
1577 return 0;
1578 }
1579
reset_idle_timer()1580 void Handler::reset_idle_timer() {
1581 auto now = util::timestamp(loop_);
1582 auto idle_expiry = ngtcp2_conn_get_idle_expiry(conn_);
1583 timer_.repeat =
1584 idle_expiry > now
1585 ? static_cast<ev_tstamp>(idle_expiry - now) / NGTCP2_SECONDS
1586 : 1e-9;
1587
1588 if (!config.quiet) {
1589 std::cerr << "Set idle timer=" << std::fixed << timer_.repeat << "s"
1590 << std::defaultfloat << std::endl;
1591 }
1592
1593 ev_timer_again(loop_, &timer_);
1594 }
1595
handle_expiry()1596 int Handler::handle_expiry() {
1597 auto now = util::timestamp(loop_);
1598 if (auto rv = ngtcp2_conn_handle_expiry(conn_, now); rv != 0) {
1599 std::cerr << "ngtcp2_conn_handle_expiry: " << ngtcp2_strerror(rv)
1600 << std::endl;
1601 last_error_ = quic_err_transport(rv);
1602 return handle_error();
1603 }
1604
1605 return 0;
1606 }
1607
on_write()1608 int Handler::on_write() {
1609 if (ngtcp2_conn_is_in_closing_period(conn_) ||
1610 ngtcp2_conn_is_in_draining_period(conn_)) {
1611 return 0;
1612 }
1613
1614 if (auto rv = write_streams(); rv != 0) {
1615 return rv;
1616 }
1617
1618 schedule_retransmit();
1619
1620 return 0;
1621 }
1622
write_streams()1623 int Handler::write_streams() {
1624 std::array<nghttp3_vec, 16> vec;
1625 ngtcp2_path_storage ps, prev_ps;
1626 uint32_t prev_ecn = 0;
1627 size_t pktcnt = 0;
1628 auto max_udp_payload_size = ngtcp2_conn_get_path_max_udp_payload_size(conn_);
1629 size_t max_pktcnt =
1630 std::min(static_cast<size_t>(64_k), ngtcp2_conn_get_send_quantum(conn_)) /
1631 max_udp_payload_size;
1632 std::array<uint8_t, 64_k> buf;
1633 uint8_t *bufpos = buf.data();
1634 ngtcp2_pkt_info pi;
1635 auto ts = util::timestamp(loop_);
1636
1637 ngtcp2_path_storage_zero(&ps);
1638 ngtcp2_path_storage_zero(&prev_ps);
1639
1640 if (config.cc_algo != NGTCP2_CC_ALGO_BBR) {
1641 /* If bbr is chosen, pacing is enabled. No need to cap the number
1642 of datagrams to send. */
1643 max_pktcnt =
1644 std::min(max_pktcnt, static_cast<size_t>(config.max_gso_dgrams));
1645 }
1646
1647 for (;;) {
1648 int64_t stream_id = -1;
1649 int fin = 0;
1650 nghttp3_ssize sveccnt = 0;
1651
1652 if (httpconn_ && ngtcp2_conn_get_max_data_left(conn_)) {
1653 sveccnt = nghttp3_conn_writev_stream(httpconn_, &stream_id, &fin,
1654 vec.data(), vec.size());
1655 if (sveccnt < 0) {
1656 std::cerr << "nghttp3_conn_writev_stream: " << nghttp3_strerror(sveccnt)
1657 << std::endl;
1658 last_error_ = quic_err_app(sveccnt);
1659 return handle_error();
1660 }
1661 }
1662
1663 ngtcp2_ssize ndatalen;
1664 auto v = vec.data();
1665 auto vcnt = static_cast<size_t>(sveccnt);
1666
1667 uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE;
1668 if (fin) {
1669 flags |= NGTCP2_WRITE_STREAM_FLAG_FIN;
1670 }
1671
1672 auto nwrite = ngtcp2_conn_writev_stream(
1673 conn_, &ps.path, &pi, bufpos, max_udp_payload_size, &ndatalen, flags,
1674 stream_id, reinterpret_cast<const ngtcp2_vec *>(v), vcnt, ts);
1675 if (nwrite < 0) {
1676 switch (nwrite) {
1677 case NGTCP2_ERR_STREAM_DATA_BLOCKED:
1678 assert(ndatalen == -1);
1679 if (auto rv = nghttp3_conn_block_stream(httpconn_, stream_id);
1680 rv != 0) {
1681 std::cerr << "nghttp3_conn_block_stream: " << nghttp3_strerror(rv)
1682 << std::endl;
1683 last_error_ = quic_err_app(rv);
1684 return handle_error();
1685 }
1686 continue;
1687 case NGTCP2_ERR_STREAM_SHUT_WR:
1688 assert(ndatalen == -1);
1689 if (auto rv = nghttp3_conn_shutdown_stream_write(httpconn_, stream_id);
1690 rv != 0) {
1691 std::cerr << "nghttp3_conn_shutdown_stream_write: "
1692 << nghttp3_strerror(rv) << std::endl;
1693 last_error_ = quic_err_app(rv);
1694 return handle_error();
1695 }
1696 continue;
1697 case NGTCP2_ERR_WRITE_MORE:
1698 assert(ndatalen >= 0);
1699 if (auto rv =
1700 nghttp3_conn_add_write_offset(httpconn_, stream_id, ndatalen);
1701 rv != 0) {
1702 std::cerr << "nghttp3_conn_add_write_offset: " << nghttp3_strerror(rv)
1703 << std::endl;
1704 last_error_ = quic_err_app(rv);
1705 return handle_error();
1706 }
1707 continue;
1708 }
1709
1710 assert(ndatalen == -1);
1711
1712 std::cerr << "ngtcp2_conn_writev_stream: " << ngtcp2_strerror(nwrite)
1713 << std::endl;
1714 last_error_ = quic_err_transport(nwrite);
1715 return handle_error();
1716 } else if (ndatalen >= 0) {
1717 if (auto rv =
1718 nghttp3_conn_add_write_offset(httpconn_, stream_id, ndatalen);
1719 rv != 0) {
1720 std::cerr << "nghttp3_conn_add_write_offset: " << nghttp3_strerror(rv)
1721 << std::endl;
1722 last_error_ = quic_err_app(rv);
1723 return handle_error();
1724 }
1725 }
1726
1727 if (nwrite == 0) {
1728 if (bufpos - buf.data()) {
1729 server_->send_packet(*static_cast<Endpoint *>(prev_ps.path.user_data),
1730 prev_ps.path.local, prev_ps.path.remote, prev_ecn,
1731 buf.data(), bufpos - buf.data(),
1732 max_udp_payload_size);
1733 reset_idle_timer();
1734 }
1735 // We are congestion limited.
1736 ngtcp2_conn_update_pkt_tx_time(conn_, ts);
1737 return 0;
1738 }
1739
1740 bufpos += nwrite;
1741
1742 #if NGTCP2_ENABLE_UDP_GSO
1743 if (pktcnt == 0) {
1744 ngtcp2_path_copy(&prev_ps.path, &ps.path);
1745 prev_ecn = pi.ecn;
1746 } else if (!ngtcp2_path_eq(&prev_ps.path, &ps.path) || prev_ecn != pi.ecn) {
1747 server_->send_packet(*static_cast<Endpoint *>(prev_ps.path.user_data),
1748 prev_ps.path.local, prev_ps.path.remote, prev_ecn,
1749 buf.data(), bufpos - buf.data() - nwrite,
1750 max_udp_payload_size);
1751
1752 server_->send_packet(*static_cast<Endpoint *>(ps.path.user_data),
1753 ps.path.local, ps.path.remote, pi.ecn,
1754 bufpos - nwrite, nwrite, max_udp_payload_size);
1755
1756 ngtcp2_conn_update_pkt_tx_time(conn_, ts);
1757 reset_idle_timer();
1758 ev_io_start(loop_, &wev_);
1759 return 0;
1760 }
1761
1762 if (++pktcnt == max_pktcnt ||
1763 static_cast<size_t>(nwrite) < max_udp_payload_size) {
1764 server_->send_packet(*static_cast<Endpoint *>(ps.path.user_data),
1765 ps.path.local, ps.path.remote, pi.ecn, buf.data(),
1766 bufpos - buf.data(), max_udp_payload_size);
1767 ngtcp2_conn_update_pkt_tx_time(conn_, ts);
1768 reset_idle_timer();
1769 ev_io_start(loop_, &wev_);
1770 return 0;
1771 }
1772 #else // !NGTCP2_ENABLE_UDP_GSO
1773 reset_idle_timer();
1774
1775 server_->send_packet(*static_cast<Endpoint *>(ps.path.user_data),
1776 ps.path.local, ps.path.remote, pi.ecn, buf.data(),
1777 bufpos - buf.data(), 0);
1778 if (++pktcnt == max_pktcnt) {
1779 ngtcp2_conn_update_pkt_tx_time(conn_, ts);
1780 ev_io_start(loop_, &wev_);
1781 return 0;
1782 }
1783
1784 bufpos = buf.data();
1785 #endif // !NGTCP2_ENABLE_UDP_GSO
1786 }
1787 }
1788
signal_write()1789 void Handler::signal_write() { ev_io_start(loop_, &wev_); }
1790
draining() const1791 bool Handler::draining() const { return draining_; }
1792
start_draining_period()1793 void Handler::start_draining_period() {
1794 draining_ = true;
1795
1796 ev_timer_stop(loop_, &rttimer_);
1797
1798 timer_.repeat =
1799 static_cast<ev_tstamp>(ngtcp2_conn_get_pto(conn_)) / NGTCP2_SECONDS * 3;
1800 ev_timer_again(loop_, &timer_);
1801
1802 if (!config.quiet) {
1803 std::cerr << "Draining period has started (" << timer_.repeat << " seconds)"
1804 << std::endl;
1805 }
1806 }
1807
start_closing_period()1808 int Handler::start_closing_period() {
1809 if (!conn_ || ngtcp2_conn_is_in_closing_period(conn_)) {
1810 return 0;
1811 }
1812
1813 ev_timer_stop(loop_, &rttimer_);
1814
1815 timer_.repeat =
1816 static_cast<ev_tstamp>(ngtcp2_conn_get_pto(conn_)) / NGTCP2_SECONDS * 3;
1817 ev_timer_again(loop_, &timer_);
1818
1819 if (!config.quiet) {
1820 std::cerr << "Closing period has started (" << timer_.repeat << " seconds)"
1821 << std::endl;
1822 }
1823
1824 conn_closebuf_ = std::make_unique<Buffer>(NGTCP2_MAX_UDP_PAYLOAD_SIZE);
1825
1826 ngtcp2_path_storage ps;
1827
1828 ngtcp2_path_storage_zero(&ps);
1829
1830 ngtcp2_pkt_info pi;
1831 if (last_error_.type == QUICErrorType::Transport) {
1832 auto n = ngtcp2_conn_write_connection_close(
1833 conn_, &ps.path, &pi, conn_closebuf_->wpos(), conn_closebuf_->left(),
1834 last_error_.code, util::timestamp(loop_));
1835 if (n < 0) {
1836 std::cerr << "ngtcp2_conn_write_connection_close: " << ngtcp2_strerror(n)
1837 << std::endl;
1838 return -1;
1839 }
1840 conn_closebuf_->push(n);
1841 } else {
1842 auto n = ngtcp2_conn_write_application_close(
1843 conn_, &ps.path, &pi, conn_closebuf_->wpos(), conn_closebuf_->left(),
1844 last_error_.code, util::timestamp(loop_));
1845 if (n < 0) {
1846 std::cerr << "ngtcp2_conn_write_application_close: " << ngtcp2_strerror(n)
1847 << std::endl;
1848 return -1;
1849 }
1850 conn_closebuf_->push(n);
1851 }
1852
1853 return 0;
1854 }
1855
handle_error()1856 int Handler::handle_error() {
1857 if (start_closing_period() != 0) {
1858 return -1;
1859 }
1860
1861 if (auto rv = send_conn_close(); rv != NETWORK_ERR_OK) {
1862 return rv;
1863 }
1864
1865 return NETWORK_ERR_CLOSE_WAIT;
1866 }
1867
send_conn_close()1868 int Handler::send_conn_close() {
1869 if (!config.quiet) {
1870 std::cerr << "Closing Period: TX CONNECTION_CLOSE" << std::endl;
1871 }
1872
1873 assert(conn_closebuf_ && conn_closebuf_->size());
1874 assert(conn_);
1875
1876 auto path = ngtcp2_conn_get_path(conn_);
1877
1878 return server_->send_packet(
1879 *static_cast<Endpoint *>(path->user_data), path->local, path->remote,
1880 /* ecn = */ 0, conn_closebuf_->rpos(), conn_closebuf_->size(), 0);
1881 }
1882
schedule_retransmit()1883 void Handler::schedule_retransmit() {
1884 auto expiry = ngtcp2_conn_get_expiry(conn_);
1885 auto now = util::timestamp(loop_);
1886 auto t = expiry < now ? 1e-9
1887 : static_cast<ev_tstamp>(expiry - now) / NGTCP2_SECONDS;
1888 if (!config.quiet) {
1889 std::cerr << "Set timer=" << std::fixed << t << "s" << std::defaultfloat
1890 << std::endl;
1891 }
1892 rttimer_.repeat = t;
1893 ev_timer_again(loop_, &rttimer_);
1894 }
1895
recv_stream_data(uint32_t flags,int64_t stream_id,const uint8_t * data,size_t datalen)1896 int Handler::recv_stream_data(uint32_t flags, int64_t stream_id,
1897 const uint8_t *data, size_t datalen) {
1898 if (!config.quiet && !config.no_quic_dump) {
1899 debug::print_stream_data(stream_id, data, datalen);
1900 }
1901
1902 if (!httpconn_) {
1903 return 0;
1904 }
1905
1906 auto nconsumed = nghttp3_conn_read_stream(
1907 httpconn_, stream_id, data, datalen, flags & NGTCP2_STREAM_DATA_FLAG_FIN);
1908 if (nconsumed < 0) {
1909 std::cerr << "nghttp3_conn_read_stream: " << nghttp3_strerror(nconsumed)
1910 << std::endl;
1911 last_error_ = quic_err_app(nconsumed);
1912 return -1;
1913 }
1914
1915 ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, nconsumed);
1916 ngtcp2_conn_extend_max_offset(conn_, nconsumed);
1917
1918 return 0;
1919 }
1920
update_key(uint8_t * rx_secret,uint8_t * tx_secret,ngtcp2_crypto_aead_ctx * rx_aead_ctx,uint8_t * rx_iv,ngtcp2_crypto_aead_ctx * tx_aead_ctx,uint8_t * tx_iv,const uint8_t * current_rx_secret,const uint8_t * current_tx_secret,size_t secretlen)1921 int Handler::update_key(uint8_t *rx_secret, uint8_t *tx_secret,
1922 ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
1923 ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
1924 const uint8_t *current_rx_secret,
1925 const uint8_t *current_tx_secret, size_t secretlen) {
1926 auto crypto_ctx = ngtcp2_conn_get_crypto_ctx(conn_);
1927 auto aead = &crypto_ctx->aead;
1928 auto keylen = ngtcp2_crypto_aead_keylen(aead);
1929 auto ivlen = ngtcp2_crypto_packet_protection_ivlen(aead);
1930
1931 ++nkey_update_;
1932
1933 std::array<uint8_t, 64> rx_key, tx_key;
1934
1935 if (ngtcp2_crypto_update_key(conn_, rx_secret, tx_secret, rx_aead_ctx,
1936 rx_key.data(), rx_iv, tx_aead_ctx, tx_key.data(),
1937 tx_iv, current_rx_secret, current_tx_secret,
1938 secretlen) != 0) {
1939 return -1;
1940 }
1941
1942 if (!config.quiet && config.show_secret) {
1943 std::cerr << "application_traffic rx secret " << nkey_update_ << std::endl;
1944 debug::print_secrets(rx_secret, secretlen, rx_key.data(), keylen, rx_iv,
1945 ivlen);
1946 std::cerr << "application_traffic tx secret " << nkey_update_ << std::endl;
1947 debug::print_secrets(tx_secret, secretlen, tx_key.data(), keylen, tx_iv,
1948 ivlen);
1949 }
1950
1951 return 0;
1952 }
1953
server() const1954 Server *Handler::server() const { return server_; }
1955
on_stream_close(int64_t stream_id,uint64_t app_error_code)1956 int Handler::on_stream_close(int64_t stream_id, uint64_t app_error_code) {
1957 if (!config.quiet) {
1958 std::cerr << "QUIC stream " << stream_id << " closed" << std::endl;
1959 }
1960
1961 if (httpconn_) {
1962 if (app_error_code == 0) {
1963 app_error_code = NGHTTP3_H3_NO_ERROR;
1964 }
1965 auto rv = nghttp3_conn_close_stream(httpconn_, stream_id, app_error_code);
1966 switch (rv) {
1967 case 0:
1968 break;
1969 case NGHTTP3_ERR_STREAM_NOT_FOUND:
1970 if (ngtcp2_is_bidi_stream(stream_id)) {
1971 assert(!ngtcp2_conn_is_local_stream(conn_, stream_id));
1972 ngtcp2_conn_extend_max_streams_bidi(conn_, 1);
1973 }
1974 break;
1975 default:
1976 std::cerr << "nghttp3_conn_close_stream: " << nghttp3_strerror(rv)
1977 << std::endl;
1978 last_error_ = quic_err_app(rv);
1979 return -1;
1980 }
1981 }
1982
1983 return 0;
1984 }
1985
shutdown_read(int64_t stream_id,int app_error_code)1986 void Handler::shutdown_read(int64_t stream_id, int app_error_code) {
1987 ngtcp2_conn_shutdown_stream_read(conn_, stream_id, app_error_code);
1988 }
1989
1990 namespace {
sreadcb(struct ev_loop * loop,ev_io * w,int revents)1991 void sreadcb(struct ev_loop *loop, ev_io *w, int revents) {
1992 auto ep = static_cast<Endpoint *>(w->data);
1993
1994 ep->server->on_read(*ep);
1995 }
1996 } // namespace
1997
1998 namespace {
siginthandler(struct ev_loop * loop,ev_signal * watcher,int revents)1999 void siginthandler(struct ev_loop *loop, ev_signal *watcher, int revents) {
2000 ev_break(loop, EVBREAK_ALL);
2001 }
2002 } // namespace
2003
Server(struct ev_loop * loop,const TLSServerContext & tls_ctx)2004 Server::Server(struct ev_loop *loop, const TLSServerContext &tls_ctx)
2005 : loop_(loop), tls_ctx_(tls_ctx) {
2006 ev_signal_init(&sigintev_, siginthandler, SIGINT);
2007 }
2008
~Server()2009 Server::~Server() {
2010 disconnect();
2011 close();
2012 }
2013
disconnect()2014 void Server::disconnect() {
2015 config.tx_loss_prob = 0;
2016
2017 for (auto &ep : endpoints_) {
2018 ev_io_stop(loop_, &ep.rev);
2019 }
2020
2021 ev_signal_stop(loop_, &sigintev_);
2022
2023 while (!handlers_.empty()) {
2024 auto it = std::begin(handlers_);
2025 auto &h = (*it).second;
2026
2027 h->handle_error();
2028
2029 remove(h);
2030 }
2031 }
2032
close()2033 void Server::close() {
2034 for (auto &ep : endpoints_) {
2035 ::close(ep.fd);
2036 }
2037
2038 endpoints_.clear();
2039 }
2040
2041 namespace {
create_sock(Address & local_addr,const char * addr,const char * port,int family)2042 int create_sock(Address &local_addr, const char *addr, const char *port,
2043 int family) {
2044 addrinfo hints{};
2045 addrinfo *res, *rp;
2046 int val = 1;
2047
2048 hints.ai_family = family;
2049 hints.ai_socktype = SOCK_DGRAM;
2050 hints.ai_flags = AI_PASSIVE;
2051
2052 if (strcmp(addr, "*") == 0) {
2053 addr = nullptr;
2054 }
2055
2056 if (auto rv = getaddrinfo(addr, port, &hints, &res); rv != 0) {
2057 std::cerr << "getaddrinfo: " << gai_strerror(rv) << std::endl;
2058 return -1;
2059 }
2060
2061 auto res_d = defer(freeaddrinfo, res);
2062
2063 int fd = -1;
2064
2065 for (rp = res; rp; rp = rp->ai_next) {
2066 fd = util::create_nonblock_socket(rp->ai_family, rp->ai_socktype,
2067 rp->ai_protocol);
2068 if (fd == -1) {
2069 continue;
2070 }
2071
2072 if (rp->ai_family == AF_INET6) {
2073 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
2074 static_cast<socklen_t>(sizeof(val))) == -1) {
2075 close(fd);
2076 continue;
2077 }
2078
2079 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val,
2080 static_cast<socklen_t>(sizeof(val))) == -1) {
2081 close(fd);
2082 continue;
2083 }
2084 } else if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &val,
2085 static_cast<socklen_t>(sizeof(val))) == -1) {
2086 close(fd);
2087 continue;
2088 }
2089
2090 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
2091 static_cast<socklen_t>(sizeof(val))) == -1) {
2092 close(fd);
2093 continue;
2094 }
2095
2096 fd_set_recv_ecn(fd, rp->ai_family);
2097
2098 if (bind(fd, rp->ai_addr, rp->ai_addrlen) != -1) {
2099 break;
2100 }
2101
2102 close(fd);
2103 }
2104
2105 if (!rp) {
2106 std::cerr << "Could not bind" << std::endl;
2107 return -1;
2108 }
2109
2110 socklen_t len = sizeof(local_addr.su.storage);
2111 if (getsockname(fd, &local_addr.su.sa, &len) == -1) {
2112 std::cerr << "getsockname: " << strerror(errno) << std::endl;
2113 close(fd);
2114 return -1;
2115 }
2116 local_addr.len = len;
2117 local_addr.ifindex = 0;
2118
2119 return fd;
2120 }
2121
2122 } // namespace
2123
2124 namespace {
add_endpoint(std::vector<Endpoint> & endpoints,const char * addr,const char * port,int af)2125 int add_endpoint(std::vector<Endpoint> &endpoints, const char *addr,
2126 const char *port, int af) {
2127 Address dest;
2128 auto fd = create_sock(dest, addr, port, af);
2129 if (fd == -1) {
2130 return -1;
2131 }
2132
2133 endpoints.emplace_back();
2134 auto &ep = endpoints.back();
2135 ep.addr = dest;
2136 ep.fd = fd;
2137 ev_io_init(&ep.rev, sreadcb, 0, EV_READ);
2138
2139 return 0;
2140 }
2141 } // namespace
2142
2143 namespace {
add_endpoint(std::vector<Endpoint> & endpoints,const Address & addr)2144 int add_endpoint(std::vector<Endpoint> &endpoints, const Address &addr) {
2145 auto fd = util::create_nonblock_socket(addr.su.sa.sa_family, SOCK_DGRAM, 0);
2146 if (fd == -1) {
2147 std::cerr << "socket: " << strerror(errno) << std::endl;
2148 return -1;
2149 }
2150
2151 int val = 1;
2152 if (addr.su.sa.sa_family == AF_INET6) {
2153 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
2154 static_cast<socklen_t>(sizeof(val))) == -1) {
2155 std::cerr << "setsockopt: " << strerror(errno) << std::endl;
2156 close(fd);
2157 return -1;
2158 }
2159
2160 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val,
2161 static_cast<socklen_t>(sizeof(val))) == -1) {
2162 std::cerr << "setsockopt: " << strerror(errno) << std::endl;
2163 close(fd);
2164 return -1;
2165 }
2166 } else if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &val,
2167 static_cast<socklen_t>(sizeof(val))) == -1) {
2168 std::cerr << "setsockopt: " << strerror(errno) << std::endl;
2169 close(fd);
2170 return -1;
2171 }
2172
2173 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
2174 static_cast<socklen_t>(sizeof(val))) == -1) {
2175 close(fd);
2176 return -1;
2177 }
2178
2179 fd_set_recv_ecn(fd, addr.su.sa.sa_family);
2180
2181 if (bind(fd, &addr.su.sa, addr.len) == -1) {
2182 std::cerr << "bind: " << strerror(errno) << std::endl;
2183 close(fd);
2184 return -1;
2185 }
2186
2187 endpoints.emplace_back(Endpoint{});
2188 auto &ep = endpoints.back();
2189 ep.addr = addr;
2190 ep.fd = fd;
2191 ev_io_init(&ep.rev, sreadcb, 0, EV_READ);
2192
2193 return 0;
2194 }
2195 } // namespace
2196
init(const char * addr,const char * port)2197 int Server::init(const char *addr, const char *port) {
2198 endpoints_.reserve(4);
2199
2200 auto ready = false;
2201 if (!util::numeric_host(addr, AF_INET6) &&
2202 add_endpoint(endpoints_, addr, port, AF_INET) == 0) {
2203 ready = true;
2204 }
2205 if (!util::numeric_host(addr, AF_INET) &&
2206 add_endpoint(endpoints_, addr, port, AF_INET6) == 0) {
2207 ready = true;
2208 }
2209 if (!ready) {
2210 return -1;
2211 }
2212
2213 if (config.preferred_ipv4_addr.len &&
2214 add_endpoint(endpoints_, config.preferred_ipv4_addr) != 0) {
2215 return -1;
2216 }
2217 if (config.preferred_ipv6_addr.len &&
2218 add_endpoint(endpoints_, config.preferred_ipv6_addr) != 0) {
2219 return -1;
2220 }
2221
2222 for (auto &ep : endpoints_) {
2223 ep.server = this;
2224 ep.rev.data = &ep;
2225
2226 ev_io_set(&ep.rev, ep.fd, EV_READ);
2227
2228 ev_io_start(loop_, &ep.rev);
2229 }
2230
2231 ev_signal_start(loop_, &sigintev_);
2232
2233 return 0;
2234 }
2235
on_read(Endpoint & ep)2236 int Server::on_read(Endpoint &ep) {
2237 sockaddr_union su;
2238 std::array<uint8_t, 64_k> buf;
2239 ngtcp2_pkt_hd hd;
2240 size_t pktcnt = 0;
2241 ngtcp2_pkt_info pi;
2242
2243 iovec msg_iov;
2244 msg_iov.iov_base = buf.data();
2245 msg_iov.iov_len = buf.size();
2246
2247 msghdr msg{};
2248 msg.msg_name = &su;
2249 msg.msg_iov = &msg_iov;
2250 msg.msg_iovlen = 1;
2251
2252 uint8_t
2253 msg_ctrl[CMSG_SPACE(sizeof(uint8_t)) + CMSG_SPACE(sizeof(in6_pktinfo))];
2254 msg.msg_control = msg_ctrl;
2255
2256 for (; pktcnt < 10;) {
2257 msg.msg_namelen = sizeof(su);
2258 msg.msg_controllen = sizeof(msg_ctrl);
2259
2260 auto nread = recvmsg(ep.fd, &msg, 0);
2261 if (nread == -1) {
2262 if (!(errno == EAGAIN || errno == ENOTCONN)) {
2263 std::cerr << "recvmsg: " << strerror(errno) << std::endl;
2264 }
2265 return 0;
2266 }
2267
2268 ++pktcnt;
2269
2270 pi.ecn = msghdr_get_ecn(&msg, su.storage.ss_family);
2271 auto local_addr = msghdr_get_local_addr(&msg, su.storage.ss_family);
2272 if (!local_addr) {
2273 std::cerr << "Unable to obtain local address" << std::endl;
2274 continue;
2275 }
2276
2277 set_port(*local_addr, ep.addr);
2278
2279 if (!config.quiet) {
2280 std::array<char, IF_NAMESIZE> ifname;
2281 std::cerr << "Received packet: local="
2282 << util::straddr(&local_addr->su.sa, local_addr->len)
2283 << " remote=" << util::straddr(&su.sa, msg.msg_namelen)
2284 << " if=" << if_indextoname(local_addr->ifindex, ifname.data())
2285 << " ecn=0x" << std::hex << pi.ecn << std::dec << " " << nread
2286 << " bytes" << std::endl;
2287 }
2288
2289 if (debug::packet_lost(config.rx_loss_prob)) {
2290 if (!config.quiet) {
2291 std::cerr << "** Simulated incoming packet loss **" << std::endl;
2292 }
2293 continue;
2294 }
2295
2296 if (nread == 0) {
2297 continue;
2298 }
2299
2300 uint32_t version;
2301 const uint8_t *dcid, *scid;
2302 size_t dcidlen, scidlen;
2303
2304 switch (auto rv = ngtcp2_pkt_decode_version_cid(&version, &dcid, &dcidlen,
2305 &scid, &scidlen, buf.data(),
2306 nread, NGTCP2_SV_SCIDLEN);
2307 rv) {
2308 case 0:
2309 break;
2310 case NGTCP2_ERR_VERSION_NEGOTIATION:
2311 send_version_negotiation(version, scid, scidlen, dcid, dcidlen, ep,
2312 *local_addr, &su.sa, msg.msg_namelen);
2313 continue;
2314 default:
2315 std::cerr << "Could not decode version and CID from QUIC packet header: "
2316 << ngtcp2_strerror(rv) << std::endl;
2317 continue;
2318 }
2319
2320 auto dcid_key = util::make_cid_key(dcid, dcidlen);
2321
2322 auto handler_it = handlers_.find(dcid_key);
2323 if (handler_it == std::end(handlers_)) {
2324 switch (auto rv = ngtcp2_accept(&hd, buf.data(), nread); rv) {
2325 case 0:
2326 break;
2327 case NGTCP2_ERR_RETRY:
2328 send_retry(&hd, ep, *local_addr, &su.sa, msg.msg_namelen);
2329 continue;
2330 case NGTCP2_ERR_VERSION_NEGOTIATION:
2331 if (!config.quiet) {
2332 std::cerr << "Unsupported version: Send Version Negotiation"
2333 << std::endl;
2334 }
2335 send_version_negotiation(hd.version, hd.scid.data, hd.scid.datalen,
2336 hd.dcid.data, hd.dcid.datalen, ep, *local_addr,
2337 &su.sa, msg.msg_namelen);
2338 continue;
2339 default:
2340 if (!config.quiet) {
2341 std::cerr << "Unexpected packet received: length=" << nread
2342 << std::endl;
2343 }
2344 continue;
2345 }
2346
2347 ngtcp2_cid ocid;
2348 ngtcp2_cid *pocid = nullptr;
2349
2350 assert(hd.type == NGTCP2_PKT_INITIAL);
2351
2352 if (config.validate_addr || hd.token.len) {
2353 std::cerr << "Perform stateless address validation" << std::endl;
2354 if (hd.token.len == 0) {
2355 send_retry(&hd, ep, *local_addr, &su.sa, msg.msg_namelen);
2356 continue;
2357 }
2358
2359 if (hd.token.base[0] != NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY &&
2360 hd.dcid.datalen < NGTCP2_MIN_INITIAL_DCIDLEN) {
2361 send_stateless_connection_close(&hd, ep, *local_addr, &su.sa,
2362 msg.msg_namelen);
2363 continue;
2364 }
2365
2366 switch (hd.token.base[0]) {
2367 case NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY:
2368 if (verify_retry_token(&ocid, &hd, &su.sa, msg.msg_namelen) != 0) {
2369 send_stateless_connection_close(&hd, ep, *local_addr, &su.sa,
2370 msg.msg_namelen);
2371 continue;
2372 }
2373 pocid = &ocid;
2374 break;
2375 case NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR:
2376 if (verify_token(&hd, &su.sa, msg.msg_namelen) != 0) {
2377 if (config.validate_addr) {
2378 send_retry(&hd, ep, *local_addr, &su.sa, msg.msg_namelen);
2379 continue;
2380 }
2381
2382 hd.token.base = nullptr;
2383 hd.token.len = 0;
2384 }
2385 break;
2386 default:
2387 if (!config.quiet) {
2388 std::cerr << "Ignore unrecognized token" << std::endl;
2389 }
2390 if (config.validate_addr) {
2391 send_retry(&hd, ep, *local_addr, &su.sa, msg.msg_namelen);
2392 continue;
2393 }
2394
2395 hd.token.base = nullptr;
2396 hd.token.len = 0;
2397 break;
2398 }
2399 }
2400
2401 auto h = std::make_unique<Handler>(loop_, this);
2402 if (h->init(ep, *local_addr, &su.sa, msg.msg_namelen, &hd.scid, &hd.dcid,
2403 pocid, hd.token.base, hd.token.len, hd.version,
2404 tls_ctx_) != 0) {
2405 continue;
2406 }
2407
2408 switch (h->on_read(ep, *local_addr, &su.sa, msg.msg_namelen, &pi,
2409 buf.data(), nread)) {
2410 case 0:
2411 break;
2412 case NETWORK_ERR_RETRY:
2413 send_retry(&hd, ep, *local_addr, &su.sa, msg.msg_namelen);
2414 continue;
2415 default:
2416 continue;
2417 }
2418
2419 switch (h->on_write()) {
2420 case 0:
2421 break;
2422 default:
2423 continue;
2424 }
2425
2426 std::array<ngtcp2_cid, 2> scids;
2427 auto conn = h->conn();
2428
2429 auto num_scid = ngtcp2_conn_get_num_scid(conn);
2430
2431 assert(num_scid <= scids.size());
2432
2433 ngtcp2_conn_get_scid(conn, scids.data());
2434
2435 for (size_t i = 0; i < num_scid; ++i) {
2436 handlers_.emplace(util::make_cid_key(&scids[i]), h.get());
2437 }
2438
2439 handlers_.emplace(dcid_key, h.get());
2440
2441 h.release();
2442
2443 continue;
2444 }
2445
2446 auto h = (*handler_it).second;
2447 if (ngtcp2_conn_is_in_closing_period(h->conn())) {
2448 // TODO do exponential backoff.
2449 switch (h->send_conn_close()) {
2450 case 0:
2451 break;
2452 default:
2453 remove(h);
2454 }
2455 continue;
2456 }
2457 if (h->draining()) {
2458 continue;
2459 }
2460
2461 if (auto rv = h->on_read(ep, *local_addr, &su.sa, msg.msg_namelen, &pi,
2462 buf.data(), nread);
2463 rv != 0) {
2464 if (rv != NETWORK_ERR_CLOSE_WAIT) {
2465 remove(h);
2466 }
2467 continue;
2468 }
2469
2470 h->signal_write();
2471 }
2472
2473 return 0;
2474 }
2475
2476 namespace {
generate_reserved_version(const sockaddr * sa,socklen_t salen,uint32_t version)2477 uint32_t generate_reserved_version(const sockaddr *sa, socklen_t salen,
2478 uint32_t version) {
2479 uint32_t h = 0x811C9DC5u;
2480 const uint8_t *p = (const uint8_t *)sa;
2481 const uint8_t *ep = p + salen;
2482 for (; p != ep; ++p) {
2483 h ^= *p;
2484 h *= 0x01000193u;
2485 }
2486 version = htonl(version);
2487 p = (const uint8_t *)&version;
2488 ep = p + sizeof(version);
2489 for (; p != ep; ++p) {
2490 h ^= *p;
2491 h *= 0x01000193u;
2492 }
2493 h &= 0xf0f0f0f0u;
2494 h |= 0x0a0a0a0au;
2495 return h;
2496 }
2497 } // namespace
2498
send_version_negotiation(uint32_t version,const uint8_t * dcid,size_t dcidlen,const uint8_t * scid,size_t scidlen,Endpoint & ep,const Address & local_addr,const sockaddr * sa,socklen_t salen)2499 int Server::send_version_negotiation(uint32_t version, const uint8_t *dcid,
2500 size_t dcidlen, const uint8_t *scid,
2501 size_t scidlen, Endpoint &ep,
2502 const Address &local_addr,
2503 const sockaddr *sa, socklen_t salen) {
2504 Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE};
2505 std::array<uint32_t, 16> sv;
2506
2507 static_assert(sv.size() >= 2 + (NGTCP2_PROTO_VER_DRAFT_MAX -
2508 NGTCP2_PROTO_VER_DRAFT_MIN + 1));
2509
2510 sv[0] = generate_reserved_version(sa, salen, version);
2511 sv[1] = NGTCP2_PROTO_VER_V1;
2512
2513 size_t svlen = 2;
2514 for (auto v = NGTCP2_PROTO_VER_DRAFT_MIN; v <= NGTCP2_PROTO_VER_DRAFT_MAX;
2515 ++v) {
2516 sv[svlen++] = v;
2517 }
2518
2519 auto nwrite = ngtcp2_pkt_write_version_negotiation(
2520 buf.wpos(), buf.left(),
2521 std::uniform_int_distribution<uint8_t>(
2522 0, std::numeric_limits<uint8_t>::max())(randgen),
2523 dcid, dcidlen, scid, scidlen, sv.data(), svlen);
2524 if (nwrite < 0) {
2525 std::cerr << "ngtcp2_pkt_write_version_negotiation: "
2526 << ngtcp2_strerror(nwrite) << std::endl;
2527 return -1;
2528 }
2529
2530 buf.push(nwrite);
2531
2532 ngtcp2_addr laddr{
2533 const_cast<sockaddr *>(&local_addr.su.sa),
2534 local_addr.len,
2535 };
2536 ngtcp2_addr raddr{
2537 const_cast<sockaddr *>(sa),
2538 salen,
2539 };
2540
2541 if (send_packet(ep, laddr, raddr, /* ecn = */ 0, buf.rpos(), buf.size(), 0) !=
2542 NETWORK_ERR_OK) {
2543 return -1;
2544 }
2545
2546 return 0;
2547 }
2548
send_retry(const ngtcp2_pkt_hd * chd,Endpoint & ep,const Address & local_addr,const sockaddr * sa,socklen_t salen)2549 int Server::send_retry(const ngtcp2_pkt_hd *chd, Endpoint &ep,
2550 const Address &local_addr, const sockaddr *sa,
2551 socklen_t salen) {
2552 std::array<char, NI_MAXHOST> host;
2553 std::array<char, NI_MAXSERV> port;
2554
2555 if (auto rv = getnameinfo(sa, salen, host.data(), host.size(), port.data(),
2556 port.size(), NI_NUMERICHOST | NI_NUMERICSERV);
2557 rv != 0) {
2558 std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
2559 return -1;
2560 }
2561
2562 if (!config.quiet) {
2563 std::cerr << "Sending Retry packet to [" << host.data()
2564 << "]:" << port.data() << std::endl;
2565 }
2566
2567 ngtcp2_cid scid;
2568
2569 scid.datalen = NGTCP2_SV_SCIDLEN;
2570 if (util::generate_secure_random(scid.data, scid.datalen) != 0) {
2571 return -1;
2572 }
2573
2574 std::array<uint8_t, NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN> token;
2575
2576 auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
2577 std::chrono::system_clock::now().time_since_epoch())
2578 .count();
2579
2580 auto tokenlen = ngtcp2_crypto_generate_retry_token(
2581 token.data(), config.static_secret.data(), config.static_secret.size(),
2582 sa, salen, &scid, &chd->dcid, t);
2583 if (tokenlen < 0) {
2584 return -1;
2585 }
2586
2587 if (!config.quiet) {
2588 std::cerr << "Generated address validation token:" << std::endl;
2589 util::hexdump(stderr, token.data(), tokenlen);
2590 }
2591
2592 Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE};
2593
2594 auto nwrite = ngtcp2_crypto_write_retry(buf.wpos(), buf.left(), chd->version,
2595 &chd->scid, &scid, &chd->dcid,
2596 token.data(), tokenlen);
2597 if (nwrite < 0) {
2598 std::cerr << "ngtcp2_crypto_write_retry failed" << std::endl;
2599 return -1;
2600 }
2601
2602 buf.push(nwrite);
2603
2604 ngtcp2_addr laddr{
2605 const_cast<sockaddr *>(&local_addr.su.sa),
2606 local_addr.len,
2607 };
2608 ngtcp2_addr raddr{
2609 const_cast<sockaddr *>(sa),
2610 salen,
2611 };
2612
2613 if (send_packet(ep, laddr, raddr, /* ecn = */ 0, buf.rpos(), buf.size(), 0) !=
2614 NETWORK_ERR_OK) {
2615 return -1;
2616 }
2617
2618 return 0;
2619 }
2620
send_stateless_connection_close(const ngtcp2_pkt_hd * chd,Endpoint & ep,const Address & local_addr,const sockaddr * sa,socklen_t salen)2621 int Server::send_stateless_connection_close(const ngtcp2_pkt_hd *chd,
2622 Endpoint &ep,
2623 const Address &local_addr,
2624 const sockaddr *sa,
2625 socklen_t salen) {
2626 Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE};
2627
2628 auto nwrite = ngtcp2_crypto_write_connection_close(
2629 buf.wpos(), buf.left(), chd->version, &chd->scid, &chd->dcid,
2630 NGTCP2_INVALID_TOKEN);
2631 if (nwrite < 0) {
2632 std::cerr << "ngtcp2_crypto_write_connection_close failed" << std::endl;
2633 return -1;
2634 }
2635
2636 buf.push(nwrite);
2637
2638 ngtcp2_addr laddr{
2639 const_cast<sockaddr *>(&local_addr.su.sa),
2640 local_addr.len,
2641 };
2642 ngtcp2_addr raddr{
2643 const_cast<sockaddr *>(sa),
2644 salen,
2645 };
2646
2647 if (send_packet(ep, laddr, raddr, /* ecn = */ 0, buf.rpos(), buf.size(), 0) !=
2648 NETWORK_ERR_OK) {
2649 return -1;
2650 }
2651
2652 return 0;
2653 }
2654
verify_retry_token(ngtcp2_cid * ocid,const ngtcp2_pkt_hd * hd,const sockaddr * sa,socklen_t salen)2655 int Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd,
2656 const sockaddr *sa, socklen_t salen) {
2657 std::array<char, NI_MAXHOST> host;
2658 std::array<char, NI_MAXSERV> port;
2659
2660 if (auto rv = getnameinfo(sa, salen, host.data(), host.size(), port.data(),
2661 port.size(), NI_NUMERICHOST | NI_NUMERICSERV);
2662 rv != 0) {
2663 std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
2664 return -1;
2665 }
2666
2667 if (!config.quiet) {
2668 std::cerr << "Verifying Retry token from [" << host.data()
2669 << "]:" << port.data() << std::endl;
2670 util::hexdump(stderr, hd->token.base, hd->token.len);
2671 }
2672
2673 auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
2674 std::chrono::system_clock::now().time_since_epoch())
2675 .count();
2676
2677 if (ngtcp2_crypto_verify_retry_token(
2678 ocid, hd->token.base, hd->token.len, config.static_secret.data(),
2679 config.static_secret.size(), sa, salen, &hd->dcid,
2680 10 * NGTCP2_SECONDS, t) != 0) {
2681 std::cerr << "Could not verify Retry token" << std::endl;
2682
2683 return -1;
2684 }
2685
2686 if (!config.quiet) {
2687 std::cerr << "Token was successfully validated" << std::endl;
2688 }
2689
2690 return 0;
2691 }
2692
verify_token(const ngtcp2_pkt_hd * hd,const sockaddr * sa,socklen_t salen)2693 int Server::verify_token(const ngtcp2_pkt_hd *hd, const sockaddr *sa,
2694 socklen_t salen) {
2695 std::array<char, NI_MAXHOST> host;
2696 std::array<char, NI_MAXSERV> port;
2697
2698 if (auto rv = getnameinfo(sa, salen, host.data(), host.size(), port.data(),
2699 port.size(), NI_NUMERICHOST | NI_NUMERICSERV);
2700 rv != 0) {
2701 std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
2702 return -1;
2703 }
2704
2705 if (!config.quiet) {
2706 std::cerr << "Verifying token from [" << host.data() << "]:" << port.data()
2707 << std::endl;
2708 util::hexdump(stderr, hd->token.base, hd->token.len);
2709 }
2710
2711 auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
2712 std::chrono::system_clock::now().time_since_epoch())
2713 .count();
2714
2715 if (ngtcp2_crypto_verify_regular_token(hd->token.base, hd->token.len,
2716 config.static_secret.data(),
2717 config.static_secret.size(), sa, salen,
2718 3600 * NGTCP2_SECONDS, t) != 0) {
2719 if (!config.quiet) {
2720 std::cerr << "Could not verify token" << std::endl;
2721 }
2722 return -1;
2723 }
2724
2725 if (!config.quiet) {
2726 std::cerr << "Token was successfully validated" << std::endl;
2727 }
2728
2729 return 0;
2730 }
2731
send_packet(Endpoint & ep,const ngtcp2_addr & local_addr,const ngtcp2_addr & remote_addr,unsigned int ecn,const uint8_t * data,size_t datalen,size_t gso_size)2732 int Server::send_packet(Endpoint &ep, const ngtcp2_addr &local_addr,
2733 const ngtcp2_addr &remote_addr, unsigned int ecn,
2734 const uint8_t *data, size_t datalen, size_t gso_size) {
2735 if (debug::packet_lost(config.tx_loss_prob)) {
2736 if (!config.quiet) {
2737 std::cerr << "** Simulated outgoing packet loss **" << std::endl;
2738 }
2739 return NETWORK_ERR_OK;
2740 }
2741
2742 iovec msg_iov;
2743 msg_iov.iov_base = const_cast<uint8_t *>(data);
2744 msg_iov.iov_len = datalen;
2745
2746 msghdr msg{};
2747 msg.msg_name = const_cast<sockaddr *>(remote_addr.addr);
2748 msg.msg_namelen = remote_addr.addrlen;
2749 msg.msg_iov = &msg_iov;
2750 msg.msg_iovlen = 1;
2751
2752 uint8_t msg_ctrl[
2753 #if NGTCP2_ENABLE_UDP_GSO
2754 CMSG_SPACE(sizeof(uint16_t)) +
2755 #endif // NGTCP2_ENABLE_UDP_GSO
2756 CMSG_SPACE(sizeof(in6_pktinfo))];
2757
2758 memset(msg_ctrl, 0, sizeof(msg_ctrl));
2759
2760 msg.msg_control = msg_ctrl;
2761 msg.msg_controllen = sizeof(msg_ctrl);
2762
2763 size_t controllen = 0;
2764
2765 auto cm = CMSG_FIRSTHDR(&msg);
2766
2767 switch (local_addr.addr->sa_family) {
2768 case AF_INET: {
2769 controllen += CMSG_SPACE(sizeof(in_pktinfo));
2770 cm->cmsg_level = IPPROTO_IP;
2771 cm->cmsg_type = IP_PKTINFO;
2772 cm->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
2773 auto pktinfo = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cm));
2774 memset(pktinfo, 0, sizeof(in_pktinfo));
2775 auto addrin = reinterpret_cast<sockaddr_in *>(local_addr.addr);
2776 pktinfo->ipi_spec_dst = addrin->sin_addr;
2777 break;
2778 }
2779 case AF_INET6: {
2780 controllen += CMSG_SPACE(sizeof(in6_pktinfo));
2781 cm->cmsg_level = IPPROTO_IPV6;
2782 cm->cmsg_type = IPV6_PKTINFO;
2783 cm->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
2784 auto pktinfo = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cm));
2785 memset(pktinfo, 0, sizeof(in6_pktinfo));
2786 auto addrin = reinterpret_cast<sockaddr_in6 *>(local_addr.addr);
2787 pktinfo->ipi6_addr = addrin->sin6_addr;
2788 break;
2789 }
2790 default:
2791 assert(0);
2792 }
2793
2794 #if NGTCP2_ENABLE_UDP_GSO
2795 if (gso_size && datalen > gso_size) {
2796 controllen += CMSG_SPACE(sizeof(uint16_t));
2797 cm = CMSG_NXTHDR(&msg, cm);
2798 cm->cmsg_level = SOL_UDP;
2799 cm->cmsg_type = UDP_SEGMENT;
2800 cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
2801 *(reinterpret_cast<uint16_t *>(CMSG_DATA(cm))) = gso_size;
2802 }
2803 #endif // NGTCP2_ENABLE_UDP_GSO
2804
2805 msg.msg_controllen = controllen;
2806
2807 if (ep.ecn != ecn) {
2808 ep.ecn = ecn;
2809 fd_set_ecn(ep.fd, ep.addr.su.storage.ss_family, ecn);
2810 }
2811
2812 ssize_t nwrite = 0;
2813
2814 do {
2815 nwrite = sendmsg(ep.fd, &msg, 0);
2816 } while (nwrite == -1 && errno == EINTR);
2817
2818 if (nwrite == -1) {
2819 std::cerr << "sendmsg: " << strerror(errno) << std::endl;
2820 // TODO We have packet which is expected to fail to send (e.g.,
2821 // path validation to old path).
2822 return NETWORK_ERR_OK;
2823 }
2824
2825 if (!config.quiet) {
2826 std::cerr << "Sent packet: local="
2827 << util::straddr(local_addr.addr, local_addr.addrlen)
2828 << " remote="
2829 << util::straddr(remote_addr.addr, remote_addr.addrlen)
2830 << " ecn=0x" << std::hex << ecn << std::dec << " " << nwrite
2831 << " bytes" << std::endl;
2832 }
2833
2834 return NETWORK_ERR_OK;
2835 }
2836
associate_cid(const ngtcp2_cid * cid,Handler * h)2837 void Server::associate_cid(const ngtcp2_cid *cid, Handler *h) {
2838 handlers_.emplace(util::make_cid_key(cid), h);
2839 }
2840
dissociate_cid(const ngtcp2_cid * cid)2841 void Server::dissociate_cid(const ngtcp2_cid *cid) {
2842 handlers_.erase(util::make_cid_key(cid));
2843 }
2844
remove(const Handler * h)2845 void Server::remove(const Handler *h) {
2846 auto conn = h->conn();
2847
2848 handlers_.erase(
2849 util::make_cid_key(ngtcp2_conn_get_client_initial_dcid(conn)));
2850
2851 std::vector<ngtcp2_cid> cids(ngtcp2_conn_get_num_scid(conn));
2852 ngtcp2_conn_get_scid(conn, cids.data());
2853
2854 for (auto &cid : cids) {
2855 handlers_.erase(util::make_cid_key(&cid));
2856 }
2857
2858 delete h;
2859 }
2860
2861 namespace {
parse_host_port(Address & dest,int af,const char * first,const char * last)2862 int parse_host_port(Address &dest, int af, const char *first,
2863 const char *last) {
2864 if (std::distance(first, last) == 0) {
2865 return -1;
2866 }
2867
2868 const char *host_begin, *host_end, *it;
2869 if (*first == '[') {
2870 host_begin = first + 1;
2871 it = std::find(host_begin, last, ']');
2872 if (it == last) {
2873 return -1;
2874 }
2875 host_end = it;
2876 ++it;
2877 if (it == last || *it != ':') {
2878 return -1;
2879 }
2880 } else {
2881 host_begin = first;
2882 it = std::find(host_begin, last, ':');
2883 if (it == last) {
2884 return -1;
2885 }
2886 host_end = it;
2887 }
2888
2889 if (++it == last) {
2890 return -1;
2891 }
2892 auto svc_begin = it;
2893
2894 std::array<char, NI_MAXHOST> host;
2895 *std::copy(host_begin, host_end, std::begin(host)) = '\0';
2896
2897 addrinfo hints{}, *res;
2898 hints.ai_family = af;
2899 hints.ai_socktype = SOCK_DGRAM;
2900
2901 if (auto rv = getaddrinfo(host.data(), svc_begin, &hints, &res); rv != 0) {
2902 std::cerr << "getaddrinfo: [" << host.data() << "]:" << svc_begin << ": "
2903 << gai_strerror(rv) << std::endl;
2904 return -1;
2905 }
2906
2907 dest.len = res->ai_addrlen;
2908 memcpy(&dest.su, res->ai_addr, res->ai_addrlen);
2909
2910 freeaddrinfo(res);
2911
2912 return 0;
2913 }
2914 } // namespace
2915
2916 namespace {
print_usage()2917 void print_usage() {
2918 std::cerr << "Usage: server [OPTIONS] <ADDR> <PORT> <PRIVATE_KEY_FILE> "
2919 "<CERTIFICATE_FILE>"
2920 << std::endl;
2921 }
2922 } // namespace
2923
2924 namespace {
config_set_default(Config & config)2925 void config_set_default(Config &config) {
2926 config = Config{};
2927 config.tx_loss_prob = 0.;
2928 config.rx_loss_prob = 0.;
2929 config.ciphers = util::crypto_default_ciphers();
2930 config.groups = util::crypto_default_groups();
2931 config.timeout = 30 * NGTCP2_SECONDS;
2932 {
2933 auto path = realpath(".", nullptr);
2934 assert(path);
2935 config.htdocs = path;
2936 free(path);
2937 }
2938 config.mime_types_file = "/etc/mime.types";
2939 config.max_data = 1_m;
2940 config.max_stream_data_bidi_local = 256_k;
2941 config.max_stream_data_bidi_remote = 256_k;
2942 config.max_stream_data_uni = 256_k;
2943 config.max_window = 6_m;
2944 config.max_stream_window = 6_m;
2945 config.max_streams_bidi = 100;
2946 config.max_streams_uni = 3;
2947 config.max_dyn_length = 20_m;
2948 config.cc_algo = NGTCP2_CC_ALGO_CUBIC;
2949 config.initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT;
2950 config.max_gso_dgrams = 10;
2951 }
2952 } // namespace
2953
2954 namespace {
print_help()2955 void print_help() {
2956 print_usage();
2957
2958 config_set_default(config);
2959
2960 std::cout << R"(
2961 <ADDR> Address to listen to. '*' binds to any address.
2962 <PORT> Port
2963 <PRIVATE_KEY_FILE>
2964 Path to private key file
2965 <CERTIFICATE_FILE>
2966 Path to certificate file
2967 Options:
2968 -t, --tx-loss=<P>
2969 The probability of losing outgoing packets. <P> must be
2970 [0.0, 1.0], inclusive. 0.0 means no packet loss. 1.0
2971 means 100% packet loss.
2972 -r, --rx-loss=<P>
2973 The probability of losing incoming packets. <P> must be
2974 [0.0, 1.0], inclusive. 0.0 means no packet loss. 1.0
2975 means 100% packet loss.
2976 --ciphers=<CIPHERS>
2977 Specify the cipher suite list to enable.
2978 Default: )"
2979 << config.ciphers << R"(
2980 --groups=<GROUPS>
2981 Specify the supported groups.
2982 Default: )"
2983 << config.groups << R"(
2984 -d, --htdocs=<PATH>
2985 Specify document root. If this option is not specified,
2986 the document root is the current working directory.
2987 -q, --quiet Suppress debug output.
2988 -s, --show-secret
2989 Print out secrets unless --quiet is used.
2990 --timeout=<DURATION>
2991 Specify idle timeout.
2992 Default: )"
2993 << util::format_duration(config.timeout) << R"(
2994 -V, --validate-addr
2995 Perform address validation.
2996 --preferred-ipv4-addr=<ADDR>:<PORT>
2997 Specify preferred IPv4 address and port.
2998 --preferred-ipv6-addr=<ADDR>:<PORT>
2999 Specify preferred IPv6 address and port. A numeric IPv6
3000 address must be enclosed by '[' and ']' (e.g.,
3001 [::1]:8443)
3002 --mime-types-file=<PATH>
3003 Path to file that contains MIME media types and the
3004 extensions.
3005 Default: )"
3006 << config.mime_types_file << R"(
3007 --early-response
3008 Start sending response when it receives HTTP header
3009 fields without waiting for request body. If HTTP
3010 response data is written before receiving request body,
3011 STOP_SENDING is sent.
3012 --verify-client
3013 Request a client certificate. At the moment, we just
3014 request a certificate and no verification is done.
3015 --qlog-dir=<PATH>
3016 Path to the directory where qlog file is stored. The
3017 file name of each qlog is the Source Connection ID of
3018 server.
3019 --no-quic-dump
3020 Disables printing QUIC STREAM and CRYPTO frame data out.
3021 --no-http-dump
3022 Disables printing HTTP response body out.
3023 --max-data=<SIZE>
3024 The initial connection-level flow control window.
3025 Default: )"
3026 << util::format_uint_iec(config.max_data) << R"(
3027 --max-stream-data-bidi-local=<SIZE>
3028 The initial stream-level flow control window for a
3029 bidirectional stream that the local endpoint initiates.
3030 Default: )"
3031 << util::format_uint_iec(config.max_stream_data_bidi_local) << R"(
3032 --max-stream-data-bidi-remote=<SIZE>
3033 The initial stream-level flow control window for a
3034 bidirectional stream that the remote endpoint initiates.
3035 Default: )"
3036 << util::format_uint_iec(config.max_stream_data_bidi_remote) << R"(
3037 --max-stream-data-uni=<SIZE>
3038 The initial stream-level flow control window for a
3039 unidirectional stream.
3040 Default: )"
3041 << util::format_uint_iec(config.max_stream_data_uni) << R"(
3042 --max-streams-bidi=<N>
3043 The number of the concurrent bidirectional streams.
3044 Default: )"
3045 << config.max_streams_bidi << R"(
3046 --max-streams-uni=<N>
3047 The number of the concurrent unidirectional streams.
3048 Default: )"
3049 << config.max_streams_uni << R"(
3050 --max-dyn-length=<SIZE>
3051 The maximum length of a dynamically generated content.
3052 Default: )"
3053 << util::format_uint_iec(config.max_dyn_length) << R"(
3054 --cc=(cubic|reno|bbr)
3055 The name of congestion controller algorithm.
3056 Default: )"
3057 << util::strccalgo(config.cc_algo) << R"(
3058 --initial-rtt=<DURATION>
3059 Set an initial RTT.
3060 Default: )"
3061 << util::format_duration(config.initial_rtt) << R"(
3062 --max-udp-payload-size=<SIZE>
3063 Override maximum UDP payload size that server transmits.
3064 --send-trailers
3065 Send trailer fields.
3066 --max-window=<SIZE>
3067 Maximum connection-level flow control window size. The
3068 window auto-tuning is enabled if nonzero value is given,
3069 and window size is scaled up to this value.
3070 Default: )"
3071 << util::format_uint_iec(config.max_window) << R"(
3072 --max-stream-window=<SIZE>
3073 Maximum stream-level flow control window size. The
3074 window auto-tuning is enabled if nonzero value is given,
3075 and window size is scaled up to this value.
3076 Default: )"
3077 << util::format_uint_iec(config.max_stream_window) << R"(
3078 --max-gso-dgrams=<N>
3079 Maximum number of UDP datagrams that are sent in a
3080 single GSO sendmsg call.
3081 Default: )"
3082 << config.max_gso_dgrams << R"(
3083 -h, --help Display this help and exit.
3084
3085 ---
3086
3087 The <SIZE> argument is an integer and an optional unit (e.g., 10K is
3088 10 * 1024). Units are K, M and G (powers of 1024).
3089
3090 The <DURATION> argument is an integer and an optional unit (e.g., 1s
3091 is 1 second and 500ms is 500 milliseconds). Units are h, m, s, ms,
3092 us, or ns (hours, minutes, seconds, milliseconds, microseconds, and
3093 nanoseconds respectively). If a unit is omitted, a second is used
3094 as unit.)" << std::endl;
3095 }
3096 } // namespace
3097
3098 std::ofstream keylog_file;
3099
main(int argc,char ** argv)3100 int main(int argc, char **argv) {
3101 config_set_default(config);
3102
3103 for (;;) {
3104 static int flag = 0;
3105 constexpr static option long_opts[] = {
3106 {"help", no_argument, nullptr, 'h'},
3107 {"tx-loss", required_argument, nullptr, 't'},
3108 {"rx-loss", required_argument, nullptr, 'r'},
3109 {"htdocs", required_argument, nullptr, 'd'},
3110 {"quiet", no_argument, nullptr, 'q'},
3111 {"show-secret", no_argument, nullptr, 's'},
3112 {"validate-addr", no_argument, nullptr, 'V'},
3113 {"ciphers", required_argument, &flag, 1},
3114 {"groups", required_argument, &flag, 2},
3115 {"timeout", required_argument, &flag, 3},
3116 {"preferred-ipv4-addr", required_argument, &flag, 4},
3117 {"preferred-ipv6-addr", required_argument, &flag, 5},
3118 {"mime-types-file", required_argument, &flag, 6},
3119 {"early-response", no_argument, &flag, 7},
3120 {"verify-client", no_argument, &flag, 8},
3121 {"qlog-dir", required_argument, &flag, 9},
3122 {"no-quic-dump", no_argument, &flag, 10},
3123 {"no-http-dump", no_argument, &flag, 11},
3124 {"max-data", required_argument, &flag, 12},
3125 {"max-stream-data-bidi-local", required_argument, &flag, 13},
3126 {"max-stream-data-bidi-remote", required_argument, &flag, 14},
3127 {"max-stream-data-uni", required_argument, &flag, 15},
3128 {"max-streams-bidi", required_argument, &flag, 16},
3129 {"max-streams-uni", required_argument, &flag, 17},
3130 {"max-dyn-length", required_argument, &flag, 18},
3131 {"cc", required_argument, &flag, 19},
3132 {"initial-rtt", required_argument, &flag, 20},
3133 {"max-udp-payload-size", required_argument, &flag, 21},
3134 {"send-trailers", no_argument, &flag, 22},
3135 {"max-window", required_argument, &flag, 23},
3136 {"max-stream-window", required_argument, &flag, 24},
3137 {"max-gso-dgrams", required_argument, &flag, 25},
3138 {nullptr, 0, nullptr, 0}};
3139
3140 auto optidx = 0;
3141 auto c = getopt_long(argc, argv, "d:hqr:st:V", long_opts, &optidx);
3142 if (c == -1) {
3143 break;
3144 }
3145 switch (c) {
3146 case 'd': {
3147 // --htdocs
3148 auto path = realpath(optarg, nullptr);
3149 if (path == nullptr) {
3150 std::cerr << "path: invalid path " << std::quoted(optarg) << std::endl;
3151 exit(EXIT_FAILURE);
3152 }
3153 config.htdocs = path;
3154 free(path);
3155 break;
3156 }
3157 case 'h':
3158 // --help
3159 print_help();
3160 exit(EXIT_SUCCESS);
3161 case 'q':
3162 // --quiet
3163 config.quiet = true;
3164 break;
3165 case 'r':
3166 // --rx-loss
3167 config.rx_loss_prob = strtod(optarg, nullptr);
3168 break;
3169 case 's':
3170 // --show-secret
3171 config.show_secret = true;
3172 break;
3173 case 't':
3174 // --tx-loss
3175 config.tx_loss_prob = strtod(optarg, nullptr);
3176 break;
3177 case 'V':
3178 // --validate-addr
3179 config.validate_addr = true;
3180 break;
3181 case '?':
3182 print_usage();
3183 exit(EXIT_FAILURE);
3184 case 0:
3185 switch (flag) {
3186 case 1:
3187 // --ciphers
3188 config.ciphers = optarg;
3189 break;
3190 case 2:
3191 // --groups
3192 config.groups = optarg;
3193 break;
3194 case 3:
3195 // --timeout
3196 if (auto t = util::parse_duration(optarg); !t) {
3197 std::cerr << "timeout: invalid argument" << std::endl;
3198 exit(EXIT_FAILURE);
3199 } else {
3200 config.timeout = *t;
3201 }
3202 break;
3203 case 4:
3204 // --preferred-ipv4-addr
3205 if (parse_host_port(config.preferred_ipv4_addr, AF_INET, optarg,
3206 optarg + strlen(optarg)) != 0) {
3207 std::cerr << "preferred-ipv4-addr: could not use "
3208 << std::quoted(optarg) << std::endl;
3209 exit(EXIT_FAILURE);
3210 }
3211 break;
3212 case 5:
3213 // --preferred-ipv6-addr
3214 if (parse_host_port(config.preferred_ipv6_addr, AF_INET6, optarg,
3215 optarg + strlen(optarg)) != 0) {
3216 std::cerr << "preferred-ipv6-addr: could not use "
3217 << std::quoted(optarg) << std::endl;
3218 exit(EXIT_FAILURE);
3219 }
3220 break;
3221 case 6:
3222 // --mime-types-file
3223 config.mime_types_file = optarg;
3224 break;
3225 case 7:
3226 // --early-response
3227 config.early_response = true;
3228 break;
3229 case 8:
3230 // --verify-client
3231 config.verify_client = true;
3232 break;
3233 case 9:
3234 // --qlog-dir
3235 config.qlog_dir = optarg;
3236 break;
3237 case 10:
3238 // --no-quic-dump
3239 config.no_quic_dump = true;
3240 break;
3241 case 11:
3242 // --no-http-dump
3243 config.no_http_dump = true;
3244 break;
3245 case 12:
3246 // --max-data
3247 if (auto n = util::parse_uint_iec(optarg); !n) {
3248 std::cerr << "max-data: invalid argument" << std::endl;
3249 exit(EXIT_FAILURE);
3250 } else {
3251 config.max_data = *n;
3252 }
3253 break;
3254 case 13:
3255 // --max-stream-data-bidi-local
3256 if (auto n = util::parse_uint_iec(optarg); !n) {
3257 std::cerr << "max-stream-data-bidi-local: invalid argument"
3258 << std::endl;
3259 exit(EXIT_FAILURE);
3260 } else {
3261 config.max_stream_data_bidi_local = *n;
3262 }
3263 break;
3264 case 14:
3265 // --max-stream-data-bidi-remote
3266 if (auto n = util::parse_uint_iec(optarg); !n) {
3267 std::cerr << "max-stream-data-bidi-remote: invalid argument"
3268 << std::endl;
3269 exit(EXIT_FAILURE);
3270 } else {
3271 config.max_stream_data_bidi_remote = *n;
3272 }
3273 break;
3274 case 15:
3275 // --max-stream-data-uni
3276 if (auto n = util::parse_uint_iec(optarg); !n) {
3277 std::cerr << "max-stream-data-uni: invalid argument" << std::endl;
3278 exit(EXIT_FAILURE);
3279 } else {
3280 config.max_stream_data_uni = *n;
3281 }
3282 break;
3283 case 16:
3284 // --max-streams-bidi
3285 if (auto n = util::parse_uint(optarg); !n) {
3286 std::cerr << "max-streams-bidi: invalid argument" << std::endl;
3287 exit(EXIT_FAILURE);
3288 } else {
3289 config.max_streams_bidi = *n;
3290 }
3291 break;
3292 case 17:
3293 // --max-streams-uni
3294 if (auto n = util::parse_uint(optarg); !n) {
3295 std::cerr << "max-streams-uni: invalid argument" << std::endl;
3296 exit(EXIT_FAILURE);
3297 } else {
3298 config.max_streams_uni = *n;
3299 }
3300 break;
3301 case 18:
3302 // --max-dyn-length
3303 if (auto n = util::parse_uint_iec(optarg); !n) {
3304 std::cerr << "max-dyn-length: invalid argument" << std::endl;
3305 exit(EXIT_FAILURE);
3306 } else {
3307 config.max_dyn_length = *n;
3308 }
3309 break;
3310 case 19:
3311 // --cc
3312 if (strcmp("cubic", optarg) == 0) {
3313 config.cc_algo = NGTCP2_CC_ALGO_CUBIC;
3314 break;
3315 }
3316 if (strcmp("reno", optarg) == 0) {
3317 config.cc_algo = NGTCP2_CC_ALGO_RENO;
3318 break;
3319 }
3320 if (strcmp("bbr", optarg) == 0) {
3321 config.cc_algo = NGTCP2_CC_ALGO_BBR;
3322 break;
3323 }
3324 std::cerr << "cc: specify cubic, reno, or bbr" << std::endl;
3325 exit(EXIT_FAILURE);
3326 case 20:
3327 // --initial-rtt
3328 if (auto t = util::parse_duration(optarg); !t) {
3329 std::cerr << "initial-rtt: invalid argument" << std::endl;
3330 exit(EXIT_FAILURE);
3331 } else {
3332 config.initial_rtt = *t;
3333 }
3334 break;
3335 case 21:
3336 // --max-udp-payload-size
3337 if (auto n = util::parse_uint_iec(optarg); !n) {
3338 std::cerr << "max-udp-payload-size: invalid argument" << std::endl;
3339 exit(EXIT_FAILURE);
3340 } else if (*n > 64_k) {
3341 std::cerr << "max-udp-payload-size: must not exceed 65536"
3342 << std::endl;
3343 exit(EXIT_FAILURE);
3344 } else {
3345 config.max_udp_payload_size = *n;
3346 }
3347 break;
3348 case 22:
3349 // --send-trailers
3350 config.send_trailers = true;
3351 break;
3352 case 23:
3353 // --max-window
3354 if (auto n = util::parse_uint_iec(optarg); !n) {
3355 std::cerr << "max-window: invalid argument" << std::endl;
3356 exit(EXIT_FAILURE);
3357 } else {
3358 config.max_window = *n;
3359 }
3360 break;
3361 case 24:
3362 // --max-stream-window
3363 if (auto n = util::parse_uint_iec(optarg); !n) {
3364 std::cerr << "max-stream-window: invalid argument" << std::endl;
3365 exit(EXIT_FAILURE);
3366 } else {
3367 config.max_stream_window = *n;
3368 }
3369 break;
3370 case 25:
3371 // --max-gso-dgrams
3372 if (auto n = util::parse_uint(optarg); !n) {
3373 std::cerr << "max-gso-dgrams: invalid argument" << std::endl;
3374 exit(EXIT_FAILURE);
3375 } else {
3376 config.max_gso_dgrams = *n;
3377 }
3378 break;
3379 }
3380 break;
3381 default:
3382 break;
3383 };
3384 }
3385
3386 if (argc - optind < 4) {
3387 std::cerr << "Too few arguments" << std::endl;
3388 print_usage();
3389 exit(EXIT_FAILURE);
3390 }
3391
3392 auto addr = argv[optind++];
3393 auto port = argv[optind++];
3394 auto private_key_file = argv[optind++];
3395 auto cert_file = argv[optind++];
3396
3397 if (auto n = util::parse_uint(port); !n) {
3398 std::cerr << "port: invalid port number" << std::endl;
3399 exit(EXIT_FAILURE);
3400 } else if (*n > 65535) {
3401 std::cerr << "port: must not exceed 65535" << std::endl;
3402 exit(EXIT_FAILURE);
3403 } else {
3404 config.port = *n;
3405 }
3406
3407 if (auto mt = util::read_mime_types(config.mime_types_file); !mt) {
3408 std::cerr << "mime-types-file: Could not read MIME media types file "
3409 << std::quoted(config.mime_types_file) << std::endl;
3410 } else {
3411 config.mime_types = std::move(*mt);
3412 }
3413
3414 TLSServerContext tls_ctx;
3415
3416 if (tls_ctx.init(private_key_file, cert_file, AppProtocol::H3) != 0) {
3417 exit(EXIT_FAILURE);
3418 }
3419
3420 if (config.htdocs.back() != '/') {
3421 config.htdocs += '/';
3422 }
3423
3424 std::cerr << "Using document root " << config.htdocs << std::endl;
3425
3426 auto ev_loop_d = defer(ev_loop_destroy, EV_DEFAULT);
3427
3428 auto keylog_filename = getenv("SSLKEYLOGFILE");
3429 if (keylog_filename) {
3430 keylog_file.open(keylog_filename, std::ios_base::app);
3431 if (keylog_file) {
3432 tls_ctx.enable_keylog();
3433 }
3434 }
3435
3436 if (util::generate_secret(config.static_secret.data(),
3437 config.static_secret.size()) != 0) {
3438 std::cerr << "Unable to generate static secret" << std::endl;
3439 exit(EXIT_FAILURE);
3440 }
3441
3442 Server s(EV_DEFAULT, tls_ctx);
3443 if (s.init(addr, port) != 0) {
3444 exit(EXIT_FAILURE);
3445 }
3446
3447 ev_run(EV_DEFAULT, 0);
3448
3449 s.disconnect();
3450 s.close();
3451
3452 return EXIT_SUCCESS;
3453 }
3454