diff --git a/CMakeLists.txt b/CMakeLists.txt index 1376e89..8db5119 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,13 +10,15 @@ configure_file ( "${PROJECT_BINARY_DIR}/config.h" ) -include_directories("${PROJECT_BINARY_DIR}") +include_directories(${PROJECT_BINARY_DIR}) +include_directories(${Boost_INCLUDE_DIRS}) set(CMAKE_CXX_FLAGS_DEBUG "-O0 -ggdb -Wall -pedantic -Weffc++ -Wextra") set(CMAKE_CXX_FLAGS "-O2 -Wall -pedantic -Wextra -Weffc++") set(CMAKE_C_FLAGS_DEBUG "-O0 -ggdb -Wall -pedantic -Wextra") set(CMAKE_C_FLAGS "-O2 -Wall -pedantic -Wextra") +find_package(Boost 1.55.0 COMPONENTS program_options REQUIRED) set(SRCS main.cpp @@ -32,7 +34,7 @@ epaper/bsp.c ) add_executable(doorlockd ${SRCS}) -target_link_libraries(doorlockd wiringPi jsoncpp ldap) +target_link_libraries(doorlockd wiringPi jsoncpp ldap ${Boost_LIBRARIES}) install(TARGETS doorlockd DESTINATION sbin) install(FILES img/template.png DESTINATION share/doorlockd) diff --git a/config.h.in b/config.h.in old mode 100644 new mode 100755 index c03e0d7..d6391a1 --- a/config.h.in +++ b/config.h.in @@ -9,7 +9,6 @@ #define DEFAULT_LOG_LEVEL LogLevel::info #endif -#define TOKEN_TIMEOUT 60 #define LOCKPAGE_PREFIX "https://lock.binary.kitchen/" #define FIFO_LOCATION "/var/run/doorlockd/doorlockd" diff --git a/logic.cpp b/logic.cpp old mode 100644 new mode 100755 index c4fcacb..1a46073 --- a/logic.cpp +++ b/logic.cpp @@ -1,5 +1,4 @@ -#include -#include +#include #include #include @@ -7,6 +6,8 @@ #define LDAP_DEPRECATED 1 #include +#include + #include "util.h" #include "logic.h" @@ -18,27 +19,47 @@ const string Logic::_ldapServer = LDAP_SERVER; const string Logic::_bindDN = BINDDN; const string Logic::_allowedIpPrefix = ALLOWEDIPPREFIX; -Logic &Logic::get() +Logic &Logic::get(const chrono::seconds tokenTimeout) { - static Logic l; + static Logic l(tokenTimeout); return l; } -Logic::Logic() : +Logic::Logic(const chrono::seconds tokenTimeout) : _logger(Logger::get()), _door(Door::get()), - _epaper(Epaper::get()) + _epaper(Epaper::get()), + _tokenTimeout(tokenTimeout) { srand(time(NULL)); - createNewToken(false); + _createNewToken(false); + + _tokenUpdater = thread([this] () { + while (_run) + { + unique_lock l(_mutex); + _c.wait_for(l, _tokenTimeout); + if (_run == false) + { + break; + } else { + _createNewToken(true); + } + } + }); } Logic::~Logic() { + _run = false; + _c.notify_one(); + _tokenUpdater.join(); } Logic::Response Logic::parseRequest(const string &str) { + unique_lock l(_mutex); + _logger("Parsing request..."); Json::Reader reader; Json::Value root; @@ -123,7 +144,7 @@ Logic::Response Logic::_lock() _door.lock(); _state = LOCKED; - createNewToken(false); + _createNewToken(false); return Success; } @@ -138,7 +159,7 @@ Logic::Response Logic::_unlock() _door.unlock(); _state = UNLOCKED; - createNewToken(false); + _createNewToken(false); return Success; } @@ -213,7 +234,7 @@ out2: return retval; } -void Logic::createNewToken(const bool stillValid) +void Logic::_createNewToken(const bool stillValid) { _prevToken = _curToken; _prevValid = stillValid; diff --git a/logic.h b/logic.h old mode 100644 new mode 100755 index 3f69db8..75e66f1 --- a/logic.h +++ b/logic.h @@ -3,7 +3,9 @@ #include #include -#include +#include +#include +#include #include "config.h" #include "epaper.h" @@ -14,7 +16,7 @@ class Logic { public: - static Logic &get(); + static Logic &get(const std::chrono::seconds tokenTimeout); ~Logic(); enum Response { @@ -32,11 +34,10 @@ public: }; Response parseRequest(const std::string &str); - void createNewToken(const bool stillValid); private: - Logic(); + Logic(const std::chrono::seconds tokenTimeout); Response _lock(); Response _unlock(); @@ -45,6 +46,7 @@ private: Response _checkLDAP(const std::string &user, const std::string &password); bool _checkIP(const std::string &ip); + void _createNewToken(const bool stillValid); const Logger &_logger; Door &_door; @@ -56,13 +58,17 @@ private: bool _prevValid = { false }; Token _prevToken = { 0x0000000000000000 }; + const std::chrono::seconds _tokenTimeout; const static std::string _lockPagePrefix; const static std::string _bindDN; const static std::string _ldapServer; const static std::string _allowedIpPrefix; - static constexpr int _tokenTimeout = TOKEN_TIMEOUT; + std::thread _tokenUpdater = {}; + std::condition_variable _c = {}; + std::mutex _mutex = {}; + bool _run = true; enum {LOCKED, UNLOCKED} _state = { LOCKED }; }; diff --git a/main.cpp b/main.cpp old mode 100644 new mode 100755 index 765cfe4..1062724 --- a/main.cpp +++ b/main.cpp @@ -2,6 +2,8 @@ #include #include +#include + #include #include #include @@ -12,21 +14,18 @@ using namespace std; +namespace po = boost::program_options; + const static Logger &l = Logger::get(); -int main(void) +int createFifo(const string &fifoLocation) { - int retval = -1; - - l(LogLevel::notice, "Starting doorlockd"); - - int fifoHandle = -1; - + int handle = -1; l(LogLevel::debug, "Creating Fifo file"); - if (access(FIFO_LOCATION, F_OK) == 0) + if (access(fifoLocation.c_str(), F_OK) == 0) { l(LogLevel::warning, "Fifo file aready existing, trying to delete"); - if (unlink(FIFO_LOCATION) != 0) + if (unlink(fifoLocation.c_str()) != 0) { fprintf(stderr, "Unable to delete Fifo file"); goto out; @@ -35,42 +34,107 @@ int main(void) umask(0); - if (mkfifo(FIFO_LOCATION, 0770) != 0) + if (mkfifo(fifoLocation.c_str(), 0770) != 0) { fprintf(stderr, "Unable to create Fifo"); goto out; } - fifoHandle = open(FIFO_LOCATION, O_RDWR | O_NONBLOCK); - if (fifoHandle == -1) + handle = open(fifoLocation.c_str(), O_RDWR | O_NONBLOCK); + if (handle == -1) { fprintf(stderr, "Unable to open Fifo"); goto out; } - if (fchown(fifoHandle, 0, 1001) != 0) + if (fchown(handle, 0, 1001) != 0) { fprintf(stderr, "Fifo chown failed"); - goto out1; + close(handle); + handle = -1; + goto out; } +out: + return handle; +} + +int closeFifo(int handle) +{ + int retval = -1; + + if (handle != -1) + { + close(handle); + } + + l(LogLevel::debug, "Removing Fifo file"); + if (unlink(FIFO_LOCATION) != 0) + { + l(LogLevel::error, "Unable to delete Fifo file"); + retval = -1; + goto out; + } + + retval = 0; + +out: + return retval; +} + +int main(int argc, char** argv) +{ + int retval = -1; + int fifoHandle = -1; + std::chrono::seconds tokenTimeout; try { - Logic &logic = Logic::get(); - struct timeval tv; + unsigned int timeout; + po::options_description desc("usage: doorlockd"); + desc.add_options() + ("help,h", "print help") + ("tokentimeout,t", po::value(&timeout)->required(), "tokentimeout in seconds"); + + po::variables_map vm; + po::store(po::command_line_parser(argc, argv).options(desc).run(), vm); + + if (vm.count("help")) + { + std::cout << desc << std::endl; + retval = 0; + goto out; + } + + po::notify(vm); + + tokenTimeout = std::chrono::seconds(timeout>3 ? timeout-3 : timeout); // Epaper refresh takes ~3 seconds + } + catch(const std::exception &e) + { + std::cerr << "Error: " << e.what() << "\n"; + goto out; + } + + l(LogLevel::notice, "Starting doorlockd"); + + fifoHandle = createFifo(FIFO_LOCATION); + if (fifoHandle == -1) + { + goto out; + } + + try { + Logic &logic = Logic::get(tokenTimeout); fd_set set; for (;;) { FD_ZERO(&set); FD_SET(fifoHandle, &set); - tv.tv_sec = TOKEN_TIMEOUT; - tv.tv_usec = 0; - int i = select(fifoHandle+1, &set, nullptr, nullptr, &tv); + int i = select(fifoHandle+1, &set, nullptr, nullptr, nullptr); if (i == 0) { - logic.createNewToken(true); continue; } else if (i == -1) { throw "Fifo select() failed"; @@ -99,7 +163,7 @@ int main(void) } } - int rc = logic.parseRequest(payload); + const auto rc = logic.parseRequest(payload); } retval = 0; @@ -109,20 +173,13 @@ int main(void) str << "FATAL ERROR: " << ex; l(str, LogLevel::error); retval = -1; + goto out1; } + retval = 0; + out1: - if (fifoHandle != -1) - { - close(fifoHandle); - } - - l(LogLevel::debug, "Removing Fifo file"); - if (unlink(FIFO_LOCATION) != 0) - { - throw("Unable to delete Fifo file"); - } - + retval = closeFifo(fifoHandle); out: Door::get().lock(); l(LogLevel::notice, "Doorlockd stopped");