diff --git a/CMakeLists.txt b/CMakeLists.txt index d40960a..bb48e9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ add_executable(FlashMQ unscopedlock.cpp scopedsocket.cpp bindaddr.cpp + oneinstancelock.cpp ) target_link_libraries(FlashMQ pthread dl ssl crypto) diff --git a/mainapp.cpp b/mainapp.cpp index 3132cf6..c659b44 100644 --- a/mainapp.cpp +++ b/mainapp.cpp @@ -378,6 +378,13 @@ MainApp *MainApp::getMainApp() void MainApp::start() { +#ifndef NDEBUG + if (fuzzFilePath.empty()) + { + oneInstanceLock.lock(); + } +#endif + timer.start(); std::map> listenerMap; // For finding listeners by fd. @@ -516,6 +523,8 @@ void MainApp::start() } } + oneInstanceLock.unlock(); + for(std::shared_ptr &thread : threads) { thread->queueQuit(); diff --git a/mainapp.h b/mainapp.h index 0c44522..ae64046 100644 --- a/mainapp.h +++ b/mainapp.h @@ -23,6 +23,7 @@ #include "configfileparser.h" #include "timer.h" #include "scopedsocket.h" +#include "oneinstancelock.h" class MainApp { @@ -44,6 +45,7 @@ class MainApp std::mutex quitMutex; std::string fuzzFilePath; bool fuzzWebsockets = false; + OneInstanceLock oneInstanceLock; Logger *logger = Logger::getInstance(); diff --git a/oneinstancelock.cpp b/oneinstancelock.cpp new file mode 100644 index 0000000..c8e39a7 --- /dev/null +++ b/oneinstancelock.cpp @@ -0,0 +1,56 @@ +#include "oneinstancelock.h" + +#include + +#include "utils.h" + +OneInstanceLock::OneInstanceLock() +{ + std::string dir("/tmp"); + + char *d = getenv("HOME"); + if (d != NULL && d[0] == '/') + { + dir = std::string(d); + } + lockFilePath = dir + "/.FlashMQ.lock"; +} + +OneInstanceLock::~OneInstanceLock() +{ + unlock(); +} + +void OneInstanceLock::lock() +{ + fd = open(lockFilePath.c_str(), O_RDWR | O_CREAT, 0600); + if (fd < 0) + throw std::runtime_error(formatString("Can't create '%s': %s", lockFilePath.c_str(), strerror(errno))); + + struct flock fl; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + if (fcntl(fd, F_SETLK, &fl) < 0) + { + throw std::runtime_error("Can't acquire lock: another instance is already running?"); + } +} + +void OneInstanceLock::unlock() +{ + if (fd > 0) + { + close(fd); + fd = 0; + if (!lockFilePath.empty()) + { + if (unlink(lockFilePath.c_str()) < 0) + { + logger->logf(LOG_ERR, "Can't delete '%': %s", lockFilePath.c_str(), strerror(errno)); + } + lockFilePath.clear(); + } + } +} diff --git a/oneinstancelock.h b/oneinstancelock.h new file mode 100644 index 0000000..f019094 --- /dev/null +++ b/oneinstancelock.h @@ -0,0 +1,23 @@ +#ifndef ONEINSTANCELOCK_H +#define ONEINSTANCELOCK_H + +#include +#include +#include +#include +#include "logger.h" + +class OneInstanceLock +{ + int fd = -1; + std::string lockFilePath; + Logger *logger = Logger::getInstance(); + +public: + OneInstanceLock(); + ~OneInstanceLock(); + void lock(); + void unlock(); +}; + +#endif // ONEINSTANCELOCK_H