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