diff options
Diffstat (limited to '')
-rw-r--r-- | examples/h09server.h | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/examples/h09server.h b/examples/h09server.h new file mode 100644 index 0000000..8ab11f5 --- /dev/null +++ b/examples/h09server.h @@ -0,0 +1,237 @@ +/* + * ngtcp2 + * + * Copyright (c) 2017 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef SERVER_H +#define SERVER_H + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif // HAVE_CONFIG_H + +#include <vector> +#include <unordered_map> +#include <string> +#include <deque> +#include <string_view> +#include <memory> +#include <set> + +#include <ngtcp2/ngtcp2.h> +#include <ngtcp2/ngtcp2_crypto.h> +#include <nghttp3/nghttp3.h> + +#include <ev.h> + +#include "server_base.h" +#include "tls_server_context.h" +#include "network.h" +#include "shared.h" + +using namespace ngtcp2; + +struct HTTPHeader { + HTTPHeader(const std::string_view &name, const std::string_view &value) + : name(name), value(value) {} + + std::string_view name; + std::string_view value; +}; + +class Handler; +struct FileEntry; + +struct Stream { + Stream(int64_t stream_id, Handler *handler); + + int start_response(); + std::pair<FileEntry, int> open_file(const std::string &path); + void map_file(const FileEntry &fe); + int send_status_response(unsigned int status_code); + + int64_t stream_id; + Handler *handler; + // uri is request uri/path. + std::string uri; + std::string status_resp_body; + nghttp3_buf respbuf; + http_parser htp; + // eos gets true when one HTTP request message is seen. + bool eos; +}; + +struct StreamIDLess { + constexpr bool operator()(const Stream *lhs, const Stream *rhs) const { + return lhs->stream_id < rhs->stream_id; + } +}; + +class Server; + +// Endpoint is a local endpoint. +struct Endpoint { + Address addr; + ev_io rev; + Server *server; + int fd; + // ecn is the last ECN bits set to fd. + unsigned int ecn; +}; + +class Handler : public HandlerBase { +public: + Handler(struct ev_loop *loop, Server *server); + ~Handler(); + + int init(const Endpoint &ep, const Address &local_addr, const sockaddr *sa, + socklen_t salen, const ngtcp2_cid *dcid, const ngtcp2_cid *scid, + const ngtcp2_cid *ocid, const uint8_t *token, size_t tokenlen, + uint32_t version, TLSServerContext &tls_ctx); + + int on_read(const Endpoint &ep, const Address &local_addr, const sockaddr *sa, + socklen_t salen, const ngtcp2_pkt_info *pi, uint8_t *data, + size_t datalen); + int on_write(); + int write_streams(); + int feed_data(const Endpoint &ep, const Address &local_addr, + const sockaddr *sa, socklen_t salen, const ngtcp2_pkt_info *pi, + uint8_t *data, size_t datalen); + void update_timer(); + int handle_expiry(); + void signal_write(); + int handshake_completed(); + + Server *server() const; + int recv_stream_data(uint32_t flags, int64_t stream_id, const uint8_t *data, + size_t datalen); + int acked_stream_data_offset(int64_t stream_id, uint64_t offset, + uint64_t datalen); + uint32_t version() const; + void on_stream_open(int64_t stream_id); + int on_stream_close(int64_t stream_id, uint64_t app_error_code); + void start_draining_period(); + int start_closing_period(); + int handle_error(); + int send_conn_close(); + + int update_key(uint8_t *rx_secret, uint8_t *tx_secret, + ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, + ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, + const uint8_t *current_rx_secret, + const uint8_t *current_tx_secret, size_t secretlen); + + Stream *find_stream(int64_t stream_id); + int extend_max_stream_data(int64_t stream_id, uint64_t max_data); + void shutdown_read(int64_t stream_id, int app_error_code); + + void write_qlog(const void *data, size_t datalen); + void add_sendq(Stream *stream); + + void on_send_blocked(Endpoint &ep, const ngtcp2_addr &local_addr, + const ngtcp2_addr &remote_addr, unsigned int ecn, + const uint8_t *data, size_t datalen, size_t gso_size); + void start_wev_endpoint(const Endpoint &ep); + int send_blocked_packet(); + +private: + struct ev_loop *loop_; + Server *server_; + ev_io wev_; + ev_timer timer_; + FILE *qlog_; + ngtcp2_cid scid_; + std::unordered_map<int64_t, std::unique_ptr<Stream>> streams_; + std::set<Stream *, StreamIDLess> sendq_; + // conn_closebuf_ contains a packet which contains CONNECTION_CLOSE. + // This packet is repeatedly sent as a response to the incoming + // packet in draining period. + std::unique_ptr<Buffer> conn_closebuf_; + // nkey_update_ is the number of key update occurred. + size_t nkey_update_; + bool no_gso_; + + struct { + bool send_blocked; + size_t num_blocked; + size_t num_blocked_sent; + // blocked field is effective only when send_blocked is true. + struct { + Endpoint *endpoint; + Address local_addr; + Address remote_addr; + unsigned int ecn; + const uint8_t *data; + size_t datalen; + size_t gso_size; + } blocked[2]; + std::unique_ptr<uint8_t[]> data; + } tx_; +}; + +class Server { +public: + Server(struct ev_loop *loop, TLSServerContext &tls_ctx); + ~Server(); + + int init(const char *addr, const char *port); + void disconnect(); + void close(); + + int on_read(Endpoint &ep); + int send_version_negotiation(uint32_t version, const uint8_t *dcid, + size_t dcidlen, const uint8_t *scid, + size_t scidlen, Endpoint &ep, + const Address &local_addr, const sockaddr *sa, + socklen_t salen); + int send_retry(const ngtcp2_pkt_hd *chd, Endpoint &ep, + const Address &local_addr, const sockaddr *sa, socklen_t salen, + size_t max_pktlen); + int send_stateless_connection_close(const ngtcp2_pkt_hd *chd, Endpoint &ep, + const Address &local_addr, + const sockaddr *sa, socklen_t salen); + int verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd, + const sockaddr *sa, socklen_t salen); + int verify_token(const ngtcp2_pkt_hd *hd, const sockaddr *sa, + socklen_t salen); + int send_packet(Endpoint &ep, const ngtcp2_addr &local_addr, + const ngtcp2_addr &remote_addr, unsigned int ecn, + const uint8_t *data, size_t datalen); + std::pair<size_t, int> send_packet(Endpoint &ep, bool &no_gso, + const ngtcp2_addr &local_addr, + const ngtcp2_addr &remote_addr, + unsigned int ecn, const uint8_t *data, + size_t datalen, size_t gso_size); + void remove(const Handler *h); + + void associate_cid(const ngtcp2_cid *cid, Handler *h); + void dissociate_cid(const ngtcp2_cid *cid); + +private: + std::unordered_map<std::string, Handler *> handlers_; + struct ev_loop *loop_; + std::vector<Endpoint> endpoints_; + TLSServerContext &tls_ctx_; + ev_signal sigintev_; +}; + +#endif // SERVER_H |