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