diff options
author | David Robillard <d@drobilla.net> | 2015-11-08 03:19:58 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2015-11-08 03:19:58 +0000 |
commit | 36219bce05febf199e7ed6433d428c7821010620 (patch) | |
tree | 70e8c083111ca4c3dd2014a24085124244a817d4 /src | |
parent | 9c2bb9e0e2bfd726eef5d7680bc674915817832f (diff) | |
download | ingen-36219bce05febf199e7ed6433d428c7821010620.tar.gz ingen-36219bce05febf199e7ed6433d428c7821010620.tar.bz2 ingen-36219bce05febf199e7ed6433d428c7821010620.zip |
Gracefully handle UNIX socket after a crash
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@5814 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r-- | src/server/SocketListener.cpp | 62 |
1 files changed, 59 insertions, 3 deletions
diff --git a/src/server/SocketListener.cpp b/src/server/SocketListener.cpp index b00a5c79..462b2a37 100644 --- a/src/server/SocketListener.cpp +++ b/src/server/SocketListener.cpp @@ -16,8 +16,12 @@ #include <errno.h> #include <poll.h> +#include <signal.h> +#include <sys/stat.h> +#include <unistd.h> #include <sstream> +#include <string> #include <thread> #include "ingen/Configuration.hpp" @@ -34,6 +38,26 @@ namespace Ingen { namespace Server { +static std::string +get_link_target(const char* link_path) +{ + // Stat the link to get the required size for the target path + struct stat link_stat; + if (lstat(link_path, &link_stat)) { + return std::string(); + } + + // Allocate buffer and read link target + char* target = (char*)calloc(1, link_stat.st_size + 1); + if (readlink(link_path, target, link_stat.st_size) != -1) { + const std::string result(target); + free(target); + return result; + } + + return std::string(); +} + void SocketListener::ingen_listen(Engine* engine, Raul::Socket* unix_sock, @@ -41,15 +65,43 @@ SocketListener::ingen_listen(Engine* engine, { Ingen::World* world = engine->world(); - const std::string unix_path(world->conf().option("socket").ptr<char>()); + const std::string link_path(world->conf().option("socket").ptr<char>()); + const std::string unix_path(link_path + "." + std::to_string(getpid())); - // Bind UNIX socket + // Bind UNIX socket and create PID-less symbolic link const Raul::URI unix_uri(unix_scheme + unix_path); + bool make_link = true; if (!unix_sock->bind(unix_uri) || !unix_sock->listen()) { world->log().error("Failed to create UNIX socket\n"); unix_sock->close(); + make_link = false; } else { - world->log().info(fmt("Listening on socket %1%\n") % unix_uri); + const std::string old_path = get_link_target(link_path.c_str()); + if (!old_path.empty()) { + const std::string suffix = old_path.substr(old_path.find_last_of(".") + 1); + const pid_t pid = std::stoi(suffix); + if (!kill(pid, 0)) { + make_link = false; + world->log().warn(fmt("Another Ingen instance is running at %1% => %2%\n") + % link_path % old_path); + } else { + world->log().warn(fmt("Replacing old link %1% => %2%\n") + % link_path % old_path); + unlink(link_path.c_str()); + } + } + + if (make_link) { + if (!symlink(unix_path.c_str(), link_path.c_str())) { + world->log().info(fmt("Listening on %1%\n") % + (unix_scheme + link_path)); + } else { + world->log().error(fmt("Failed to link %1% => %2% (%3%)\n") + % link_path % unix_path % strerror(errno)); + } + } else { + world->log().info(fmt("Listening on %1%\n") % unix_uri); + } } // Bind TCP socket @@ -109,6 +161,10 @@ SocketListener::ingen_listen(Engine* engine, } } } + + if (make_link) { + unlink(link_path.c_str()); + } } } // namespace Server |