Sun, 27 Nov 2022 10:07:37 +0100
fix listener ssl initialization
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2013 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <errno.h> #include <pthread.h> #include <fcntl.h> #include <poll.h> #include "../util/pool.h" #include "../public/nsapi.h" #include "../util/plist.h" #include "../util/date.h" #include <cx/string.h> #include "webserver.h" #include "log.h" #include "httprequest.h" #include "httplistener.h" #include "srvctrl.h" #include "configmanager.h" #define LOG_THREAD_STACK_SIZE 32768 #define LOG_THREAD_MAX_POLL_FAILS 10 #define LOG_THREAD_READ_BUF 2048 static int std_out[2]; static int std_err[2]; static WSBool is_daemon; void test() { time_t t = time(NULL); pool_handle_t *pool = pool_create(); cxmutstr date = date_format_http(t, pool); printf("%s\n", date.ptr); } WSBool main_is_daemon(void) { return is_daemon; } /* * SIGUSR1: reload the configuration files */ void sig_usr1_reload(int sig) { log_ereport(LOG_INFORM, "sig reload"); CfgManager mgr; if(cfgmgr_load_config(&mgr) != 0) { log_ereport(LOG_FAILURE, "cannot reload server.conf"); } else { if(cfgmgr_apply_config(&mgr)) { log_ereport(LOG_FAILURE, "cannot reload config"); } } // start newly created listeners start_all_listener(); signal(SIGUSR1, sig_usr1_reload); } /* * SIGTERM: stop the server */ void sig_term(int sig) { webserver_shutdown(); //exit(EXIT_SUCCESS); } static void set_pipe_nonblocking(int fd) { int flags = 0; flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); } static char log_pipe_readbuf[LOG_THREAD_READ_BUF]; static char log_pipe_stdout_buf[LOG_THREAD_READ_BUF]; static char log_pipe_stderr_buf[LOG_THREAD_READ_BUF]; static size_t log_pipe_stdout_tmp_pos = 0; static size_t log_pipe_stderr_tmp_pos = 0; static int log_pipe(const char *name, int fd, char *buf, size_t *pos) { ssize_t r = read(fd, log_pipe_readbuf, 2); if(r <= 0) { return 1; } char *tmp = buf; int tmplen = *pos; int s = 0; for(int i=0;i<r;i++) { if(log_pipe_readbuf[i] == '\n') { if(tmplen + i-s > 0) { log_message(name, "%.*s%.*s", tmplen, tmp, i-s, log_pipe_readbuf + s); } tmplen = 0; *pos = 0; s = i+1; } } int remaining = r - s; if(tmplen + remaining >= LOG_THREAD_READ_BUF) { log_message(name, "%.*s%.*s", tmplen, tmp, remaining, log_pipe_readbuf + s); *pos = 0; } else if(remaining > 0) { memcpy(buf + *pos, log_pipe_readbuf + s, remaining); *pos += remaining; } return 0; } void* log_pipe_thread(void *data) { set_pipe_nonblocking(std_out[0]); set_pipe_nonblocking(std_err[0]); struct pollfd fds[2]; fds[0].fd = std_out[0]; fds[0].events = POLLIN; fds[1].fd = std_err[0]; fds[1].events = POLLIN; int poll_fails = 0; for(;;) { if(poll(fds, 1, 1000000) < 0) { if(errno == EINTR) { continue; } log_ereport(LOG_FAILURE, "log thread poll failed: %s", strerror(errno)); if(poll_fails++ > LOG_THREAD_MAX_POLL_FAILS) { break; } } // check stdout if(fds[0].revents & POLLIN) { if(log_pipe("stdout", fds[0].fd, log_pipe_stdout_buf, &log_pipe_stdout_tmp_pos)) { break; } } // check stderr if(fds[1].revents & POLLIN) { if(log_pipe("stderr", fds[0].fd, log_pipe_stderr_buf, &log_pipe_stderr_tmp_pos)) { break; } } } log_ereport(LOG_INFORM, "log thread end"); return NULL; } int main(int argc, char **argv) { //test(); // if the -c parameter is specified, we don't create a daemon is_daemon = 1; for(int i=0;i<argc;i++) { char *p = argv[i]; if(p[0] == '-' && p[1] == 'c') { is_daemon = 0; break; } } if(is_daemon) { // create daemon pid_t pid = fork(); if(pid < 0) { return EXIT_FAILURE; } else if(pid > 0) { return EXIT_SUCCESS; } if(setsid() < 0) { fprintf(stderr, "setsid failed\n"); return EXIT_FAILURE; } printf("start daemon\n"); for(int i=0;i<3;i++) { close(i); } // stdio redirection // create pipes if(pipe(std_out) != 0) { perror("pipe"); return EXIT_FAILURE; } if(pipe(std_err) != 0) { perror("pipe"); return EXIT_FAILURE; } dup2(std_out[1], 1); dup2(std_err[1], 2); close(std_err[1]); // set log thread stack size pthread_attr_t tattr; pthread_attr_init(&tattr); pthread_attr_setstacksize(&tattr, LOG_THREAD_STACK_SIZE); pthread_t tid; pthread_create(&tid, &tattr, log_pipe_thread, NULL); } pool_init(NULL, NULL, NULL); // add signal handler signal(SIGUSR1, sig_usr1_reload); signal(SIGTERM, sig_term); signal(SIGINT, sig_term); struct sigaction act; ZERO(&act, sizeof(struct sigaction)); act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, NULL); // start webserver log_ereport(LOG_INFORM, "startup"); int status; status = webserver_init(); if(status != 0) { log_ereport(LOG_FAILURE, "cannot initialize server."); return EXIT_FAILURE; } status = webserver_run(); if(status != 0) { log_ereport(LOG_FAILURE, "cannot run server."); return EXIT_FAILURE; } if(srvctrl_wait()) { return EXIT_FAILURE; } /* TODO: join threads (or not?) */ /* while(1) { if(is_daemon) { fflush(stdout); fflush(stderr); } sleep(10000); if(0) { break; } } */ return EXIT_SUCCESS; }