• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  #ifndef H2LOAD_H
26  #define H2LOAD_H
27  
28  #include "nghttp2_config.h"
29  
30  #include <sys/types.h>
31  #ifdef HAVE_SYS_SOCKET_H
32  #  include <sys/socket.h>
33  #endif // HAVE_SYS_SOCKET_H
34  #ifdef HAVE_NETDB_H
35  #  include <netdb.h>
36  #endif // HAVE_NETDB_H
37  #include <sys/un.h>
38  
39  #include <vector>
40  #include <string>
41  #include <unordered_map>
42  #include <memory>
43  #include <chrono>
44  #include <array>
45  
46  #include <nghttp2/nghttp2.h>
47  
48  #ifdef ENABLE_HTTP3
49  #  include <ngtcp2/ngtcp2.h>
50  #  include <ngtcp2/ngtcp2_crypto.h>
51  #endif // ENABLE_HTTP3
52  
53  #include <ev.h>
54  
55  #include <openssl/ssl.h>
56  
57  #include "http2.h"
58  #ifdef ENABLE_HTTP3
59  #  include "quic.h"
60  #endif // ENABLE_HTTP3
61  #include "memchunk.h"
62  #include "template.h"
63  
64  using namespace nghttp2;
65  
66  namespace h2load {
67  
68  constexpr auto BACKOFF_WRITE_BUFFER_THRES = 16_k;
69  
70  class Session;
71  struct Worker;
72  
73  struct Config {
74    std::vector<std::vector<nghttp2_nv>> nva;
75    std::vector<std::string> h1reqs;
76    std::vector<std::chrono::steady_clock::duration> timings;
77    nghttp2::Headers custom_headers;
78    std::string scheme;
79    std::string host;
80    std::string connect_to_host;
81    std::string ifile;
82    std::string ciphers;
83    std::string tls13_ciphers;
84    // supported groups (or curves).
85    std::string groups;
86    // length of upload data
87    int64_t data_length;
88    // memory mapped upload data
89    uint8_t *data;
90    addrinfo *addrs;
91    size_t nreqs;
92    size_t nclients;
93    size_t nthreads;
94    // The maximum number of concurrent streams per session.
95    ssize_t max_concurrent_streams;
96    size_t window_bits;
97    size_t connection_window_bits;
98    size_t max_frame_size;
99    // rate at which connections should be made
100    size_t rate;
101    ev_tstamp rate_period;
102    // amount of time for main measurements in timing-based test
103    ev_tstamp duration;
104    // amount of time to wait before starting measurements in timing-based test
105    ev_tstamp warm_up_time;
106    // amount of time to wait for activity on a given connection
107    ev_tstamp conn_active_timeout;
108    // amount of time to wait after the last request is made on a connection
109    ev_tstamp conn_inactivity_timeout;
110    enum { PROTO_HTTP2, PROTO_HTTP1_1 } no_tls_proto;
111    uint32_t header_table_size;
112    uint32_t encoder_header_table_size;
113    // file descriptor for upload data
114    int data_fd;
115    // file descriptor to write per-request stats to.
116    int log_fd;
117    // base file name of qlog output files
118    std::string qlog_file_base;
119    uint16_t port;
120    uint16_t default_port;
121    uint16_t connect_to_port;
122    bool verbose;
123    bool timing_script;
124    std::string base_uri;
125    // true if UNIX domain socket is used.  In this case, base_uri is
126    // not used in usual way.
127    bool base_uri_unix;
128    // used when UNIX domain socket is used (base_uri_unix is true).
129    sockaddr_un unix_addr;
130    // list of supported NPN/ALPN protocol strings in the order of
131    // preference.
132    std::vector<std::string> npn_list;
133    // The number of request per second for each client.
134    double rps;
135    // Disables GSO for UDP connections.
136    bool no_udp_gso;
137    // The maximum UDP datagram payload size to send.
138    size_t max_udp_payload_size;
139    // Enable ktls.
140    bool ktls;
141  
142    Config();
143    ~Config();
144  
145    bool is_rate_mode() const;
146    bool is_timing_based_mode() const;
147    bool has_base_uri() const;
148    bool rps_enabled() const;
149    bool is_quic() const;
150  };
151  
152  struct RequestStat {
153    // time point when request was sent
154    std::chrono::steady_clock::time_point request_time;
155    // same, but in wall clock reference frame
156    std::chrono::system_clock::time_point request_wall_time;
157    // time point when stream was closed
158    std::chrono::steady_clock::time_point stream_close_time;
159    // upload data length sent so far
160    int64_t data_offset;
161    // HTTP status code
162    int status;
163    // true if stream was successfully closed.  This means stream was
164    // not reset, but it does not mean HTTP level error (e.g., 404).
165    bool completed;
166  };
167  
168  struct ClientStat {
169    // time client started (i.e., first connect starts)
170    std::chrono::steady_clock::time_point client_start_time;
171    // time client end (i.e., client somehow processed all requests it
172    // is responsible for, and disconnected)
173    std::chrono::steady_clock::time_point client_end_time;
174    // The number of requests completed successful, but not necessarily
175    // means successful HTTP status code.
176    size_t req_success;
177  
178    // The following 3 numbers are overwritten each time when connection
179    // is made.
180  
181    // time connect starts
182    std::chrono::steady_clock::time_point connect_start_time;
183    // time to connect
184    std::chrono::steady_clock::time_point connect_time;
185    // time to first byte (TTFB)
186    std::chrono::steady_clock::time_point ttfb;
187  };
188  
189  struct SDStat {
190    // min, max, mean and sd (standard deviation)
191    double min, max, mean, sd;
192    // percentage of samples inside mean -/+ sd
193    double within_sd;
194  };
195  
196  struct SDStats {
197    // time for request
198    SDStat request;
199    // time for connect
200    SDStat connect;
201    // time to first byte (TTFB)
202    SDStat ttfb;
203    // request per second for each client
204    SDStat rps;
205  };
206  
207  struct Stats {
208    Stats(size_t req_todo, size_t nclients);
209    // The total number of requests
210    size_t req_todo;
211    // The number of requests issued so far
212    size_t req_started;
213    // The number of requests finished
214    size_t req_done;
215    // The number of requests completed successful, but not necessarily
216    // means successful HTTP status code.
217    size_t req_success;
218    // The number of requests marked as success.  HTTP status code is
219    // also considered as success. This is subset of req_done.
220    size_t req_status_success;
221    // The number of requests failed. This is subset of req_done.
222    size_t req_failed;
223    // The number of requests failed due to network errors. This is
224    // subset of req_failed.
225    size_t req_error;
226    // The number of requests that failed due to timeout.
227    size_t req_timedout;
228    // The number of bytes received on the "wire". If SSL/TLS is used,
229    // this is the number of decrypted bytes the application received.
230    int64_t bytes_total;
231    // The number of bytes received for header fields.  This is
232    // compressed version.
233    int64_t bytes_head;
234    // The number of bytes received for header fields after they are
235    // decompressed.
236    int64_t bytes_head_decomp;
237    // The number of bytes received in DATA frame.
238    int64_t bytes_body;
239    // The number of each HTTP status category, status[i] is status code
240    // in the range [i*100, (i+1)*100).
241    std::array<size_t, 6> status;
242    // The statistics per request
243    std::vector<RequestStat> req_stats;
244    // The statistics per client
245    std::vector<ClientStat> client_stats;
246    // The number of UDP datagrams received.
247    size_t udp_dgram_recv;
248    // The number of UDP datagrams sent.
249    size_t udp_dgram_sent;
250  };
251  
252  enum ClientState { CLIENT_IDLE, CLIENT_CONNECTED };
253  
254  // This type tells whether the client is in warmup phase or not or is over
255  enum class Phase {
256    INITIAL_IDLE,  // Initial idle state before warm-up phase
257    WARM_UP,       // Warm up phase when no measurements are done
258    MAIN_DURATION, // Main measurement phase; if timing-based
259                   // test is not run, this is the default phase
260    DURATION_OVER  // This phase occurs after the measurements are over
261  };
262  
263  struct Client;
264  
265  // We use reservoir sampling method
266  struct Sampling {
267    // maximum number of samples
268    size_t max_samples;
269    // number of samples seen, including discarded samples.
270    size_t n;
271  };
272  
273  struct Worker {
274    MemchunkPool mcpool;
275    std::mt19937 randgen;
276    Stats stats;
277    Sampling request_times_smp;
278    Sampling client_smp;
279    struct ev_loop *loop;
280    SSL_CTX *ssl_ctx;
281    Config *config;
282    size_t progress_interval;
283    uint32_t id;
284    bool tls_info_report_done;
285    bool app_info_report_done;
286    size_t nconns_made;
287    // number of clients this worker handles
288    size_t nclients;
289    // number of requests each client issues
290    size_t nreqs_per_client;
291    // at most nreqs_rem clients get an extra request
292    size_t nreqs_rem;
293    size_t rate;
294    // maximum number of samples in this worker thread
295    size_t max_samples;
296    ev_timer timeout_watcher;
297    // The next client ID this worker assigns
298    uint32_t next_client_id;
299    // Keeps track of the current phase (for timing-based experiment) for the
300    // worker
301    Phase current_phase;
302    // We need to keep track of the clients in order to stop them when needed
303    std::vector<Client *> clients;
304    // This is only active when there is not a bounded number of requests
305    // specified
306    ev_timer duration_watcher;
307    ev_timer warmup_watcher;
308  
309    Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t nreq_todo, size_t nclients,
310           size_t rate, size_t max_samples, Config *config);
311    ~Worker();
312    Worker(Worker &&o) = default;
313    void run();
314    void sample_req_stat(RequestStat *req_stat);
315    void sample_client_stat(ClientStat *cstat);
316    void report_progress();
317    void report_rate_progress();
318    // This function calls the destructors of all the clients.
319    void stop_all_clients();
320    // This function frees a client from the list of clients for this Worker.
321    void free_client(Client *);
322  };
323  
324  struct Stream {
325    RequestStat req_stat;
326    int status_success;
327    Stream();
328  };
329  
330  struct Client {
331    DefaultMemchunks wb;
332    std::unordered_map<int32_t, Stream> streams;
333    ClientStat cstat;
334    std::unique_ptr<Session> session;
335    ev_io wev;
336    ev_io rev;
337    std::function<int(Client &)> readfn, writefn;
338    Worker *worker;
339    SSL *ssl;
340  #ifdef ENABLE_HTTP3
341    struct {
342      ngtcp2_crypto_conn_ref conn_ref;
343      ev_timer pkt_timer;
344      ngtcp2_conn *conn;
345      ngtcp2_ccerr last_error;
346      bool close_requested;
347      FILE *qlog_file;
348  
349      struct {
350        bool send_blocked;
351        size_t num_blocked;
352        size_t num_blocked_sent;
353        struct {
354          Address remote_addr;
355          const uint8_t *data;
356          size_t datalen;
357          size_t gso_size;
358        } blocked[2];
359        std::unique_ptr<uint8_t[]> data;
360      } tx;
361    } quic;
362  #endif // ENABLE_HTTP3
363    ev_timer request_timeout_watcher;
364    addrinfo *next_addr;
365    // Address for the current address.  When try_new_connection() is
366    // used and current_addr is not nullptr, it is used instead of
367    // trying next address though next_addr.  To try new address, set
368    // nullptr to current_addr before calling connect().
369    addrinfo *current_addr;
370    size_t reqidx;
371    ClientState state;
372    // The number of requests this client has to issue.
373    size_t req_todo;
374    // The number of requests left to issue
375    size_t req_left;
376    // The number of requests currently have started, but not abandoned
377    // or finished.
378    size_t req_inflight;
379    // The number of requests this client has issued so far.
380    size_t req_started;
381    // The number of requests this client has done so far.
382    size_t req_done;
383    // The client id per worker
384    uint32_t id;
385    int fd;
386    Address local_addr;
387    ev_timer conn_active_watcher;
388    ev_timer conn_inactivity_watcher;
389    std::string selected_proto;
390    bool new_connection_requested;
391    // true if the current connection will be closed, and no more new
392    // request cannot be processed.
393    bool final;
394    // rps_watcher is a timer to invoke callback periodically to
395    // generate a new request.
396    ev_timer rps_watcher;
397    // The timestamp that starts the period which contributes to the
398    // next request generation.
399    std::chrono::steady_clock::time_point rps_duration_started;
400    // The number of requests allowed by rps, but limited by stream
401    // concurrency.
402    size_t rps_req_pending;
403    // The number of in-flight streams.  req_inflight has similar value
404    // but it only measures requests made during Phase::MAIN_DURATION.
405    // rps_req_inflight measures the number of requests in all phases,
406    // and it is only used if --rps is given.
407    size_t rps_req_inflight;
408  
409    enum { ERR_CONNECT_FAIL = -100 };
410  
411    Client(uint32_t id, Worker *worker, size_t req_todo);
412    ~Client();
413    int make_socket(addrinfo *addr);
414    int connect();
415    void disconnect();
416    void fail();
417    // Call this function when do_read() returns -1.  This function
418    // tries to connect to the remote host again if it is requested.  If
419    // so, this function returns 0, and this object should be retained.
420    // Otherwise, this function returns -1, and this object should be
421    // deleted.
422    int try_again_or_fail();
423    void timeout();
424    void restart_timeout();
425    int submit_request();
426    void process_request_failure();
427    void process_timedout_streams();
428    void process_abandoned_streams();
429    void report_tls_info();
430    void report_app_info();
431    void terminate_session();
432    // Asks client to create new connection, instead of just fail.
433    void try_new_connection();
434  
435    int do_read();
436    int do_write();
437  
438    // low-level I/O callback functions called by do_read/do_write
439    int connected();
440    int read_clear();
441    int write_clear();
442    int tls_handshake();
443    int read_tls();
444    int write_tls();
445  
446    int on_read(const uint8_t *data, size_t len);
447    int on_write();
448  
449    int connection_made();
450  
451    void on_request(int32_t stream_id);
452    void on_header(int32_t stream_id, const uint8_t *name, size_t namelen,
453                   const uint8_t *value, size_t valuelen);
454    void on_status_code(int32_t stream_id, uint16_t status);
455    // |success| == true means that the request/response was exchanged
456    // |successfully, but it does not mean response carried successful
457    // |HTTP status code.
458    void on_stream_close(int32_t stream_id, bool success, bool final = false);
459    // Returns RequestStat for |stream_id|.  This function must be
460    // called after on_request(stream_id), and before
461    // on_stream_close(stream_id, ...).  Otherwise, this will return
462    // nullptr.
463    RequestStat *get_req_stat(int32_t stream_id);
464  
465    void record_request_time(RequestStat *req_stat);
466    void record_connect_start_time();
467    void record_connect_time();
468    void record_ttfb();
469    void clear_connect_times();
470    void record_client_start_time();
471    void record_client_end_time();
472  
473    void signal_write();
474  
475  #ifdef ENABLE_HTTP3
476    // QUIC
477    int quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
478                  const sockaddr *remote_addr, socklen_t remote_addrlen);
479    void quic_free();
480    int read_quic();
481    int write_quic();
482    int write_udp(const sockaddr *addr, socklen_t addrlen, const uint8_t *data,
483                  size_t datalen, size_t gso_size);
484    void on_send_blocked(const ngtcp2_addr &remote_addr, const uint8_t *data,
485                         size_t datalen, size_t gso_size);
486    int send_blocked_packet();
487    void quic_close_connection();
488  
489    int quic_handshake_completed();
490    int quic_recv_stream_data(uint32_t flags, int64_t stream_id,
491                              const uint8_t *data, size_t datalen);
492    int quic_acked_stream_data_offset(int64_t stream_id, size_t datalen);
493    int quic_stream_close(int64_t stream_id, uint64_t app_error_code);
494    int quic_stream_reset(int64_t stream_id, uint64_t app_error_code);
495    int quic_stream_stop_sending(int64_t stream_id, uint64_t app_error_code);
496    int quic_extend_max_local_streams();
497    int quic_extend_max_stream_data(int64_t stream_id);
498  
499    int quic_write_client_handshake(ngtcp2_encryption_level level,
500                                    const uint8_t *data, size_t datalen);
501    int quic_pkt_timeout();
502    void quic_restart_pkt_timer();
503    void quic_write_qlog(const void *data, size_t datalen);
504    int quic_make_http3_session();
505  #endif // ENABLE_HTTP3
506  };
507  
508  } // namespace h2load
509  
510  #endif // H2LOAD_H
511