2 * nghttp2 - HTTP/2 C Library
4 * Copyright (c) 2012 Tatsuhiro Tsujikawa
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:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
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.
25 #include "shrpx_connection_handler.h"
29 #endif // HAVE_UNISTD_H
30 #include <sys/types.h>
36 #include "shrpx_client_handler.h"
37 #include "shrpx_ssl.h"
38 #include "shrpx_worker.h"
39 #include "shrpx_config.h"
40 #include "shrpx_http2_session.h"
41 #include "shrpx_connect_blocker.h"
42 #include "shrpx_downstream_connection.h"
43 #include "shrpx_accept_handler.h"
47 using namespace nghttp2;
52 void acceptor_disable_cb(struct ev_loop *loop, ev_timer *w, int revent) {
53 auto h = static_cast<ConnectionHandler *>(w->data);
55 // If we are in graceful shutdown period, we must not enable
57 if (h->get_graceful_shutdown()) {
66 void ocsp_cb(struct ev_loop *loop, ev_timer *w, int revent) {
67 auto h = static_cast<ConnectionHandler *>(w->data);
69 // If we are in graceful shutdown period, we won't do ocsp query.
70 if (h->get_graceful_shutdown()) {
74 LOG(NOTICE) << "Start ocsp update";
76 h->proceed_next_cert_ocsp();
81 void ocsp_read_cb(struct ev_loop *loop, ev_io *w, int revent) {
82 auto h = static_cast<ConnectionHandler *>(w->data);
89 void ocsp_chld_cb(struct ev_loop *loop, ev_child *w, int revent) {
90 auto h = static_cast<ConnectionHandler *>(w->data);
92 h->handle_ocsp_complete();
96 ConnectionHandler::ConnectionHandler(struct ev_loop *loop)
97 : single_worker_(nullptr), loop_(loop), worker_round_robin_cnt_(0),
98 graceful_shutdown_(false) {
99 ev_timer_init(&disable_acceptor_timer_, acceptor_disable_cb, 0., 0.);
100 disable_acceptor_timer_.data = this;
102 ev_timer_init(&ocsp_timer_, ocsp_cb, 0., 0.);
103 ocsp_timer_.data = this;
105 ev_io_init(&ocsp_.rev, ocsp_read_cb, -1, EV_READ);
106 ocsp_.rev.data = this;
108 ev_child_init(&ocsp_.chldev, ocsp_chld_cb, 0, 0);
109 ocsp_.chldev.data = this;
117 ConnectionHandler::~ConnectionHandler() {
118 ev_timer_stop(loop_, &disable_acceptor_timer_);
119 ev_timer_stop(loop_, &ocsp_timer_);
122 void ConnectionHandler::worker_reopen_log_files() {
125 memset(&wev, 0, sizeof(wev));
126 wev.type = REOPEN_LOG;
128 for (auto &worker : workers_) {
133 void ConnectionHandler::worker_renew_ticket_keys(
134 const std::shared_ptr<TicketKeys> &ticket_keys) {
137 memset(&wev, 0, sizeof(wev));
138 wev.type = RENEW_TICKET_KEYS;
139 wev.ticket_keys = ticket_keys;
141 for (auto &worker : workers_) {
146 void ConnectionHandler::create_single_worker() {
147 auto cert_tree = ssl::create_cert_lookup_tree();
148 auto sv_ssl_ctx = ssl::setup_server_ssl_context(all_ssl_ctx_, cert_tree);
149 auto cl_ssl_ctx = ssl::setup_client_ssl_context();
151 single_worker_ = make_unique<Worker>(loop_, sv_ssl_ctx, cl_ssl_ctx, cert_tree,
155 void ConnectionHandler::create_worker_thread(size_t num) {
157 assert(workers_.size() == 0);
159 auto cert_tree = ssl::create_cert_lookup_tree();
160 auto sv_ssl_ctx = ssl::setup_server_ssl_context(all_ssl_ctx_, cert_tree);
161 auto cl_ssl_ctx = ssl::setup_client_ssl_context();
163 for (size_t i = 0; i < num; ++i) {
164 auto loop = ev_loop_new(0);
166 auto worker = make_unique<Worker>(loop, sv_ssl_ctx, cl_ssl_ctx, cert_tree,
169 workers_.push_back(std::move(worker));
171 if (LOG_ENABLED(INFO)) {
172 LLOG(INFO, this) << "Created thread #" << workers_.size() - 1;
178 void ConnectionHandler::join_worker() {
182 if (LOG_ENABLED(INFO)) {
183 LLOG(INFO, this) << "Waiting for worker thread to join: n="
187 for (auto &worker : workers_) {
189 if (LOG_ENABLED(INFO)) {
190 LLOG(INFO, this) << "Thread #" << n << " joined";
197 void ConnectionHandler::graceful_shutdown_worker() {
198 if (get_config()->num_worker == 1) {
203 memset(&wev, 0, sizeof(wev));
204 wev.type = GRACEFUL_SHUTDOWN;
206 if (LOG_ENABLED(INFO)) {
207 LLOG(INFO, this) << "Sending graceful shutdown signal to worker";
210 for (auto &worker : workers_) {
216 int ConnectionHandler::handle_connection(int fd, sockaddr *addr, int addrlen) {
217 if (LOG_ENABLED(INFO)) {
218 LLOG(INFO, this) << "Accepted connection. fd=" << fd;
221 if (get_config()->num_worker == 1) {
223 if (single_worker_->get_worker_stat()->num_connections >=
224 get_config()->worker_frontend_connections) {
226 if (LOG_ENABLED(INFO)) {
227 LLOG(INFO, this) << "Too many connections >="
228 << get_config()->worker_frontend_connections;
236 ssl::accept_connection(single_worker_.get(), fd, addr, addrlen);
238 LLOG(ERROR, this) << "ClientHandler creation failed";
247 size_t idx = worker_round_robin_cnt_ % workers_.size();
248 if (LOG_ENABLED(INFO)) {
249 LOG(INFO) << "Dispatch connection to worker #" << idx;
251 ++worker_round_robin_cnt_;
253 memset(&wev, 0, sizeof(wev));
254 wev.type = NEW_CONNECTION;
256 memcpy(&wev.client_addr, addr, addrlen);
257 wev.client_addrlen = addrlen;
259 workers_[idx]->send(wev);
264 struct ev_loop *ConnectionHandler::get_loop() const {
268 Worker *ConnectionHandler::get_single_worker() const {
269 return single_worker_.get();
272 void ConnectionHandler::set_acceptor(std::unique_ptr<AcceptHandler> h) {
273 acceptor_ = std::move(h);
276 AcceptHandler *ConnectionHandler::get_acceptor() const {
277 return acceptor_.get();
280 void ConnectionHandler::set_acceptor6(std::unique_ptr<AcceptHandler> h) {
281 acceptor6_ = std::move(h);
284 AcceptHandler *ConnectionHandler::get_acceptor6() const {
285 return acceptor6_.get();
288 void ConnectionHandler::enable_acceptor() {
294 acceptor6_->enable();
298 void ConnectionHandler::disable_acceptor() {
300 acceptor_->disable();
304 acceptor6_->disable();
308 void ConnectionHandler::disable_acceptor_temporary(ev_tstamp t) {
309 if (t == 0. || ev_is_active(&disable_acceptor_timer_)) {
315 ev_timer_set(&disable_acceptor_timer_, t, 0.);
316 ev_timer_start(loop_, &disable_acceptor_timer_);
319 void ConnectionHandler::accept_pending_connection() {
321 acceptor_->accept_connection();
324 acceptor6_->accept_connection();
329 ConnectionHandler::set_ticket_keys(std::shared_ptr<TicketKeys> ticket_keys) {
330 ticket_keys_ = std::move(ticket_keys);
331 if (single_worker_) {
332 single_worker_->set_ticket_keys(ticket_keys_);
336 const std::shared_ptr<TicketKeys> &ConnectionHandler::get_ticket_keys() const {
340 void ConnectionHandler::set_graceful_shutdown(bool f) {
341 graceful_shutdown_ = f;
342 if (single_worker_) {
343 single_worker_->set_graceful_shutdown(f);
347 bool ConnectionHandler::get_graceful_shutdown() const {
348 return graceful_shutdown_;
351 void ConnectionHandler::cancel_ocsp_update() {
352 if (ocsp_.pid == 0) {
356 kill(ocsp_.pid, SIGTERM);
359 // inspired by h2o_read_command function from h2o project:
360 // https://github.com/h2o/h2o
361 int ConnectionHandler::start_ocsp_update(const char *cert_file) {
365 if (LOG_ENABLED(INFO)) {
366 LOG(INFO) << "Start ocsp update for " << cert_file;
369 assert(!ev_is_active(&ocsp_.rev));
370 assert(!ev_is_active(&ocsp_.chldev));
372 char *const argv[] = {
373 const_cast<char *>(get_config()->fetch_ocsp_response_file.get()),
374 const_cast<char *>(cert_file), nullptr};
375 char *const envp[] = {nullptr};
378 if (pipe2(pfd, O_CLOEXEC) == -1) {
382 if (pipe(pfd) == -1) {
385 util::make_socket_closeonexec(pfd[0]);
386 util::make_socket_closeonexec(pfd[1]);
389 auto closer = defer([&pfd]() {
402 LOG(WARN) << "Could not execute ocsp query command for " << cert_file
403 << ": " << argv[0] << ", fork() failed, errno=" << error;
412 rv = execve(argv[0], argv, envp);
415 LOG(WARN) << "Could not execute ocsp query command: " << argv[0]
416 << ", execve() faild, errno=" << error;
430 util::make_socket_nonblocking(ocsp_.fd);
431 ev_io_set(&ocsp_.rev, ocsp_.fd, EV_READ);
432 ev_io_start(loop_, &ocsp_.rev);
434 ev_child_set(&ocsp_.chldev, ocsp_.pid, 0);
435 ev_child_start(loop_, &ocsp_.chldev);
440 void ConnectionHandler::read_ocsp_chunk() {
441 std::array<uint8_t, 4096> buf;
444 while ((n = read(ocsp_.fd, buf.data(), buf.size())) == -1 && errno == EINTR)
448 if (errno == EAGAIN || errno == EWOULDBLOCK) {
452 LOG(WARN) << "Reading from ocsp query command failed: errno=" << error;
462 std::copy_n(std::begin(buf), n, std::back_inserter(ocsp_.resp));
465 ev_io_stop(loop_, &ocsp_.rev);
468 void ConnectionHandler::handle_ocsp_complete() {
469 ev_io_stop(loop_, &ocsp_.rev);
470 ev_child_stop(loop_, &ocsp_.chldev);
472 assert(ocsp_.next < all_ssl_ctx_.size());
474 auto ssl_ctx = all_ssl_ctx_[ocsp_.next];
476 static_cast<ssl::TLSContextData *>(SSL_CTX_get_app_data(ssl_ctx));
478 auto rstatus = ocsp_.chldev.rstatus;
479 auto status = WEXITSTATUS(rstatus);
480 if (ocsp_.error || !WIFEXITED(rstatus) || status != 0) {
481 LOG(WARN) << "ocsp query command for " << tls_ctx_data->cert_file
482 << " failed: error=" << ocsp_.error << ", rstatus=" << rstatus
483 << ", status=" << status;
485 proceed_next_cert_ocsp();
489 if (LOG_ENABLED(INFO)) {
490 LOG(INFO) << "ocsp update for " << tls_ctx_data->cert_file
491 << " finished successfully";
495 std::lock_guard<std::mutex> g(tls_ctx_data->mu);
496 tls_ctx_data->ocsp_data = std::move(ocsp_.resp);
500 proceed_next_cert_ocsp();
503 void ConnectionHandler::reset_ocsp() {
504 if (ocsp_.fd != -1) {
511 ocsp_.resp = std::vector<uint8_t>();
514 void ConnectionHandler::proceed_next_cert_ocsp() {
517 if (ocsp_.next == all_ssl_ctx_.size()) {
519 // We have updated all ocsp response, and schedule next update.
520 ev_timer_set(&ocsp_timer_, get_config()->ocsp_update_interval, 0.);
521 ev_timer_start(loop_, &ocsp_timer_);
525 auto ssl_ctx = all_ssl_ctx_[ocsp_.next];
527 static_cast<ssl::TLSContextData *>(SSL_CTX_get_app_data(ssl_ctx));
528 auto cert_file = tls_ctx_data->cert_file;
530 if (start_ocsp_update(cert_file) != 0) {