diff options
author | Jenkins2 <jenkins2@gerrit.asterisk.org> | 2017-07-26 09:17:40 -0500 |
---|---|---|
committer | Gerrit Code Review <gerrit2@gerrit.digium.api> | 2017-07-26 09:17:40 -0500 |
commit | 1bec535df2e8a7968a810cbef594fa17f7b642bc (patch) | |
tree | f3df3f11f0d958494683973a95e656d5982a806d /main | |
parent | b610295b62abfdcac068b2fe1406ba74df8a00b5 (diff) | |
parent | 70d2ccb9daa1926788b1296c6ccb2611341302d0 (diff) |
Merge "Core: Add support for systemd socket activation."
Diffstat (limited to 'main')
-rw-r--r-- | main/asterisk.c | 29 | ||||
-rw-r--r-- | main/io.c | 74 | ||||
-rw-r--r-- | main/tcptls.c | 17 |
3 files changed, 117 insertions, 3 deletions
diff --git a/main/asterisk.c b/main/asterisk.c index 04298385a..a302836a4 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -350,6 +350,7 @@ struct ast_eid ast_eid_default; char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR; static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */ +static int ast_socket_is_sd = 0; /*!< Is socket activation responsible for ast_socket? */ static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */ pid_t ast_mainpid; struct console { @@ -1576,8 +1577,16 @@ static int ast_makesocket(void) uid_t uid = -1; gid_t gid = -1; - for (x = 0; x < AST_MAX_CONNECTS; x++) + for (x = 0; x < AST_MAX_CONNECTS; x++) { consoles[x].fd = -1; + } + + if (ast_socket_is_sd) { + ast_socket = ast_sd_get_fd_un(SOCK_STREAM, ast_config_AST_SOCKET); + + goto start_lthread; + } + unlink(ast_config_AST_SOCKET); ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0); if (ast_socket < 0) { @@ -1602,12 +1611,19 @@ static int ast_makesocket(void) return -1; } +start_lthread: if (ast_pthread_create_background(<hread, NULL, listener, NULL)) { ast_log(LOG_WARNING, "Unable to create listener thread.\n"); close(ast_socket); return -1; } + if (ast_socket_is_sd) { + /* owner/group/permissions are set by systemd, we might not even have access + * to socket file so leave it alone */ + return 0; + } + if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) { struct passwd *pw; if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) @@ -2075,7 +2091,9 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart) pthread_cancel(lthread); close(ast_socket); ast_socket = -1; - unlink(ast_config_AST_SOCKET); + if (!ast_socket_is_sd) { + unlink(ast_config_AST_SOCKET); + } pthread_kill(lthread, SIGURG); pthread_join(lthread, NULL); } @@ -4319,7 +4337,12 @@ int main(int argc, char *argv[]) /* Initial value of the maximum active system verbosity level. */ ast_verb_sys_level = option_verbose; - if (ast_tryconnect()) { + if (ast_sd_get_fd_un(SOCK_STREAM, ast_config_AST_SOCKET) > 0) { + ast_socket_is_sd = 1; + } + + /* DO NOT perform check for existing daemon if systemd has CLI socket activation */ + if (!ast_socket_is_sd && ast_tryconnect()) { /* One is already running */ if (ast_opt_remote) { multi_thread_safe = 1; @@ -36,6 +36,10 @@ #include "asterisk/utils.h" #ifdef HAVE_SYSTEMD #include <systemd/sd-daemon.h> + +#ifndef SD_LISTEN_FDS_START +#define SD_LISTEN_FDS_START 3 +#endif #endif #ifdef DEBUG_IO @@ -392,3 +396,73 @@ int ast_sd_notify(const char *state) { return 0; #endif } + +/*! + * \internal \brief Check the type and sockaddr of a file descriptor. + * \param fd File Descriptor to check. + * \param type SOCK_STREAM or SOCK_DGRAM + * \param addr The socket address to match. + * \retval 0 if matching + * \retval -1 if not matching + */ +#ifdef HAVE_SYSTEMD +static int ast_sd_is_socket_sockaddr(int fd, int type, const struct ast_sockaddr* addr) +{ + int canretry = 1; + struct ast_sockaddr fd_addr; + struct sockaddr ss; + socklen_t ss_len; + + if (sd_is_socket(fd, AF_UNSPEC, type, 1) <= 0) { + return -1; + } + +doretry: + if (getsockname(fd, &ss, &ss_len) != 0) { + return -1; + } + + if (ss.sa_family == AF_UNSPEC && canretry) { + /* An unknown bug can cause silent failure from + * the first call to getsockname. */ + canretry = 0; + goto doretry; + } + + ast_sockaddr_copy_sockaddr(&fd_addr, &ss, ss_len); + + return ast_sockaddr_cmp(addr, &fd_addr); +} +#endif + +int ast_sd_get_fd(int type, const struct ast_sockaddr *addr) +{ +#ifdef HAVE_SYSTEMD + int count = sd_listen_fds(0); + int idx; + + for (idx = 0; idx < count; idx++) { + if (!ast_sd_is_socket_sockaddr(idx + SD_LISTEN_FDS_START, type, addr)) { + return idx + SD_LISTEN_FDS_START; + } + } +#endif + + return -1; +} + +int ast_sd_get_fd_un(int type, const char *path) +{ +#ifdef HAVE_SYSTEMD + int count = sd_listen_fds(0); + int idx; + + for (idx = 0; idx < count; idx++) { + if (sd_is_socket_unix(idx + SD_LISTEN_FDS_START, type, 1, path, 0) > 0) { + return idx + SD_LISTEN_FDS_START; + } + } +#endif + + return -1; +} diff --git a/main/tcptls.c b/main/tcptls.c index a3c7dfa72..85859a343 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -40,6 +40,7 @@ #include "asterisk/compat.h" #include "asterisk/tcptls.h" +#include "asterisk/io.h" #include "asterisk/http.h" #include "asterisk/utils.h" #include "asterisk/strings.h" @@ -618,6 +619,7 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) int flags; int x = 1; int tls_changed = 0; + int sd_socket; if (desc->tls_cfg) { char hash[41]; @@ -689,6 +691,19 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) pthread_join(desc->master, NULL); } + sd_socket = ast_sd_get_fd(SOCK_STREAM, &desc->local_address); + + if (sd_socket != -1) { + if (desc->accept_fd != sd_socket) { + if (desc->accept_fd != -1) { + close(desc->accept_fd); + } + desc->accept_fd = sd_socket; + } + + goto systemd_socket_activation; + } + if (desc->accept_fd != -1) { close(desc->accept_fd); } @@ -718,6 +733,8 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name); goto error; } + +systemd_socket_activation: flags = fcntl(desc->accept_fd, F_GETFL); fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK); if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) { |