1/* 2 * nghttp2 - HTTP/2 C Library 3 * 4 * Copyright (c) 2015 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 "shrpx_worker_process.h" 26 27#include <sys/types.h> 28#ifdef HAVE_UNISTD_H 29# include <unistd.h> 30#endif // HAVE_UNISTD_H 31#include <sys/resource.h> 32#include <sys/wait.h> 33#include <grp.h> 34 35#include <cinttypes> 36#include <cstdlib> 37 38#include <openssl/rand.h> 39 40#include <ev.h> 41 42#include <ares.h> 43 44#include "shrpx_config.h" 45#include "shrpx_connection_handler.h" 46#include "shrpx_log_config.h" 47#include "shrpx_worker.h" 48#include "shrpx_accept_handler.h" 49#include "shrpx_http2_upstream.h" 50#include "shrpx_http2_session.h" 51#include "shrpx_memcached_dispatcher.h" 52#include "shrpx_memcached_request.h" 53#include "shrpx_process.h" 54#include "shrpx_tls.h" 55#include "shrpx_log.h" 56#include "util.h" 57#include "app_helper.h" 58#include "template.h" 59#include "xsi_strerror.h" 60 61using namespace nghttp2; 62 63namespace shrpx { 64 65namespace { 66void drop_privileges( 67#ifdef HAVE_NEVERBLEED 68 neverbleed_t *nb 69#endif // HAVE_NEVERBLEED 70) { 71 std::array<char, STRERROR_BUFSIZE> errbuf; 72 auto config = get_config(); 73 74 if (getuid() == 0 && config->uid != 0) { 75#ifdef HAVE_NEVERBLEED 76 if (nb) { 77 neverbleed_setuidgid(nb, config->user.c_str(), 1); 78 } 79#endif // HAVE_NEVERBLEED 80 81 if (initgroups(config->user.c_str(), config->gid) != 0) { 82 auto error = errno; 83 LOG(FATAL) << "Could not change supplementary groups: " 84 << xsi_strerror(error, errbuf.data(), errbuf.size()); 85 exit(EXIT_FAILURE); 86 } 87 if (setgid(config->gid) != 0) { 88 auto error = errno; 89 LOG(FATAL) << "Could not change gid: " 90 << xsi_strerror(error, errbuf.data(), errbuf.size()); 91 exit(EXIT_FAILURE); 92 } 93 if (setuid(config->uid) != 0) { 94 auto error = errno; 95 LOG(FATAL) << "Could not change uid: " 96 << xsi_strerror(error, errbuf.data(), errbuf.size()); 97 exit(EXIT_FAILURE); 98 } 99 if (setuid(0) != -1) { 100 LOG(FATAL) << "Still have root privileges?"; 101 exit(EXIT_FAILURE); 102 } 103 } 104} 105} // namespace 106 107namespace { 108void graceful_shutdown(ConnectionHandler *conn_handler) { 109 if (conn_handler->get_graceful_shutdown()) { 110 return; 111 } 112 113 LOG(NOTICE) << "Graceful shutdown signal received"; 114 115 conn_handler->set_graceful_shutdown(true); 116 117 // TODO What happens for the connections not established in the 118 // kernel? 119 conn_handler->accept_pending_connection(); 120 conn_handler->delete_acceptor(); 121 122 conn_handler->graceful_shutdown_worker(); 123 124 auto single_worker = conn_handler->get_single_worker(); 125 if (single_worker) { 126 auto worker_stat = single_worker->get_worker_stat(); 127 if (worker_stat->num_connections == 0 && 128 worker_stat->num_close_waits == 0) { 129 ev_break(conn_handler->get_loop()); 130 } 131 132 return; 133 } 134} 135} // namespace 136 137namespace { 138void reopen_log(ConnectionHandler *conn_handler) { 139 LOG(NOTICE) << "Reopening log files: worker process (thread main)"; 140 141 auto config = get_config(); 142 auto &loggingconf = config->logging; 143 144 (void)reopen_log_files(loggingconf); 145 redirect_stderr_to_errorlog(loggingconf); 146 147 conn_handler->worker_reopen_log_files(); 148} 149} // namespace 150 151namespace { 152void ipc_readcb(struct ev_loop *loop, ev_io *w, int revents) { 153 auto conn_handler = static_cast<ConnectionHandler *>(w->data); 154 std::array<uint8_t, 1024> buf; 155 ssize_t nread; 156 while ((nread = read(w->fd, buf.data(), buf.size())) == -1 && errno == EINTR) 157 ; 158 if (nread == -1) { 159 auto error = errno; 160 LOG(ERROR) << "Failed to read data from ipc channel: errno=" << error; 161 return; 162 } 163 164 if (nread == 0) { 165 // IPC socket closed. Perform immediate shutdown. 166 LOG(FATAL) << "IPC socket is closed. Perform immediate shutdown."; 167 nghttp2_Exit(EXIT_FAILURE); 168 } 169 170 for (ssize_t i = 0; i < nread; ++i) { 171 switch (buf[i]) { 172 case SHRPX_IPC_GRACEFUL_SHUTDOWN: 173 graceful_shutdown(conn_handler); 174 break; 175 case SHRPX_IPC_REOPEN_LOG: 176 reopen_log(conn_handler); 177 break; 178 } 179 } 180} 181} // namespace 182 183#ifdef ENABLE_HTTP3 184namespace { 185void quic_ipc_readcb(struct ev_loop *loop, ev_io *w, int revents) { 186 auto conn_handler = static_cast<ConnectionHandler *>(w->data); 187 188 if (conn_handler->quic_ipc_read() != 0) { 189 LOG(ERROR) << "Failed to read data from QUIC IPC channel"; 190 191 return; 192 } 193} 194} // namespace 195#endif // ENABLE_HTTP3 196 197namespace { 198int generate_ticket_key(TicketKey &ticket_key) { 199 ticket_key.cipher = get_config()->tls.ticket.cipher; 200 ticket_key.hmac = EVP_sha256(); 201 ticket_key.hmac_keylen = EVP_MD_size(ticket_key.hmac); 202 203 assert(static_cast<size_t>(EVP_CIPHER_key_length(ticket_key.cipher)) <= 204 ticket_key.data.enc_key.size()); 205 assert(ticket_key.hmac_keylen <= ticket_key.data.hmac_key.size()); 206 207 if (LOG_ENABLED(INFO)) { 208 LOG(INFO) << "enc_keylen=" << EVP_CIPHER_key_length(ticket_key.cipher) 209 << ", hmac_keylen=" << ticket_key.hmac_keylen; 210 } 211 212 if (RAND_bytes(reinterpret_cast<unsigned char *>(&ticket_key.data), 213 sizeof(ticket_key.data)) == 0) { 214 return -1; 215 } 216 217 return 0; 218} 219} // namespace 220 221namespace { 222void renew_ticket_key_cb(struct ev_loop *loop, ev_timer *w, int revents) { 223 auto conn_handler = static_cast<ConnectionHandler *>(w->data); 224 const auto &old_ticket_keys = conn_handler->get_ticket_keys(); 225 226 auto ticket_keys = std::make_shared<TicketKeys>(); 227 LOG(NOTICE) << "Renew new ticket keys"; 228 229 // If old_ticket_keys is not empty, it should contain at least 2 230 // keys: one for encryption, and last one for the next encryption 231 // key but decryption only. The keys in between are old keys and 232 // decryption only. The next key is provided to ensure to mitigate 233 // possible problem when one worker encrypt new key, but one worker, 234 // which did not take the that key yet, and cannot decrypt it. 235 // 236 // We keep keys for get_config()->tls_session_timeout seconds. The 237 // default is 12 hours. Thus the maximum ticket vector size is 12. 238 if (old_ticket_keys) { 239 auto &old_keys = old_ticket_keys->keys; 240 auto &new_keys = ticket_keys->keys; 241 242 assert(!old_keys.empty()); 243 244 auto max_tickets = 245 static_cast<size_t>(std::chrono::duration_cast<std::chrono::hours>( 246 get_config()->tls.session_timeout) 247 .count()); 248 249 new_keys.resize(std::min(max_tickets, old_keys.size() + 1)); 250 std::copy_n(std::begin(old_keys), new_keys.size() - 1, 251 std::begin(new_keys) + 1); 252 } else { 253 ticket_keys->keys.resize(1); 254 } 255 256 auto &new_key = ticket_keys->keys[0]; 257 258 if (generate_ticket_key(new_key) != 0) { 259 if (LOG_ENABLED(INFO)) { 260 LOG(INFO) << "failed to generate ticket key"; 261 } 262 conn_handler->set_ticket_keys(nullptr); 263 conn_handler->set_ticket_keys_to_worker(nullptr); 264 return; 265 } 266 267 if (LOG_ENABLED(INFO)) { 268 LOG(INFO) << "ticket keys generation done"; 269 assert(ticket_keys->keys.size() >= 1); 270 LOG(INFO) << 0 << " enc+dec: " 271 << util::format_hex(ticket_keys->keys[0].data.name); 272 for (size_t i = 1; i < ticket_keys->keys.size(); ++i) { 273 auto &key = ticket_keys->keys[i]; 274 LOG(INFO) << i << " dec: " << util::format_hex(key.data.name); 275 } 276 } 277 278 conn_handler->set_ticket_keys(ticket_keys); 279 conn_handler->set_ticket_keys_to_worker(ticket_keys); 280} 281} // namespace 282 283namespace { 284void memcached_get_ticket_key_cb(struct ev_loop *loop, ev_timer *w, 285 int revents) { 286 auto conn_handler = static_cast<ConnectionHandler *>(w->data); 287 auto dispatcher = conn_handler->get_tls_ticket_key_memcached_dispatcher(); 288 289 auto req = std::make_unique<MemcachedRequest>(); 290 req->key = "nghttpx:tls-ticket-key"; 291 req->op = MemcachedOp::GET; 292 req->cb = [conn_handler, w](MemcachedRequest *req, MemcachedResult res) { 293 switch (res.status_code) { 294 case MemcachedStatusCode::NO_ERROR: 295 break; 296 case MemcachedStatusCode::EXT_NETWORK_ERROR: 297 conn_handler->on_tls_ticket_key_network_error(w); 298 return; 299 default: 300 conn_handler->on_tls_ticket_key_not_found(w); 301 return; 302 } 303 304 // |version (4bytes)|len (2bytes)|key (variable length)|... 305 // (len, key) pairs are repeated as necessary. 306 307 auto &value = res.value; 308 if (value.size() < 4) { 309 LOG(WARN) << "Memcached: tls ticket key value is too small: got " 310 << value.size(); 311 conn_handler->on_tls_ticket_key_not_found(w); 312 return; 313 } 314 auto p = value.data(); 315 auto version = util::get_uint32(p); 316 // Currently supported version is 1. 317 if (version != 1) { 318 LOG(WARN) << "Memcached: tls ticket key version: want 1, got " << version; 319 conn_handler->on_tls_ticket_key_not_found(w); 320 return; 321 } 322 323 auto end = p + value.size(); 324 p += 4; 325 326 auto &ticketconf = get_config()->tls.ticket; 327 328 size_t expectedlen; 329 size_t enc_keylen; 330 size_t hmac_keylen; 331 if (ticketconf.cipher == EVP_aes_128_cbc()) { 332 expectedlen = 48; 333 enc_keylen = 16; 334 hmac_keylen = 16; 335 } else if (ticketconf.cipher == EVP_aes_256_cbc()) { 336 expectedlen = 80; 337 enc_keylen = 32; 338 hmac_keylen = 32; 339 } else { 340 return; 341 } 342 343 auto ticket_keys = std::make_shared<TicketKeys>(); 344 345 for (; p != end;) { 346 if (end - p < 2) { 347 LOG(WARN) << "Memcached: tls ticket key data is too small"; 348 conn_handler->on_tls_ticket_key_not_found(w); 349 return; 350 } 351 auto len = util::get_uint16(p); 352 p += 2; 353 if (len != expectedlen) { 354 LOG(WARN) << "Memcached: wrong tls ticket key size: want " 355 << expectedlen << ", got " << len; 356 conn_handler->on_tls_ticket_key_not_found(w); 357 return; 358 } 359 if (p + len > end) { 360 LOG(WARN) << "Memcached: too short tls ticket key payload: want " << len 361 << ", got " << (end - p); 362 conn_handler->on_tls_ticket_key_not_found(w); 363 return; 364 } 365 auto key = TicketKey(); 366 key.cipher = ticketconf.cipher; 367 key.hmac = EVP_sha256(); 368 key.hmac_keylen = hmac_keylen; 369 370 std::copy_n(p, key.data.name.size(), std::begin(key.data.name)); 371 p += key.data.name.size(); 372 373 std::copy_n(p, enc_keylen, std::begin(key.data.enc_key)); 374 p += enc_keylen; 375 376 std::copy_n(p, hmac_keylen, std::begin(key.data.hmac_key)); 377 p += hmac_keylen; 378 379 ticket_keys->keys.push_back(std::move(key)); 380 } 381 382 conn_handler->on_tls_ticket_key_get_success(ticket_keys, w); 383 }; 384 385 if (LOG_ENABLED(INFO)) { 386 LOG(INFO) << "Memcached: tls ticket key get request sent"; 387 } 388 389 dispatcher->add_request(std::move(req)); 390} 391 392} // namespace 393 394#ifdef HAVE_NEVERBLEED 395namespace { 396void nb_child_cb(struct ev_loop *loop, ev_child *w, int revents) { 397 log_chld(w->rpid, w->rstatus, "neverbleed process"); 398 399 ev_child_stop(loop, w); 400 401 LOG(FATAL) << "neverbleed process exitted; aborting now"; 402 403 nghttp2_Exit(EXIT_FAILURE); 404} 405} // namespace 406#endif // HAVE_NEVERBLEED 407 408namespace { 409int send_ready_event(int ready_ipc_fd) { 410 std::array<char, STRERROR_BUFSIZE> errbuf; 411 auto pid = getpid(); 412 ssize_t nwrite; 413 414 while ((nwrite = write(ready_ipc_fd, &pid, sizeof(pid))) == -1 && 415 errno == EINTR) 416 ; 417 418 if (nwrite < 0) { 419 auto error = errno; 420 421 LOG(ERROR) << "Writing PID to ready IPC channel failed: " 422 << xsi_strerror(error, errbuf.data(), errbuf.size()); 423 424 return -1; 425 } 426 427 return 0; 428} 429} // namespace 430 431int worker_process_event_loop(WorkerProcessConfig *wpconf) { 432 int rv; 433 std::array<char, STRERROR_BUFSIZE> errbuf; 434 (void)errbuf; 435 436 auto config = get_config(); 437 438 if (reopen_log_files(config->logging) != 0) { 439 LOG(FATAL) << "Failed to open log file"; 440 return -1; 441 } 442 443 rv = ares_library_init(ARES_LIB_INIT_ALL); 444 if (rv != 0) { 445 LOG(FATAL) << "ares_library_init failed: " << ares_strerror(rv); 446 return -1; 447 } 448 449 auto loop = EV_DEFAULT; 450 451 auto gen = util::make_mt19937(); 452 453#ifdef HAVE_NEVERBLEED 454 std::array<char, NEVERBLEED_ERRBUF_SIZE> nb_errbuf; 455 auto nb = std::make_unique<neverbleed_t>(); 456 if (neverbleed_init(nb.get(), nb_errbuf.data()) != 0) { 457 LOG(FATAL) << "neverbleed_init failed: " << nb_errbuf.data(); 458 return -1; 459 } 460 461 LOG(NOTICE) << "neverbleed process [" << nb->daemon_pid << "] spawned"; 462 463 ev_child nb_childev; 464 465 ev_child_init(&nb_childev, nb_child_cb, nb->daemon_pid, 0); 466 nb_childev.data = nullptr; 467 ev_child_start(loop, &nb_childev); 468#endif // HAVE_NEVERBLEED 469 470 auto conn_handler = std::make_unique<ConnectionHandler>(loop, gen); 471 472#ifdef HAVE_NEVERBLEED 473 conn_handler->set_neverbleed(nb.get()); 474#endif // HAVE_NEVERBLEED 475 476#ifdef ENABLE_HTTP3 477 conn_handler->set_quic_ipc_fd(wpconf->quic_ipc_fd); 478 conn_handler->set_quic_lingering_worker_processes( 479 wpconf->quic_lingering_worker_processes); 480#endif // ENABLE_HTTP3 481 482 for (auto &addr : config->conn.listener.addrs) { 483 conn_handler->add_acceptor( 484 std::make_unique<AcceptHandler>(&addr, conn_handler.get())); 485 } 486 487 MemchunkPool mcpool; 488 489 ev_timer renew_ticket_key_timer; 490 if (tls::upstream_tls_enabled(config->conn)) { 491 auto &ticketconf = config->tls.ticket; 492 auto &memcachedconf = ticketconf.memcached; 493 494 if (!memcachedconf.host.empty()) { 495 SSL_CTX *ssl_ctx = nullptr; 496 497 if (memcachedconf.tls) { 498 ssl_ctx = conn_handler->create_tls_ticket_key_memcached_ssl_ctx(); 499 } 500 501 conn_handler->set_tls_ticket_key_memcached_dispatcher( 502 std::make_unique<MemcachedDispatcher>( 503 &ticketconf.memcached.addr, loop, ssl_ctx, 504 StringRef{memcachedconf.host}, &mcpool, gen)); 505 506 ev_timer_init(&renew_ticket_key_timer, memcached_get_ticket_key_cb, 0., 507 0.); 508 renew_ticket_key_timer.data = conn_handler.get(); 509 // Get first ticket keys. 510 memcached_get_ticket_key_cb(loop, &renew_ticket_key_timer, 0); 511 } else { 512 bool auto_tls_ticket_key = true; 513 if (!ticketconf.files.empty()) { 514 if (!ticketconf.cipher_given) { 515 LOG(WARN) 516 << "It is strongly recommended to specify " 517 "--tls-ticket-key-cipher=aes-128-cbc (or " 518 "tls-ticket-key-cipher=aes-128-cbc in configuration file) " 519 "when --tls-ticket-key-file is used for the smooth " 520 "transition when the default value of --tls-ticket-key-cipher " 521 "becomes aes-256-cbc"; 522 } 523 auto ticket_keys = read_tls_ticket_key_file( 524 ticketconf.files, ticketconf.cipher, EVP_sha256()); 525 if (!ticket_keys) { 526 LOG(WARN) << "Use internal session ticket key generator"; 527 } else { 528 conn_handler->set_ticket_keys(std::move(ticket_keys)); 529 auto_tls_ticket_key = false; 530 } 531 } 532 if (auto_tls_ticket_key) { 533 // Generate new ticket key every 1hr. 534 ev_timer_init(&renew_ticket_key_timer, renew_ticket_key_cb, 0., 1_h); 535 renew_ticket_key_timer.data = conn_handler.get(); 536 ev_timer_again(loop, &renew_ticket_key_timer); 537 538 // Generate first session ticket key before running workers. 539 renew_ticket_key_cb(loop, &renew_ticket_key_timer, 0); 540 } 541 } 542 } 543 544#ifdef ENABLE_HTTP3 545 auto &quicconf = config->quic; 546 547 std::shared_ptr<QUICKeyingMaterials> qkms; 548 549 if (!quicconf.upstream.secret_file.empty()) { 550 qkms = read_quic_secret_file(quicconf.upstream.secret_file); 551 if (!qkms) { 552 LOG(WARN) << "Use QUIC keying materials generated internally"; 553 } 554 } 555 556 if (!qkms) { 557 qkms = std::make_shared<QUICKeyingMaterials>(); 558 qkms->keying_materials.resize(1); 559 560 auto &qkm = qkms->keying_materials.front(); 561 562 if (RAND_bytes(qkm.reserved.data(), qkm.reserved.size()) != 1) { 563 LOG(ERROR) << "Failed to generate QUIC secret reserved data"; 564 return -1; 565 } 566 567 if (RAND_bytes(qkm.secret.data(), qkm.secret.size()) != 1) { 568 LOG(ERROR) << "Failed to generate QUIC secret"; 569 return -1; 570 } 571 572 if (RAND_bytes(qkm.salt.data(), qkm.salt.size()) != 1) { 573 LOG(ERROR) << "Failed to generate QUIC salt"; 574 return -1; 575 } 576 } 577 578 for (auto &qkm : qkms->keying_materials) { 579 if (generate_quic_connection_id_encryption_key( 580 qkm.cid_encryption_key.data(), qkm.cid_encryption_key.size(), 581 qkm.secret.data(), qkm.secret.size(), qkm.salt.data(), 582 qkm.salt.size()) != 0) { 583 LOG(ERROR) << "Failed to generate QUIC Connection ID encryption key"; 584 return -1; 585 } 586 } 587 588 conn_handler->set_quic_keying_materials(std::move(qkms)); 589 590 conn_handler->set_cid_prefixes(wpconf->cid_prefixes); 591 conn_handler->set_quic_lingering_worker_processes( 592 wpconf->quic_lingering_worker_processes); 593#endif // ENABLE_HTTP3 594 595 if (config->single_thread) { 596 rv = conn_handler->create_single_worker(); 597 if (rv != 0) { 598 return -1; 599 } 600 } else { 601#ifndef NOTHREADS 602 sigset_t set; 603 sigemptyset(&set); 604 sigaddset(&set, SIGCHLD); 605 606 rv = pthread_sigmask(SIG_BLOCK, &set, nullptr); 607 if (rv != 0) { 608 LOG(ERROR) << "Blocking SIGCHLD failed: " 609 << xsi_strerror(rv, errbuf.data(), errbuf.size()); 610 return -1; 611 } 612#endif // !NOTHREADS 613 614 rv = conn_handler->create_worker_thread(config->num_worker); 615 if (rv != 0) { 616 return -1; 617 } 618 619#ifndef NOTHREADS 620 rv = pthread_sigmask(SIG_UNBLOCK, &set, nullptr); 621 if (rv != 0) { 622 LOG(ERROR) << "Unblocking SIGCHLD failed: " 623 << xsi_strerror(rv, errbuf.data(), errbuf.size()); 624 return -1; 625 } 626#endif // !NOTHREADS 627 } 628 629#if defined(ENABLE_HTTP3) && defined(HAVE_LIBBPF) 630 conn_handler->unload_bpf_objects(); 631#endif // defined(ENABLE_HTTP3) && defined(HAVE_LIBBPF) 632 633 drop_privileges( 634#ifdef HAVE_NEVERBLEED 635 nb.get() 636#endif // HAVE_NEVERBLEED 637 ); 638 639 ev_io ipcev; 640 ev_io_init(&ipcev, ipc_readcb, wpconf->ipc_fd, EV_READ); 641 ipcev.data = conn_handler.get(); 642 ev_io_start(loop, &ipcev); 643 644#ifdef ENABLE_HTTP3 645 ev_io quic_ipcev; 646 ev_io_init(&quic_ipcev, quic_ipc_readcb, wpconf->quic_ipc_fd, EV_READ); 647 quic_ipcev.data = conn_handler.get(); 648 ev_io_start(loop, &quic_ipcev); 649#endif // ENABLE_HTTP3 650 651 if (tls::upstream_tls_enabled(config->conn) && !config->tls.ocsp.disabled) { 652 if (config->tls.ocsp.startup) { 653 conn_handler->set_enable_acceptor_on_ocsp_completion(true); 654 conn_handler->disable_acceptor(); 655 } 656 657 conn_handler->proceed_next_cert_ocsp(); 658 } 659 660 if (LOG_ENABLED(INFO)) { 661 LOG(INFO) << "Entering event loop"; 662 } 663 664 if (send_ready_event(wpconf->ready_ipc_fd) != 0) { 665 return -1; 666 } 667 668 ev_run(loop, 0); 669 670 conn_handler->cancel_ocsp_update(); 671 672 // Destroy SSL_CTX held in conn_handler before killing neverbleed 673 // daemon. Otherwise priv_rsa_finish yields "write error" and 674 // worker process aborts. 675 conn_handler.reset(); 676 677#ifdef HAVE_NEVERBLEED 678 assert(nb->daemon_pid > 0); 679 680 rv = kill(nb->daemon_pid, SIGTERM); 681 if (rv != 0) { 682 auto error = errno; 683 LOG(ERROR) << "Could not send signal to neverbleed daemon: errno=" << error; 684 } 685 686 while ((rv = waitpid(nb->daemon_pid, nullptr, 0)) == -1 && errno == EINTR) 687 ; 688 if (rv == -1) { 689 auto error = errno; 690 LOG(ERROR) << "Error occurred while we were waiting for the completion " 691 "of neverbleed process: errno=" 692 << error; 693 } 694#endif // HAVE_NEVERBLEED 695 696 ares_library_cleanup(); 697 698 return 0; 699} 700 701} // namespace shrpx 702