summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorCorey Farrell <git@cfware.com>2017-06-18 20:24:04 -0400
committerCorey Farrell <git@cfware.com>2017-07-21 14:04:33 -0500
commiteea9da2f42c23fae72bb5b67c51dd38ab3a92a8d (patch)
treee0e69955214e682e2e4550cb8c6298c5adc147b3 /main
parent7fcb730997a54fd58a2edf47489f464c34c6e156 (diff)
Core: Add support for systemd socket activation.
This change adds support for socket activation of certain SOCK_STREAM listeners in Asterisk: * AMI / AMI over TLS * CLI * HTTP / HTTPS Example systemd units are provided. This support extends to any socket which is initialized using ast_tcptls_server_start, so any unknown modules using this function will support socket activation. Asterisk continues to function as normal if socket activation is not enabled or if systemd development headers are not available during build. ASTERISK-27063 #close Change-Id: Id814ee6a892f4b80d018365c8ad8d89063474f4d
Diffstat (limited to 'main')
-rw-r--r--main/asterisk.c29
-rw-r--r--main/io.c74
-rw-r--r--main/tcptls.c17
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(&lthread, 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;
diff --git a/main/io.c b/main/io.c
index b063c2239..ed455df97 100644
--- a/main/io.c
+++ b/main/io.c
@@ -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)) {