Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/lavabit/magma.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLadar Levison <ladar@lavabit.com>2018-11-07 22:48:56 +0300
committerLadar Levison <ladar@lavabit.com>2018-11-07 22:48:56 +0300
commit87ef4b88f3e06b44450611d9bcf1c0c0c754edd8 (patch)
tree587ce71e48f772ea524ccfe28a21defbc35c7bec
parent26d9c5dee9401bbbcf1893b5856cb5f85a3eb91c (diff)
Cleaned up the shutdown process.
-rw-r--r--check/magma/magma_check.c3
-rw-r--r--src/engine/context/signal.c79
-rw-r--r--src/engine/controller/protocol.c8
-rw-r--r--src/engine/controller/queue.c2
-rw-r--r--src/engine/status/status.c2
-rw-r--r--src/network/clients.c6
-rw-r--r--src/network/listeners.c103
-rw-r--r--src/network/network.h1
-rw-r--r--src/providers/cryptography/tls.c2
9 files changed, 122 insertions, 84 deletions
diff --git a/check/magma/magma_check.c b/check/magma/magma_check.c
index 6ffc14da..fabb8853 100644
--- a/check/magma/magma_check.c
+++ b/check/magma/magma_check.c
@@ -365,7 +365,8 @@ int main(int argc, char *argv[]) {
srunner_free(sr);
// Cleanup the background listening thread.
- thread_cancel(*net_listen_thread);
+ net_trigger(false);
+
thread_join(*net_listen_thread);
mm_free(net_listen_thread);
diff --git a/src/engine/context/signal.c b/src/engine/context/signal.c
index a3925120..02d55ec6 100644
--- a/src/engine/context/signal.c
+++ b/src/engine/context/signal.c
@@ -51,18 +51,11 @@ void signal_segfault(int signal) {
*/
void signal_shutdown(int signal) {
- ip_t ip;
- char working[64];
- struct stat64 info;
- struct rlimit64 limits;
pthread_t status_thread;
- server_t *server = NULL;
- struct sockaddr *saddr = MEMORYBUF(sizeof(struct sockaddr_in6));
- socklen_t len = sizeof(struct sockaddr_in6);
const struct timespec split = { .tv_sec = 0, .tv_nsec = 100000000 }, single = { .tv_sec = 1, .tv_nsec = 0 };
// We assume the server is being shutdown for a good reason.
- log_critical("Signal received. The Magma daemon is attempting a graceful exit. { signal = %s }", signal_name(signal, working, 32));
+ log_critical("Signal received. The Magma daemon is attempting a graceful exit. { signal = %s }", signal_name(signal, MEMORYBUF(32), 32));
// Clear the thread structure or we'll get a segfault when we attempt the thread join operation.
mm_wipe(&status_thread, sizeof(pthread_t));
@@ -70,74 +63,24 @@ void signal_shutdown(int signal) {
// Set the status flag so all the worker threads exit nicely.
thread_launch(&status_thread, &status_signal, NULL);
- // Loop through and shutdown all of the socket descriptors used to listen for incomoing connections.
- for (uint64_t i = 0; i < MAGMA_SERVER_INSTANCES; i++) {
- if ((server = magma.servers[i]) && server->enabled && server->network.sockd > 0) {
- shutdown(server->network.sockd, SHUT_RDWR);
- }
- }
-//
-// // We give threads 0.1 seconds to ensure the status update is queued and awaiting the lock.
+ // We give threads 0.1 seconds to ensure the status update is queued and awaiting the lock.
nanosleep(&split, NULL);
-//
-// // Signals the worker threads, so they unblock.
-// queue_signal();
-//
-// // We give threads 0.1 seconds to let the status update.
-// nanosleep(&split, NULL);
-//
-// // Signals the worker threads, so they unblock one more time and see the updated status, thus exiting normally.
-// queue_signal();
-//
-// // Then sleep for one second before forcibly shutting down the client connections.
+
+ // Signals the worker threads, so they unblock one more time and see the updated status, thus exiting normally.
+ queue_signal();
+
+ // Then sleep for one second before forcibly shutting down the client connections.
nanosleep(&single, NULL);
nanosleep(&single, NULL);
nanosleep(&single, NULL);
- thread_join(status_thread);
-
- // Now go through and shutdown all client connections.
- if (getrlimit64(RLIMIT_NOFILE, &limits)) {
- log_critical("Unable to determine the maximum legal file descriptor.");
- thread_join(status_thread);
- return;
- }
-
- // Loop through and check all of the potentially valid file descriptors.
- for (int fd = 0; fd <= limits.rlim_max; fd++) {
-
- mm_wipe(&info, sizeof(struct stat64));
- mm_wipe(&saddr, sizeof(struct sockaddr_in6));
-
- /// LOW: This only compares the port number for the sockets. We should also ensure the socket is owned by magmad, and/or
- /// that the server used INADDR_ANY or IN6ADDR_ANY_INIT, otherwise the logic below will close sockets that could be owned by
- /// other processes on the system that are using the same port number, while bound to a different IP interface.
- // Look for socket descriptors using ports assigned to server instances and close them.
- if (!fstat64(fd, &info) && S_ISSOCK(info.st_mode) && !getsockname(fd, saddr, &len)) {
-
- if (len == sizeof(struct sockaddr_in6) && ((struct sockaddr_in6 *)saddr)->sin6_family == AF_INET6 &&
- servers_get_count_using_port(ntohs(((struct sockaddr_in6 *)saddr)->sin6_port))) {
-
- mm_copy(&(ip.ip6), &(((struct sockaddr_in6 *)saddr)->sin6_addr), sizeof(struct in6_addr));
- ip.family = AF_INET6;
- log_info("%s:%u is being shutdown.", st_char_get(ip_presentation(&ip, PLACER(working, 64))),
- ntohs(((struct sockaddr_in6 *)saddr)->sin6_port));
- shutdown(fd, SHUT_RDWR);
- }
- else if (len == sizeof(struct sockaddr_in) && (((struct sockaddr_in *)saddr)->sin_family == AF_INET &&
- servers_get_count_using_port(ntohs(((struct sockaddr_in *)saddr)->sin_port)))) {
-
- mm_copy(&(ip.ip4), &(((struct sockaddr_in *)saddr)->sin_addr), sizeof(struct in_addr));
- ip.family = AF_INET;
- log_info("%s:%u is being shutdown.", st_char_get(ip_presentation(&ip, PLACER(working, 64))),
- ntohs(((struct sockaddr_in *)saddr)->sin_port));
- shutdown(fd, SHUT_RDWR);
- }
- }
- }
+ // Shutdown any remaining threads.
+ net_trigger(true);
// Signals the worker threads, so they unblock and see the underlying connection has been shutdown.
queue_signal();
+
+ thread_join(status_thread);
return;
}
diff --git a/src/engine/controller/protocol.c b/src/engine/controller/protocol.c
index 65394820..4f517fa2 100644
--- a/src/engine/controller/protocol.c
+++ b/src/engine/controller/protocol.c
@@ -171,8 +171,12 @@ void protocol_secure(connection_t *con) {
// Create a new TLS object.
if (!(con->network.tls = tls_server_alloc(con->server, con->network.sockd, M_SSL_BIO_NOCLOSE))) {
- log_pedantic("The TLS connection attempt failed. { ip = %s / port = %u / protocol = %.*s }", st_char_get(con_addr_presentation(con, MANAGEDBUF(256))),
- con->server->network.port, st_length_int(protocol_type(con)), st_char_get(protocol_type(con)));
+#ifdef MAGMA_PEDANTIC
+ if (status()) {
+ log_pedantic("The TLS connection attempt failed. { ip = %s / port = %u / protocol = %.*s }", st_char_get(con_addr_presentation(con, MANAGEDBUF(256))),
+ con->server->network.port, st_length_int(protocol_type(con)), st_char_get(protocol_type(con)));
+ }
+#endif
// We manually free the connection structure since calling con_destroy() would improperly decrement the statistical counters.
if (con->network.tls) tls_free(con->network.tls);
diff --git a/src/engine/controller/queue.c b/src/engine/controller/queue.c
index b40155ce..a40a79ae 100644
--- a/src/engine/controller/queue.c
+++ b/src/engine/controller/queue.c
@@ -136,7 +136,7 @@ void queue_signal(void) {
for (uint64_t i = 0; queue.workers && i < magma.system.worker_threads; i++) {
- if (queue.workers + i && (ret = thread_signal(*(queue.workers + i), SIGALRM)) && status()) {
+ if (queue.workers + i && (ret = thread_signal(*(queue.workers + i), SIGALRM))) {
log_info("Unable to signal the worker thread. {ret = %i}", ret);
}
diff --git a/src/engine/status/status.c b/src/engine/status/status.c
index a7215812..808d1f61 100644
--- a/src/engine/status/status.c
+++ b/src/engine/status/status.c
@@ -35,7 +35,7 @@ bool_t status(void) {
}
/**
- * @brief Set the status level to a specified value.
+ * @brief Set the status level to provided value.
* @see status()
* @param value the integer value of the new status level.
* @return This function returns no value.
diff --git a/src/network/clients.c b/src/network/clients.c
index 96647907..e6fba773 100644
--- a/src/network/clients.c
+++ b/src/network/clients.c
@@ -84,8 +84,12 @@ client_t * client_connect(chr_t *host, uint32_t port) {
// Resolve the hostname.
if ((ret = getaddrinfo(host, service, &hints, &info)) || !info || info->ai_socktype != SOCK_STREAM) {
- log_pedantic("Unable to resolve the host %s:%u and create a client connection. { getaddrinfo = %i / errno = %s }", host,
+
+#ifdef MAGMA_PEDANTIC
+ if (status()) log_pedantic("Unable to resolve the host %s:%u and create a client connection. { getaddrinfo = %i / errno = %s }", host,
port, ret, strerror_r(errno, MEMORYBUF(256), 256));
+#endif
+
if (info) freeaddrinfo(info);
return NULL ;
}
diff --git a/src/network/listeners.c b/src/network/listeners.c
index b0d1c661..6a9c4b15 100644
--- a/src/network/listeners.c
+++ b/src/network/listeners.c
@@ -119,7 +119,101 @@ bool_t net_init(server_t *server) {
return true;
}
+/**
+ * @brief Trigers a connection for each server instance, allowing the the listeners to shutdown cleanly. And then purges
+ * any remaining sockets.
+ */
+void net_trigger(bool_t verbose) {
+
+ ip_t lip, rip;
+ client_t *client = NULL;
+ server_t *server = NULL;
+ bool_t connected = false;
+ struct rlimit64 limits;
+ struct stat64 info;
+ socklen_t slen = sizeof(struct sockaddr_in6), rlen = sizeof(struct sockaddr_in6);
+ struct sockaddr *saddr = MEMORYBUF(sizeof(struct sockaddr_in6)), *raddr = MEMORYBUF(sizeof(struct sockaddr_in6));
+
+ // Wakeup the listening threads.
+ for (uint64_t i = 0; i < MAGMA_SERVER_INSTANCES; i++) {
+ if ((server = magma.servers[i]) && server->enabled && server->network.sockd > 0) {
+ client_connect("localhost", server->network.port);
+ client_close(client);
+ shutdown(server->network.sockd, SHUT_RDWR);
+ }
+ }
+
+ // Now go through and shutdown all client connections.
+ if (getrlimit64(RLIMIT_NOFILE, &limits)) {
+ log_critical("Unable to determine the maximum legal file descriptor.");
+ return;
+ }
+
+ // Loop through and check all of the potentially valid file descriptors.
+ for (int fd = 0; fd <= limits.rlim_max; fd++) {
+
+ connected = false;
+ mm_wipe(&lip, sizeof(ip_t));
+ mm_wipe(&rip, sizeof(ip_t));
+ mm_wipe(&info, sizeof(struct stat64));
+ mm_wipe(saddr, sizeof(struct sockaddr_in6));
+ mm_wipe(raddr, sizeof(struct sockaddr_in6));
+
+ /// LOW: This only compares the port number for the sockets. We should also ensure the socket is owned by magmad, and/or
+ /// that the server used INADDR_ANY or IN6ADDR_ANY_INIT, otherwise the logic below will close sockets that could be owned by
+ /// other processes on the system that are using the same port number, while bound to a different IP interface.
+ // Look for socket descriptors using ports assigned to server instances and close them.
+ if (!fstat64(fd, &info) && S_ISSOCK(info.st_mode) && !getsockname(fd, saddr, &slen)) {
+
+ if (!getpeername(fd, raddr, &rlen)) {
+ if (rlen == sizeof(struct sockaddr_in6) && ((struct sockaddr_in6 *)raddr)->sin6_family == AF_INET6) {
+ mm_copy(&(rip.ip6), &(((struct sockaddr_in6 *)raddr)->sin6_addr), sizeof(struct in6_addr));
+ rip.family = AF_INET6;
+ connected = true;
+ }
+ else if (rlen == sizeof(struct sockaddr_in) && ((struct sockaddr_in *)raddr)->sin_family == AF_INET) {
+ mm_copy(&(rip.ip4), &(((struct sockaddr_in *)raddr)->sin_addr), sizeof(struct in_addr));
+ rip.family = AF_INET;
+ connected = true;
+ }
+ }
+
+ if (slen == sizeof(struct sockaddr_in6) && ((struct sockaddr_in6 *)saddr)->sin6_family == AF_INET6 &&
+ servers_get_count_using_port(ntohs(((struct sockaddr_in6 *)saddr)->sin6_port))) {
+ mm_copy(&(lip.ip6), &(((struct sockaddr_in6 *)saddr)->sin6_addr), sizeof(struct in6_addr));
+ lip.family = AF_INET6;
+ shutdown(fd, SHUT_RDWR);
+ }
+ else if (slen == sizeof(struct sockaddr_in) && (((struct sockaddr_in *)saddr)->sin_family == AF_INET &&
+ servers_get_count_using_port(ntohs(((struct sockaddr_in *)saddr)->sin_port)))) {
+ mm_copy(&(lip.ip4), &(((struct sockaddr_in *)saddr)->sin_addr), sizeof(struct in_addr));
+ lip.family = AF_INET;
+ shutdown(fd, SHUT_RDWR);
+ }
+ else {
+ connected = false;
+ }
+
+ if (connected && verbose) log_info("%s:%u <-> %s:%u is being shutdown.", st_char_get(ip_presentation(&lip, PLACER(MEMORYBUF(64), 64))),
+ ntohs(((struct sockaddr_in6 *)saddr)->sin6_port), st_char_get(ip_presentation(&rip, PLACER(MEMORYBUF(64), 64))),
+ ntohs(((struct sockaddr_in6 *)raddr)->sin6_port));
+ }
+ }
+
+ // Signals the worker threads, so they unblock and see the underlying connection has been shutdown.
+ queue_signal();
+
+ return;
+}
+/**
+ * @brief Close the listening socket associated with a server.
+ * @return This function returns no value.
+ */
+void net_shutdown(server_t *server) {
+ close(server->network.sockd);
+ return;
+}
/**
* @brief The main network handler entry point; poll the listening socket of each configured protocol server, and dispatch the
@@ -289,12 +383,3 @@ bool_t net_init(server_t *server) {
//
// return true;
//}
-
-/**
- * @brief Close the listening socket associated with a server.
- * @return This function returns no value.
- */
-void net_shutdown(server_t *server) {
- close(server->network.sockd);
- return;
-}
diff --git a/src/network/network.h b/src/network/network.h
index 71b0948d..36c5839c 100644
--- a/src/network/network.h
+++ b/src/network/network.h
@@ -128,6 +128,7 @@ void con_reverse_status(connection_t *con, int_t status);
bool_t net_init(server_t *server);
void net_listen(void);
void net_shutdown(server_t *server);
+void net_trigger(bool_t verbose);
/// write.c
int64_t client_print(client_t *client, chr_t *format, ...);
diff --git a/src/providers/cryptography/tls.c b/src/providers/cryptography/tls.c
index bce6e53f..03e05c40 100644
--- a/src/providers/cryptography/tls.c
+++ b/src/providers/cryptography/tls.c
@@ -197,7 +197,7 @@ TLS * tls_server_alloc(void *server, int sockd, int flags) {
// If the result code indicates a handshake error, but the TCP connection is still alive, we retry the handshake.
do {
// Attempt the server connection setup.
- if ((result = SSL_accept_d(tls)) <= 0) {
+ if ((result = SSL_accept_d(tls)) <= 0 && status()) {
switch ((error = SSL_get_error_d(tls, result))) {