Imported Upstream version 1.46.0
[platform/upstream/nghttp2.git] / src / h2load.cc
1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2014 Tatsuhiro Tsujikawa
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 "h2load.h"
26
27 #include <getopt.h>
28 #include <signal.h>
29 #ifdef HAVE_NETINET_IN_H
30 #  include <netinet/in.h>
31 #endif // HAVE_NETINET_IN_H
32 #include <netinet/tcp.h>
33 #include <sys/stat.h>
34 #ifdef HAVE_FCNTL_H
35 #  include <fcntl.h>
36 #endif // HAVE_FCNTL_H
37 #include <sys/mman.h>
38 #include <netinet/udp.h>
39
40 #include <cstdio>
41 #include <cassert>
42 #include <cstdlib>
43 #include <iostream>
44 #include <iomanip>
45 #include <fstream>
46 #include <chrono>
47 #include <thread>
48 #include <future>
49 #include <random>
50
51 #include <openssl/err.h>
52
53 #ifdef ENABLE_HTTP3
54 #  include <ngtcp2/ngtcp2.h>
55 #endif // ENABLE_HTTP3
56
57 #include "url-parser/url_parser.h"
58
59 #include "h2load_http1_session.h"
60 #include "h2load_http2_session.h"
61 #ifdef ENABLE_HTTP3
62 #  include "h2load_http3_session.h"
63 #  include "h2load_quic.h"
64 #endif // ENABLE_HTTP3
65 #include "tls.h"
66 #include "http2.h"
67 #include "util.h"
68 #include "template.h"
69
70 #ifndef O_BINARY
71 #  define O_BINARY (0)
72 #endif // O_BINARY
73
74 using namespace nghttp2;
75
76 namespace h2load {
77
78 namespace {
79 bool recorded(const std::chrono::steady_clock::time_point &t) {
80   return std::chrono::steady_clock::duration::zero() != t.time_since_epoch();
81 }
82 } // namespace
83
84 #if OPENSSL_1_1_1_API
85 namespace {
86 std::ofstream keylog_file;
87 void keylog_callback(const SSL *ssl, const char *line) {
88   keylog_file.write(line, strlen(line));
89   keylog_file.put('\n');
90   keylog_file.flush();
91 }
92 } // namespace
93 #endif // OPENSSL_1_1_1_API
94
95 Config::Config()
96     : ciphers(tls::DEFAULT_CIPHER_LIST),
97       tls13_ciphers("TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_"
98                     "CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256"),
99       groups("X25519:P-256:P-384:P-521"),
100       data_length(-1),
101       data(nullptr),
102       addrs(nullptr),
103       nreqs(1),
104       nclients(1),
105       nthreads(1),
106       max_concurrent_streams(1),
107       window_bits(30),
108       connection_window_bits(30),
109       rate(0),
110       rate_period(1.0),
111       duration(0.0),
112       warm_up_time(0.0),
113       conn_active_timeout(0.),
114       conn_inactivity_timeout(0.),
115       no_tls_proto(PROTO_HTTP2),
116       header_table_size(4_k),
117       encoder_header_table_size(4_k),
118       data_fd(-1),
119       log_fd(-1),
120       qlog_file_base(),
121       port(0),
122       default_port(0),
123       connect_to_port(0),
124       verbose(false),
125       timing_script(false),
126       base_uri_unix(false),
127       unix_addr{},
128       rps(0.),
129       no_udp_gso(false),
130       max_udp_payload_size(0) {}
131
132 Config::~Config() {
133   if (addrs) {
134     if (base_uri_unix) {
135       delete addrs;
136     } else {
137       freeaddrinfo(addrs);
138     }
139   }
140
141   if (data_fd != -1) {
142     close(data_fd);
143   }
144 }
145
146 bool Config::is_rate_mode() const { return (this->rate != 0); }
147 bool Config::is_timing_based_mode() const { return (this->duration > 0); }
148 bool Config::has_base_uri() const { return (!this->base_uri.empty()); }
149 bool Config::rps_enabled() const { return this->rps > 0.0; }
150 bool Config::is_quic() const {
151 #ifdef ENABLE_HTTP3
152   return !npn_list.empty() &&
153          (npn_list[0] == NGHTTP3_ALPN_H3 || npn_list[0] == "\x5h3-29");
154 #else  // !ENABLE_HTTP3
155   return false;
156 #endif // !ENABLE_HTTP3
157 }
158 Config config;
159
160 namespace {
161 constexpr size_t MAX_SAMPLES = 1000000;
162 } // namespace
163
164 Stats::Stats(size_t req_todo, size_t nclients)
165     : req_todo(req_todo),
166       req_started(0),
167       req_done(0),
168       req_success(0),
169       req_status_success(0),
170       req_failed(0),
171       req_error(0),
172       req_timedout(0),
173       bytes_total(0),
174       bytes_head(0),
175       bytes_head_decomp(0),
176       bytes_body(0),
177       status(),
178       udp_dgram_recv(0),
179       udp_dgram_sent(0) {}
180
181 Stream::Stream() : req_stat{}, status_success(-1) {}
182
183 namespace {
184 std::random_device rd;
185 } // namespace
186
187 namespace {
188 std::mt19937 gen(rd());
189 } // namespace
190
191 namespace {
192 void sampling_init(Sampling &smp, size_t max_samples) {
193   smp.n = 0;
194   smp.max_samples = max_samples;
195 }
196 } // namespace
197
198 namespace {
199 void writecb(struct ev_loop *loop, ev_io *w, int revents) {
200   auto client = static_cast<Client *>(w->data);
201   client->restart_timeout();
202   auto rv = client->do_write();
203   if (rv == Client::ERR_CONNECT_FAIL) {
204     client->disconnect();
205     // Try next address
206     client->current_addr = nullptr;
207     rv = client->connect();
208     if (rv != 0) {
209       client->fail();
210       client->worker->free_client(client);
211       delete client;
212       return;
213     }
214     return;
215   }
216   if (rv != 0) {
217     client->fail();
218     client->worker->free_client(client);
219     delete client;
220   }
221 }
222 } // namespace
223
224 namespace {
225 void readcb(struct ev_loop *loop, ev_io *w, int revents) {
226   auto client = static_cast<Client *>(w->data);
227   client->restart_timeout();
228   if (client->do_read() != 0) {
229     if (client->try_again_or_fail() == 0) {
230       return;
231     }
232     client->worker->free_client(client);
233     delete client;
234     return;
235   }
236   client->signal_write();
237 }
238 } // namespace
239
240 namespace {
241 // Called every rate_period when rate mode is being used
242 void rate_period_timeout_w_cb(struct ev_loop *loop, ev_timer *w, int revents) {
243   auto worker = static_cast<Worker *>(w->data);
244   auto nclients_per_second = worker->rate;
245   auto conns_remaining = worker->nclients - worker->nconns_made;
246   auto nclients = std::min(nclients_per_second, conns_remaining);
247
248   for (size_t i = 0; i < nclients; ++i) {
249     auto req_todo = worker->nreqs_per_client;
250     if (worker->nreqs_rem > 0) {
251       ++req_todo;
252       --worker->nreqs_rem;
253     }
254     auto client =
255         std::make_unique<Client>(worker->next_client_id++, worker, req_todo);
256
257     ++worker->nconns_made;
258
259     if (client->connect() != 0) {
260       std::cerr << "client could not connect to host" << std::endl;
261       client->fail();
262     } else {
263       if (worker->config->is_timing_based_mode()) {
264         worker->clients.push_back(client.release());
265       } else {
266         client.release();
267       }
268     }
269     worker->report_rate_progress();
270   }
271   if (!worker->config->is_timing_based_mode()) {
272     if (worker->nconns_made >= worker->nclients) {
273       ev_timer_stop(worker->loop, w);
274     }
275   } else {
276     // To check whether all created clients are pushed correctly
277     assert(worker->nclients == worker->clients.size());
278   }
279 }
280 } // namespace
281
282 namespace {
283 // Called when the duration for infinite number of requests are over
284 void duration_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
285   auto worker = static_cast<Worker *>(w->data);
286
287   worker->current_phase = Phase::DURATION_OVER;
288
289   std::cout << "Main benchmark duration is over for thread #" << worker->id
290             << ". Stopping all clients." << std::endl;
291   worker->stop_all_clients();
292   std::cout << "Stopped all clients for thread #" << worker->id << std::endl;
293 }
294 } // namespace
295
296 namespace {
297 // Called when the warmup duration for infinite number of requests are over
298 void warmup_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
299   auto worker = static_cast<Worker *>(w->data);
300
301   std::cout << "Warm-up phase is over for thread #" << worker->id << "."
302             << std::endl;
303   std::cout << "Main benchmark duration is started for thread #" << worker->id
304             << "." << std::endl;
305   assert(worker->stats.req_started == 0);
306   assert(worker->stats.req_done == 0);
307
308   for (auto client : worker->clients) {
309     if (client) {
310       assert(client->req_todo == 0);
311       assert(client->req_left == 1);
312       assert(client->req_inflight == 0);
313       assert(client->req_started == 0);
314       assert(client->req_done == 0);
315
316       client->record_client_start_time();
317       client->clear_connect_times();
318       client->record_connect_start_time();
319     }
320   }
321
322   worker->current_phase = Phase::MAIN_DURATION;
323
324   ev_timer_start(worker->loop, &worker->duration_watcher);
325 }
326 } // namespace
327
328 namespace {
329 void rps_cb(struct ev_loop *loop, ev_timer *w, int revents) {
330   auto client = static_cast<Client *>(w->data);
331   auto &session = client->session;
332
333   assert(!config.timing_script);
334
335   if (client->req_left == 0) {
336     ev_timer_stop(loop, w);
337     return;
338   }
339
340   auto now = ev_now(loop);
341   auto d = now - client->rps_duration_started;
342   auto n = static_cast<size_t>(round(d * config.rps));
343   client->rps_req_pending += n;
344   client->rps_duration_started = now - d + static_cast<double>(n) / config.rps;
345
346   if (client->rps_req_pending == 0) {
347     return;
348   }
349
350   auto nreq = session->max_concurrent_streams() - client->rps_req_inflight;
351   if (nreq == 0) {
352     return;
353   }
354
355   nreq = config.is_timing_based_mode() ? std::max(nreq, client->req_left)
356                                        : std::min(nreq, client->req_left);
357   nreq = std::min(nreq, client->rps_req_pending);
358
359   client->rps_req_inflight += nreq;
360   client->rps_req_pending -= nreq;
361
362   for (; nreq > 0; --nreq) {
363     if (client->submit_request() != 0) {
364       client->process_request_failure();
365       break;
366     }
367   }
368
369   client->signal_write();
370 }
371 } // namespace
372
373 namespace {
374 // Called when an a connection has been inactive for a set period of time
375 // or a fixed amount of time after all requests have been made on a
376 // connection
377 void conn_timeout_cb(EV_P_ ev_timer *w, int revents) {
378   auto client = static_cast<Client *>(w->data);
379
380   ev_timer_stop(client->worker->loop, &client->conn_inactivity_watcher);
381   ev_timer_stop(client->worker->loop, &client->conn_active_watcher);
382
383   if (util::check_socket_connected(client->fd)) {
384     client->timeout();
385   }
386 }
387 } // namespace
388
389 namespace {
390 bool check_stop_client_request_timeout(Client *client, ev_timer *w) {
391   if (client->req_left == 0) {
392     // no more requests to make, stop timer
393     ev_timer_stop(client->worker->loop, w);
394     return true;
395   }
396
397   return false;
398 }
399 } // namespace
400
401 namespace {
402 void client_request_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
403   auto client = static_cast<Client *>(w->data);
404
405   if (client->streams.size() >= (size_t)config.max_concurrent_streams) {
406     ev_timer_stop(client->worker->loop, w);
407     return;
408   }
409
410   if (client->submit_request() != 0) {
411     ev_timer_stop(client->worker->loop, w);
412     client->process_request_failure();
413     return;
414   }
415   client->signal_write();
416
417   if (check_stop_client_request_timeout(client, w)) {
418     return;
419   }
420
421   ev_tstamp duration =
422       config.timings[client->reqidx] - config.timings[client->reqidx - 1];
423
424   while (duration < 1e-9) {
425     if (client->submit_request() != 0) {
426       ev_timer_stop(client->worker->loop, w);
427       client->process_request_failure();
428       return;
429     }
430     client->signal_write();
431     if (check_stop_client_request_timeout(client, w)) {
432       return;
433     }
434
435     duration =
436         config.timings[client->reqidx] - config.timings[client->reqidx - 1];
437   }
438
439   client->request_timeout_watcher.repeat = duration;
440   ev_timer_again(client->worker->loop, &client->request_timeout_watcher);
441 }
442 } // namespace
443
444 Client::Client(uint32_t id, Worker *worker, size_t req_todo)
445     : wb(&worker->mcpool),
446       cstat{},
447       worker(worker),
448       ssl(nullptr),
449 #ifdef ENABLE_HTTP3
450       quic{},
451 #endif // ENABLE_HTTP3
452       next_addr(config.addrs),
453       current_addr(nullptr),
454       reqidx(0),
455       state(CLIENT_IDLE),
456       req_todo(req_todo),
457       req_left(req_todo),
458       req_inflight(0),
459       req_started(0),
460       req_done(0),
461       id(id),
462       fd(-1),
463       local_addr{},
464       new_connection_requested(false),
465       final(false),
466       rps_duration_started(0),
467       rps_req_pending(0),
468       rps_req_inflight(0) {
469   if (req_todo == 0) { // this means infinite number of requests are to be made
470     // This ensures that number of requests are unbounded
471     // Just a positive number is fine, we chose the first positive number
472     req_left = 1;
473   }
474   ev_io_init(&wev, writecb, 0, EV_WRITE);
475   ev_io_init(&rev, readcb, 0, EV_READ);
476
477   wev.data = this;
478   rev.data = this;
479
480   ev_timer_init(&conn_inactivity_watcher, conn_timeout_cb, 0.,
481                 worker->config->conn_inactivity_timeout);
482   conn_inactivity_watcher.data = this;
483
484   ev_timer_init(&conn_active_watcher, conn_timeout_cb,
485                 worker->config->conn_active_timeout, 0.);
486   conn_active_watcher.data = this;
487
488   ev_timer_init(&request_timeout_watcher, client_request_timeout_cb, 0., 0.);
489   request_timeout_watcher.data = this;
490
491   ev_timer_init(&rps_watcher, rps_cb, 0., 0.);
492   rps_watcher.data = this;
493
494 #ifdef ENABLE_HTTP3
495   ev_timer_init(&quic.pkt_timer, quic_pkt_timeout_cb, 0., 0.);
496   quic.pkt_timer.data = this;
497 #endif // ENABLE_HTTP3
498 }
499
500 Client::~Client() {
501   disconnect();
502
503 #ifdef ENABLE_HTTP3
504   if (config.is_quic()) {
505     quic_free();
506   }
507 #endif // ENABLE_HTTP3
508
509   if (ssl) {
510     SSL_free(ssl);
511   }
512
513   worker->sample_client_stat(&cstat);
514   ++worker->client_smp.n;
515 }
516
517 int Client::do_read() { return readfn(*this); }
518 int Client::do_write() { return writefn(*this); }
519
520 int Client::make_socket(addrinfo *addr) {
521   int rv;
522
523   if (config.is_quic()) {
524 #ifdef ENABLE_HTTP3
525     fd = util::create_nonblock_udp_socket(addr->ai_family);
526     if (fd == -1) {
527       return -1;
528     }
529
530     rv = util::bind_any_addr_udp(fd, addr->ai_family);
531     if (rv != 0) {
532       close(fd);
533       fd = -1;
534       return -1;
535     }
536
537     socklen_t addrlen = sizeof(local_addr.su.storage);
538     rv = getsockname(fd, &local_addr.su.sa, &addrlen);
539     if (rv == -1) {
540       return -1;
541     }
542     local_addr.len = addrlen;
543
544     if (quic_init(&local_addr.su.sa, local_addr.len, addr->ai_addr,
545                   addr->ai_addrlen) != 0) {
546       std::cerr << "quic_init failed" << std::endl;
547       return -1;
548     }
549 #endif // ENABLE_HTTP3
550   } else {
551     fd = util::create_nonblock_socket(addr->ai_family);
552     if (fd == -1) {
553       return -1;
554     }
555     if (config.scheme == "https") {
556       if (!ssl) {
557         ssl = SSL_new(worker->ssl_ctx);
558       }
559
560       SSL_set_fd(ssl, fd);
561       SSL_set_connect_state(ssl);
562     }
563   }
564
565   if (ssl && !util::numeric_host(config.host.c_str())) {
566     SSL_set_tlsext_host_name(ssl, config.host.c_str());
567   }
568
569   if (config.is_quic()) {
570     return 0;
571   }
572
573   rv = ::connect(fd, addr->ai_addr, addr->ai_addrlen);
574   if (rv != 0 && errno != EINPROGRESS) {
575     if (ssl) {
576       SSL_free(ssl);
577       ssl = nullptr;
578     }
579     close(fd);
580     fd = -1;
581     return -1;
582   }
583   return 0;
584 }
585
586 int Client::connect() {
587   int rv;
588
589   if (!worker->config->is_timing_based_mode() ||
590       worker->current_phase == Phase::MAIN_DURATION) {
591     record_client_start_time();
592     clear_connect_times();
593     record_connect_start_time();
594   } else if (worker->current_phase == Phase::INITIAL_IDLE) {
595     worker->current_phase = Phase::WARM_UP;
596     std::cout << "Warm-up started for thread #" << worker->id << "."
597               << std::endl;
598     ev_timer_start(worker->loop, &worker->warmup_watcher);
599   }
600
601   if (worker->config->conn_inactivity_timeout > 0.) {
602     ev_timer_again(worker->loop, &conn_inactivity_watcher);
603   }
604
605   if (current_addr) {
606     rv = make_socket(current_addr);
607     if (rv == -1) {
608       return -1;
609     }
610   } else {
611     addrinfo *addr = nullptr;
612     while (next_addr) {
613       addr = next_addr;
614       next_addr = next_addr->ai_next;
615       rv = make_socket(addr);
616       if (rv == 0) {
617         break;
618       }
619     }
620
621     if (fd == -1) {
622       return -1;
623     }
624
625     assert(addr);
626
627     current_addr = addr;
628   }
629
630   ev_io_set(&rev, fd, EV_READ);
631   ev_io_set(&wev, fd, EV_WRITE);
632
633   ev_io_start(worker->loop, &wev);
634
635   if (config.is_quic()) {
636 #ifdef ENABLE_HTTP3
637     ev_io_start(worker->loop, &rev);
638
639     readfn = &Client::read_quic;
640     writefn = &Client::write_quic;
641 #endif // ENABLE_HTTP3
642   } else {
643     writefn = &Client::connected;
644   }
645
646   return 0;
647 }
648
649 void Client::timeout() {
650   process_timedout_streams();
651
652   disconnect();
653 }
654
655 void Client::restart_timeout() {
656   if (worker->config->conn_inactivity_timeout > 0.) {
657     ev_timer_again(worker->loop, &conn_inactivity_watcher);
658   }
659 }
660
661 int Client::try_again_or_fail() {
662   disconnect();
663
664   if (new_connection_requested) {
665     new_connection_requested = false;
666
667     if (req_left) {
668
669       if (worker->current_phase == Phase::MAIN_DURATION) {
670         // At the moment, we don't have a facility to re-start request
671         // already in in-flight.  Make them fail.
672         worker->stats.req_failed += req_inflight;
673         worker->stats.req_error += req_inflight;
674
675         req_inflight = 0;
676       }
677
678       // Keep using current address
679       if (connect() == 0) {
680         return 0;
681       }
682       std::cerr << "client could not connect to host" << std::endl;
683     }
684   }
685
686   process_abandoned_streams();
687
688   return -1;
689 }
690
691 void Client::fail() {
692   disconnect();
693
694   process_abandoned_streams();
695 }
696
697 void Client::disconnect() {
698   record_client_end_time();
699
700 #ifdef ENABLE_HTTP3
701   if (config.is_quic()) {
702     quic_close_connection();
703   }
704 #endif // ENABLE_HTTP3
705
706 #ifdef ENABLE_HTTP3
707   ev_timer_stop(worker->loop, &quic.pkt_timer);
708 #endif // ENABLE_HTTP3
709   ev_timer_stop(worker->loop, &conn_inactivity_watcher);
710   ev_timer_stop(worker->loop, &conn_active_watcher);
711   ev_timer_stop(worker->loop, &rps_watcher);
712   ev_timer_stop(worker->loop, &request_timeout_watcher);
713   streams.clear();
714   session.reset();
715   wb.reset();
716   state = CLIENT_IDLE;
717   ev_io_stop(worker->loop, &wev);
718   ev_io_stop(worker->loop, &rev);
719   if (ssl) {
720     SSL_set_shutdown(ssl, SSL_get_shutdown(ssl) | SSL_RECEIVED_SHUTDOWN);
721     ERR_clear_error();
722
723     if (SSL_shutdown(ssl) != 1) {
724       SSL_free(ssl);
725       ssl = nullptr;
726     }
727   }
728   if (fd != -1) {
729     shutdown(fd, SHUT_WR);
730     close(fd);
731     fd = -1;
732   }
733
734   final = false;
735 }
736
737 int Client::submit_request() {
738   if (session->submit_request() != 0) {
739     return -1;
740   }
741
742   if (worker->current_phase != Phase::MAIN_DURATION) {
743     return 0;
744   }
745
746   ++worker->stats.req_started;
747   ++req_started;
748   ++req_inflight;
749   if (!worker->config->is_timing_based_mode()) {
750     --req_left;
751   }
752   // if an active timeout is set and this is the last request to be submitted
753   // on this connection, start the active timeout.
754   if (worker->config->conn_active_timeout > 0. && req_left == 0) {
755     ev_timer_start(worker->loop, &conn_active_watcher);
756   }
757
758   return 0;
759 }
760
761 void Client::process_timedout_streams() {
762   if (worker->current_phase != Phase::MAIN_DURATION) {
763     return;
764   }
765
766   for (auto &p : streams) {
767     auto &req_stat = p.second.req_stat;
768     if (!req_stat.completed) {
769       req_stat.stream_close_time = std::chrono::steady_clock::now();
770     }
771   }
772
773   worker->stats.req_timedout += req_inflight;
774
775   process_abandoned_streams();
776 }
777
778 void Client::process_abandoned_streams() {
779   if (worker->current_phase != Phase::MAIN_DURATION) {
780     return;
781   }
782
783   auto req_abandoned = req_inflight + req_left;
784
785   worker->stats.req_failed += req_abandoned;
786   worker->stats.req_error += req_abandoned;
787
788   req_inflight = 0;
789   req_left = 0;
790 }
791
792 void Client::process_request_failure() {
793   if (worker->current_phase != Phase::MAIN_DURATION) {
794     return;
795   }
796
797   worker->stats.req_failed += req_left;
798   worker->stats.req_error += req_left;
799
800   req_left = 0;
801
802   if (req_inflight == 0) {
803     terminate_session();
804   }
805   std::cout << "Process Request Failure:" << worker->stats.req_failed
806             << std::endl;
807 }
808
809 namespace {
810 void print_server_tmp_key(SSL *ssl) {
811 // libressl does not have SSL_get_server_tmp_key
812 #if OPENSSL_VERSION_NUMBER >= 0x10002000L && defined(SSL_get_server_tmp_key)
813   EVP_PKEY *key;
814
815   if (!SSL_get_server_tmp_key(ssl, &key)) {
816     return;
817   }
818
819   auto key_del = defer(EVP_PKEY_free, key);
820
821   std::cout << "Server Temp Key: ";
822
823   auto pkey_id = EVP_PKEY_id(key);
824   switch (pkey_id) {
825   case EVP_PKEY_RSA:
826     std::cout << "RSA " << EVP_PKEY_bits(key) << " bits" << std::endl;
827     break;
828   case EVP_PKEY_DH:
829     std::cout << "DH " << EVP_PKEY_bits(key) << " bits" << std::endl;
830     break;
831   case EVP_PKEY_EC: {
832 #  if OPENSSL_3_0_0_API
833     std::array<char, 64> curve_name;
834     const char *cname;
835     if (!EVP_PKEY_get_utf8_string_param(key, "group", curve_name.data(),
836                                         curve_name.size(), nullptr)) {
837       cname = "<unknown>";
838     } else {
839       cname = curve_name.data();
840     }
841 #  else  // !OPENSSL_3_0_0_API
842     auto ec = EVP_PKEY_get1_EC_KEY(key);
843     auto ec_del = defer(EC_KEY_free, ec);
844     auto nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
845     auto cname = EC_curve_nid2nist(nid);
846     if (!cname) {
847       cname = OBJ_nid2sn(nid);
848     }
849 #  endif // !OPENSSL_3_0_0_API
850
851     std::cout << "ECDH " << cname << " " << EVP_PKEY_bits(key) << " bits"
852               << std::endl;
853     break;
854   }
855   default:
856     std::cout << OBJ_nid2sn(pkey_id) << " " << EVP_PKEY_bits(key) << " bits"
857               << std::endl;
858     break;
859   }
860 #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
861 }
862 } // namespace
863
864 void Client::report_tls_info() {
865   if (worker->id == 0 && !worker->tls_info_report_done) {
866     worker->tls_info_report_done = true;
867     auto cipher = SSL_get_current_cipher(ssl);
868     std::cout << "TLS Protocol: " << tls::get_tls_protocol(ssl) << "\n"
869               << "Cipher: " << SSL_CIPHER_get_name(cipher) << std::endl;
870     print_server_tmp_key(ssl);
871   }
872 }
873
874 void Client::report_app_info() {
875   if (worker->id == 0 && !worker->app_info_report_done) {
876     worker->app_info_report_done = true;
877     std::cout << "Application protocol: " << selected_proto << std::endl;
878   }
879 }
880
881 void Client::terminate_session() {
882 #ifdef ENABLE_HTTP3
883   if (config.is_quic()) {
884     quic.close_requested = true;
885   }
886 #endif // ENABLE_HTTP3
887   if (session) {
888     session->terminate();
889   }
890   // http1 session needs writecb to tear down session.
891   signal_write();
892 }
893
894 void Client::on_request(int32_t stream_id) { streams[stream_id] = Stream(); }
895
896 void Client::on_header(int32_t stream_id, const uint8_t *name, size_t namelen,
897                        const uint8_t *value, size_t valuelen) {
898   auto itr = streams.find(stream_id);
899   if (itr == std::end(streams)) {
900     return;
901   }
902   auto &stream = (*itr).second;
903
904   if (worker->current_phase != Phase::MAIN_DURATION) {
905     // If the stream is for warm-up phase, then mark as a success
906     // But we do not update the count for 2xx, 3xx, etc status codes
907     // Same has been done in on_status_code function
908     stream.status_success = 1;
909     return;
910   }
911
912   if (stream.status_success == -1 && namelen == 7 &&
913       util::streq_l(":status", name, namelen)) {
914     int status = 0;
915     for (size_t i = 0; i < valuelen; ++i) {
916       if ('0' <= value[i] && value[i] <= '9') {
917         status *= 10;
918         status += value[i] - '0';
919         if (status > 999) {
920           stream.status_success = 0;
921           return;
922         }
923       } else {
924         break;
925       }
926     }
927
928     stream.req_stat.status = status;
929     if (status >= 200 && status < 300) {
930       ++worker->stats.status[2];
931       stream.status_success = 1;
932     } else if (status < 400) {
933       ++worker->stats.status[3];
934       stream.status_success = 1;
935     } else if (status < 600) {
936       ++worker->stats.status[status / 100];
937       stream.status_success = 0;
938     } else {
939       stream.status_success = 0;
940     }
941   }
942 }
943
944 void Client::on_status_code(int32_t stream_id, uint16_t status) {
945   auto itr = streams.find(stream_id);
946   if (itr == std::end(streams)) {
947     return;
948   }
949   auto &stream = (*itr).second;
950
951   if (worker->current_phase != Phase::MAIN_DURATION) {
952     stream.status_success = 1;
953     return;
954   }
955
956   stream.req_stat.status = status;
957   if (status >= 200 && status < 300) {
958     ++worker->stats.status[2];
959     stream.status_success = 1;
960   } else if (status < 400) {
961     ++worker->stats.status[3];
962     stream.status_success = 1;
963   } else if (status < 600) {
964     ++worker->stats.status[status / 100];
965     stream.status_success = 0;
966   } else {
967     stream.status_success = 0;
968   }
969 }
970
971 void Client::on_stream_close(int32_t stream_id, bool success, bool final) {
972   if (worker->current_phase == Phase::MAIN_DURATION) {
973     if (req_inflight > 0) {
974       --req_inflight;
975     }
976     auto req_stat = get_req_stat(stream_id);
977     if (!req_stat) {
978       return;
979     }
980
981     req_stat->stream_close_time = std::chrono::steady_clock::now();
982     if (success) {
983       req_stat->completed = true;
984       ++worker->stats.req_success;
985       ++cstat.req_success;
986
987       if (streams[stream_id].status_success == 1) {
988         ++worker->stats.req_status_success;
989       } else {
990         ++worker->stats.req_failed;
991       }
992
993       worker->sample_req_stat(req_stat);
994
995       // Count up in successful cases only
996       ++worker->request_times_smp.n;
997     } else {
998       ++worker->stats.req_failed;
999       ++worker->stats.req_error;
1000     }
1001     ++worker->stats.req_done;
1002     ++req_done;
1003
1004     if (worker->config->log_fd != -1) {
1005       auto start = std::chrono::duration_cast<std::chrono::microseconds>(
1006           req_stat->request_wall_time.time_since_epoch());
1007       auto delta = std::chrono::duration_cast<std::chrono::microseconds>(
1008           req_stat->stream_close_time - req_stat->request_time);
1009
1010       std::array<uint8_t, 256> buf;
1011       auto p = std::begin(buf);
1012       p = util::utos(p, start.count());
1013       *p++ = '\t';
1014       if (success) {
1015         p = util::utos(p, req_stat->status);
1016       } else {
1017         *p++ = '-';
1018         *p++ = '1';
1019       }
1020       *p++ = '\t';
1021       p = util::utos(p, delta.count());
1022       *p++ = '\n';
1023
1024       auto nwrite = static_cast<size_t>(std::distance(std::begin(buf), p));
1025       assert(nwrite <= buf.size());
1026       while (write(worker->config->log_fd, buf.data(), nwrite) == -1 &&
1027              errno == EINTR)
1028         ;
1029     }
1030   }
1031
1032   worker->report_progress();
1033   streams.erase(stream_id);
1034   if (req_left == 0 && req_inflight == 0) {
1035     terminate_session();
1036     return;
1037   }
1038
1039   if (!final && req_left > 0) {
1040     if (config.timing_script) {
1041       if (!ev_is_active(&request_timeout_watcher)) {
1042         ev_feed_event(worker->loop, &request_timeout_watcher, EV_TIMER);
1043       }
1044     } else if (!config.rps_enabled()) {
1045       if (submit_request() != 0) {
1046         process_request_failure();
1047       }
1048     } else if (rps_req_pending) {
1049       --rps_req_pending;
1050       if (submit_request() != 0) {
1051         process_request_failure();
1052       }
1053     } else {
1054       assert(rps_req_inflight);
1055       --rps_req_inflight;
1056     }
1057   }
1058 }
1059
1060 RequestStat *Client::get_req_stat(int32_t stream_id) {
1061   auto it = streams.find(stream_id);
1062   if (it == std::end(streams)) {
1063     return nullptr;
1064   }
1065
1066   return &(*it).second.req_stat;
1067 }
1068
1069 int Client::connection_made() {
1070   if (ssl) {
1071     report_tls_info();
1072
1073     const unsigned char *next_proto = nullptr;
1074     unsigned int next_proto_len;
1075
1076 #ifndef OPENSSL_NO_NEXTPROTONEG
1077     SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
1078 #endif // !OPENSSL_NO_NEXTPROTONEG
1079 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
1080     if (next_proto == nullptr) {
1081       SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);
1082     }
1083 #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
1084
1085     if (next_proto) {
1086       auto proto = StringRef{next_proto, next_proto_len};
1087       if (config.is_quic()) {
1088 #ifdef ENABLE_HTTP3
1089         assert(session);
1090         if (!util::streq(StringRef{&NGHTTP3_ALPN_H3[1]}, proto) &&
1091             !util::streq_l("h3-29", proto)) {
1092           return -1;
1093         }
1094 #endif // ENABLE_HTTP3
1095       } else if (util::check_h2_is_selected(proto)) {
1096         session = std::make_unique<Http2Session>(this);
1097       } else if (util::streq(NGHTTP2_H1_1, proto)) {
1098         session = std::make_unique<Http1Session>(this);
1099       }
1100
1101       // Just assign next_proto to selected_proto anyway to show the
1102       // negotiation result.
1103       selected_proto = proto.str();
1104     } else if (config.is_quic()) {
1105       std::cerr << "QUIC requires ALPN negotiation" << std::endl;
1106       return -1;
1107     } else {
1108       std::cout << "No protocol negotiated. Fallback behaviour may be activated"
1109                 << std::endl;
1110
1111       for (const auto &proto : config.npn_list) {
1112         if (util::streq(NGHTTP2_H1_1_ALPN, StringRef{proto})) {
1113           std::cout
1114               << "Server does not support NPN/ALPN. Falling back to HTTP/1.1."
1115               << std::endl;
1116           session = std::make_unique<Http1Session>(this);
1117           selected_proto = NGHTTP2_H1_1.str();
1118           break;
1119         }
1120       }
1121     }
1122
1123     if (!selected_proto.empty()) {
1124       report_app_info();
1125     }
1126
1127     if (!session) {
1128       std::cout
1129           << "No supported protocol was negotiated. Supported protocols were:"
1130           << std::endl;
1131       for (const auto &proto : config.npn_list) {
1132         std::cout << proto.substr(1) << std::endl;
1133       }
1134       disconnect();
1135       return -1;
1136     }
1137   } else {
1138     switch (config.no_tls_proto) {
1139     case Config::PROTO_HTTP2:
1140       session = std::make_unique<Http2Session>(this);
1141       selected_proto = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
1142       break;
1143     case Config::PROTO_HTTP1_1:
1144       session = std::make_unique<Http1Session>(this);
1145       selected_proto = NGHTTP2_H1_1.str();
1146       break;
1147     default:
1148       // unreachable
1149       assert(0);
1150     }
1151
1152     report_app_info();
1153   }
1154
1155   state = CLIENT_CONNECTED;
1156
1157   session->on_connect();
1158
1159   record_connect_time();
1160
1161   if (config.rps_enabled()) {
1162     rps_watcher.repeat = std::max(0.01, 1. / config.rps);
1163     ev_timer_again(worker->loop, &rps_watcher);
1164     rps_duration_started = ev_now(worker->loop);
1165   }
1166
1167   if (config.rps_enabled()) {
1168     assert(req_left);
1169
1170     ++rps_req_inflight;
1171
1172     if (submit_request() != 0) {
1173       process_request_failure();
1174     }
1175   } else if (!config.timing_script) {
1176     auto nreq = config.is_timing_based_mode()
1177                     ? std::max(req_left, session->max_concurrent_streams())
1178                     : std::min(req_left, session->max_concurrent_streams());
1179
1180     for (; nreq > 0; --nreq) {
1181       if (submit_request() != 0) {
1182         process_request_failure();
1183         break;
1184       }
1185     }
1186   } else {
1187
1188     ev_tstamp duration = config.timings[reqidx];
1189
1190     while (duration < 1e-9) {
1191       if (submit_request() != 0) {
1192         process_request_failure();
1193         break;
1194       }
1195       duration = config.timings[reqidx];
1196       if (reqidx == 0) {
1197         // if reqidx wraps around back to 0, we uses up all lines and
1198         // should break
1199         break;
1200       }
1201     }
1202
1203     if (duration >= 1e-9) {
1204       // double check since we may have break due to reqidx wraps
1205       // around back to 0
1206       request_timeout_watcher.repeat = duration;
1207       ev_timer_again(worker->loop, &request_timeout_watcher);
1208     }
1209   }
1210   signal_write();
1211
1212   return 0;
1213 }
1214
1215 int Client::on_read(const uint8_t *data, size_t len) {
1216   auto rv = session->on_read(data, len);
1217   if (rv != 0) {
1218     return -1;
1219   }
1220   if (worker->current_phase == Phase::MAIN_DURATION) {
1221     worker->stats.bytes_total += len;
1222   }
1223   signal_write();
1224   return 0;
1225 }
1226
1227 int Client::on_write() {
1228   if (wb.rleft() >= BACKOFF_WRITE_BUFFER_THRES) {
1229     return 0;
1230   }
1231
1232   if (session->on_write() != 0) {
1233     return -1;
1234   }
1235   return 0;
1236 }
1237
1238 int Client::read_clear() {
1239   uint8_t buf[8_k];
1240
1241   for (;;) {
1242     ssize_t nread;
1243     while ((nread = read(fd, buf, sizeof(buf))) == -1 && errno == EINTR)
1244       ;
1245     if (nread == -1) {
1246       if (errno == EAGAIN || errno == EWOULDBLOCK) {
1247         return 0;
1248       }
1249       return -1;
1250     }
1251
1252     if (nread == 0) {
1253       return -1;
1254     }
1255
1256     if (on_read(buf, nread) != 0) {
1257       return -1;
1258     }
1259   }
1260
1261   return 0;
1262 }
1263
1264 int Client::write_clear() {
1265   std::array<struct iovec, 2> iov;
1266
1267   for (;;) {
1268     if (on_write() != 0) {
1269       return -1;
1270     }
1271
1272     auto iovcnt = wb.riovec(iov.data(), iov.size());
1273
1274     if (iovcnt == 0) {
1275       break;
1276     }
1277
1278     ssize_t nwrite;
1279     while ((nwrite = writev(fd, iov.data(), iovcnt)) == -1 && errno == EINTR)
1280       ;
1281
1282     if (nwrite == -1) {
1283       if (errno == EAGAIN || errno == EWOULDBLOCK) {
1284         ev_io_start(worker->loop, &wev);
1285         return 0;
1286       }
1287       return -1;
1288     }
1289
1290     wb.drain(nwrite);
1291   }
1292
1293   ev_io_stop(worker->loop, &wev);
1294
1295   return 0;
1296 }
1297
1298 int Client::connected() {
1299   if (!util::check_socket_connected(fd)) {
1300     return ERR_CONNECT_FAIL;
1301   }
1302   ev_io_start(worker->loop, &rev);
1303   ev_io_stop(worker->loop, &wev);
1304
1305   if (ssl) {
1306     readfn = &Client::tls_handshake;
1307     writefn = &Client::tls_handshake;
1308
1309     return do_write();
1310   }
1311
1312   readfn = &Client::read_clear;
1313   writefn = &Client::write_clear;
1314
1315   if (connection_made() != 0) {
1316     return -1;
1317   }
1318
1319   return 0;
1320 }
1321
1322 int Client::tls_handshake() {
1323   ERR_clear_error();
1324
1325   auto rv = SSL_do_handshake(ssl);
1326
1327   if (rv <= 0) {
1328     auto err = SSL_get_error(ssl, rv);
1329     switch (err) {
1330     case SSL_ERROR_WANT_READ:
1331       ev_io_stop(worker->loop, &wev);
1332       return 0;
1333     case SSL_ERROR_WANT_WRITE:
1334       ev_io_start(worker->loop, &wev);
1335       return 0;
1336     default:
1337       return -1;
1338     }
1339   }
1340
1341   ev_io_stop(worker->loop, &wev);
1342
1343   readfn = &Client::read_tls;
1344   writefn = &Client::write_tls;
1345
1346   if (connection_made() != 0) {
1347     return -1;
1348   }
1349
1350   return 0;
1351 }
1352
1353 int Client::read_tls() {
1354   uint8_t buf[8_k];
1355
1356   ERR_clear_error();
1357
1358   for (;;) {
1359     auto rv = SSL_read(ssl, buf, sizeof(buf));
1360
1361     if (rv <= 0) {
1362       auto err = SSL_get_error(ssl, rv);
1363       switch (err) {
1364       case SSL_ERROR_WANT_READ:
1365         return 0;
1366       case SSL_ERROR_WANT_WRITE:
1367         // renegotiation started
1368         return -1;
1369       default:
1370         return -1;
1371       }
1372     }
1373
1374     if (on_read(buf, rv) != 0) {
1375       return -1;
1376     }
1377   }
1378 }
1379
1380 int Client::write_tls() {
1381   ERR_clear_error();
1382
1383   struct iovec iov;
1384
1385   for (;;) {
1386     if (on_write() != 0) {
1387       return -1;
1388     }
1389
1390     auto iovcnt = wb.riovec(&iov, 1);
1391
1392     if (iovcnt == 0) {
1393       break;
1394     }
1395
1396     auto rv = SSL_write(ssl, iov.iov_base, iov.iov_len);
1397
1398     if (rv <= 0) {
1399       auto err = SSL_get_error(ssl, rv);
1400       switch (err) {
1401       case SSL_ERROR_WANT_READ:
1402         // renegotiation started
1403         return -1;
1404       case SSL_ERROR_WANT_WRITE:
1405         ev_io_start(worker->loop, &wev);
1406         return 0;
1407       default:
1408         return -1;
1409       }
1410     }
1411
1412     wb.drain(rv);
1413   }
1414
1415   ev_io_stop(worker->loop, &wev);
1416
1417   return 0;
1418 }
1419
1420 #ifdef ENABLE_HTTP3
1421 int Client::write_udp(const sockaddr *addr, socklen_t addrlen,
1422                       const uint8_t *data, size_t datalen, size_t gso_size) {
1423   iovec msg_iov;
1424   msg_iov.iov_base = const_cast<uint8_t *>(data);
1425   msg_iov.iov_len = datalen;
1426
1427   msghdr msg{};
1428   msg.msg_name = const_cast<sockaddr *>(addr);
1429   msg.msg_namelen = addrlen;
1430   msg.msg_iov = &msg_iov;
1431   msg.msg_iovlen = 1;
1432
1433 #  ifdef UDP_SEGMENT
1434   std::array<uint8_t, CMSG_SPACE(sizeof(uint16_t))> msg_ctrl{};
1435   if (gso_size && datalen > gso_size) {
1436     msg.msg_control = msg_ctrl.data();
1437     msg.msg_controllen = msg_ctrl.size();
1438
1439     auto cm = CMSG_FIRSTHDR(&msg);
1440     cm->cmsg_level = SOL_UDP;
1441     cm->cmsg_type = UDP_SEGMENT;
1442     cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
1443     *(reinterpret_cast<uint16_t *>(CMSG_DATA(cm))) = gso_size;
1444   }
1445 #  endif // UDP_SEGMENT
1446
1447   auto nwrite = sendmsg(fd, &msg, 0);
1448   if (nwrite < 0) {
1449     std::cerr << "sendto: errno=" << errno << std::endl;
1450   } else {
1451     ++worker->stats.udp_dgram_sent;
1452   }
1453
1454   ev_io_stop(worker->loop, &wev);
1455
1456   return 0;
1457 }
1458 #endif // ENABLE_HTTP3
1459
1460 void Client::record_request_time(RequestStat *req_stat) {
1461   req_stat->request_time = std::chrono::steady_clock::now();
1462   req_stat->request_wall_time = std::chrono::system_clock::now();
1463 }
1464
1465 void Client::record_connect_start_time() {
1466   cstat.connect_start_time = std::chrono::steady_clock::now();
1467 }
1468
1469 void Client::record_connect_time() {
1470   cstat.connect_time = std::chrono::steady_clock::now();
1471 }
1472
1473 void Client::record_ttfb() {
1474   if (recorded(cstat.ttfb)) {
1475     return;
1476   }
1477
1478   cstat.ttfb = std::chrono::steady_clock::now();
1479 }
1480
1481 void Client::clear_connect_times() {
1482   cstat.connect_start_time = std::chrono::steady_clock::time_point();
1483   cstat.connect_time = std::chrono::steady_clock::time_point();
1484   cstat.ttfb = std::chrono::steady_clock::time_point();
1485 }
1486
1487 void Client::record_client_start_time() {
1488   // Record start time only once at the very first connection is going
1489   // to be made.
1490   if (recorded(cstat.client_start_time)) {
1491     return;
1492   }
1493
1494   cstat.client_start_time = std::chrono::steady_clock::now();
1495 }
1496
1497 void Client::record_client_end_time() {
1498   // Unlike client_start_time, we overwrite client_end_time.  This
1499   // handles multiple connect/disconnect for HTTP/1.1 benchmark.
1500   cstat.client_end_time = std::chrono::steady_clock::now();
1501 }
1502
1503 void Client::signal_write() { ev_io_start(worker->loop, &wev); }
1504
1505 void Client::try_new_connection() { new_connection_requested = true; }
1506
1507 namespace {
1508 int get_ev_loop_flags() {
1509   if (ev_supported_backends() & ~ev_recommended_backends() & EVBACKEND_KQUEUE) {
1510     return ev_recommended_backends() | EVBACKEND_KQUEUE;
1511   }
1512
1513   return 0;
1514 }
1515 } // namespace
1516
1517 Worker::Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t req_todo, size_t nclients,
1518                size_t rate, size_t max_samples, Config *config)
1519     : stats(req_todo, nclients),
1520       loop(ev_loop_new(get_ev_loop_flags())),
1521       ssl_ctx(ssl_ctx),
1522       config(config),
1523       id(id),
1524       tls_info_report_done(false),
1525       app_info_report_done(false),
1526       nconns_made(0),
1527       nclients(nclients),
1528       nreqs_per_client(req_todo / nclients),
1529       nreqs_rem(req_todo % nclients),
1530       rate(rate),
1531       max_samples(max_samples),
1532       next_client_id(0) {
1533   if (!config->is_rate_mode() && !config->is_timing_based_mode()) {
1534     progress_interval = std::max(static_cast<size_t>(1), req_todo / 10);
1535   } else {
1536     progress_interval = std::max(static_cast<size_t>(1), nclients / 10);
1537   }
1538
1539   // Below timeout is not needed in case of timing-based benchmarking
1540   // create timer that will go off every rate_period
1541   ev_timer_init(&timeout_watcher, rate_period_timeout_w_cb, 0.,
1542                 config->rate_period);
1543   timeout_watcher.data = this;
1544
1545   if (config->is_timing_based_mode()) {
1546     stats.req_stats.reserve(std::max(req_todo, max_samples));
1547     stats.client_stats.reserve(std::max(nclients, max_samples));
1548   } else {
1549     stats.req_stats.reserve(std::min(req_todo, max_samples));
1550     stats.client_stats.reserve(std::min(nclients, max_samples));
1551   }
1552
1553   sampling_init(request_times_smp, max_samples);
1554   sampling_init(client_smp, max_samples);
1555
1556   ev_timer_init(&duration_watcher, duration_timeout_cb, config->duration, 0.);
1557   duration_watcher.data = this;
1558
1559   ev_timer_init(&warmup_watcher, warmup_timeout_cb, config->warm_up_time, 0.);
1560   warmup_watcher.data = this;
1561
1562   if (config->is_timing_based_mode()) {
1563     current_phase = Phase::INITIAL_IDLE;
1564   } else {
1565     current_phase = Phase::MAIN_DURATION;
1566   }
1567 }
1568
1569 Worker::~Worker() {
1570   ev_timer_stop(loop, &timeout_watcher);
1571   ev_timer_stop(loop, &duration_watcher);
1572   ev_timer_stop(loop, &warmup_watcher);
1573   ev_loop_destroy(loop);
1574 }
1575
1576 void Worker::stop_all_clients() {
1577   for (auto client : clients) {
1578     if (client) {
1579       client->terminate_session();
1580     }
1581   }
1582 }
1583
1584 void Worker::free_client(Client *deleted_client) {
1585   for (auto &client : clients) {
1586     if (client == deleted_client) {
1587       client->req_todo = client->req_done;
1588       stats.req_todo += client->req_todo;
1589       auto index = &client - &clients[0];
1590       clients[index] = NULL;
1591       return;
1592     }
1593   }
1594 }
1595
1596 void Worker::run() {
1597   if (!config->is_rate_mode() && !config->is_timing_based_mode()) {
1598     for (size_t i = 0; i < nclients; ++i) {
1599       auto req_todo = nreqs_per_client;
1600       if (nreqs_rem > 0) {
1601         ++req_todo;
1602         --nreqs_rem;
1603       }
1604
1605       auto client = std::make_unique<Client>(next_client_id++, this, req_todo);
1606       if (client->connect() != 0) {
1607         std::cerr << "client could not connect to host" << std::endl;
1608         client->fail();
1609       } else {
1610         client.release();
1611       }
1612     }
1613   } else if (config->is_rate_mode()) {
1614     ev_timer_again(loop, &timeout_watcher);
1615
1616     // call callback so that we don't waste the first rate_period
1617     rate_period_timeout_w_cb(loop, &timeout_watcher, 0);
1618   } else {
1619     // call the callback to start for one single time
1620     rate_period_timeout_w_cb(loop, &timeout_watcher, 0);
1621   }
1622   ev_run(loop, 0);
1623 }
1624
1625 namespace {
1626 template <typename Stats, typename Stat>
1627 void sample(Sampling &smp, Stats &stats, Stat *s) {
1628   ++smp.n;
1629   if (stats.size() < smp.max_samples) {
1630     stats.push_back(*s);
1631     return;
1632   }
1633   auto d = std::uniform_int_distribution<unsigned long>(0, smp.n - 1);
1634   auto i = d(gen);
1635   if (i < smp.max_samples) {
1636     stats[i] = *s;
1637   }
1638 }
1639 } // namespace
1640
1641 void Worker::sample_req_stat(RequestStat *req_stat) {
1642   sample(request_times_smp, stats.req_stats, req_stat);
1643 }
1644
1645 void Worker::sample_client_stat(ClientStat *cstat) {
1646   sample(client_smp, stats.client_stats, cstat);
1647 }
1648
1649 void Worker::report_progress() {
1650   if (id != 0 || config->is_rate_mode() || stats.req_done % progress_interval ||
1651       config->is_timing_based_mode()) {
1652     return;
1653   }
1654
1655   std::cout << "progress: " << stats.req_done * 100 / stats.req_todo << "% done"
1656             << std::endl;
1657 }
1658
1659 void Worker::report_rate_progress() {
1660   if (id != 0 || nconns_made % progress_interval) {
1661     return;
1662   }
1663
1664   std::cout << "progress: " << nconns_made * 100 / nclients
1665             << "% of clients started" << std::endl;
1666 }
1667
1668 namespace {
1669 // Returns percentage of number of samples within mean +/- sd.
1670 double within_sd(const std::vector<double> &samples, double mean, double sd) {
1671   if (samples.size() == 0) {
1672     return 0.0;
1673   }
1674   auto lower = mean - sd;
1675   auto upper = mean + sd;
1676   auto m = std::count_if(
1677       std::begin(samples), std::end(samples),
1678       [&lower, &upper](double t) { return lower <= t && t <= upper; });
1679   return (m / static_cast<double>(samples.size())) * 100;
1680 }
1681 } // namespace
1682
1683 namespace {
1684 // Computes statistics using |samples|. The min, max, mean, sd, and
1685 // percentage of number of samples within mean +/- sd are computed.
1686 // If |sampling| is true, this computes sample variance.  Otherwise,
1687 // population variance.
1688 SDStat compute_time_stat(const std::vector<double> &samples,
1689                          bool sampling = false) {
1690   if (samples.empty()) {
1691     return {0.0, 0.0, 0.0, 0.0, 0.0};
1692   }
1693   // standard deviation calculated using Rapid calculation method:
1694   // https://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
1695   double a = 0, q = 0;
1696   size_t n = 0;
1697   double sum = 0;
1698   auto res = SDStat{std::numeric_limits<double>::max(),
1699                     std::numeric_limits<double>::min()};
1700   for (const auto &t : samples) {
1701     ++n;
1702     res.min = std::min(res.min, t);
1703     res.max = std::max(res.max, t);
1704     sum += t;
1705
1706     auto na = a + (t - a) / n;
1707     q += (t - a) * (t - na);
1708     a = na;
1709   }
1710
1711   assert(n > 0);
1712   res.mean = sum / n;
1713   res.sd = sqrt(q / (sampling && n > 1 ? n - 1 : n));
1714   res.within_sd = within_sd(samples, res.mean, res.sd);
1715
1716   return res;
1717 }
1718 } // namespace
1719
1720 namespace {
1721 SDStats
1722 process_time_stats(const std::vector<std::unique_ptr<Worker>> &workers) {
1723   auto request_times_sampling = false;
1724   auto client_times_sampling = false;
1725   size_t nrequest_times = 0;
1726   size_t nclient_times = 0;
1727   for (const auto &w : workers) {
1728     nrequest_times += w->stats.req_stats.size();
1729     request_times_sampling = w->request_times_smp.n > w->stats.req_stats.size();
1730
1731     nclient_times += w->stats.client_stats.size();
1732     client_times_sampling = w->client_smp.n > w->stats.client_stats.size();
1733   }
1734
1735   std::vector<double> request_times;
1736   request_times.reserve(nrequest_times);
1737
1738   std::vector<double> connect_times, ttfb_times, rps_values;
1739   connect_times.reserve(nclient_times);
1740   ttfb_times.reserve(nclient_times);
1741   rps_values.reserve(nclient_times);
1742
1743   for (const auto &w : workers) {
1744     for (const auto &req_stat : w->stats.req_stats) {
1745       if (!req_stat.completed) {
1746         continue;
1747       }
1748       request_times.push_back(
1749           std::chrono::duration_cast<std::chrono::duration<double>>(
1750               req_stat.stream_close_time - req_stat.request_time)
1751               .count());
1752     }
1753
1754     const auto &stat = w->stats;
1755
1756     for (const auto &cstat : stat.client_stats) {
1757       if (recorded(cstat.client_start_time) &&
1758           recorded(cstat.client_end_time)) {
1759         auto t = std::chrono::duration_cast<std::chrono::duration<double>>(
1760                      cstat.client_end_time - cstat.client_start_time)
1761                      .count();
1762         if (t > 1e-9) {
1763           rps_values.push_back(cstat.req_success / t);
1764         }
1765       }
1766
1767       // We will get connect event before FFTB.
1768       if (!recorded(cstat.connect_start_time) ||
1769           !recorded(cstat.connect_time)) {
1770         continue;
1771       }
1772
1773       connect_times.push_back(
1774           std::chrono::duration_cast<std::chrono::duration<double>>(
1775               cstat.connect_time - cstat.connect_start_time)
1776               .count());
1777
1778       if (!recorded(cstat.ttfb)) {
1779         continue;
1780       }
1781
1782       ttfb_times.push_back(
1783           std::chrono::duration_cast<std::chrono::duration<double>>(
1784               cstat.ttfb - cstat.connect_start_time)
1785               .count());
1786     }
1787   }
1788
1789   return {compute_time_stat(request_times, request_times_sampling),
1790           compute_time_stat(connect_times, client_times_sampling),
1791           compute_time_stat(ttfb_times, client_times_sampling),
1792           compute_time_stat(rps_values, client_times_sampling)};
1793 }
1794 } // namespace
1795
1796 namespace {
1797 void resolve_host() {
1798   if (config.base_uri_unix) {
1799     auto res = std::make_unique<addrinfo>();
1800     res->ai_family = config.unix_addr.sun_family;
1801     res->ai_socktype = SOCK_STREAM;
1802     res->ai_addrlen = sizeof(config.unix_addr);
1803     res->ai_addr =
1804         static_cast<struct sockaddr *>(static_cast<void *>(&config.unix_addr));
1805
1806     config.addrs = res.release();
1807     return;
1808   };
1809
1810   int rv;
1811   addrinfo hints{}, *res;
1812
1813   hints.ai_family = AF_UNSPEC;
1814   hints.ai_socktype = SOCK_STREAM;
1815   hints.ai_protocol = 0;
1816   hints.ai_flags = AI_ADDRCONFIG;
1817
1818   const auto &resolve_host =
1819       config.connect_to_host.empty() ? config.host : config.connect_to_host;
1820   auto port =
1821       config.connect_to_port == 0 ? config.port : config.connect_to_port;
1822
1823   rv =
1824       getaddrinfo(resolve_host.c_str(), util::utos(port).c_str(), &hints, &res);
1825   if (rv != 0) {
1826     std::cerr << "getaddrinfo() failed: " << gai_strerror(rv) << std::endl;
1827     exit(EXIT_FAILURE);
1828   }
1829   if (res == nullptr) {
1830     std::cerr << "No address returned" << std::endl;
1831     exit(EXIT_FAILURE);
1832   }
1833   config.addrs = res;
1834 }
1835 } // namespace
1836
1837 namespace {
1838 std::string get_reqline(const char *uri, const http_parser_url &u) {
1839   std::string reqline;
1840
1841   if (util::has_uri_field(u, UF_PATH)) {
1842     reqline = util::get_uri_field(uri, u, UF_PATH).str();
1843   } else {
1844     reqline = "/";
1845   }
1846
1847   if (util::has_uri_field(u, UF_QUERY)) {
1848     reqline += '?';
1849     reqline += util::get_uri_field(uri, u, UF_QUERY);
1850   }
1851
1852   return reqline;
1853 }
1854 } // namespace
1855
1856 #ifndef OPENSSL_NO_NEXTPROTONEG
1857 namespace {
1858 int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
1859                                 unsigned char *outlen, const unsigned char *in,
1860                                 unsigned int inlen, void *arg) {
1861   if (util::select_protocol(const_cast<const unsigned char **>(out), outlen, in,
1862                             inlen, config.npn_list)) {
1863     return SSL_TLSEXT_ERR_OK;
1864   }
1865
1866   // OpenSSL will terminate handshake with fatal alert if we return
1867   // NOACK.  So there is no way to fallback.
1868   return SSL_TLSEXT_ERR_NOACK;
1869 }
1870 } // namespace
1871 #endif // !OPENSSL_NO_NEXTPROTONEG
1872
1873 namespace {
1874 constexpr char UNIX_PATH_PREFIX[] = "unix:";
1875 } // namespace
1876
1877 namespace {
1878 bool parse_base_uri(const StringRef &base_uri) {
1879   http_parser_url u{};
1880   if (http_parser_parse_url(base_uri.c_str(), base_uri.size(), 0, &u) != 0 ||
1881       !util::has_uri_field(u, UF_SCHEMA) || !util::has_uri_field(u, UF_HOST)) {
1882     return false;
1883   }
1884
1885   config.scheme = util::get_uri_field(base_uri.c_str(), u, UF_SCHEMA).str();
1886   config.host = util::get_uri_field(base_uri.c_str(), u, UF_HOST).str();
1887   config.default_port = util::get_default_port(base_uri.c_str(), u);
1888   if (util::has_uri_field(u, UF_PORT)) {
1889     config.port = u.port;
1890   } else {
1891     config.port = config.default_port;
1892   }
1893
1894   return true;
1895 }
1896 } // namespace
1897 namespace {
1898 // Use std::vector<std::string>::iterator explicitly, without that,
1899 // http_parser_url u{} fails with clang-3.4.
1900 std::vector<std::string> parse_uris(std::vector<std::string>::iterator first,
1901                                     std::vector<std::string>::iterator last) {
1902   std::vector<std::string> reqlines;
1903
1904   if (first == last) {
1905     std::cerr << "no URI available" << std::endl;
1906     exit(EXIT_FAILURE);
1907   }
1908
1909   if (!config.has_base_uri()) {
1910
1911     if (!parse_base_uri(StringRef{*first})) {
1912       std::cerr << "invalid URI: " << *first << std::endl;
1913       exit(EXIT_FAILURE);
1914     }
1915
1916     config.base_uri = *first;
1917   }
1918
1919   for (; first != last; ++first) {
1920     http_parser_url u{};
1921
1922     auto uri = (*first).c_str();
1923
1924     if (http_parser_parse_url(uri, (*first).size(), 0, &u) != 0) {
1925       std::cerr << "invalid URI: " << uri << std::endl;
1926       exit(EXIT_FAILURE);
1927     }
1928
1929     reqlines.push_back(get_reqline(uri, u));
1930   }
1931
1932   return reqlines;
1933 }
1934 } // namespace
1935
1936 namespace {
1937 std::vector<std::string> read_uri_from_file(std::istream &infile) {
1938   std::vector<std::string> uris;
1939   std::string line_uri;
1940   while (std::getline(infile, line_uri)) {
1941     uris.push_back(line_uri);
1942   }
1943
1944   return uris;
1945 }
1946 } // namespace
1947
1948 namespace {
1949 void read_script_from_file(std::istream &infile,
1950                            std::vector<ev_tstamp> &timings,
1951                            std::vector<std::string> &uris) {
1952   std::string script_line;
1953   int line_count = 0;
1954   while (std::getline(infile, script_line)) {
1955     line_count++;
1956     if (script_line.empty()) {
1957       std::cerr << "Empty line detected at line " << line_count
1958                 << ". Ignoring and continuing." << std::endl;
1959       continue;
1960     }
1961
1962     std::size_t pos = script_line.find("\t");
1963     if (pos == std::string::npos) {
1964       std::cerr << "Invalid line format detected, no tab character at line "
1965                 << line_count << ". \n\t" << script_line << std::endl;
1966       exit(EXIT_FAILURE);
1967     }
1968
1969     const char *start = script_line.c_str();
1970     char *end;
1971     auto v = std::strtod(start, &end);
1972
1973     errno = 0;
1974     if (v < 0.0 || !std::isfinite(v) || end == start || errno != 0) {
1975       auto error = errno;
1976       std::cerr << "Time value error at line " << line_count << ". \n\t"
1977                 << "value = " << script_line.substr(0, pos) << std::endl;
1978       if (error != 0) {
1979         std::cerr << "\t" << strerror(error) << std::endl;
1980       }
1981       exit(EXIT_FAILURE);
1982     }
1983
1984     timings.push_back(v / 1000.0);
1985     uris.push_back(script_line.substr(pos + 1, script_line.size()));
1986   }
1987 }
1988 } // namespace
1989
1990 namespace {
1991 std::unique_ptr<Worker> create_worker(uint32_t id, SSL_CTX *ssl_ctx,
1992                                       size_t nreqs, size_t nclients,
1993                                       size_t rate, size_t max_samples) {
1994   std::stringstream rate_report;
1995   if (config.is_rate_mode() && nclients > rate) {
1996     rate_report << "Up to " << rate << " client(s) will be created every "
1997                 << util::duration_str(config.rate_period) << " ";
1998   }
1999
2000   if (config.is_timing_based_mode()) {
2001     std::cout << "spawning thread #" << id << ": " << nclients
2002               << " total client(s). Timing-based test with "
2003               << config.warm_up_time << "s of warm-up time and "
2004               << config.duration << "s of main duration for measurements."
2005               << std::endl;
2006   } else {
2007     std::cout << "spawning thread #" << id << ": " << nclients
2008               << " total client(s). " << rate_report.str() << nreqs
2009               << " total requests" << std::endl;
2010   }
2011
2012   if (config.is_rate_mode()) {
2013     return std::make_unique<Worker>(id, ssl_ctx, nreqs, nclients, rate,
2014                                     max_samples, &config);
2015   } else {
2016     // Here rate is same as client because the rate_timeout callback
2017     // will be called only once
2018     return std::make_unique<Worker>(id, ssl_ctx, nreqs, nclients, nclients,
2019                                     max_samples, &config);
2020   }
2021 }
2022 } // namespace
2023
2024 namespace {
2025 int parse_header_table_size(uint32_t &dst, const char *opt,
2026                             const char *optarg) {
2027   auto n = util::parse_uint_with_unit(optarg);
2028   if (n == -1) {
2029     std::cerr << "--" << opt << ": Bad option value: " << optarg << std::endl;
2030     return -1;
2031   }
2032   if (n > std::numeric_limits<uint32_t>::max()) {
2033     std::cerr << "--" << opt
2034               << ": Value too large.  It should be less than or equal to "
2035               << std::numeric_limits<uint32_t>::max() << std::endl;
2036     return -1;
2037   }
2038
2039   dst = n;
2040
2041   return 0;
2042 }
2043 } // namespace
2044
2045 namespace {
2046 void print_version(std::ostream &out) {
2047   out << "h2load nghttp2/" NGHTTP2_VERSION << std::endl;
2048 }
2049 } // namespace
2050
2051 namespace {
2052 void print_usage(std::ostream &out) {
2053   out << R"(Usage: h2load [OPTIONS]... [URI]...
2054 benchmarking tool for HTTP/2 server)"
2055       << std::endl;
2056 }
2057 } // namespace
2058
2059 namespace {
2060 constexpr char DEFAULT_NPN_LIST[] = "h2,h2-16,h2-14,http/1.1";
2061 } // namespace
2062
2063 namespace {
2064 void print_help(std::ostream &out) {
2065   print_usage(out);
2066
2067   auto config = Config();
2068
2069   out << R"(
2070   <URI>       Specify URI to access.   Multiple URIs can be specified.
2071               URIs are used  in this order for each  client.  All URIs
2072               are used, then  first URI is used and then  2nd URI, and
2073               so  on.  The  scheme, host  and port  in the  subsequent
2074               URIs, if present,  are ignored.  Those in  the first URI
2075               are used solely.  Definition of a base URI overrides all
2076               scheme, host or port values.
2077 Options:
2078   -n, --requests=<N>
2079               Number of  requests across all  clients.  If it  is used
2080               with --timing-script-file option,  this option specifies
2081               the number of requests  each client performs rather than
2082               the number of requests  across all clients.  This option
2083               is ignored if timing-based  benchmarking is enabled (see
2084               --duration option).
2085               Default: )"
2086       << config.nreqs << R"(
2087   -c, --clients=<N>
2088               Number  of concurrent  clients.   With  -r option,  this
2089               specifies the maximum number of connections to be made.
2090               Default: )"
2091       << config.nclients << R"(
2092   -t, --threads=<N>
2093               Number of native threads.
2094               Default: )"
2095       << config.nthreads << R"(
2096   -i, --input-file=<PATH>
2097               Path of a file with multiple URIs are separated by EOLs.
2098               This option will disable URIs getting from command-line.
2099               If '-' is given as <PATH>, URIs will be read from stdin.
2100               URIs are used  in this order for each  client.  All URIs
2101               are used, then  first URI is used and then  2nd URI, and
2102               so  on.  The  scheme, host  and port  in the  subsequent
2103               URIs, if present,  are ignored.  Those in  the first URI
2104               are used solely.  Definition of a base URI overrides all
2105               scheme, host or port values.
2106   -m, --max-concurrent-streams=<N>
2107               Max  concurrent  streams  to issue  per  session.   When
2108               http/1.1  is used,  this  specifies the  number of  HTTP
2109               pipelining requests in-flight.
2110               Default: 1
2111   -w, --window-bits=<N>
2112               Sets the stream level initial window size to (2**<N>)-1.
2113               For QUIC, <N> is capped to 26 (roughly 64MiB).
2114               Default: )"
2115       << config.window_bits << R"(
2116   -W, --connection-window-bits=<N>
2117               Sets  the  connection  level   initial  window  size  to
2118               (2**<N>)-1.
2119               Default: )"
2120       << config.connection_window_bits << R"(
2121   -H, --header=<HEADER>
2122               Add/Override a header to the requests.
2123   --ciphers=<SUITE>
2124               Set  allowed cipher  list  for TLSv1.2  or ealier.   The
2125               format of the string is described in OpenSSL ciphers(1).
2126               Default: )"
2127       << config.ciphers << R"(
2128   --tls13-ciphers=<SUITE>
2129               Set allowed cipher list for  TLSv1.3.  The format of the
2130               string is described in OpenSSL ciphers(1).
2131               Default: )"
2132       << config.tls13_ciphers << R"(
2133   -p, --no-tls-proto=<PROTOID>
2134               Specify ALPN identifier of the  protocol to be used when
2135               accessing http URI without SSL/TLS.
2136               Available protocols: )"
2137       << NGHTTP2_CLEARTEXT_PROTO_VERSION_ID << R"( and )" << NGHTTP2_H1_1 << R"(
2138               Default: )"
2139       << NGHTTP2_CLEARTEXT_PROTO_VERSION_ID << R"(
2140   -d, --data=<PATH>
2141               Post FILE to  server.  The request method  is changed to
2142               POST.   For  http/1.1 connection,  if  -d  is used,  the
2143               maximum number of in-flight pipelined requests is set to
2144               1.
2145   -r, --rate=<N>
2146               Specifies  the  fixed  rate  at  which  connections  are
2147               created.   The   rate  must   be  a   positive  integer,
2148               representing the  number of  connections to be  made per
2149               rate period.   The maximum  number of connections  to be
2150               made  is  given  in  -c   option.   This  rate  will  be
2151               distributed among  threads as  evenly as  possible.  For
2152               example,  with   -t2  and   -r4,  each  thread   gets  2
2153               connections per period.  When the rate is 0, the program
2154               will run  as it  normally does, creating  connections at
2155               whatever variable rate it  wants.  The default value for
2156               this option is 0.  -r and -D are mutually exclusive.
2157   --rate-period=<DURATION>
2158               Specifies the time  period between creating connections.
2159               The period  must be a positive  number, representing the
2160               length of the period in time.  This option is ignored if
2161               the rate option is not used.  The default value for this
2162               option is 1s.
2163   -D, --duration=<DURATION>
2164               Specifies the main duration for the measurements in case
2165               of timing-based  benchmarking.  -D  and -r  are mutually
2166               exclusive.
2167   --warm-up-time=<DURATION>
2168               Specifies the  time  period  before  starting the actual
2169               measurements, in  case  of  timing-based benchmarking.
2170               Needs to provided along with -D option.
2171   -T, --connection-active-timeout=<DURATION>
2172               Specifies  the maximum  time that  h2load is  willing to
2173               keep a  connection open,  regardless of the  activity on
2174               said connection.  <DURATION> must be a positive integer,
2175               specifying the amount of time  to wait.  When no timeout
2176               value is  set (either  active or inactive),  h2load will
2177               keep  a  connection  open indefinitely,  waiting  for  a
2178               response.
2179   -N, --connection-inactivity-timeout=<DURATION>
2180               Specifies the amount  of time that h2load  is willing to
2181               wait to see activity  on a given connection.  <DURATION>
2182               must  be a  positive integer,  specifying the  amount of
2183               time  to wait.   When no  timeout value  is set  (either
2184               active or inactive), h2load  will keep a connection open
2185               indefinitely, waiting for a response.
2186   --timing-script-file=<PATH>
2187               Path of a file containing one or more lines separated by
2188               EOLs.  Each script line is composed of two tab-separated
2189               fields.  The first field represents the time offset from
2190               the start of execution, expressed as a positive value of
2191               milliseconds  with microsecond  resolution.  The  second
2192               field represents the URI.  This option will disable URIs
2193               getting from  command-line.  If '-' is  given as <PATH>,
2194               script lines will be read  from stdin.  Script lines are
2195               used in order for each client.   If -n is given, it must
2196               be less  than or  equal to the  number of  script lines,
2197               larger values are clamped to the number of script lines.
2198               If -n is not given,  the number of requests will default
2199               to the  number of  script lines.   The scheme,  host and
2200               port defined in  the first URI are  used solely.  Values
2201               contained  in  other  URIs,  if  present,  are  ignored.
2202               Definition of a  base URI overrides all  scheme, host or
2203               port   values.   --timing-script-file   and  --rps   are
2204               mutually exclusive.
2205   -B, --base-uri=(<URI>|unix:<PATH>)
2206               Specify URI from which the scheme, host and port will be
2207               used  for  all requests.   The  base  URI overrides  all
2208               values  defined either  at  the command  line or  inside
2209               input files.  If argument  starts with "unix:", then the
2210               rest  of the  argument will  be treated  as UNIX  domain
2211               socket path.   The connection is made  through that path
2212               instead of TCP.   In this case, scheme  is inferred from
2213               the first  URI appeared  in the  command line  or inside
2214               input files as usual.
2215   --npn-list=<LIST>
2216               Comma delimited list of  ALPN protocol identifier sorted
2217               in the  order of preference.  That  means most desirable
2218               protocol comes  first.  This  is used  in both  ALPN and
2219               NPN.  The parameter must be  delimited by a single comma
2220               only  and any  white spaces  are  treated as  a part  of
2221               protocol string.
2222               Default: )"
2223       << DEFAULT_NPN_LIST << R"(
2224   --h1        Short        hand         for        --npn-list=http/1.1
2225               --no-tls-proto=http/1.1,    which   effectively    force
2226               http/1.1 for both http and https URI.
2227   --header-table-size=<SIZE>
2228               Specify decoder header table size.
2229               Default: )"
2230       << util::utos_unit(config.header_table_size) << R"(
2231   --encoder-header-table-size=<SIZE>
2232               Specify encoder header table size.  The decoder (server)
2233               specifies  the maximum  dynamic table  size it  accepts.
2234               Then the negotiated dynamic table size is the minimum of
2235               this option value and the value which server specified.
2236               Default: )"
2237       << util::utos_unit(config.encoder_header_table_size) << R"(
2238   --log-file=<PATH>
2239               Write per-request information to a file as tab-separated
2240               columns: start  time as  microseconds since  epoch; HTTP
2241               status code;  microseconds until end of  response.  More
2242               columns may be added later.  Rows are ordered by end-of-
2243               response  time when  using  one worker  thread, but  may
2244               appear slightly  out of order with  multiple threads due
2245               to buffering.  Status code is -1 for failed streams.
2246   --qlog-file-base=<PATH>
2247               Enable qlog output and specify base file name for qlogs.
2248               Qlog  is emitted  for each connection.
2249               For  a  given  base  name "base", each  output file name
2250               becomes  "base.M.N.qlog"  where M is worker ID  and N is
2251               client ID (e.g. "base.0.3.qlog").
2252               Only effective in QUIC runs.
2253   --connect-to=<HOST>[:<PORT>]
2254               Host and port to connect  instead of using the authority
2255               in <URI>.
2256   --rps=<N>   Specify request  per second for each  client.  --rps and
2257               --timing-script-file are mutually exclusive.
2258   --groups=<GROUPS>
2259               Specify the supported groups.
2260               Default: )"
2261       << config.groups << R"(
2262   --no-udp-gso
2263               Disable UDP GSO.
2264   --max-udp-payload-size=<SIZE>
2265               Specify the maximum outgoing UDP datagram payload size.
2266   -v, --verbose
2267               Output debug information.
2268   --version   Display version information and exit.
2269   -h, --help  Display this help and exit.
2270
2271 --
2272
2273   The <SIZE> argument is an integer and an optional unit (e.g., 10K is
2274   10 * 1024).  Units are K, M and G (powers of 1024).
2275
2276   The <DURATION> argument is an integer and an optional unit (e.g., 1s
2277   is 1 second and 500ms is 500 milliseconds).  Units are h, m, s or ms
2278   (hours, minutes, seconds and milliseconds, respectively).  If a unit
2279   is omitted, a second is used as unit.)"
2280       << std::endl;
2281 }
2282 } // namespace
2283
2284 int main(int argc, char **argv) {
2285   tls::libssl_init();
2286
2287 #ifndef NOTHREADS
2288   tls::LibsslGlobalLock lock;
2289 #endif // NOTHREADS
2290
2291   std::string datafile;
2292   std::string logfile;
2293   std::string qlog_base;
2294   bool nreqs_set_manually = false;
2295   while (1) {
2296     static int flag = 0;
2297     constexpr static option long_options[] = {
2298         {"requests", required_argument, nullptr, 'n'},
2299         {"clients", required_argument, nullptr, 'c'},
2300         {"data", required_argument, nullptr, 'd'},
2301         {"threads", required_argument, nullptr, 't'},
2302         {"max-concurrent-streams", required_argument, nullptr, 'm'},
2303         {"window-bits", required_argument, nullptr, 'w'},
2304         {"connection-window-bits", required_argument, nullptr, 'W'},
2305         {"input-file", required_argument, nullptr, 'i'},
2306         {"header", required_argument, nullptr, 'H'},
2307         {"no-tls-proto", required_argument, nullptr, 'p'},
2308         {"verbose", no_argument, nullptr, 'v'},
2309         {"help", no_argument, nullptr, 'h'},
2310         {"version", no_argument, &flag, 1},
2311         {"ciphers", required_argument, &flag, 2},
2312         {"rate", required_argument, nullptr, 'r'},
2313         {"connection-active-timeout", required_argument, nullptr, 'T'},
2314         {"connection-inactivity-timeout", required_argument, nullptr, 'N'},
2315         {"duration", required_argument, nullptr, 'D'},
2316         {"timing-script-file", required_argument, &flag, 3},
2317         {"base-uri", required_argument, nullptr, 'B'},
2318         {"npn-list", required_argument, &flag, 4},
2319         {"rate-period", required_argument, &flag, 5},
2320         {"h1", no_argument, &flag, 6},
2321         {"header-table-size", required_argument, &flag, 7},
2322         {"encoder-header-table-size", required_argument, &flag, 8},
2323         {"warm-up-time", required_argument, &flag, 9},
2324         {"log-file", required_argument, &flag, 10},
2325         {"connect-to", required_argument, &flag, 11},
2326         {"rps", required_argument, &flag, 12},
2327         {"groups", required_argument, &flag, 13},
2328         {"tls13-ciphers", required_argument, &flag, 14},
2329         {"no-udp-gso", no_argument, &flag, 15},
2330         {"qlog-file-base", required_argument, &flag, 16},
2331         {"max-udp-payload-size", required_argument, &flag, 17},
2332         {nullptr, 0, nullptr, 0}};
2333     int option_index = 0;
2334     auto c = getopt_long(argc, argv,
2335                          "hvW:c:d:m:n:p:t:w:H:i:r:T:N:D:B:", long_options,
2336                          &option_index);
2337     if (c == -1) {
2338       break;
2339     }
2340     switch (c) {
2341     case 'n':
2342       config.nreqs = strtoul(optarg, nullptr, 10);
2343       nreqs_set_manually = true;
2344       break;
2345     case 'c':
2346       config.nclients = strtoul(optarg, nullptr, 10);
2347       break;
2348     case 'd':
2349       datafile = optarg;
2350       break;
2351     case 't':
2352 #ifdef NOTHREADS
2353       std::cerr << "-t: WARNING: Threading disabled at build time, "
2354                 << "no threads created." << std::endl;
2355 #else
2356       config.nthreads = strtoul(optarg, nullptr, 10);
2357 #endif // NOTHREADS
2358       break;
2359     case 'm':
2360       config.max_concurrent_streams = strtoul(optarg, nullptr, 10);
2361       break;
2362     case 'w':
2363     case 'W': {
2364       errno = 0;
2365       char *endptr = nullptr;
2366       auto n = strtoul(optarg, &endptr, 10);
2367       if (errno == 0 && *endptr == '\0' && n < 31) {
2368         if (c == 'w') {
2369           config.window_bits = n;
2370         } else {
2371           config.connection_window_bits = n;
2372         }
2373       } else {
2374         std::cerr << "-" << static_cast<char>(c)
2375                   << ": specify the integer in the range [0, 30], inclusive"
2376                   << std::endl;
2377         exit(EXIT_FAILURE);
2378       }
2379       break;
2380     }
2381     case 'H': {
2382       char *header = optarg;
2383       // Skip first possible ':' in the header name
2384       char *value = strchr(optarg + 1, ':');
2385       if (!value || (header[0] == ':' && header + 1 == value)) {
2386         std::cerr << "-H: invalid header: " << optarg << std::endl;
2387         exit(EXIT_FAILURE);
2388       }
2389       *value = 0;
2390       value++;
2391       while (isspace(*value)) {
2392         value++;
2393       }
2394       if (*value == 0) {
2395         // This could also be a valid case for suppressing a header
2396         // similar to curl
2397         std::cerr << "-H: invalid header - value missing: " << optarg
2398                   << std::endl;
2399         exit(EXIT_FAILURE);
2400       }
2401       // Note that there is no processing currently to handle multiple
2402       // message-header fields with the same field name
2403       config.custom_headers.emplace_back(header, value);
2404       util::inp_strlower(config.custom_headers.back().name);
2405       break;
2406     }
2407     case 'i':
2408       config.ifile = optarg;
2409       break;
2410     case 'p': {
2411       auto proto = StringRef{optarg};
2412       if (util::strieq(StringRef::from_lit(NGHTTP2_CLEARTEXT_PROTO_VERSION_ID),
2413                        proto)) {
2414         config.no_tls_proto = Config::PROTO_HTTP2;
2415       } else if (util::strieq(NGHTTP2_H1_1, proto)) {
2416         config.no_tls_proto = Config::PROTO_HTTP1_1;
2417       } else {
2418         std::cerr << "-p: unsupported protocol " << proto << std::endl;
2419         exit(EXIT_FAILURE);
2420       }
2421       break;
2422     }
2423     case 'r':
2424       config.rate = strtoul(optarg, nullptr, 10);
2425       if (config.rate == 0) {
2426         std::cerr << "-r: the rate at which connections are made "
2427                   << "must be positive." << std::endl;
2428         exit(EXIT_FAILURE);
2429       }
2430       break;
2431     case 'T':
2432       config.conn_active_timeout = util::parse_duration_with_unit(optarg);
2433       if (!std::isfinite(config.conn_active_timeout)) {
2434         std::cerr << "-T: bad value for the conn_active_timeout wait time: "
2435                   << optarg << std::endl;
2436         exit(EXIT_FAILURE);
2437       }
2438       break;
2439     case 'N':
2440       config.conn_inactivity_timeout = util::parse_duration_with_unit(optarg);
2441       if (!std::isfinite(config.conn_inactivity_timeout)) {
2442         std::cerr << "-N: bad value for the conn_inactivity_timeout wait time: "
2443                   << optarg << std::endl;
2444         exit(EXIT_FAILURE);
2445       }
2446       break;
2447     case 'B': {
2448       auto arg = StringRef{optarg};
2449       config.base_uri = "";
2450       config.base_uri_unix = false;
2451
2452       if (util::istarts_with_l(arg, UNIX_PATH_PREFIX)) {
2453         // UNIX domain socket path
2454         sockaddr_un un;
2455
2456         auto path = StringRef{std::begin(arg) + str_size(UNIX_PATH_PREFIX),
2457                               std::end(arg)};
2458
2459         if (path.size() == 0 || path.size() + 1 > sizeof(un.sun_path)) {
2460           std::cerr << "--base-uri: invalid UNIX domain socket path: " << arg
2461                     << std::endl;
2462           exit(EXIT_FAILURE);
2463         }
2464
2465         config.base_uri_unix = true;
2466
2467         auto &unix_addr = config.unix_addr;
2468         std::copy(std::begin(path), std::end(path), unix_addr.sun_path);
2469         unix_addr.sun_path[path.size()] = '\0';
2470         unix_addr.sun_family = AF_UNIX;
2471
2472         break;
2473       }
2474
2475       if (!parse_base_uri(arg)) {
2476         std::cerr << "--base-uri: invalid base URI: " << arg << std::endl;
2477         exit(EXIT_FAILURE);
2478       }
2479
2480       config.base_uri = arg.str();
2481       break;
2482     }
2483     case 'D':
2484       config.duration = util::parse_duration_with_unit(optarg);
2485       if (!std::isfinite(config.duration)) {
2486         std::cerr << "-D: value error " << optarg << std::endl;
2487         exit(EXIT_FAILURE);
2488       }
2489       break;
2490     case 'v':
2491       config.verbose = true;
2492       break;
2493     case 'h':
2494       print_help(std::cout);
2495       exit(EXIT_SUCCESS);
2496     case '?':
2497       util::show_candidates(argv[optind - 1], long_options);
2498       exit(EXIT_FAILURE);
2499     case 0:
2500       switch (flag) {
2501       case 1:
2502         // version option
2503         print_version(std::cout);
2504         exit(EXIT_SUCCESS);
2505       case 2:
2506         // ciphers option
2507         config.ciphers = optarg;
2508         break;
2509       case 3:
2510         // timing-script option
2511         config.ifile = optarg;
2512         config.timing_script = true;
2513         break;
2514       case 4:
2515         // npn-list option
2516         config.npn_list = util::parse_config_str_list(StringRef{optarg});
2517         break;
2518       case 5:
2519         // rate-period
2520         config.rate_period = util::parse_duration_with_unit(optarg);
2521         if (!std::isfinite(config.rate_period)) {
2522           std::cerr << "--rate-period: value error " << optarg << std::endl;
2523           exit(EXIT_FAILURE);
2524         }
2525         break;
2526       case 6:
2527         // --h1
2528         config.npn_list =
2529             util::parse_config_str_list(StringRef::from_lit("http/1.1"));
2530         config.no_tls_proto = Config::PROTO_HTTP1_1;
2531         break;
2532       case 7:
2533         // --header-table-size
2534         if (parse_header_table_size(config.header_table_size,
2535                                     "header-table-size", optarg) != 0) {
2536           exit(EXIT_FAILURE);
2537         }
2538         break;
2539       case 8:
2540         // --encoder-header-table-size
2541         if (parse_header_table_size(config.encoder_header_table_size,
2542                                     "encoder-header-table-size", optarg) != 0) {
2543           exit(EXIT_FAILURE);
2544         }
2545         break;
2546       case 9:
2547         // --warm-up-time
2548         config.warm_up_time = util::parse_duration_with_unit(optarg);
2549         if (!std::isfinite(config.warm_up_time)) {
2550           std::cerr << "--warm-up-time: value error " << optarg << std::endl;
2551           exit(EXIT_FAILURE);
2552         }
2553         break;
2554       case 10:
2555         // --log-file
2556         logfile = optarg;
2557         break;
2558       case 11: {
2559         // --connect-to
2560         auto p = util::split_hostport(StringRef{optarg});
2561         int64_t port = 0;
2562         if (p.first.empty() ||
2563             (!p.second.empty() && (port = util::parse_uint(p.second)) == -1)) {
2564           std::cerr << "--connect-to: Invalid value " << optarg << std::endl;
2565           exit(EXIT_FAILURE);
2566         }
2567         config.connect_to_host = p.first.str();
2568         config.connect_to_port = port;
2569         break;
2570       }
2571       case 12: {
2572         char *end;
2573         auto v = std::strtod(optarg, &end);
2574         if (end == optarg || *end != '\0' || !std::isfinite(v) ||
2575             1. / v < 1e-6) {
2576           std::cerr << "--rps: Invalid value " << optarg << std::endl;
2577           exit(EXIT_FAILURE);
2578         }
2579         config.rps = v;
2580         break;
2581       }
2582       case 13:
2583         // --groups
2584         config.groups = optarg;
2585         break;
2586       case 14:
2587         // --tls13-ciphers
2588         config.tls13_ciphers = optarg;
2589         break;
2590       case 15:
2591         // --no-udp-gso
2592         config.no_udp_gso = true;
2593         break;
2594       case 16:
2595         // --qlog-file-base
2596         qlog_base = optarg;
2597         break;
2598       case 17: {
2599         // --max-udp-payload-size
2600         auto n = util::parse_uint_with_unit(optarg);
2601         if (n == -1) {
2602           std::cerr << "--max-udp-payload-size: bad option value: " << optarg
2603                     << std::endl;
2604           exit(EXIT_FAILURE);
2605         }
2606         if (static_cast<uint64_t>(n) > 64_k) {
2607           std::cerr << "--max-udp-payload-size: must not exceed 65536"
2608                     << std::endl;
2609           exit(EXIT_FAILURE);
2610         }
2611         config.max_udp_payload_size = n;
2612         break;
2613       }
2614       }
2615       break;
2616     default:
2617       break;
2618     }
2619   }
2620
2621   if (argc == optind) {
2622     if (config.ifile.empty()) {
2623       std::cerr << "no URI or input file given" << std::endl;
2624       exit(EXIT_FAILURE);
2625     }
2626   }
2627
2628   if (config.nclients == 0) {
2629     std::cerr << "-c: the number of clients must be strictly greater than 0."
2630               << std::endl;
2631     exit(EXIT_FAILURE);
2632   }
2633
2634   if (config.npn_list.empty()) {
2635     config.npn_list =
2636         util::parse_config_str_list(StringRef::from_lit(DEFAULT_NPN_LIST));
2637   }
2638
2639   // serialize the APLN tokens
2640   for (auto &proto : config.npn_list) {
2641     proto.insert(proto.begin(), static_cast<unsigned char>(proto.size()));
2642   }
2643
2644   std::vector<std::string> reqlines;
2645
2646   if (config.ifile.empty()) {
2647     std::vector<std::string> uris;
2648     std::copy(&argv[optind], &argv[argc], std::back_inserter(uris));
2649     reqlines = parse_uris(std::begin(uris), std::end(uris));
2650   } else {
2651     std::vector<std::string> uris;
2652     if (!config.timing_script) {
2653       if (config.ifile == "-") {
2654         uris = read_uri_from_file(std::cin);
2655       } else {
2656         std::ifstream infile(config.ifile);
2657         if (!infile) {
2658           std::cerr << "cannot read input file: " << config.ifile << std::endl;
2659           exit(EXIT_FAILURE);
2660         }
2661
2662         uris = read_uri_from_file(infile);
2663       }
2664     } else {
2665       if (config.ifile == "-") {
2666         read_script_from_file(std::cin, config.timings, uris);
2667       } else {
2668         std::ifstream infile(config.ifile);
2669         if (!infile) {
2670           std::cerr << "cannot read input file: " << config.ifile << std::endl;
2671           exit(EXIT_FAILURE);
2672         }
2673
2674         read_script_from_file(infile, config.timings, uris);
2675       }
2676
2677       if (nreqs_set_manually) {
2678         if (config.nreqs > uris.size()) {
2679           std::cerr << "-n: the number of requests must be less than or equal "
2680                        "to the number of timing script entries. Setting number "
2681                        "of requests to "
2682                     << uris.size() << std::endl;
2683
2684           config.nreqs = uris.size();
2685         }
2686       } else {
2687         config.nreqs = uris.size();
2688       }
2689     }
2690
2691     reqlines = parse_uris(std::begin(uris), std::end(uris));
2692   }
2693
2694   if (reqlines.empty()) {
2695     std::cerr << "No URI given" << std::endl;
2696     exit(EXIT_FAILURE);
2697   }
2698
2699   if (config.is_timing_based_mode() && config.is_rate_mode()) {
2700     std::cerr << "-r, -D: they are mutually exclusive." << std::endl;
2701     exit(EXIT_FAILURE);
2702   }
2703
2704   if (config.timing_script && config.rps_enabled()) {
2705     std::cerr << "--timing-script-file, --rps: they are mutually exclusive."
2706               << std::endl;
2707     exit(EXIT_FAILURE);
2708   }
2709
2710   if (config.nreqs == 0 && !config.is_timing_based_mode()) {
2711     std::cerr << "-n: the number of requests must be strictly greater than 0 "
2712                  "if timing-based test is not being run."
2713               << std::endl;
2714     exit(EXIT_FAILURE);
2715   }
2716
2717   if (config.max_concurrent_streams == 0) {
2718     std::cerr << "-m: the max concurrent streams must be strictly greater "
2719               << "than 0." << std::endl;
2720     exit(EXIT_FAILURE);
2721   }
2722
2723   if (config.nthreads == 0) {
2724     std::cerr << "-t: the number of threads must be strictly greater than 0."
2725               << std::endl;
2726     exit(EXIT_FAILURE);
2727   }
2728
2729   if (config.nthreads > std::thread::hardware_concurrency()) {
2730     std::cerr << "-t: warning: the number of threads is greater than hardware "
2731               << "cores." << std::endl;
2732   }
2733
2734   // With timing script, we don't distribute config.nreqs to each
2735   // client or thread.
2736   if (!config.timing_script && config.nreqs < config.nclients &&
2737       !config.is_timing_based_mode()) {
2738     std::cerr << "-n, -c: the number of requests must be greater than or "
2739               << "equal to the clients." << std::endl;
2740     exit(EXIT_FAILURE);
2741   }
2742
2743   if (config.nclients < config.nthreads) {
2744     std::cerr << "-c, -t: the number of clients must be greater than or equal "
2745               << "to the number of threads." << std::endl;
2746     exit(EXIT_FAILURE);
2747   }
2748
2749   if (config.is_timing_based_mode()) {
2750     config.nreqs = 0;
2751   }
2752
2753   if (config.is_rate_mode()) {
2754     if (config.rate < config.nthreads) {
2755       std::cerr << "-r, -t: the connection rate must be greater than or equal "
2756                 << "to the number of threads." << std::endl;
2757       exit(EXIT_FAILURE);
2758     }
2759
2760     if (config.rate > config.nclients) {
2761       std::cerr << "-r, -c: the connection rate must be smaller than or equal "
2762                    "to the number of clients."
2763                 << std::endl;
2764       exit(EXIT_FAILURE);
2765     }
2766   }
2767
2768   if (!datafile.empty()) {
2769     config.data_fd = open(datafile.c_str(), O_RDONLY | O_BINARY);
2770     if (config.data_fd == -1) {
2771       std::cerr << "-d: Could not open file " << datafile << std::endl;
2772       exit(EXIT_FAILURE);
2773     }
2774     struct stat data_stat;
2775     if (fstat(config.data_fd, &data_stat) == -1) {
2776       std::cerr << "-d: Could not stat file " << datafile << std::endl;
2777       exit(EXIT_FAILURE);
2778     }
2779     config.data_length = data_stat.st_size;
2780     auto addr = mmap(nullptr, config.data_length, PROT_READ, MAP_SHARED,
2781                      config.data_fd, 0);
2782     if (addr == MAP_FAILED) {
2783       std::cerr << "-d: Could not mmap file " << datafile << std::endl;
2784       exit(EXIT_FAILURE);
2785     }
2786     config.data = static_cast<uint8_t *>(addr);
2787   }
2788
2789   if (!logfile.empty()) {
2790     config.log_fd = open(logfile.c_str(), O_WRONLY | O_CREAT | O_APPEND,
2791                          S_IRUSR | S_IWUSR | S_IRGRP);
2792     if (config.log_fd == -1) {
2793       std::cerr << "--log-file: Could not open file " << logfile << std::endl;
2794       exit(EXIT_FAILURE);
2795     }
2796   }
2797
2798   if (!qlog_base.empty()) {
2799     if (!config.is_quic()) {
2800       std::cerr
2801           << "Warning: --qlog-file-base: only effective in quic, ignoring."
2802           << std::endl;
2803     } else {
2804 #ifdef ENABLE_HTTP3
2805       config.qlog_file_base = qlog_base;
2806 #endif // ENABLE_HTTP3
2807     }
2808   }
2809
2810   struct sigaction act {};
2811   act.sa_handler = SIG_IGN;
2812   sigaction(SIGPIPE, &act, nullptr);
2813
2814   auto ssl_ctx = SSL_CTX_new(TLS_client_method());
2815   if (!ssl_ctx) {
2816     std::cerr << "Failed to create SSL_CTX: "
2817               << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
2818     exit(EXIT_FAILURE);
2819   }
2820
2821   auto ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
2822                   SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION |
2823                   SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
2824
2825   SSL_CTX_set_options(ssl_ctx, ssl_opts);
2826   SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
2827   SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
2828
2829   if (config.is_quic()) {
2830 #ifdef ENABLE_HTTP3
2831     SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
2832     SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
2833 #endif // ENABLE_HTTP3
2834   } else if (nghttp2::tls::ssl_ctx_set_proto_versions(
2835                  ssl_ctx, nghttp2::tls::NGHTTP2_TLS_MIN_VERSION,
2836                  nghttp2::tls::NGHTTP2_TLS_MAX_VERSION) != 0) {
2837     std::cerr << "Could not set TLS versions" << std::endl;
2838     exit(EXIT_FAILURE);
2839   }
2840
2841   if (SSL_CTX_set_cipher_list(ssl_ctx, config.ciphers.c_str()) == 0) {
2842     std::cerr << "SSL_CTX_set_cipher_list with " << config.ciphers
2843               << " failed: " << ERR_error_string(ERR_get_error(), nullptr)
2844               << std::endl;
2845     exit(EXIT_FAILURE);
2846   }
2847
2848 #if OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
2849   if (SSL_CTX_set_ciphersuites(ssl_ctx, config.tls13_ciphers.c_str()) == 0) {
2850     std::cerr << "SSL_CTX_set_ciphersuites with " << config.tls13_ciphers
2851               << " failed: " << ERR_error_string(ERR_get_error(), nullptr)
2852               << std::endl;
2853     exit(EXIT_FAILURE);
2854   }
2855 #endif // OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
2856
2857 #if OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
2858   if (SSL_CTX_set1_groups_list(ssl_ctx, config.groups.c_str()) != 1) {
2859     std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl;
2860     exit(EXIT_FAILURE);
2861   }
2862 #else  // !(OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL))
2863   if (SSL_CTX_set1_curves_list(ssl_ctx, config.groups.c_str()) != 1) {
2864     std::cerr << "SSL_CTX_set1_curves_list failed" << std::endl;
2865     exit(EXIT_FAILURE);
2866   }
2867 #endif // !(OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL))
2868
2869 #ifndef OPENSSL_NO_NEXTPROTONEG
2870   SSL_CTX_set_next_proto_select_cb(ssl_ctx, client_select_next_proto_cb,
2871                                    nullptr);
2872 #endif // !OPENSSL_NO_NEXTPROTONEG
2873
2874 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
2875   std::vector<unsigned char> proto_list;
2876   for (const auto &proto : config.npn_list) {
2877     std::copy_n(proto.c_str(), proto.size(), std::back_inserter(proto_list));
2878   }
2879
2880   SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size());
2881 #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
2882
2883 #if OPENSSL_1_1_1_API
2884   auto keylog_filename = getenv("SSLKEYLOGFILE");
2885   if (keylog_filename) {
2886     keylog_file.open(keylog_filename, std::ios_base::app);
2887     if (keylog_file) {
2888       SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
2889     }
2890   }
2891 #endif // OPENSSL_1_1_1_API
2892
2893   std::string user_agent = "h2load nghttp2/" NGHTTP2_VERSION;
2894   Headers shared_nva;
2895   shared_nva.emplace_back(":scheme", config.scheme);
2896   if (config.port != config.default_port) {
2897     shared_nva.emplace_back(":authority",
2898                             config.host + ":" + util::utos(config.port));
2899   } else {
2900     shared_nva.emplace_back(":authority", config.host);
2901   }
2902   shared_nva.emplace_back(":method", config.data_fd == -1 ? "GET" : "POST");
2903   shared_nva.emplace_back("user-agent", user_agent);
2904
2905   // list header fields that can be overridden.
2906   auto override_hdrs = make_array<std::string>(":authority", ":host", ":method",
2907                                                ":scheme", "user-agent");
2908
2909   for (auto &kv : config.custom_headers) {
2910     if (std::find(std::begin(override_hdrs), std::end(override_hdrs),
2911                   kv.name) != std::end(override_hdrs)) {
2912       // override header
2913       for (auto &nv : shared_nva) {
2914         if ((nv.name == ":authority" && kv.name == ":host") ||
2915             (nv.name == kv.name)) {
2916           nv.value = kv.value;
2917         }
2918       }
2919     } else {
2920       // add additional headers
2921       shared_nva.push_back(kv);
2922     }
2923   }
2924
2925   std::string content_length_str;
2926   if (config.data_fd != -1) {
2927     content_length_str = util::utos(config.data_length);
2928   }
2929
2930   auto method_it =
2931       std::find_if(std::begin(shared_nva), std::end(shared_nva),
2932                    [](const Header &nv) { return nv.name == ":method"; });
2933   assert(method_it != std::end(shared_nva));
2934
2935   config.h1reqs.reserve(reqlines.size());
2936   config.nva.reserve(reqlines.size());
2937
2938   for (auto &req : reqlines) {
2939     // For HTTP/1.1
2940     auto h1req = (*method_it).value;
2941     h1req += ' ';
2942     h1req += req;
2943     h1req += " HTTP/1.1\r\n";
2944     for (auto &nv : shared_nva) {
2945       if (nv.name == ":authority") {
2946         h1req += "Host: ";
2947         h1req += nv.value;
2948         h1req += "\r\n";
2949         continue;
2950       }
2951       if (nv.name[0] == ':') {
2952         continue;
2953       }
2954       h1req += nv.name;
2955       h1req += ": ";
2956       h1req += nv.value;
2957       h1req += "\r\n";
2958     }
2959
2960     if (!content_length_str.empty()) {
2961       h1req += "Content-Length: ";
2962       h1req += content_length_str;
2963       h1req += "\r\n";
2964     }
2965     h1req += "\r\n";
2966
2967     config.h1reqs.push_back(std::move(h1req));
2968
2969     // For nghttp2
2970     std::vector<nghttp2_nv> nva;
2971     // 2 for :path, and possible content-length
2972     nva.reserve(2 + shared_nva.size());
2973
2974     nva.push_back(http2::make_nv_ls(":path", req));
2975
2976     for (auto &nv : shared_nva) {
2977       nva.push_back(http2::make_nv(nv.name, nv.value, false));
2978     }
2979
2980     if (!content_length_str.empty()) {
2981       nva.push_back(http2::make_nv(StringRef::from_lit("content-length"),
2982                                    StringRef{content_length_str}));
2983     }
2984
2985     config.nva.push_back(std::move(nva));
2986   }
2987
2988   // Don't DOS our server!
2989   if (config.host == "nghttp2.org") {
2990     std::cerr << "Using h2load against public server " << config.host
2991               << " should be prohibited." << std::endl;
2992     exit(EXIT_FAILURE);
2993   }
2994
2995   resolve_host();
2996
2997   std::cout << "starting benchmark..." << std::endl;
2998
2999   std::vector<std::unique_ptr<Worker>> workers;
3000   workers.reserve(config.nthreads);
3001
3002 #ifndef NOTHREADS
3003   size_t nreqs_per_thread = 0;
3004   ssize_t nreqs_rem = 0;
3005
3006   if (!config.timing_script) {
3007     nreqs_per_thread = config.nreqs / config.nthreads;
3008     nreqs_rem = config.nreqs % config.nthreads;
3009   }
3010
3011   size_t nclients_per_thread = config.nclients / config.nthreads;
3012   ssize_t nclients_rem = config.nclients % config.nthreads;
3013
3014   size_t rate_per_thread = config.rate / config.nthreads;
3015   ssize_t rate_per_thread_rem = config.rate % config.nthreads;
3016
3017   size_t max_samples_per_thread =
3018       std::max(static_cast<size_t>(256), MAX_SAMPLES / config.nthreads);
3019
3020   std::mutex mu;
3021   std::condition_variable cv;
3022   auto ready = false;
3023
3024   std::vector<std::future<void>> futures;
3025   for (size_t i = 0; i < config.nthreads; ++i) {
3026     auto rate = rate_per_thread;
3027     if (rate_per_thread_rem > 0) {
3028       --rate_per_thread_rem;
3029       ++rate;
3030     }
3031     auto nclients = nclients_per_thread;
3032     if (nclients_rem > 0) {
3033       --nclients_rem;
3034       ++nclients;
3035     }
3036
3037     size_t nreqs;
3038     if (config.timing_script) {
3039       // With timing script, each client issues config.nreqs requests.
3040       // We divide nreqs by number of clients in Worker ctor to
3041       // distribute requests to those clients evenly, so multiply
3042       // config.nreqs here by config.nclients.
3043       nreqs = config.nreqs * nclients;
3044     } else {
3045       nreqs = nreqs_per_thread;
3046       if (nreqs_rem > 0) {
3047         --nreqs_rem;
3048         ++nreqs;
3049       }
3050     }
3051
3052     workers.push_back(create_worker(i, ssl_ctx, nreqs, nclients, rate,
3053                                     max_samples_per_thread));
3054     auto &worker = workers.back();
3055     futures.push_back(
3056         std::async(std::launch::async, [&worker, &mu, &cv, &ready]() {
3057           {
3058             std::unique_lock<std::mutex> ulk(mu);
3059             cv.wait(ulk, [&ready] { return ready; });
3060           }
3061           worker->run();
3062         }));
3063   }
3064
3065   {
3066     std::lock_guard<std::mutex> lg(mu);
3067     ready = true;
3068     cv.notify_all();
3069   }
3070
3071   auto start = std::chrono::steady_clock::now();
3072
3073   for (auto &fut : futures) {
3074     fut.get();
3075   }
3076
3077 #else  // NOTHREADS
3078   auto rate = config.rate;
3079   auto nclients = config.nclients;
3080   auto nreqs =
3081       config.timing_script ? config.nreqs * config.nclients : config.nreqs;
3082
3083   workers.push_back(
3084       create_worker(0, ssl_ctx, nreqs, nclients, rate, MAX_SAMPLES));
3085
3086   auto start = std::chrono::steady_clock::now();
3087
3088   workers.back()->run();
3089 #endif // NOTHREADS
3090
3091   auto end = std::chrono::steady_clock::now();
3092   auto duration =
3093       std::chrono::duration_cast<std::chrono::microseconds>(end - start);
3094
3095   Stats stats(0, 0);
3096   for (const auto &w : workers) {
3097     const auto &s = w->stats;
3098
3099     stats.req_todo += s.req_todo;
3100     stats.req_started += s.req_started;
3101     stats.req_done += s.req_done;
3102     stats.req_timedout += s.req_timedout;
3103     stats.req_success += s.req_success;
3104     stats.req_status_success += s.req_status_success;
3105     stats.req_failed += s.req_failed;
3106     stats.req_error += s.req_error;
3107     stats.bytes_total += s.bytes_total;
3108     stats.bytes_head += s.bytes_head;
3109     stats.bytes_head_decomp += s.bytes_head_decomp;
3110     stats.bytes_body += s.bytes_body;
3111     stats.udp_dgram_recv += s.udp_dgram_recv;
3112     stats.udp_dgram_sent += s.udp_dgram_sent;
3113
3114     for (size_t i = 0; i < stats.status.size(); ++i) {
3115       stats.status[i] += s.status[i];
3116     }
3117   }
3118
3119   auto ts = process_time_stats(workers);
3120
3121   // Requests which have not been issued due to connection errors, are
3122   // counted towards req_failed and req_error.
3123   auto req_not_issued =
3124       (stats.req_todo - stats.req_status_success - stats.req_failed);
3125   stats.req_failed += req_not_issued;
3126   stats.req_error += req_not_issued;
3127
3128   // UI is heavily inspired by weighttp[1] and wrk[2]
3129   //
3130   // [1] https://github.com/lighttpd/weighttp
3131   // [2] https://github.com/wg/wrk
3132   double rps = 0;
3133   int64_t bps = 0;
3134   if (duration.count() > 0) {
3135     if (config.is_timing_based_mode()) {
3136       // we only want to consider the main duration if warm-up is given
3137       rps = stats.req_success / config.duration;
3138       bps = stats.bytes_total / config.duration;
3139     } else {
3140       auto secd = std::chrono::duration_cast<
3141           std::chrono::duration<double, std::chrono::seconds::period>>(
3142           duration);
3143       rps = stats.req_success / secd.count();
3144       bps = stats.bytes_total / secd.count();
3145     }
3146   }
3147
3148   double header_space_savings = 0.;
3149   if (stats.bytes_head_decomp > 0) {
3150     header_space_savings =
3151         1. - static_cast<double>(stats.bytes_head) / stats.bytes_head_decomp;
3152   }
3153
3154   std::cout << std::fixed << std::setprecision(2) << R"(
3155 finished in )"
3156             << util::format_duration(duration) << ", " << rps << " req/s, "
3157             << util::utos_funit(bps) << R"(B/s
3158 requests: )" << stats.req_todo
3159             << " total, " << stats.req_started << " started, " << stats.req_done
3160             << " done, " << stats.req_status_success << " succeeded, "
3161             << stats.req_failed << " failed, " << stats.req_error
3162             << " errored, " << stats.req_timedout << R"( timeout
3163 status codes: )"
3164             << stats.status[2] << " 2xx, " << stats.status[3] << " 3xx, "
3165             << stats.status[4] << " 4xx, " << stats.status[5] << R"( 5xx
3166 traffic: )" << util::utos_funit(stats.bytes_total)
3167             << "B (" << stats.bytes_total << ") total, "
3168             << util::utos_funit(stats.bytes_head) << "B (" << stats.bytes_head
3169             << ") headers (space savings " << header_space_savings * 100
3170             << "%), " << util::utos_funit(stats.bytes_body) << "B ("
3171             << stats.bytes_body << R"() data)" << std::endl;
3172 #ifdef ENABLE_HTTP3
3173   if (config.is_quic()) {
3174     std::cout << "UDP datagram: " << stats.udp_dgram_sent << " sent, "
3175               << stats.udp_dgram_recv << " received" << std::endl;
3176   }
3177 #endif // ENABLE_HTTP3
3178   std::cout
3179       << R"(                     min         max         mean         sd        +/- sd
3180 time for request: )"
3181       << std::setw(10) << util::format_duration(ts.request.min) << "  "
3182       << std::setw(10) << util::format_duration(ts.request.max) << "  "
3183       << std::setw(10) << util::format_duration(ts.request.mean) << "  "
3184       << std::setw(10) << util::format_duration(ts.request.sd) << std::setw(9)
3185       << util::dtos(ts.request.within_sd) << "%"
3186       << "\ntime for connect: " << std::setw(10)
3187       << util::format_duration(ts.connect.min) << "  " << std::setw(10)
3188       << util::format_duration(ts.connect.max) << "  " << std::setw(10)
3189       << util::format_duration(ts.connect.mean) << "  " << std::setw(10)
3190       << util::format_duration(ts.connect.sd) << std::setw(9)
3191       << util::dtos(ts.connect.within_sd) << "%"
3192       << "\ntime to 1st byte: " << std::setw(10)
3193       << util::format_duration(ts.ttfb.min) << "  " << std::setw(10)
3194       << util::format_duration(ts.ttfb.max) << "  " << std::setw(10)
3195       << util::format_duration(ts.ttfb.mean) << "  " << std::setw(10)
3196       << util::format_duration(ts.ttfb.sd) << std::setw(9)
3197       << util::dtos(ts.ttfb.within_sd) << "%"
3198       << "\nreq/s           : " << std::setw(10) << ts.rps.min << "  "
3199       << std::setw(10) << ts.rps.max << "  " << std::setw(10) << ts.rps.mean
3200       << "  " << std::setw(10) << ts.rps.sd << std::setw(9)
3201       << util::dtos(ts.rps.within_sd) << "%" << std::endl;
3202
3203   SSL_CTX_free(ssl_ctx);
3204
3205   if (config.log_fd != -1) {
3206     close(config.log_fd);
3207   }
3208
3209   return 0;
3210 }
3211
3212 } // namespace h2load
3213
3214 int main(int argc, char **argv) { return h2load::main(argc, argv); }