diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f0c2947..ebfd1ad6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,7 +175,7 @@ add_executable( owgw src/SDKcalls.cpp src/SDKcalls.h src/StateUtils.cpp src/StateUtils.h - src/AP_WS_ReactorPool.h + src/AP_WS_Reactor_Pool.h src/AP_WS_Connection.h src/AP_WS_Connection.cpp src/TelemetryClient.h src/TelemetryClient.cpp @@ -211,7 +211,8 @@ add_executable( owgw src/RegulatoryInfo.cpp src/RegulatoryInfo.h src/RADIUSSessionTracker.cpp src/RADIUSSessionTracker.h src/libs/Scheduler.h src/libs/InterruptableSleep.h src/libs/ctpl_stl.h src/libs/Cron.h - src/GenericScheduler.cpp src/GenericScheduler.h src/framework/default_device_types.h src/AP_WS_Process_rebootLog.cpp src/AP_WS_ConfigAutoUpgrader.cpp src/AP_WS_ConfigAutoUpgrader.h src/RESTAPI/RESTAPI_default_firmwares.cpp src/RESTAPI/RESTAPI_default_firmwares.h src/RESTAPI/RESTAPI_default_firmware.cpp src/RESTAPI/RESTAPI_default_firmware.h src/storage/storage_def_firmware.cpp src/firmware_revision_cache.h src/sdks/sdk_fms.h) + src/GenericScheduler.cpp src/GenericScheduler.h src/framework/default_device_types.h src/AP_WS_Process_rebootLog.cpp src/AP_WS_ConfigAutoUpgrader.cpp src/AP_WS_ConfigAutoUpgrader.h src/RESTAPI/RESTAPI_default_firmwares.cpp src/RESTAPI/RESTAPI_default_firmwares.h src/RESTAPI/RESTAPI_default_firmware.cpp src/RESTAPI/RESTAPI_default_firmware.h src/storage/storage_def_firmware.cpp src/firmware_revision_cache.h src/sdks/sdk_fms.h + src/AP_WS_LookForUpgrade.cpp) if(NOT SMALL_BUILD) diff --git a/build b/build index 9a037142..4e9e2884 100644 --- a/build +++ b/build @@ -1 +1 @@ -10 \ No newline at end of file +63 \ No newline at end of file diff --git a/owgw.properties.tmpl b/owgw.properties.tmpl index fd9353c2..15d733b8 100644 --- a/owgw.properties.tmpl +++ b/owgw.properties.tmpl @@ -145,7 +145,7 @@ storage.type.sqlite.db = devices.db storage.type.sqlite.idletime = 120 storage.type.sqlite.maxsessions = 128 -storage.type.postgresql.maxsessions = 64 +storage.type.postgresql.maxsessions = 250 storage.type.postgresql.idletime = 60 storage.type.postgresql.host = ${STORAGE_TYPE_POSTGRESQL_HOST} storage.type.postgresql.username = ${STORAGE_TYPE_POSTGRESQL_USERNAME} diff --git a/src/AP_WS_Connection.cpp b/src/AP_WS_Connection.cpp index 216cf75b..3c33094e 100644 --- a/src/AP_WS_Connection.cpp +++ b/src/AP_WS_Connection.cpp @@ -36,22 +36,20 @@ namespace OpenWifi { -#define DBL \ - { \ - std::cout << __LINE__ << " ID: " << ConnectionId_ << " Ser: " << SerialNumber_ \ - << std::endl; \ - } - void AP_WS_Connection::LogException(const Poco::Exception &E) { poco_information(Logger_, fmt::format("EXCEPTION({}): {}", CId_, E.displayText())); } AP_WS_Connection::AP_WS_Connection(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response, - uint64_t connection_id, Poco::Logger &L, - Poco::Net::SocketReactor &R) - : Logger_(L), Reactor_(R) { - State_.sessionId = connection_id; + uint64_t session_id, Poco::Logger &L, + std::pair, std::shared_ptr> R) + : Logger_(L) { + + Reactor_ = R.first; + DbSession_ = R.second; + State_.sessionId = session_id; + WS_ = std::make_unique(request, response); auto TS = Poco::Timespan(360, 0); @@ -61,29 +59,89 @@ namespace OpenWifi { WS_->setNoDelay(false); WS_->setKeepAlive(true); WS_->setBlocking(false); + uuid_ = MicroServiceRandom(std::numeric_limits::max()-1); + } - Reactor_.addEventHandler(*WS_, - Poco::NObserver( - *this, &AP_WS_Connection::OnSocketReadable)); - Reactor_.addEventHandler(*WS_, - Poco::NObserver( - *this, &AP_WS_Connection::OnSocketShutdown)); - Reactor_.addEventHandler(*WS_, - Poco::NObserver( - *this, &AP_WS_Connection::OnSocketError)); + void AP_WS_Connection::Start() { Registered_ = true; - Valid_ = true; - uuid_ = MicroServiceRandom(std::numeric_limits::max()-1); + LastContact_ = Utils::Now(); + + Reactor_->addEventHandler(*WS_, + Poco::NObserver( + *this, &AP_WS_Connection::OnSocketReadable)); + Reactor_->addEventHandler(*WS_, + Poco::NObserver( + *this, &AP_WS_Connection::OnSocketShutdown)); + Reactor_->addEventHandler(*WS_, + Poco::NObserver( + *this, &AP_WS_Connection::OnSocketError)); + + } + + AP_WS_Connection::~AP_WS_Connection() { +// poco_information(Logger_, fmt::format("DESTRUCTOR({}): 0 - Session={} Connection closed.", SerialNumber_, +// State_.sessionId)); + std::lock_guard G(ConnectionMutex_); +// poco_information(Logger_, fmt::format("DESTRUCTOR({}): 1 - Session={} Connection closed.", SerialNumber_, +// State_.sessionId)); + EndConnection(false); + poco_debug(Logger_, fmt::format("TERMINATION({}): Session={}, Connection removed.", SerialNumber_, + State_.sessionId)); + } + + static void NotifyKafkaDisconnect(const std::string &SerialNumber, std::uint64_t uuid) { + try { + Poco::JSON::Object Disconnect; + Poco::JSON::Object Details; + Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber); + Details.set(uCentralProtocol::TIMESTAMP, Utils::Now()); + Details.set(uCentralProtocol::UUID,uuid); + Disconnect.set(uCentralProtocol::DISCONNECTION, Details); + KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, Disconnect); + } catch (...) { + } + } + + void AP_WS_Connection::EndConnection(bool Clean) { + bool expectedValue=false; + if (Dead_.compare_exchange_strong(expectedValue,true,std::memory_order_release,std::memory_order_relaxed)) { + + if(!SerialNumber_.empty() && State_.LastContact!=0) { + StorageService()->SetDeviceLastRecordedContact(SerialNumber_, State_.LastContact); + } + + if (Registered_) { + Registered_ = false; + Reactor_->removeEventHandler( + *WS_, Poco::NObserver( + *this, &AP_WS_Connection::OnSocketReadable)); + Reactor_->removeEventHandler( + *WS_, Poco::NObserver( + *this, &AP_WS_Connection::OnSocketShutdown)); + Reactor_->removeEventHandler( + *WS_, Poco::NObserver( + *this, &AP_WS_Connection::OnSocketError)); + Registered_=false; + } + WS_->close(); + + if(!SerialNumber_.empty()) { + DeviceDisconnectionCleanup(SerialNumber_, uuid_); + } + + if(Clean) + AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_); + } } bool AP_WS_Connection::ValidatedDevice() { - if (DeviceValidated_) - return true; - if (!Valid_) + if(Dead_) return false; - std::lock_guard Lock(ConnectionMutex_); + if (DeviceValidated_) + return true; + try { auto SockImpl = dynamic_cast(WS_->impl()); auto SS = @@ -98,7 +156,6 @@ namespace OpenWifi { poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Connection is " "NOT secure. Device is not allowed.", CId_, State_.sessionId)); - EndConnection(); return false; } @@ -111,7 +168,6 @@ namespace OpenWifi { Logger_, fmt::format("TLS-CONNECTION({}): Session={} No certificates available..", CId_, State_.sessionId)); - EndConnection(); return false; } @@ -122,11 +178,19 @@ namespace OpenWifi { fmt::format("TLS-CONNECTION({}): Session={} Device certificate is not " "valid. Device is not allowed.", CId_, State_.sessionId)); - EndConnection(); return false; } CN_ = Poco::trim(Poco::toLower(PeerCert.commonName())); + if(!Utils::ValidSerialNumber(CN_)) { + poco_trace(Logger_, + fmt::format("TLS-CONNECTION({}): Session={} Invalid serial number: CN={}", CId_, + State_.sessionId, CN_)); + return false; + } + SerialNumber_ = CN_; + SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_); + State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE; poco_trace(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_, @@ -136,31 +200,27 @@ namespace OpenWifi { poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Sim Device {} is " "not allowed. Disconnecting.", CId_, State_.sessionId, CN_)); - EndConnection(); return false; } - if(AP_WS_Server::IsSim(CN_)) { + if(AP_WS_Server::IsSim(SerialNumber_)) { State_.VerifiedCertificate = GWObjects::SIMULATED; Simulated_ = true; } std::string reason, author; std::uint64_t created; - if (!CN_.empty() && StorageService()->IsBlackListed(CN_, reason, author, created)) { + if (!CN_.empty() && StorageService()->IsBlackListed(SerialNumberInt_, reason, author, created)) { DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_); poco_warning( Logger_, fmt::format( "TLS-CONNECTION({}): Session={} Device {} is black listed. Disconnecting.", CId_, State_.sessionId, CN_)); - EndConnection(); return false; } State_.certificateExpiryDate = PeerCert.expiresOn().timestamp().epochTime(); - SerialNumber_ = CN_; - SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_); poco_trace(Logger_, fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_, @@ -224,149 +284,14 @@ namespace OpenWifi { return false; } - static void NotifyKafkaDisconnect(const std::string &SerialNumber, std::uint64_t uuid) { - try { - Poco::JSON::Object Disconnect; - Poco::JSON::Object Details; - Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber); - Details.set(uCentralProtocol::TIMESTAMP, Utils::Now()); - Details.set(uCentralProtocol::UUID,uuid); - Disconnect.set(uCentralProtocol::DISCONNECTION, Details); - KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, Disconnect); - } catch (...) { - } - } - - AP_WS_Connection::~AP_WS_Connection() { - Valid_ = false; - EndConnection(); - } - - void DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid) { + void AP_WS_Connection::DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid) { if (KafkaManager()->Enabled()) { NotifyKafkaDisconnect(SerialNumber, uuid); } RADIUSSessionTracker()->DeviceDisconnect(SerialNumber); - } - - void AP_WS_Connection::EndConnection(bool DeleteSession) { - Valid_ = false; - if (!Dead_.test_and_set()) { - - if(!SerialNumber_.empty() && State_.LastContact!=0) { - StorageService()->SetDeviceLastRecordedContact(SerialNumber_, State_.LastContact); - } - - if (Registered_) { - Registered_ = false; - Reactor_.removeEventHandler( - *WS_, Poco::NObserver( - *this, &AP_WS_Connection::OnSocketReadable)); - Reactor_.removeEventHandler( - *WS_, Poco::NObserver( - *this, &AP_WS_Connection::OnSocketShutdown)); - Reactor_.removeEventHandler( - *WS_, Poco::NObserver( - *this, &AP_WS_Connection::OnSocketError)); - } - WS_->close(); - - if(!SerialNumber_.empty()) { - std::thread Cleanup(DeviceDisconnectionCleanup,SerialNumber_, uuid_); - Cleanup.detach(); - } - - bool SessionDeleted = false; - if(DeleteSession) - SessionDeleted = AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_); - - if (SessionDeleted || !DeleteSession) { - GWWebSocketNotifications::SingleDevice_t N; - N.content.serialNumber = SerialNumber_; - GWWebSocketNotifications::DeviceDisconnected(N); - } - } - } - - bool AP_WS_Connection::LookForUpgrade(const uint64_t UUID, uint64_t &UpgradedUUID) { - - // A UUID of zero means ignore updates for that connection. - if (UUID == 0) - return false; - - uint64_t GoodConfig = ConfigurationCache().CurrentConfig(SerialNumberInt_); - if (GoodConfig && (GoodConfig == UUID || GoodConfig == State_.PendingUUID)) { - UpgradedUUID = UUID; - return false; - } - - GWObjects::Device D; - if (StorageService()->GetDevice(SerialNumber_, D)) { - - if(D.pendingUUID!=0 && UUID==D.pendingUUID) { - // so we sent an upgrade to a device, and now it is completing now... - UpgradedUUID = D.pendingUUID; - StorageService()->CompleteDeviceConfigurationChange(SerialNumber_); - return true; - } - - // This is the case where the cache is empty after a restart. So GoodConfig will 0. If - // the device already has the right UUID, we just return. - if (D.UUID == UUID) { - UpgradedUUID = UUID; - ConfigurationCache().Add(SerialNumberInt_, UUID); - return false; - } - - Config::Config Cfg(D.Configuration); - if (UUID > D.UUID) { - // so we have a problem, the device has a newer config than we have. So we need to - // make sure our config is newer. - D.UUID = UUID + 2; - UpgradedUUID = D.UUID; - } - - Cfg.SetUUID(D.UUID); - D.Configuration = Cfg.get(); - State_.PendingUUID = UpgradedUUID = D.UUID; - - GWObjects::CommandDetails Cmd; - Cmd.SerialNumber = SerialNumber_; - Cmd.UUID = MicroServiceCreateUUID(); - Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM; - Cmd.Status = uCentralProtocol::PENDING; - Cmd.Command = uCentralProtocol::CONFIGURE; - Poco::JSON::Parser P; - auto ParsedConfig = P.parse(D.Configuration).extract(); - Poco::JSON::Object Params; - Params.set(uCentralProtocol::SERIAL, SerialNumber_); - Params.set(uCentralProtocol::UUID, D.UUID); - Params.set(uCentralProtocol::WHEN, 0); - Params.set(uCentralProtocol::CONFIG, ParsedConfig); - - std::ostringstream O; - Poco::JSON::Stringifier::stringify(Params, O); - Cmd.Details = O.str(); - poco_information(Logger_, - fmt::format("CFG-UPGRADE({}): Current ID: {}, newer configuration {}.", - CId_, UUID, D.UUID)); - bool Sent; - - StorageService()->AddCommand(SerialNumber_, Cmd, - Storage::CommandExecutionType::COMMAND_EXECUTED); - CommandManager()->PostCommand( - CommandManager()->Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()), - SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent, false, false); - - GWWebSocketNotifications::SingleDeviceConfigurationChange_t Notification; - Notification.content.serialNumber = D.SerialNumber; - Notification.content.oldUUID = UUID; - Notification.content.newUUID = UpgradedUUID; - GWWebSocketNotifications::DeviceConfigurationChange(Notification); - - return true; - } - return false; + GWWebSocketNotifications::SingleDevice_t N; + N.content.serialNumber = SerialNumber; + GWWebSocketNotifications::DeviceDisconnected(N); } void AP_WS_Connection::ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc) { @@ -447,7 +372,7 @@ namespace OpenWifi { std::string reason, author; std::uint64_t created; - if (StorageService()->IsBlackListed(Serial, reason, author, created)) { + if (StorageService()->IsBlackListed(SerialNumberInt_, reason, author, created)) { DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_); Poco::Exception E( fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.", @@ -578,17 +503,17 @@ namespace OpenWifi { } bool AP_WS_Connection::SetWebSocketTelemetryReporting( - uint64_t RPCID, uint64_t Interval, uint64_t LifeTime, + std::uint64_t RPCID, std::uint64_t Interval, std::uint64_t LifeTime, const std::vector &TelemetryTypes) { std::unique_lock Lock(TelemetryMutex_); TelemetryWebSocketRefCount_++; TelemetryInterval_ = TelemetryInterval_ - ? (Interval < TelemetryInterval_ ? Interval : TelemetryInterval_) + ? (Interval < (std::uint64_t)TelemetryInterval_ ? Interval : (std::uint64_t )TelemetryInterval_) : Interval; auto TelemetryWebSocketTimer = LifeTime + Utils::Now(); - TelemetryWebSocketTimer_ = TelemetryWebSocketTimer > TelemetryWebSocketTimer_ - ? TelemetryWebSocketTimer - : TelemetryWebSocketTimer_; + TelemetryWebSocketTimer_ = TelemetryWebSocketTimer > (std::uint64_t)TelemetryWebSocketTimer_ + ? (std::uint64_t)TelemetryWebSocketTimer + : (std::uint64_t)TelemetryWebSocketTimer_; UpdateCounts(); if (!TelemetryReporting_) { TelemetryReporting_ = true; @@ -604,11 +529,11 @@ namespace OpenWifi { std::unique_lock Lock(TelemetryMutex_); TelemetryKafkaRefCount_++; TelemetryInterval_ = TelemetryInterval_ - ? (Interval < TelemetryInterval_ ? Interval : TelemetryInterval_) + ? (Interval < (std::uint64_t)TelemetryInterval_ ? (std::uint64_t)Interval : (std::uint64_t)TelemetryInterval_) : Interval; auto TelemetryKafkaTimer = LifeTime + Utils::Now(); TelemetryKafkaTimer_ = - TelemetryKafkaTimer > TelemetryKafkaTimer_ ? TelemetryKafkaTimer : TelemetryKafkaTimer_; + TelemetryKafkaTimer > (std::uint64_t)TelemetryKafkaTimer_ ? (std::uint64_t)TelemetryKafkaTimer : (std::uint64_t)TelemetryKafkaTimer_; UpdateCounts(); if (!TelemetryReporting_) { TelemetryReporting_ = true; @@ -644,49 +569,50 @@ namespace OpenWifi { void AP_WS_Connection::OnSocketShutdown( [[maybe_unused]] const Poco::AutoPtr &pNf) { poco_trace(Logger_, fmt::format("SOCKET-SHUTDOWN({}): Closing.", CId_)); + std::lock_guard G(ConnectionMutex_); return EndConnection(); } void AP_WS_Connection::OnSocketError( [[maybe_unused]] const Poco::AutoPtr &pNf) { poco_trace(Logger_, fmt::format("SOCKET-ERROR({}): Closing.", CId_)); + std::lock_guard G(ConnectionMutex_); return EndConnection(); } void AP_WS_Connection::OnSocketReadable( [[maybe_unused]] const Poco::AutoPtr &pNf) { - if (!Valid_) + if (Dead_) // we are dead, so we do not process anything. return; - if (!AP_WS_Server()->Running()) - return EndConnection(); - - if (!ValidatedDevice()) - return; + std::lock_guard DeviceLock(ConnectionMutex_); - try { - return ProcessIncomingFrame(); - } catch (const Poco::Exception &E) { - Logger_.log(E); - return EndConnection(); - } catch (const std::exception &E) { - std::string W = E.what(); - poco_information( - Logger_, - fmt::format("std::exception caught: {}. Connection terminated with {}", W, CId_)); - return EndConnection(); - } catch (...) { - poco_information(Logger_, - fmt::format("Unknown exception for {}. Connection terminated.", CId_)); - return EndConnection(); + State_.LastContact = LastContact_ = Utils::Now(); + if (AP_WS_Server()->Running() && (DeviceValidated_ || ValidatedDevice())) { + try { + return ProcessIncomingFrame(); + } catch (const Poco::Exception &E) { + Logger_.log(E); + } catch (const std::exception &E) { + std::string W = E.what(); + poco_information( + Logger_, fmt::format("std::exception caught: {}. Connection terminated with {}", + W, CId_)); + } catch (...) { + poco_information( + Logger_, fmt::format("Unknown exception for {}. Connection terminated.", CId_)); + } } + EndConnection(); } void AP_WS_Connection::ProcessIncomingFrame() { Poco::Buffer IncomingFrame(0); + + bool KillConnection=false; try { - int Op, flags; + int Op, flags; auto IncomingSize = WS_->receiveFrame(IncomingFrame, flags); Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK; @@ -706,83 +632,81 @@ namespace OpenWifi { State_.LastContact = Utils::Now(); switch (Op) { - case Poco::Net::WebSocket::FRAME_OP_PING: { - poco_trace(Logger_, fmt::format("WS-PING({}): received. PONG sent back.", CId_)); - WS_->sendFrame("", 0, - (int)Poco::Net::WebSocket::FRAME_OP_PONG | - (int)Poco::Net::WebSocket::FRAME_FLAG_FIN); - - if (KafkaManager()->Enabled()) { - Poco::JSON::Object PingObject; - Poco::JSON::Object PingDetails; - PingDetails.set(uCentralProtocol::FIRMWARE, State_.Firmware); - PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_); - PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_); - PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_); - PingDetails.set(uCentralProtocol::TIMESTAMP, Utils::Now()); - PingDetails.set(uCentralProtocol::UUID, uuid_); - PingDetails.set("locale", State_.locale); - PingObject.set(uCentralProtocol::PING, PingDetails); - poco_trace(Logger_,fmt::format("Sending PING for {}", SerialNumber_)); - KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,PingObject); - } - return; - } break; + case Poco::Net::WebSocket::FRAME_OP_PING: { + poco_trace(Logger_, fmt::format("WS-PING({}): received. PONG sent back.", CId_)); + WS_->sendFrame("", 0, + (int)Poco::Net::WebSocket::FRAME_OP_PONG | + (int)Poco::Net::WebSocket::FRAME_FLAG_FIN); + + if (KafkaManager()->Enabled()) { + Poco::JSON::Object PingObject; + Poco::JSON::Object PingDetails; + PingDetails.set(uCentralProtocol::FIRMWARE, State_.Firmware); + PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_); + PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_); + PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_); + PingDetails.set(uCentralProtocol::TIMESTAMP, Utils::Now()); + PingDetails.set(uCentralProtocol::UUID, uuid_); + PingDetails.set("locale", State_.locale); + PingObject.set(uCentralProtocol::PING, PingDetails); + poco_trace(Logger_,fmt::format("Sending PING for {}", SerialNumber_)); + KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,PingObject); + } + } break; - case Poco::Net::WebSocket::FRAME_OP_PONG: { - poco_trace(Logger_, fmt::format("PONG({}): received and ignored.", CId_)); - return; - } break; + case Poco::Net::WebSocket::FRAME_OP_PONG: { + poco_trace(Logger_, fmt::format("PONG({}): received and ignored.", CId_)); + } break; - case Poco::Net::WebSocket::FRAME_OP_TEXT: { - poco_trace(Logger_, - fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}", - CId_, IncomingSize, flags, IncomingFrame.begin())); - - Poco::JSON::Parser parser; - auto ParsedMessage = parser.parse(IncomingFrame.begin()); - auto IncomingJSON = ParsedMessage.extract(); - - if (IncomingJSON->has(uCentralProtocol::JSONRPC)) { - if (IncomingJSON->has(uCentralProtocol::METHOD) && - IncomingJSON->has(uCentralProtocol::PARAMS)) { - ProcessJSONRPCEvent(IncomingJSON); - } else if (IncomingJSON->has(uCentralProtocol::RESULT) && - IncomingJSON->has(uCentralProtocol::ID)) { - poco_trace(Logger_, fmt::format("RPC-RESULT({}): payload: {}", CId_, - IncomingFrame.begin())); - ProcessJSONRPCResult(IncomingJSON); + case Poco::Net::WebSocket::FRAME_OP_TEXT: { + poco_trace(Logger_, + fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}", + CId_, IncomingSize, flags, IncomingFrame.begin())); + + Poco::JSON::Parser parser; + auto ParsedMessage = parser.parse(IncomingFrame.begin()); + auto IncomingJSON = ParsedMessage.extract(); + + if (IncomingJSON->has(uCentralProtocol::JSONRPC)) { + if (IncomingJSON->has(uCentralProtocol::METHOD) && + IncomingJSON->has(uCentralProtocol::PARAMS)) { + ProcessJSONRPCEvent(IncomingJSON); + } else if (IncomingJSON->has(uCentralProtocol::RESULT) && + IncomingJSON->has(uCentralProtocol::ID)) { + poco_trace(Logger_, fmt::format("RPC-RESULT({}): payload: {}", CId_, + IncomingFrame.begin())); + ProcessJSONRPCResult(IncomingJSON); + } else { + poco_warning( + Logger_, + fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}", + CId_, IncomingFrame.begin())); + } + } else if (IncomingJSON->has(uCentralProtocol::RADIUS)) { + ProcessIncomingRadiusData(IncomingJSON); } else { + std::ostringstream iS; + IncomingJSON->stringify(iS); poco_warning( Logger_, - fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}", - CId_, IncomingFrame.begin())); + fmt::format("FRAME({}): illegal transaction header, missing 'jsonrpc': {}", + CId_, iS.str())); + Errors_++; } - } else if (IncomingJSON->has(uCentralProtocol::RADIUS)) { - ProcessIncomingRadiusData(IncomingJSON); - } else { - std::ostringstream iS; - IncomingJSON->stringify(iS); - std::cout << iS.str() << std::endl; - poco_warning( - Logger_, - fmt::format("FRAME({}): illegal transaction header, missing 'jsonrpc'", - CId_)); - Errors_++; - } - return; - } break; + } break; - case Poco::Net::WebSocket::FRAME_OP_CLOSE: { - poco_information(Logger_, - fmt::format("CLOSE({}): Device is closing its connection.", CId_)); - return EndConnection(); - } break; + case Poco::Net::WebSocket::FRAME_OP_CLOSE: { + poco_information(Logger_, + fmt::format("CLOSE({}): Device is closing its connection.", CId_)); + KillConnection=true; + } break; - default: { - poco_warning(Logger_, fmt::format("UNKNOWN({}): unknown WS Frame operation: {}", - CId_, std::to_string(Op))); - } break; + default: { + poco_warning(Logger_, fmt::format("UNKNOWN({}): unknown WS Frame operation: {}", + CId_, std::to_string(Op))); + Errors_++; + return; + } } } catch (const Poco::Net::ConnectionResetException &E) { poco_warning(Logger_, @@ -790,21 +714,21 @@ namespace OpenWifi { CId_, E.displayText(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), State_.sessionId)); - return EndConnection(); + KillConnection=true; } catch (const Poco::JSON::JSONException &E) { poco_warning(Logger_, fmt::format("JSONException({}): Text:{} Payload:{} Session:{}", CId_, E.displayText(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), State_.sessionId)); - return EndConnection(); + KillConnection=true; } catch (const Poco::Net::WebSocketException &E) { poco_warning(Logger_, fmt::format("WebSocketException({}): Text:{} Payload:{} Session:{}", CId_, E.displayText(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), State_.sessionId)); - return EndConnection(); + KillConnection=true; } catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) { poco_warning( Logger_, @@ -813,54 +737,54 @@ namespace OpenWifi { CId_, E.displayText(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), State_.sessionId)); - return EndConnection(); + KillConnection=true; } catch (const Poco::Net::SSLException &E) { poco_warning(Logger_, fmt::format("SSLException({}): Text:{} Payload:{} Session:{}", CId_, E.displayText(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), State_.sessionId)); - return EndConnection(); + KillConnection=true; } catch (const Poco::Net::NetException &E) { poco_warning(Logger_, fmt::format("NetException({}): Text:{} Payload:{} Session:{}", CId_, E.displayText(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), State_.sessionId)); - return EndConnection(); + KillConnection=true; } catch (const Poco::IOException &E) { poco_warning(Logger_, fmt::format("IOException({}): Text:{} Payload:{} Session:{}", CId_, E.displayText(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), State_.sessionId)); - return EndConnection(); + KillConnection=true; } catch (const Poco::Exception &E) { poco_warning(Logger_, fmt::format("Exception({}): Text:{} Payload:{} Session:{}", CId_, E.displayText(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), State_.sessionId)); - return EndConnection(); + KillConnection=true; } catch (const std::exception &E) { poco_warning(Logger_, fmt::format("std::exception({}): Text:{} Payload:{} Session:{}", CId_, E.what(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), State_.sessionId)); - return EndConnection(); + KillConnection=true; } catch (...) { poco_error(Logger_, fmt::format("UnknownException({}): Device must be disconnected. " "Unknown exception. Session:{}", CId_, State_.sessionId)); - return EndConnection(); + KillConnection=true; } - if (Errors_ < 10) + if (!KillConnection && Errors_ < 10) return; - poco_warning(Logger_, fmt::format("DISCONNECTING({}): Too many errors", CId_)); - return EndConnection(); + poco_warning(Logger_, fmt::format("DISCONNECTING({}): ConnectionException: {} Errors: {}", CId_, KillConnection, Errors_ )); + EndConnection(); } bool AP_WS_Connection::Send(const std::string &Payload) { @@ -972,4 +896,36 @@ namespace OpenWifi { } } } + + void AP_WS_Connection::SetLastStats(const std::string &LastStats) { + RawLastStats_ = LastStats; + try { + Poco::JSON::Parser P; + auto Stats = P.parse(LastStats).extract(); + hasGPS_ = Stats->isObject("gps"); + auto Unit = Stats->getObject("unit"); + auto Memory = Unit->getObject("memory"); + std::uint64_t TotalMemory = Memory->get("total"); + std::uint64_t FreeMemory = Memory->get("free"); + if (TotalMemory > 0) { + memory_used_ = + (100.0 * ((double)TotalMemory - (double)FreeMemory)) / (double)TotalMemory; + } + if (Unit->isArray("load")) { + Poco::JSON::Array::Ptr Load = Unit->getArray("load"); + if (Load->size() > 1) { + cpu_load_ = Load->get(1); + } + } + if (Unit->isArray("temperature")) { + Poco::JSON::Array::Ptr Temperature = Unit->getArray("temperature"); + if (Temperature->size() > 1) { + temperature_ = Temperature->get(0); + } + } + } catch (const Poco::Exception &E) { + poco_error(Logger_, "Failed to parse last stats: " + E.displayText()); + } + } + } // namespace OpenWifi \ No newline at end of file diff --git a/src/AP_WS_Connection.h b/src/AP_WS_Connection.h index e56a9d99..be6d37ee 100644 --- a/src/AP_WS_Connection.h +++ b/src/AP_WS_Connection.h @@ -14,8 +14,10 @@ #include "Poco/Net/SocketReactor.h" #include "Poco/Net/StreamSocket.h" #include "Poco/Net/WebSocket.h" +#include #include "RESTObjects/RESTAPI_GWobjects.h" +#include namespace OpenWifi { @@ -25,16 +27,17 @@ namespace OpenWifi { public: explicit AP_WS_Connection(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response, uint64_t connection_id, - Poco::Logger &L, Poco::Net::SocketReactor &R); + Poco::Logger &L, std::pair, std::shared_ptr> R); ~AP_WS_Connection(); - void EndConnection(bool DeleteSession=true); + void EndConnection(bool Clean = true); void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc); void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc); void ProcessIncomingFrame(); void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc); [[nodiscard]] bool Send(const std::string &Payload); + [[nodiscard]] inline bool MustBeSecureRTTY() const { return RTTYMustBeSecure_; } bool SendRadiusAuthenticationData(const unsigned char *buffer, std::size_t size); bool SendRadiusAccountingData(const unsigned char *buffer, std::size_t size); @@ -43,10 +46,7 @@ namespace OpenWifi { void OnSocketReadable(const Poco::AutoPtr &pNf); void OnSocketShutdown(const Poco::AutoPtr &pNf); void OnSocketError(const Poco::AutoPtr &pNf); - bool LookForUpgrade(uint64_t UUID, uint64_t &UpgradedUUID); - static bool ExtractBase64CompressedData(const std::string &CompressedData, - std::string &UnCompressedData, - uint64_t compress_sz); + bool LookForUpgrade(Poco::Data::Session &Session, uint64_t UUID, uint64_t &UpgradedUUID); void LogException(const Poco::Exception &E); inline Poco::Logger &Logger() { return Logger_; } bool SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t interval, @@ -59,82 +59,34 @@ namespace OpenWifi { bool StopKafkaTelemetry(uint64_t RPCID); inline void GetLastStats(std::string &LastStats) { - std::lock_guard G(ConnectionMutex_); - LastStats = RawLastStats_; - } - - inline void SetLastStats(const std::string &LastStats) { - std::lock_guard G(ConnectionMutex_); - RawLastStats_ = LastStats; - try { - Poco::JSON::Parser P; - auto Stats = P.parse(LastStats).extract(); - hasGPS = Stats->isObject("gps"); - auto Unit = Stats->getObject("unit"); - auto Memory = Unit->getObject("memory"); - std::uint64_t TotalMemory = Memory->get("total"); - std::uint64_t FreeMemory = Memory->get("free"); - if(TotalMemory>0) { - memory_used_ = - (100.0 * ((double)TotalMemory - (double)FreeMemory)) / (double)TotalMemory; - } - if(Unit->isArray("load")) { - Poco::JSON::Array::Ptr Load = Unit->getArray("load"); - if(Load->size()>1) { - cpu_load_ = Load->get(1); - } - } - if(Unit->isArray("temperature")) { - Poco::JSON::Array::Ptr Temperature = Unit->getArray("temperature"); - if(Temperature->size()>1) { - temperature_ = Temperature->get(0); - } - } - } catch (...) { - + if(!Dead_) { + std::lock_guard G(ConnectionMutex_); + LastStats = RawLastStats_; } } - inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) { - std::lock_guard G(ConnectionMutex_); - RawLastHealthcheck_ = H; - } - inline void GetLastHealthCheck(GWObjects::HealthCheck &H) { - std::lock_guard G(ConnectionMutex_); - H = RawLastHealthcheck_; + if(!Dead_) { + std::lock_guard G(ConnectionMutex_); + H = RawLastHealthcheck_; + } } - inline void GetState(GWObjects::ConnectionState &State) const { - std::lock_guard G(ConnectionMutex_); - State = State_; + inline void GetState(GWObjects::ConnectionState &State) { + if(!Dead_) { + std::lock_guard G(ConnectionMutex_); + State = State_; + } } - inline bool HasGPS() { return hasGPS; } + [[nodiscard]] inline bool HasGPS() const { return hasGPS_; } + [[nodiscard]] bool ValidatedDevice(); - inline void GetRestrictions(GWObjects::DeviceRestrictions &R) const { + inline void GetRestrictions(GWObjects::DeviceRestrictions &R) { std::lock_guard G(ConnectionMutex_); R = Restrictions_; } - void Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial); - void Process_state(Poco::JSON::Object::Ptr ParamsObj); - void Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj); - void Process_log(Poco::JSON::Object::Ptr ParamsObj); - void Process_crashlog(Poco::JSON::Object::Ptr ParamsObj); - void Process_ping(Poco::JSON::Object::Ptr ParamsObj); - void Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj); - void Process_recovery(Poco::JSON::Object::Ptr ParamsObj); - void Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial); - void Process_telemetry(Poco::JSON::Object::Ptr ParamsObj); - void Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj); - void Process_event(Poco::JSON::Object::Ptr ParamsObj); - void Process_wifiscan(Poco::JSON::Object::Ptr ParamsObj); - void Process_alarm(Poco::JSON::Object::Ptr ParamsObj); - void Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj); - - bool ValidatedDevice(); - inline bool GetTelemetryParameters(bool &Reporting, uint64_t &Interval, uint64_t &WebSocketTimer, uint64_t &KafkaTimer, uint64_t &WebSocketCount, uint64_t &KafkaCount, @@ -153,18 +105,18 @@ namespace OpenWifi { friend class AP_WS_Server; - inline GWObjects::DeviceRestrictions Restrictions() const { + inline GWObjects::DeviceRestrictions Restrictions() { std::lock_guard G(ConnectionMutex_); return Restrictions_; } - - inline bool MustBeSecureRtty() const { return RttyMustBeSecure_; } + void Start(); private: - mutable std::mutex ConnectionMutex_; + std::recursive_mutex ConnectionMutex_; std::mutex TelemetryMutex_; Poco::Logger &Logger_; - Poco::Net::SocketReactor &Reactor_; + std::shared_ptr Reactor_; + std::shared_ptr DbSession_; std::unique_ptr WS_; std::string SerialNumber_; uint64_t SerialNumberInt_ = 0; @@ -175,34 +127,56 @@ namespace OpenWifi { uint64_t Errors_ = 0; Poco::Net::IPAddress PeerAddress_; volatile bool TelemetryReporting_ = false; - volatile uint64_t TelemetryWebSocketRefCount_ = 0; - volatile uint64_t TelemetryKafkaRefCount_ = 0; - volatile uint64_t TelemetryWebSocketTimer_ = 0; - volatile uint64_t TelemetryKafkaTimer_ = 0; - volatile uint64_t TelemetryInterval_ = 0; - volatile uint64_t TelemetryWebSocketPackets_ = 0; - volatile uint64_t TelemetryKafkaPackets_ = 0; + std::atomic_uint64_t TelemetryWebSocketRefCount_ = 0; + std::atomic_uint64_t TelemetryKafkaRefCount_ = 0; + std::atomic_uint64_t TelemetryWebSocketTimer_ = 0; + std::atomic_uint64_t TelemetryKafkaTimer_ = 0; + std::atomic_uint64_t TelemetryInterval_ = 0; + std::atomic_uint64_t TelemetryWebSocketPackets_ = 0; + std::atomic_uint64_t TelemetryKafkaPackets_ = 0; GWObjects::ConnectionState State_; - std::string RawLastStats_; + Utils::CompressedString RawLastStats_; GWObjects::HealthCheck RawLastHealthcheck_; std::chrono::time_point ConnectionStart_ = std::chrono::high_resolution_clock::now(); std::chrono::duration ConnectionCompletionTime_{0.0}; - std::atomic_flag Dead_ = false; + std::atomic Dead_ = false; std::atomic_bool DeviceValidated_ = false; - std::atomic_bool Valid_ = false; OpenWifi::GWObjects::DeviceRestrictions Restrictions_; - bool RttyMustBeSecure_ = false; + bool RTTYMustBeSecure_ = false; + bool hasGPS_=false; + std::double_t memory_used_=0.0, cpu_load_ = 0.0, temperature_ = 0.0; + std::uint64_t uuid_=0; + bool Simulated_=false; + std::uint64_t LastContact_=0; static inline std::atomic_uint64_t ConcurrentStartingDevices_ = 0; bool StartTelemetry(uint64_t RPCID, const std::vector &TelemetryTypes); bool StopTelemetry(uint64_t RPCID); void UpdateCounts(); - bool hasGPS=false; - std::double_t memory_used_=0.0, cpu_load_ = 0.0, temperature_ = 0.0; - std::uint64_t uuid_=0; - bool Simulated_=false; + static void DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid); + void SetLastStats(const std::string &LastStats); + void Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial); + void Process_state(Poco::JSON::Object::Ptr ParamsObj); + void Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj); + void Process_log(Poco::JSON::Object::Ptr ParamsObj); + void Process_crashlog(Poco::JSON::Object::Ptr ParamsObj); + void Process_ping(Poco::JSON::Object::Ptr ParamsObj); + void Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj); + void Process_recovery(Poco::JSON::Object::Ptr ParamsObj); + void Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial); + void Process_telemetry(Poco::JSON::Object::Ptr ParamsObj); + void Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj); + void Process_event(Poco::JSON::Object::Ptr ParamsObj); + void Process_wifiscan(Poco::JSON::Object::Ptr ParamsObj); + void Process_alarm(Poco::JSON::Object::Ptr ParamsObj); + void Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj); + + inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) { + RawLastHealthcheck_ = H; + } + }; } // namespace OpenWifi \ No newline at end of file diff --git a/src/AP_WS_LookForUpgrade.cpp b/src/AP_WS_LookForUpgrade.cpp new file mode 100644 index 00000000..bb581109 --- /dev/null +++ b/src/AP_WS_LookForUpgrade.cpp @@ -0,0 +1,88 @@ + +#include +#include "ConfigurationCache.h" +#include "UI_GW_WebSocketNotifications.h" +#include "CommandManager.h" + +namespace OpenWifi { + bool AP_WS_Connection::LookForUpgrade(Poco::Data::Session &Session, const uint64_t UUID, uint64_t &UpgradedUUID) { + + // A UUID of zero means ignore updates for that connection. + if (UUID == 0) + return false; + + uint64_t GoodConfig = ConfigurationCache().CurrentConfig(SerialNumberInt_); + if (GoodConfig && (GoodConfig == UUID || GoodConfig == State_.PendingUUID)) { + UpgradedUUID = UUID; + return false; + } + + GWObjects::Device D; + if (StorageService()->GetDevice(Session,SerialNumber_, D)) { + if(D.pendingUUID!=0 && UUID==D.pendingUUID) { + // so we sent an upgrade to a device, and now it is completing now... + UpgradedUUID = D.pendingUUID; + StorageService()->CompleteDeviceConfigurationChange(Session, SerialNumber_); + return true; + } + + // This is the case where the cache is empty after a restart. So GoodConfig will 0. If + // the device already has the right UUID, we just return. + if (D.UUID == UUID) { + UpgradedUUID = UUID; + ConfigurationCache().Add(SerialNumberInt_, UUID); + return false; + } + + Config::Config Cfg(D.Configuration); + if (UUID > D.UUID) { + // so we have a problem, the device has a newer config than we have. So we need to + // make sure our config is newer. + D.UUID = UUID + 2; + UpgradedUUID = D.UUID; + } + + Cfg.SetUUID(D.UUID); + D.Configuration = Cfg.get(); + State_.PendingUUID = UpgradedUUID = D.UUID; + + GWObjects::CommandDetails Cmd; + Cmd.SerialNumber = SerialNumber_; + Cmd.UUID = MicroServiceCreateUUID(); + Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM; + Cmd.Status = uCentralProtocol::PENDING; + Cmd.Command = uCentralProtocol::CONFIGURE; + Poco::JSON::Parser P; + auto ParsedConfig = P.parse(D.Configuration).extract(); + Poco::JSON::Object Params; + Params.set(uCentralProtocol::SERIAL, SerialNumber_); + Params.set(uCentralProtocol::UUID, D.UUID); + Params.set(uCentralProtocol::WHEN, 0); + Params.set(uCentralProtocol::CONFIG, ParsedConfig); + + std::ostringstream O; + Poco::JSON::Stringifier::stringify(Params, O); + Cmd.Details = O.str(); + poco_information(Logger_, + fmt::format("CFG-UPGRADE({}): Current ID: {}, newer configuration {}.", + CId_, UUID, D.UUID)); + bool Sent; + + StorageService()->AddCommand(SerialNumber_, Cmd, + Storage::CommandExecutionType::COMMAND_EXECUTED); + CommandManager()->PostCommand( + CommandManager()->Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()), + SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent, false, false); + + GWWebSocketNotifications::SingleDeviceConfigurationChange_t Notification; + Notification.content.serialNumber = D.SerialNumber; + Notification.content.oldUUID = UUID; + Notification.content.newUUID = UpgradedUUID; + GWWebSocketNotifications::DeviceConfigurationChange(Notification); + + return true; + } + return false; + } + +} \ No newline at end of file diff --git a/src/AP_WS_Process_connect.cpp b/src/AP_WS_Process_connect.cpp index e5af1409..7e7a61bd 100644 --- a/src/AP_WS_Process_connect.cpp +++ b/src/AP_WS_Process_connect.cpp @@ -71,9 +71,8 @@ namespace OpenWifi { CommandManager()->ClearQueue(SerialNumberInt_); - AP_WS_Server()->SetSessionDetails(State_.sessionId, SerialNumberInt_); + AP_WS_Server()->StartSession(State_.sessionId, SerialNumberInt_); - std::lock_guard Lock(ConnectionMutex_); Config::Capabilities Caps(Capabilities); Compatible_ = Caps.Compatible(); @@ -100,36 +99,24 @@ namespace OpenWifi { Restrictions_.from_json(RestrictionObject); } - if (Capabilities->has("developer")) { + if (Capabilities->has("developer") && !Capabilities->isNull("developer")) { Restrictions_.developer = Capabilities->getValue("developer"); } if(Capabilities->has("secure-rtty")) { - RttyMustBeSecure_ = Capabilities->getValue("secure-rtty"); + RTTYMustBeSecure_ = Capabilities->getValue("secure-rtty"); } State_.locale = FindCountryFromIP()->Get(IP); GWObjects::Device DeviceInfo; - auto DeviceExists = StorageService()->GetDevice(SerialNumber_, DeviceInfo); + std::lock_guard DbSessionLock(DbSession_->Mutex()); + + auto DeviceExists = StorageService()->GetDevice(DbSession_->Session(), SerialNumber_, DeviceInfo); if (Daemon()->AutoProvisioning() && !DeviceExists) { // check the firmware version. if this is too old, we cannot let that device connect yet, we must // force a firmware upgrade GWObjects::DefaultFirmware MinimumFirmware; if(FirmwareRevisionCache()->DeviceMustUpgrade(Compatible_, Firmware, MinimumFirmware)) { -/* - - { "jsonrpc" : "2.0" , - "method" : "upgrade" , - "params" : { - "serial" : , - "when" : Optional - , - "uri" : , - "FWsignature" : (optional) - }, - "id" : - } - - */ Poco::JSON::Object UpgradeCommand, Params; UpgradeCommand.set(uCentralProtocol::JSONRPC,uCentralProtocol::JSONRPC_VERSION); UpgradeCommand.set(uCentralProtocol::METHOD,uCentralProtocol::UPGRADE); @@ -157,7 +144,7 @@ namespace OpenWifi { } return; } else { - StorageService()->CreateDefaultDevice( + StorageService()->CreateDefaultDevice( DbSession_->Session(), SerialNumber_, Caps, Firmware, PeerAddress_, State_.VerifiedCertificate == GWObjects::SIMULATED); } @@ -166,7 +153,7 @@ namespace OpenWifi { poco_warning(Logger(),fmt::format("Device {} is a {} from {} and cannot be provisioned.",SerialNumber_,Compatible_, CId_)); return EndConnection(); } else if (DeviceExists) { - StorageService()->UpdateDeviceCapabilities(SerialNumber_, Caps); + StorageService()->UpdateDeviceCapabilities(DbSession_->Session(), SerialNumber_, Caps); int Updated{0}; if (!Firmware.empty()) { if (Firmware != DeviceInfo.Firmware) { @@ -238,12 +225,12 @@ namespace OpenWifi { } if (Updated) { - StorageService()->UpdateDevice(DeviceInfo); + StorageService()->UpdateDevice(DbSession_->Session(), DeviceInfo); } if(!Simulated_) { uint64_t UpgradedUUID = 0; - LookForUpgrade(UUID, UpgradedUUID); + LookForUpgrade(DbSession_->Session(), UUID, UpgradedUUID); State_.UUID = UpgradedUUID; } } diff --git a/src/AP_WS_Process_crashlog.cpp b/src/AP_WS_Process_crashlog.cpp index 9b8773c3..c56ea198 100644 --- a/src/AP_WS_Process_crashlog.cpp +++ b/src/AP_WS_Process_crashlog.cpp @@ -29,7 +29,7 @@ namespace OpenWifi { .Recorded = Utils::Now(), .LogType = 1, .UUID = ParamsObj->get(uCentralProtocol::UUID)}; - StorageService()->AddLog(DeviceLog); + StorageService()->AddLog(*DbSession_, DeviceLog); DeviceLogKafkaEvent E(DeviceLog); } else { poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_)); diff --git a/src/AP_WS_Process_deviceupdate.cpp b/src/AP_WS_Process_deviceupdate.cpp index b48c3cea..c1056d29 100644 --- a/src/AP_WS_Process_deviceupdate.cpp +++ b/src/AP_WS_Process_deviceupdate.cpp @@ -21,7 +21,7 @@ namespace OpenWifi { if (ParamsObj->has("currentPassword")) { auto Password = ParamsObj->get("currentPassword").toString(); - StorageService()->SetDevicePassword(Serial, Password); + StorageService()->SetDevicePassword(*DbSession_,Serial, Password); poco_trace( Logger_, fmt::format("DEVICE-UPDATE({}): Device is updating its login password.", Serial)); diff --git a/src/AP_WS_Process_healthcheck.cpp b/src/AP_WS_Process_healthcheck.cpp index 14b2cf30..5b0f2bd9 100644 --- a/src/AP_WS_Process_healthcheck.cpp +++ b/src/AP_WS_Process_healthcheck.cpp @@ -3,6 +3,7 @@ // #include "AP_WS_Connection.h" +#include "AP_WS_Server.h" #include "StorageService.h" #include "fmt/format.h" @@ -48,14 +49,14 @@ namespace OpenWifi { Check.Data = CheckData; Check.Sanity = Sanity; - StorageService()->AddHealthCheckData(Check); + StorageService()->AddHealthCheckData(*DbSession_, Check); if (!request_uuid.empty()) { StorageService()->SetCommandResult(request_uuid, CheckData); } SetLastHealthCheck(Check); - if (KafkaManager()->Enabled()) { + if (KafkaManager()->Enabled() && !AP_WS_Server()->KafkaDisableHealthChecks()) { KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, *ParamsObj); } } else { diff --git a/src/AP_WS_Process_log.cpp b/src/AP_WS_Process_log.cpp index 20fe77df..64c7f265 100644 --- a/src/AP_WS_Process_log.cpp +++ b/src/AP_WS_Process_log.cpp @@ -36,7 +36,7 @@ namespace OpenWifi { .Recorded = (uint64_t)time(nullptr), .LogType = 0, .UUID = State_.UUID}; - StorageService()->AddLog(DeviceLog); + StorageService()->AddLog(*DbSession_, DeviceLog); DeviceLogKafkaEvent E(DeviceLog); } else { poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_)); diff --git a/src/AP_WS_Process_rebootLog.cpp b/src/AP_WS_Process_rebootLog.cpp index 070aafd9..871d4422 100644 --- a/src/AP_WS_Process_rebootLog.cpp +++ b/src/AP_WS_Process_rebootLog.cpp @@ -35,7 +35,7 @@ namespace OpenWifi { .Recorded = ParamsObj->get(uCentralProtocol::DATE), .LogType = 2, .UUID = ParamsObj->get(uCentralProtocol::UUID)}; - StorageService()->AddLog(DeviceLog); + StorageService()->AddLog(*DbSession_, DeviceLog); DeviceLogKafkaEvent E(DeviceLog); } else { poco_warning(Logger_, fmt::format("REBOOT-LOG({}): Missing parameters.", CId_)); diff --git a/src/AP_WS_Process_recovery.cpp b/src/AP_WS_Process_recovery.cpp index a9100b2c..8871c654 100644 --- a/src/AP_WS_Process_recovery.cpp +++ b/src/AP_WS_Process_recovery.cpp @@ -35,7 +35,7 @@ namespace OpenWifi { .LogType = 1, .UUID = 0}; - StorageService()->AddLog(DeviceLog); + StorageService()->AddLog(*DbSession_, DeviceLog); if (ParamsObj->get(uCentralProtocol::REBOOT).toString() == "true") { GWObjects::CommandDetails Cmd; diff --git a/src/AP_WS_Process_state.cpp b/src/AP_WS_Process_state.cpp index 646b37de..8abb1e2b 100644 --- a/src/AP_WS_Process_state.cpp +++ b/src/AP_WS_Process_state.cpp @@ -3,6 +3,7 @@ // #include "AP_WS_Connection.h" +#include "AP_WS_Server.h" #include "StateUtils.h" #include "StorageService.h" @@ -39,17 +40,19 @@ namespace OpenWifi { UUID, request_uuid)); } + std::lock_guard Guard(DbSession_->Mutex()); if(!Simulated_) { uint64_t UpgradedUUID; - LookForUpgrade(UUID, UpgradedUUID); + LookForUpgrade(DbSession_->Session(), UUID, UpgradedUUID); State_.UUID = UpgradedUUID; } + SetLastStats(StateStr); GWObjects::Statistics Stats{ .SerialNumber = SerialNumber_, .UUID = UUID, .Data = StateStr}; Stats.Recorded = Utils::Now(); - StorageService()->AddStatisticsData(Stats); + StorageService()->AddStatisticsData(DbSession_->Session(),Stats); if (!request_uuid.empty()) { StorageService()->SetCommandResult(request_uuid, StateStr); } @@ -57,7 +60,7 @@ namespace OpenWifi { StateUtils::ComputeAssociations(StateObj, State_.Associations_2G, State_.Associations_5G, State_.Associations_6G); - if (KafkaManager()->Enabled()) { + if (KafkaManager()->Enabled() && !AP_WS_Server()->KafkaDisableState()) { KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, *ParamsObj); } diff --git a/src/AP_WS_Process_telemetry.cpp b/src/AP_WS_Process_telemetry.cpp index d5827237..9ea35cb7 100644 --- a/src/AP_WS_Process_telemetry.cpp +++ b/src/AP_WS_Process_telemetry.cpp @@ -35,8 +35,7 @@ namespace OpenWifi { } if (TelemetryWebSocketRefCount_) { if (now < TelemetryWebSocketTimer_) { - // std::cout << SerialNumber_ << ": Updating WebSocket telemetry" << - // std::endl; + TelemetryWebSocketPackets_++; State_.websocketPackets = TelemetryWebSocketPackets_; TelemetryStream()->NotifyEndPoint(SerialNumberInt_, KafkaPayload); @@ -46,7 +45,6 @@ namespace OpenWifi { } if (TelemetryKafkaRefCount_) { if (KafkaManager()->Enabled() && now < TelemetryKafkaTimer_) { - // std::cout << SerialNumber_ << ": Updating Kafka telemetry" << std::endl; TelemetryKafkaPackets_++; State_.kafkaPackets = TelemetryKafkaPackets_; KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_, diff --git a/src/AP_WS_ReactorPool.h b/src/AP_WS_Reactor_Pool.h similarity index 51% rename from src/AP_WS_ReactorPool.h rename to src/AP_WS_Reactor_Pool.h index 205c29dc..654810c4 100644 --- a/src/AP_WS_ReactorPool.h +++ b/src/AP_WS_Reactor_Pool.h @@ -9,30 +9,39 @@ #include "Poco/Environment.h" #include "Poco/Net/SocketAcceptor.h" - +#include #include "framework/utils.h" +#include namespace OpenWifi { + class AP_WS_ReactorThreadPool { public: - explicit AP_WS_ReactorThreadPool() { + explicit AP_WS_ReactorThreadPool(Poco::Logger &Logger) : Logger_(Logger) { NumberOfThreads_ = Poco::Environment::processorCount() * 4; if (NumberOfThreads_ == 0) - NumberOfThreads_ = 4; + NumberOfThreads_ = 8; + NumberOfThreads_ = std::min(NumberOfThreads_, (std::uint64_t) 128); } ~AP_WS_ReactorThreadPool() { Stop(); } void Start() { + Reactors_.reserve(NumberOfThreads_); + DbSessions_.reserve(NumberOfThreads_); + Threads_.reserve(NumberOfThreads_); + Logger_.information(fmt::format("WebSocket Processor: starting {} threads.", NumberOfThreads_)); for (uint64_t i = 0; i < NumberOfThreads_; ++i) { - auto NewReactor = std::make_unique(); + auto NewReactor = std::make_shared(); auto NewThread = std::make_unique(); NewThread->start(*NewReactor); std::string ThreadName{"ap:react:" + std::to_string(i)}; Utils::SetThreadName(*NewThread, ThreadName.c_str()); Reactors_.emplace_back(std::move(NewReactor)); Threads_.emplace_back(std::move(NewThread)); + DbSessions_.emplace_back(std::make_shared()); } + Logger_.information(fmt::format("WebSocket Processor: {} threads started.", NumberOfThreads_)); } void Stop() { @@ -43,20 +52,24 @@ namespace OpenWifi { } Reactors_.clear(); Threads_.clear(); + DbSessions_.clear(); } - Poco::Net::SocketReactor &NextReactor() { + std::pair, std::shared_ptr > NextReactor() { std::lock_guard Lock(Mutex_); NextReactor_++; NextReactor_ %= NumberOfThreads_; - return *Reactors_[NextReactor_]; + return std::make_pair(Reactors_[NextReactor_], DbSessions_[NextReactor_]); } private: std::mutex Mutex_; uint64_t NumberOfThreads_; uint64_t NextReactor_ = 0; - std::vector> Reactors_; - std::vector> Threads_; + std::vector> Reactors_; + std::vector> Threads_; + std::vector> DbSessions_; + Poco::Logger &Logger_; + }; } // namespace OpenWifi \ No newline at end of file diff --git a/src/AP_WS_Server.cpp b/src/AP_WS_Server.cpp index a99b7a57..87fc8949 100644 --- a/src/AP_WS_Server.cpp +++ b/src/AP_WS_Server.cpp @@ -23,15 +23,47 @@ namespace OpenWifi { - void AP_WS_RequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request, - Poco::Net::HTTPServerResponse &response) { - try { - AP_WS_Server()->AddConnection( - id_, std::make_shared(request, response, id_, Logger_, - AP_WS_Server()->NextReactor())); - } catch (...) { - poco_warning(Logger_, "Exception during WS creation"); + class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler { + public: + explicit AP_WS_RequestHandler(Poco::Logger &L, std::uint64_t session_id) : Logger_(L), + session_id_(session_id) { + }; + + void handleRequest( Poco::Net::HTTPServerRequest &request, + Poco::Net::HTTPServerResponse &response) override { + try { + auto NewConnection = std::make_shared(request, response, session_id_, Logger_, + AP_WS_Server()->NextReactor()); + AP_WS_Server()->AddConnection(NewConnection); + NewConnection->Start(); + } catch (...) { + poco_warning(Logger_, "Exception during WS creation"); + } + }; + + private: + Poco::Logger &Logger_; + std::uint64_t session_id_; + }; + + class AP_WS_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { + public: + inline explicit AP_WS_RequestHandlerFactory(Poco::Logger &L) : Logger_(L) {} + + inline Poco::Net::HTTPRequestHandler * + createRequestHandler(const Poco::Net::HTTPServerRequest &request) override { + if (request.find("Upgrade") != request.end() && + Poco::icompare(request["Upgrade"], "websocket") == 0) { + Utils::SetThreadName("ws:conn-init"); + session_id_++; + return new AP_WS_RequestHandler(Logger_, session_id_); + } else { + return nullptr; + } } + private: + Poco::Logger &Logger_; + inline static std::atomic_uint64_t session_id_ = 0; }; bool AP_WS_Server::ValidateCertificate(const std::string &ConnectionId, @@ -57,7 +89,7 @@ namespace OpenWifi { SessionTimeOut_ = MicroServiceConfigGetInt("openwifi.session.timeout", 10*60); - Reactor_pool_ = std::make_unique(); + Reactor_pool_ = std::make_unique(Logger()); Reactor_pool_->Start(); for (const auto &Svr : ConfigServersList_) { @@ -135,6 +167,9 @@ namespace OpenWifi { WebServerHttpParams); WebServers_.push_back(std::move(NewWebServer)); } + + KafkaDisableState_ = MicroServiceConfigGetBool("openwifi.kafka.disablestate", false); + KafkaDisableHealthChecks_ = MicroServiceConfigGetBool("openwifi.kafka.disablehealthchecks", false); } for (auto &server : WebServers_) { @@ -156,243 +191,345 @@ namespace OpenWifi { UseDefaultConfig_ = true; } - SimulatorId_ = MicroServiceConfigGetString("simulatorid", ""); + SimulatorId_ = Poco::toLower(MicroServiceConfigGetString("simulatorid", "")); SimulatorEnabled_ = !SimulatorId_.empty(); Utils::SetThreadName(ReactorThread_, "dev:react:head"); - GarbageCollectorCallback_ = std::make_unique>( - *this, &AP_WS_Server::onGarbageCollecting); - Timer_.setStartInterval(10 * 1000); - Timer_.setPeriodicInterval(10 * 1000); // every minute - Timer_.start(*GarbageCollectorCallback_, MicroServiceTimerPool()); - Running_ = true; + GarbageCollector_.setName("ws:garbage"); + GarbageCollector_.start(*this); return 0; } - void AP_WS_Server::onGarbageCollecting([[maybe_unused]] Poco::Timer &timer) { - static uint64_t last_log = Utils::Now(), last_zombie_run = 0; - auto now = Utils::Now(); + void AP_WS_Server::run() { + uint64_t last_log = Utils::Now(), + last_zombie_run = 0, + last_garbage_run = 0; - { - { - std::lock_guard SessionLock(SessionMutex_); - if (!Garbage_.empty()) { - Garbage_.clear(); - } + Poco::Logger &LocalLogger = Poco::Logger::create( + "WS-Session-Janitor", Poco::Logger::root().getChannel(), Poco::Logger::root().getLevel()); + + while(Running_) { + + if(!Poco::Thread::trySleep(30000)) { + break; } - uint64_t total_connected_time = 0; - - if(now-last_zombie_run > 20) { - poco_information(Logger(), fmt::format("Garbage collecting...")); - std::vector SessionsToRemove; - NumberOfConnectedDevices_ = 0; - NumberOfConnectingDevices_ = 0; - AverageDeviceConnectionTime_ = 0; - last_zombie_run = now; - for(int hashIndex=0;hashIndex<256;hashIndex++) { - std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto hint = SerialNumbers_[hashIndex].begin(); - while (hint != end(SerialNumbers_[hashIndex])) { - if (hint->second.second == nullptr) { - hint = SerialNumbers_[hashIndex].erase(hint); - } else if ((now - hint->second.second->State_.LastContact) > - SessionTimeOut_) { - hint->second.second->EndConnection(false); - poco_information( - Logger(), - fmt::format( - "{}: Session seems idle. Controller disconnecting device.", - hint->second.second->SerialNumber_)); - SessionsToRemove.emplace_back(hint->second.first); - Garbage_.push_back(hint->second.second); - hint = SerialNumbers_[hashIndex].erase(hint); - } else if (hint->second.second->State_.Connected) { - NumberOfConnectedDevices_++; - total_connected_time += (now - hint->second.second->State_.started); - hint++; - } else { - NumberOfConnectingDevices_++; - hint++; + LocalLogger.information(fmt::format("Garbage collecting starting run." )); + + uint64_t total_connected_time = 0, now = Utils::Now(); + + if(now-last_zombie_run > 60) { + try { + poco_information(LocalLogger, + fmt::format("Garbage collecting zombies... (step 1)")); + NumberOfConnectedDevices_ = 0; + NumberOfConnectingDevices_ = 0; + AverageDeviceConnectionTime_ = 0; + int waits = 0; + for (int hashIndex = 0; hashIndex < MACHash::HashMax(); hashIndex++) { + last_zombie_run = now; + waits = 0; + while (true) { + if (SerialNumbersMutex_[hashIndex].try_lock()) { + waits = 0; + auto hint = SerialNumbers_[hashIndex].begin(); + while (hint != end(SerialNumbers_[hashIndex])) { + + if (hint->second == nullptr) { + poco_information( + LocalLogger, + fmt::format("Dead device found in hash index {}", hashIndex)); + // hint = SerialNumbers_[hashIndex].erase(hint); + hint++; + continue; + } + auto Device = hint->second; + if(Device->ConnectionMutex_.try_lock()) { + auto RightNow = Utils::Now(); + if (RightNow > Device->LastContact_ && + (RightNow - Device->LastContact_) > SessionTimeOut_) { + poco_information( + LocalLogger, + fmt::format("{}: Session seems idle. Controller disconnecting device.", + Device->SerialNumber_)); + hint = SerialNumbers_[hashIndex].erase(hint); + } else if (Device->State_.Connected) { + NumberOfConnectedDevices_++; + total_connected_time += + (RightNow - Device->State_.started); + ++hint; + } else { + ++hint; + } + Device->ConnectionMutex_.unlock(); + continue; + } else { + poco_warning(LocalLogger, fmt::format("Could not lock device mutex for {}", + Device->SerialNumber_)); + } + ++NumberOfConnectingDevices_; + ++hint; + } + SerialNumbersMutex_[hashIndex].unlock(); + break; + } else if (waits < 5) { + waits++; + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } else { + break; + } } } - } - if(SessionsToRemove.empty()) { - poco_information(Logger(), fmt::format("Removing {} sessions.", SessionsToRemove.size())); - std::lock_guard Lock(SessionMutex_); - for (const auto &Session : SessionsToRemove) { - Sessions_.erase(Session); + poco_information(LocalLogger, + fmt::format("Garbage collecting zombies... (step 2)")); + LeftOverSessions_ = 0; + for (int i = 0; i < SessionHash::HashMax(); i++) { + waits = 0; + while (true) { + if (SessionMutex_[i].try_lock()) { + waits = 0; + auto hint = Sessions_[i].begin(); + auto RightNow = Utils::Now(); + while (hint != end(Sessions_[i])) { + if (hint->second == nullptr) { + hint = Sessions_[i].erase(hint); + } else if (RightNow > hint->second->LastContact_ && + (RightNow - hint->second->LastContact_) > + SessionTimeOut_) { + poco_information( + LocalLogger, + fmt::format("{}: Session seems idle. Controller disconnecting device.", + hint->second->SerialNumber_)); + hint = Sessions_[i].erase(hint); + } else { + ++LeftOverSessions_; + ++hint; + } + } + SessionMutex_[i].unlock(); + break; + } else if (waits < 5) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + waits++; + } else { + break; + } + } } - } - AverageDeviceConnectionTime_ = - NumberOfConnectedDevices_ > 0 ? total_connected_time / NumberOfConnectedDevices_ - : 0; + AverageDeviceConnectionTime_ = + NumberOfConnectedDevices_ > 0 + ? total_connected_time / NumberOfConnectedDevices_ + : 0; + poco_information(LocalLogger, fmt::format("Garbage collecting zombies done...")); + } catch (const Poco::Exception &E) { + poco_error(LocalLogger, fmt::format("Poco::Exception: Garbage collecting zombies failed: {}", E.displayText())); + } catch (const std::exception &E) { + poco_error(LocalLogger, fmt::format("std::exception: Garbage collecting zombies failed: {}", E.what())); + } catch (...) { + poco_error(LocalLogger, fmt::format("exception:Garbage collecting zombies failed: {}", "unknown")); + } - poco_information(Logger(), fmt::format("Garbage collecting done...")); } else { - std::lock_guard SessionLock(SessionMutex_); - NumberOfConnectedDevices_ = Sessions_.size(); - AverageDeviceConnectionTime_ += 10; + NumberOfConnectedDevices_=0; + for(int i=0;i 0) { + AverageDeviceConnectionTime_ += (now - last_garbage_run); + } + } else { + AverageDeviceConnectionTime_ = 0; + } } - if ((now - last_log) > 120) { + if ((now - last_log) > 60) { last_log = now; - poco_information(Logger(), - fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds", + poco_information(LocalLogger, + fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds. Left Over Sessions: {}", NumberOfConnectedDevices_, NumberOfConnectingDevices_, - AverageDeviceConnectionTime_)); + AverageDeviceConnectionTime_, LeftOverSessions_)); } - } - GWWebSocketNotifications::NumberOfConnection_t Notification; - Notification.content.numberOfConnectingDevices = NumberOfConnectingDevices_; - Notification.content.numberOfDevices = NumberOfConnectedDevices_; - Notification.content.averageConnectedTime = AverageDeviceConnectionTime_; - GetTotalDataStatistics(Notification.content.tx,Notification.content.rx); - GWWebSocketNotifications::NumberOfConnections(Notification); + GWWebSocketNotifications::NumberOfConnection_t Notification; + Notification.content.numberOfConnectingDevices = NumberOfConnectingDevices_; + Notification.content.numberOfDevices = NumberOfConnectedDevices_; + Notification.content.averageConnectedTime = AverageDeviceConnectionTime_; + GetTotalDataStatistics(Notification.content.tx,Notification.content.rx); + GWWebSocketNotifications::NumberOfConnections(Notification); - Poco::JSON::Object KafkaNotification; - Notification.to_json(KafkaNotification); + Poco::JSON::Object KafkaNotification; + Notification.to_json(KafkaNotification); - Poco::JSON::Object FullEvent; - FullEvent.set("type", "load-update"); - FullEvent.set("timestamp", now); - FullEvent.set("payload", KafkaNotification); + Poco::JSON::Object FullEvent; + FullEvent.set("type", "load-update"); + FullEvent.set("timestamp", now); + FullEvent.set("payload", KafkaNotification); - KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, "system", FullEvent); + KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, "system", FullEvent); + LocalLogger.information(fmt::format("Garbage collection finished run." )); + last_garbage_run = now; + } + LocalLogger.information(fmt::format("Garbage collector done for the day." )); } void AP_WS_Server::Stop() { poco_information(Logger(), "Stopping..."); Running_ = false; - Timer_.stop(); + GarbageCollector_.wakeUp(); + GarbageCollector_.join(); for (auto &server : WebServers_) { server->stopAll(); } + Reactor_pool_->Stop(); Reactor_.stop(); ReactorThread_.join(); poco_information(Logger(), "Stopped..."); } + bool AP_WS_Server::GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector & SerialNumbers) { + SerialNumbers.clear(); + for(int i=0;iRawLastHealthcheck_.Sanity >= lowLimit && + connection.second->RawLastHealthcheck_.Sanity <= highLimit) { + SerialNumbers.push_back(connection.second->SerialNumber_); + } + } + } + return true; + } + bool AP_WS_Server::GetStatistics(uint64_t SerialNumber, std::string &Statistics) const { - auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber); + auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); auto Device = SerialNumbers_[hashIndex].find(SerialNumber); - if (Device == SerialNumbers_[hashIndex].end() || Device->second.second == nullptr) { + if (Device == SerialNumbers_[hashIndex].end() || Device->second == nullptr) { return false; } - Device->second.second->GetLastStats(Statistics); + Device->second->GetLastStats(Statistics); return true; } bool AP_WS_Server::GetState(uint64_t SerialNumber, GWObjects::ConnectionState &State) const { - auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber); - std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto Device = SerialNumbers_[hashIndex].find(SerialNumber); - if (Device == SerialNumbers_[hashIndex].end() || Device->second.second == nullptr) { - return false; + std::shared_ptr Connection; + { + auto hashIndex = MACHash::Hash(SerialNumber); + std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); + auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); + if (DeviceHint == SerialNumbers_[hashIndex].end() || + DeviceHint->second == nullptr) { + return false; + } + Connection = DeviceHint->second; } - Device->second.second->GetState(State); + Connection->GetState(State); return true; } bool AP_WS_Server::GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck &CheckData) const { - auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber); + auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); auto Device = SerialNumbers_[hashIndex].find(SerialNumber); - if (Device == SerialNumbers_[hashIndex].end() || Device->second.second == nullptr) { + if (Device == SerialNumbers_[hashIndex].end() || Device->second == nullptr) { return false; } - Device->second.second->GetLastHealthCheck(CheckData); + Device->second->GetLastHealthCheck(CheckData); return true; } - void AP_WS_Server::SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber) { - std::lock_guard SessionLock(SessionMutex_); - auto Conn = Sessions_.find(connection_id); - if (Conn == end(Sessions_)) - return; - - auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber); - std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto CurrentSerialNumber = SerialNumbers_[hashIndex].find(SerialNumber); - if ((CurrentSerialNumber == SerialNumbers_[hashIndex].end()) || - (CurrentSerialNumber->second.first < connection_id)) { - SerialNumbers_[hashIndex][SerialNumber] = std::make_pair(connection_id, Conn->second); - return; + void AP_WS_Server::StartSession(uint64_t session_id, uint64_t SerialNumber) { + auto deviceHash = MACHash::Hash(SerialNumber); + auto sessionHash = SessionHash::Hash(session_id); + std::lock_guard SessionLock(SessionMutex_[sessionHash]); + auto SessionHint = Sessions_[sessionHash].find(session_id); + if (SessionHint != end(Sessions_[sessionHash])) { + std::lock_guard Lock(SerialNumbersMutex_[deviceHash]); + SerialNumbers_[deviceHash][SerialNumber] = SessionHint->second; + Sessions_[sessionHash].erase(SessionHint); + } else { + poco_error(Logger(), fmt::format("StartSession: Could not find session '{}'", session_id)); } } bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t SerialNumber) { - std::lock_guard SessionLock(SessionMutex_); - auto Session = Sessions_.find(session_id); - if (Session == end(Sessions_)) - return false; - - Garbage_.push_back(Session->second); - - auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber); - std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto Device = SerialNumbers_[hashIndex].find(SerialNumber); - if (Device == end(SerialNumbers_[hashIndex])) { - Sessions_.erase(Session); - return false; + { + auto sessionHash = SessionHash::Hash(session_id); + std::lock_guard SessionLock(SessionMutex_[sessionHash]); + Sessions_[sessionHash].erase(session_id); } - if (Device->second.first == session_id) { - Sessions_.erase(Session); - SerialNumbers_[hashIndex].erase(Device); - return true; + { + auto hashIndex = MACHash::Hash(SerialNumber); + std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); + auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); + if (DeviceHint == SerialNumbers_[hashIndex].end() + || DeviceHint->second == nullptr + || DeviceHint->second->State_.sessionId != session_id) { + return false; + } + SerialNumbers_[hashIndex].erase(DeviceHint); } - - Sessions_.erase(Session); - - return false; + return true; } + bool AP_WS_Server::Connected(uint64_t SerialNumber, GWObjects::DeviceRestrictions &Restrictions) const { - auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber); - std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto Device = SerialNumbers_[hashIndex].find(SerialNumber); - if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) { + auto hashIndex = MACHash::Hash(SerialNumber); + std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); + auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); + if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) { return false; } - Device->second.second->GetRestrictions(Restrictions); - return Device->second.second->State_.Connected; + if(!DeviceHint->second->Dead_) { + DeviceHint->second->GetRestrictions(Restrictions); + return DeviceHint->second->State_.Connected; + } + return false; } + bool AP_WS_Server::Connected(uint64_t SerialNumber) const { - auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber); + auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto Device = SerialNumbers_[hashIndex].find(SerialNumber); - if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) { + auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); + if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) { return false; } - return Device->second.second->State_.Connected; + if(!DeviceHint->second->Dead_) { + return DeviceHint->second->State_.Connected; + } + return false; } bool AP_WS_Server::SendFrame(uint64_t SerialNumber, const std::string &Payload) const { - auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber); + auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto Device = SerialNumbers_[hashIndex].find(SerialNumber); - if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) { + auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); + if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) { + return false; + } + + if(DeviceHint->second->Dead_) { return false; } try { - return Device->second.second->Send(Payload); + return DeviceHint->second->Send(Payload); } catch (...) { poco_debug(Logger(), fmt::format(": SendFrame: Could not send data to device '{}'", Utils::IntToSerialNumber(SerialNumber))); @@ -401,48 +538,48 @@ namespace OpenWifi { } void AP_WS_Server::StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber) { - auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber); + auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); auto Device = SerialNumbers_[hashIndex].find(SerialNumber); - if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) { + if (Device == end(SerialNumbers_[hashIndex]) || Device->second == nullptr) { return; } - Device->second.second->StopWebSocketTelemetry(RPCID); + Device->second->StopWebSocketTelemetry(RPCID); } void AP_WS_Server::SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime, const std::vector &TelemetryTypes) { - auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber); - std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto Device = SerialNumbers_[hashIndex].find(SerialNumber); - if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) { + auto hashIndex = MACHash::Hash(SerialNumber); + std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); + auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); + if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) { return; } - Device->second.second->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes); + DeviceHint->second->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes); } void AP_WS_Server::SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime, const std::vector &TelemetryTypes) { - auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber); + auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto Device = SerialNumbers_[hashIndex].find(SerialNumber); - if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) { + auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); + if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) { return; } - Device->second.second->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes); + DeviceHint->second->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes); } void AP_WS_Server::StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber) { - auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber); - std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto Device = SerialNumbers_[hashIndex].find(SerialNumber); - if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) { + auto hashIndex = MACHash::Hash(SerialNumber); + std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]); + auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); + if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) { return; } - Device->second.second->StopKafkaTelemetry(RPCID); + DeviceHint->second->StopKafkaTelemetry(RPCID); } void AP_WS_Server::GetTelemetryParameters( @@ -451,14 +588,14 @@ namespace OpenWifi { uint64_t &TelemetryWebSocketCount, uint64_t &TelemetryKafkaCount, uint64_t &TelemetryWebSocketPackets, uint64_t &TelemetryKafkaPackets) { - auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber); - std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto Device = SerialNumbers_[hashIndex].find(SerialNumber); - if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) { + auto hashIndex = MACHash::Hash(SerialNumber); + std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]); + auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); + if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) { return; } - Device->second.second->GetTelemetryParameters(TelemetryRunning, TelemetryInterval, + DeviceHint->second->GetTelemetryParameters(TelemetryRunning, TelemetryInterval, TelemetryWebSocketTimer, TelemetryKafkaTimer, TelemetryWebSocketCount, TelemetryKafkaCount, TelemetryWebSocketPackets, TelemetryKafkaPackets); @@ -468,15 +605,19 @@ namespace OpenWifi { const unsigned char *buffer, std::size_t size) { auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber); - auto hashIndex = Utils::CalculateMacAddressHash(IntSerialNumber); - std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto Device = SerialNumbers_[hashIndex].find(IntSerialNumber); - if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) { + auto hashIndex = MACHash::Hash(IntSerialNumber); + std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]); + auto DeviceHint = SerialNumbers_[hashIndex].find(IntSerialNumber); + if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) { + return false; + } + + if(DeviceHint->second->Dead_) { return false; } try { - return Device->second.second->SendRadiusAccountingData(buffer, size); + return DeviceHint->second->SendRadiusAccountingData(buffer, size); } catch (...) { poco_debug( Logger(), @@ -489,15 +630,19 @@ namespace OpenWifi { bool AP_WS_Server::SendRadiusAuthenticationData(const std::string &SerialNumber, const unsigned char *buffer, std::size_t size) { auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber); - auto hashIndex = Utils::CalculateMacAddressHash(IntSerialNumber); - std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto Device = SerialNumbers_[hashIndex].find(IntSerialNumber); - if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) { + auto hashIndex = MACHash::Hash(IntSerialNumber); + std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]); + auto DeviceHint = SerialNumbers_[hashIndex].find(IntSerialNumber); + if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) { + return false; + } + + if(DeviceHint->second->Dead_) { return false; } try { - return Device->second.second->SendRadiusAuthenticationData(buffer, size); + return DeviceHint->second->SendRadiusAuthenticationData(buffer, size); } catch (...) { poco_debug( Logger(), @@ -510,15 +655,18 @@ namespace OpenWifi { bool AP_WS_Server::SendRadiusCoAData(const std::string &SerialNumber, const unsigned char *buffer, std::size_t size) { auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber); - auto hashIndex = Utils::CalculateMacAddressHash(IntSerialNumber); - std::lock_guard Lock(SerialNumbersMutex_[hashIndex]); - auto Device = SerialNumbers_[hashIndex].find(IntSerialNumber); - if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) { + auto hashIndex = MACHash::Hash(IntSerialNumber); + std::lock_guard DevicesGuard(SerialNumbersMutex_[hashIndex]); + auto DeviceHint = SerialNumbers_[hashIndex].find(IntSerialNumber); + if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) { return false; } + if(DeviceHint->second->Dead_) { + return false; + } try { - return Device->second.second->SendRadiusCoAData(buffer, size); + return DeviceHint->second->SendRadiusCoAData(buffer, size); } catch (...) { poco_debug(Logger(), fmt::format(": SendRadiusCoAData: Could not send data to device '{}'", @@ -527,4 +675,32 @@ namespace OpenWifi { return false; } + bool AP_WS_Server::ExtendedAttributes(const std::string &serialNumber, + bool & hasGPS, + std::uint64_t &Sanity, + std::double_t &MemoryUsed, + std::double_t &Load, + std::double_t &Temperature + ) { + + auto serialNumberInt = Utils::SerialNumberToInt(serialNumber); + auto hashIndex = MACHash::Hash(serialNumberInt); + std::lock_guard DevicesGuard(SerialNumbersMutex_[hashIndex]); + auto DeviceHint = SerialNumbers_[hashIndex].find(Utils::SerialNumberToInt(serialNumber)); + if(DeviceHint==end(SerialNumbers_[hashIndex])) { + return false; + } + if(DeviceHint->second->Dead_) { + return false; + } + std::lock_guard DeviceGuard(DeviceHint->second->ConnectionMutex_); + hasGPS = DeviceHint->second->hasGPS_; + Sanity = DeviceHint->second->RawLastHealthcheck_.Sanity; + MemoryUsed = DeviceHint->second->memory_used_; + Load = DeviceHint->second->cpu_load_; + Temperature = DeviceHint->second->temperature_; + return true; + } + + } // namespace OpenWifi \ No newline at end of file diff --git a/src/AP_WS_Server.h b/src/AP_WS_Server.h index 37dc5b10..4391451b 100644 --- a/src/AP_WS_Server.h +++ b/src/AP_WS_Server.h @@ -24,46 +24,51 @@ #include "Poco/Timer.h" #include "AP_WS_Connection.h" -#include "AP_WS_ReactorPool.h" +#include "AP_WS_Reactor_Pool.h" #include "framework/SubSystemServer.h" #include "framework/utils.h" namespace OpenWifi { - class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler { + constexpr uint MACHashMax = 256; + constexpr uint MACHashMask = MACHashMax-1; + class MACHash { public: - explicit AP_WS_RequestHandler(Poco::Logger &L, uint64_t id) : Logger_(L), id_(id){}; + [[nodiscard]] static inline uint16_t Hash(std::uint64_t value) { + uint8_t hash = 0, i=6; + while(i) { + hash ^= (value & MACHashMask) + 1; + value >>= 8; + --i; + } + return hash; + } - void handleRequest(Poco::Net::HTTPServerRequest &request, - Poco::Net::HTTPServerResponse &response) override; + [[nodiscard]] static inline uint16_t Hash(const std::string & value) { + return Hash(Utils::MACToInt(value)); + } - private: - Poco::Logger &Logger_; - uint64_t id_ = 0; + [[nodiscard]] static inline uint16_t HashMax() { + return MACHashMax; + } }; - class AP_WS_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { + constexpr uint SessionHashMax = 256; + constexpr uint SessionHashMask = SessionHashMax-1; + class SessionHash { public: - inline explicit AP_WS_RequestHandlerFactory(Poco::Logger &L) : Logger_(L) {} - - inline Poco::Net::HTTPRequestHandler * - createRequestHandler(const Poco::Net::HTTPServerRequest &request) override { - if (request.find("Upgrade") != request.end() && - Poco::icompare(request["Upgrade"], "websocket") == 0) { - Utils::SetThreadName("ws:conn-init"); - return new AP_WS_RequestHandler(Logger_, id_++); - } else { - return nullptr; - } + [[nodiscard]] static inline uint16_t Hash(std::uint64_t value) { + return (value & SessionHashMask); } - private: - Poco::Logger &Logger_; - inline static uint64_t id_ = 1; + [[nodiscard]] static inline uint16_t HashMax() { + return SessionHashMax; + } }; - class AP_WS_Server : public SubSystemServer { + + class AP_WS_Server : public SubSystemServer, public Poco::Runnable { public: static auto instance() { static auto instance_ = new AP_WS_Server; @@ -77,48 +82,47 @@ namespace OpenWifi { const Poco::Crypto::X509Certificate &Certificate); inline bool IsSimSerialNumber(const std::string &SerialNumber) const { - return IsSim(Poco::toLower(SerialNumber)) && - Poco::toLower(SerialNumber) == Poco::toLower(SimulatorId_); + return IsSim(SerialNumber) && + SerialNumber == SimulatorId_; } inline static bool IsSim(const std::string &SerialNumber) { return SerialNumber.substr(0, 6) == "53494d"; } - inline bool IsSimEnabled() const { return SimulatorEnabled_; } - - inline bool AllowSerialNumberMismatch() const { return AllowSerialNumberMismatch_; } - - inline uint64_t MismatchDepth() const { return MismatchDepth_; } - - inline bool UseProvisioning() const { return LookAtProvisioning_; } - inline bool UseDefaults() const { return UseDefaultConfig_; } - - [[nodiscard]] inline Poco::Net::SocketReactor &NextReactor() { + void run() override; // Garbage collector thread. + [[nodiscard]] inline bool IsSimEnabled() const { return SimulatorEnabled_; } + [[nodiscard]] inline bool AllowSerialNumberMismatch() const { return AllowSerialNumberMismatch_; } + [[nodiscard]] inline uint64_t MismatchDepth() const { return MismatchDepth_; } + [[nodiscard]] inline bool UseProvisioning() const { return LookAtProvisioning_; } + [[nodiscard]] inline bool UseDefaults() const { return UseDefaultConfig_; } + [[nodiscard]] inline bool Running() const { return Running_; } + [[nodiscard]] inline std::pair, std::shared_ptr> NextReactor() { return Reactor_pool_->NextReactor(); } - [[nodiscard]] inline bool Running() const { return Running_; } - inline void AddConnection(uint64_t session_id, - std::shared_ptr Connection) { - std::lock_guard Lock(SessionMutex_); - Sessions_[session_id] = std::move(Connection); + inline void AddConnection(std::shared_ptr Connection) { + std::uint64_t sessionHash = SessionHash::Hash(Connection->State_.sessionId); + std::lock_guard Lock(SessionMutex_[sessionHash]); + if(Sessions_[sessionHash].find(Connection->State_.sessionId)==end(Sessions_[sessionHash])) { + Sessions_[sessionHash][Connection->State_.sessionId] = std::move(Connection); + } } - inline bool DeviceRequiresSecureRtty(uint64_t serialNumber) const { - auto hashIndex = Utils::CalculateMacAddressHash(serialNumber); + [[nodiscard]] inline bool DeviceRequiresSecureRTTY(uint64_t serialNumber) const { + auto hashIndex = MACHash::Hash(serialNumber); std::lock_guard G(SerialNumbersMutex_[hashIndex]); auto Connection = SerialNumbers_[hashIndex].find(serialNumber); - if (Connection==end(SerialNumbers_[hashIndex]) || Connection->second.second==nullptr) + if (Connection==end(SerialNumbers_[hashIndex]) || Connection->second==nullptr) return false; - return Connection->second.second->RttyMustBeSecure_; + return Connection->second->RTTYMustBeSecure_; } inline bool GetStatistics(const std::string &SerialNumber, std::string &Statistics) const { return GetStatistics(Utils::SerialNumberToInt(SerialNumber), Statistics); } - bool GetStatistics(uint64_t SerialNumber, std::string &Statistics) const; + [[nodiscard]] bool GetStatistics(uint64_t SerialNumber, std::string &Statistics) const; inline bool GetState(const std::string &SerialNumber, GWObjects::ConnectionState &State) const { @@ -134,13 +138,7 @@ namespace OpenWifi { bool Connected(uint64_t SerialNumber, GWObjects::DeviceRestrictions &Restrictions) const; bool Connected(uint64_t SerialNumber) const; - - inline bool SendFrame(const std::string &SerialNumber, const std::string &Payload) const { - return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload); - } - bool SendFrame(uint64_t SerialNumber, const std::string &Payload) const; - bool SendRadiusAuthenticationData(const std::string &SerialNumber, const unsigned char *buffer, std::size_t size); bool SendRadiusAccountingData(const std::string &SerialNumber, const unsigned char *buffer, @@ -148,9 +146,8 @@ namespace OpenWifi { bool SendRadiusCoAData(const std::string &SerialNumber, const unsigned char *buffer, std::size_t size); - void SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber); - bool EndSession(uint64_t connection_id, uint64_t serial_number); - bool EndSessionUnSafe(uint64_t session_id, uint64_t serial_number); + void StartSession(uint64_t session_id, uint64_t SerialNumber); + bool EndSession(uint64_t session_id, uint64_t SerialNumber); void SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime, const std::vector &TelemetryTypes); @@ -167,7 +164,9 @@ namespace OpenWifi { uint64_t &TelemetryWebSocketPackets, uint64_t &TelemetryKafkaPackets); - void onGarbageCollecting(Poco::Timer &timer); + bool GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector & SerialNumbers); + bool ExtendedAttributes(const std::string &serialNumber, bool & hasGPS, std::uint64_t &Sanity, + std::double_t &MemoryUsed, std::double_t &Load, std::double_t &Temperature); inline void AverageDeviceStatistics(uint64_t &Connections, uint64_t &AverageConnectionTime, uint64_t &NumberOfConnectingDevices) const { @@ -176,94 +175,60 @@ namespace OpenWifi { NumberOfConnectingDevices = NumberOfConnectingDevices_; } + inline bool SendFrame(const std::string &SerialNumber, const std::string &Payload) const { + return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload); + } + inline void AddRX(std::uint64_t bytes) { - std::lock_guard G(StatsMutex_); RX_ += bytes; } inline void AddTX(std::uint64_t bytes) { - std::lock_guard G(StatsMutex_); TX_ += bytes; } inline void GetTotalDataStatistics(std::uint64_t &TX, std::uint64_t &RX) const { - std::lock_guard G(StatsMutex_); TX = TX_; RX = RX_; } - // TOD: move to hash based map. - inline bool GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector & SerialNumbers) { - std::lock_guard Lock(SessionMutex_); - for(const auto &connection:Sessions_) { - if( connection.second->RawLastHealthcheck_.Sanity>=lowLimit && - connection.second->RawLastHealthcheck_.Sanity<=highLimit) { - SerialNumbers.push_back(connection.second->SerialNumber_); - } - } - return true; - } - - inline bool ExtendedAttributes(const std::string &serialNumber, - bool & hasGPS, - std::uint64_t &Sanity, - std::double_t &MemoryUsed, - std::double_t &Load, - std::double_t &Temperature - ) { - - auto serialNumberInt = Utils::SerialNumberToInt(serialNumber); - auto hashIndex = Utils::CalculateMacAddressHash(serialNumberInt); - std::lock_guard G(SerialNumbersMutex_[hashIndex]); - auto session_hint = SerialNumbers_[hashIndex].find(Utils::SerialNumberToInt(serialNumber)); - if(session_hint==end(SerialNumbers_[hashIndex])) { - return false; - } - hasGPS = session_hint->second.second->hasGPS; - Sanity = session_hint->second.second->RawLastHealthcheck_.Sanity; - MemoryUsed = session_hint->second.second->memory_used_; - Load = session_hint->second.second->cpu_load_; - Temperature = session_hint->second.second->temperature_; - return true; - } + bool KafkaDisableState() const { return KafkaDisableState_; } + bool KafkaDisableHealthChecks() const { return KafkaDisableHealthChecks_; } private: - mutable std::mutex SessionMutex_; - mutable std::mutex StatsMutex_; + std::array SessionMutex_; + std::array>,SessionHashMax> Sessions_; + using SerialNumberMap = std::map>; + std::array SerialNumbers_; + mutable std::array SerialNumbersMutex_; + std::unique_ptr IssuerCert_; std::list> WebServers_; + Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 4, 256}; Poco::Net::SocketReactor Reactor_; Poco::Thread ReactorThread_; std::string SimulatorId_; - Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 2, 64}; bool LookAtProvisioning_ = false; bool UseDefaultConfig_ = true; bool SimulatorEnabled_ = false; + bool AllowSerialNumberMismatch_ = true; + std::unique_ptr Reactor_pool_; std::atomic_bool Running_ = false; - std::map> Sessions_; - - using SerialNumberMap = std::map>>; - - std::array SerialNumbers_; - mutable std::array SerialNumbersMutex_; - - std::atomic_bool AllowSerialNumberMismatch_ = true; - std::atomic_uint64_t MismatchDepth_ = 2; + std::uint64_t MismatchDepth_ = 2; std::uint64_t NumberOfConnectedDevices_ = 0; std::uint64_t AverageDeviceConnectionTime_ = 0; std::uint64_t NumberOfConnectingDevices_ = 0; std::uint64_t SessionTimeOut_ = 10*60; - + std::uint64_t LeftOverSessions_ = 0; std::atomic_uint64_t TX_=0,RX_=0; - std::vector> Garbage_; + std::atomic_bool KafkaDisableState_=false, + KafkaDisableHealthChecks_=false; - std::unique_ptr> GarbageCollectorCallback_; - Poco::Timer Timer_; - Poco::Thread GarbageCollector_; + Poco::Thread GarbageCollector_; AP_WS_Server() noexcept : SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {} diff --git a/src/CommandManager.cpp b/src/CommandManager.cpp index c9ee370a..82ccd332 100644 --- a/src/CommandManager.cpp +++ b/src/CommandManager.cpp @@ -45,11 +45,9 @@ namespace OpenWifi { std::lock_guard Lock(LocalMutex_); auto RPC = OutStandingRequests_.find(ID); if (RPC == OutStandingRequests_.end()) { - // std::cout << __LINE__ << std::endl; poco_debug(Logger(), fmt::format("({}): RPC {} cannot be found.", SerialNumberStr, ID)); } else if (RPC->second.SerialNumber != Resp->SerialNumber_) { - // std::cout << __LINE__ << std::endl; poco_debug( Logger(), fmt::format("({}): RPC {} serial number mismatch {}!={}.", @@ -60,7 +58,6 @@ namespace OpenWifi { std::chrono::duration rpc_execution_time = std::chrono::high_resolution_clock::now() - RPC->second.submitted; - // std::cout << __LINE__ << std::endl; poco_debug(Logger(), fmt::format("({}): Received RPC answer {}. Command={}", SerialNumberStr, ID, @@ -140,7 +137,6 @@ namespace OpenWifi { } } } else { - // std::cout << __LINE__ << std::endl; } Command.State = 0; @@ -163,7 +159,6 @@ namespace OpenWifi { if (Command.rpc_entry) { TmpRpcEntry = Command.rpc_entry; } - // std::cout << __LINE__ << " State=" << Command.State << std::endl; if (Command.State == 2) { // look at the payload to see if we should continue or not... if (Payload->has("result")) { @@ -173,12 +168,10 @@ namespace OpenWifi { std::uint64_t Error = Status->get("error"); if (Error == 0) { - // std::cout << __LINE__ << std::endl; StorageService()->CommandCompleted(Command.UUID, Payload, rpc_execution_time, true); Command.State = 1; } else { - // std::cout << __LINE__ << std::endl; StorageService()->CommandCompleted(Command.UUID, Payload, rpc_execution_time, true); std::string ErrorTxt = Status->get("result"); @@ -186,14 +179,11 @@ namespace OpenWifi { Command.State = 0; } } else { - // std::cout << __LINE__ << std::endl; } } else { - // std::cout << __LINE__ << std::endl; Command.State = 0; } } else if (Command.State == 1) { - // std::cout << "Completing script 2 phase commit." << std::endl; StorageService()->CommandCompleted(Command.UUID, Payload, rpc_execution_time, true); if (Command.Deferred) { Reply = false; @@ -202,7 +192,6 @@ namespace OpenWifi { } if (Command.State == 0) { - // std::cout << __LINE__ << " State=" << Command.State << std::endl; OutStandingRequests_.erase(Command.Id); } if (Reply && TmpRpcEntry != nullptr) @@ -262,8 +251,6 @@ namespace OpenWifi { for (auto request = OutStandingRequests_.begin(); request != OutStandingRequests_.end();) { std::chrono::duration delta = now - request->second.submitted; if (delta > 10min) { - // std::cout << __LINE__ << " -->> " << request->second.Id << - // std::endl; MyLogger.debug(fmt::format("{}: Command={} for {} Timed out.", request->second.UUID, APCommands::to_string(request->second.Command), Utils::IntToSerialNumber(request->second.SerialNumber))); @@ -275,8 +262,6 @@ namespace OpenWifi { StorageService()->SetCommandTimedOut(request->second.UUID); request = OutStandingRequests_.erase(request); } else { - // std::cout << __LINE__ << " -->> " << request->second.Id << - // std::endl; ++request; } } diff --git a/src/Dashboard.cpp b/src/Dashboard.cpp index 43cff93e..ff76b41f 100644 --- a/src/Dashboard.cpp +++ b/src/Dashboard.cpp @@ -21,7 +21,6 @@ namespace OpenWifi { void DeviceDashboard::Generate(GWObjects::Dashboard &D, Poco::Logger &Logger) { if (GeneratingDashboard_.load()) { - // std::cout << "Trying to generate dashboard but already being generated" << std::endl; while (GeneratingDashboard_.load()) { Poco::Thread::trySleep(100); } @@ -31,7 +30,6 @@ namespace OpenWifi { GeneratingDashboard_ = true; ValidDashboard_ = false; try { - // std::cout << "Generating dashboard." << std::endl; poco_information(Logger, "DASHBOARD: Generating a new dashboard."); GWObjects::Dashboard NewData; StorageService()->AnalyzeCommands(NewData.commands); diff --git a/src/ParseWifiScan.h b/src/ParseWifiScan.h index 67df6e78..f27a009e 100644 --- a/src/ParseWifiScan.h +++ b/src/ParseWifiScan.h @@ -1753,7 +1753,6 @@ namespace OpenWifi { nlohmann::json new_ie; nlohmann::json content; - // std::cout << BufferToHex(&data[0],data.size()) << std::endl; uint offset = 0; auto sub_ie = data[offset++]; switch (sub_ie) { @@ -1788,7 +1787,6 @@ namespace OpenWifi { try { nlohmann::json D = nlohmann::json::parse(ofs.str()); - // std::cout << "Start of parsing wifi" << std::endl; if (D.contains("status")) { auto Status = D["status"]; if (Status.contains("scan") && Status["scan"].is_array()) { @@ -1803,8 +1801,6 @@ namespace OpenWifi { if (ie.contains("type") && ie.contains("data")) { uint64_t ie_type = ie["type"]; std::string ie_data = ie["data"]; - // std::cout << "TYPE:" << ie_type << " DATA:" << ie_data - // << std::endl; auto data = Base64Decode2Vec(ie_data); if (ie_type == ieee80211_eid::WLAN_EID_COUNTRY) { new_ies.push_back(WFS_WLAN_EID_COUNTRY(data)); @@ -1858,18 +1854,12 @@ namespace OpenWifi { } else if (ie_type == ieee80211_eid::WLAN_EID_EXTENSION) { new_ies.push_back(WFS_WLAN_EID_EXTENSION(data)); } else { - // std::cout - // << "Skipping IE: no parsing available: " << ie_type - // << std::endl; new_ies.push_back(ie); } } else { - // std::cout << "Skipping IE: no data and type" << - // std::endl; new_ies.push_back(ie); } } catch (...) { - // std::cout << "Skipping IE: exception" << std::endl; Logger.information(fmt::format("Error parsing IEs")); new_ies.push_back(ie); } @@ -1877,7 +1867,6 @@ namespace OpenWifi { scan_entry["ies"] = new_ies; ParsedScan.push_back(scan_entry); } else { - // std::cout << "Skipping scan" << std::endl; ParsedScan.push_back(scan_entry); } } @@ -1886,7 +1875,6 @@ namespace OpenWifi { } } Result << to_string(D); - // std::cout << "End of parsing wifi" << std::endl; return true; } catch (const Poco::Exception &E) { Logger.log(E); diff --git a/src/RADIUSSessionTracker.cpp b/src/RADIUSSessionTracker.cpp index e7020874..7442126b 100644 --- a/src/RADIUSSessionTracker.cpp +++ b/src/RADIUSSessionTracker.cpp @@ -177,15 +177,6 @@ namespace OpenWifi { } else { session_hint->second->lastTransaction = Utils::Now(); } - -/* - if(ap_hint!=AccountingSessions_.end()) { - std::cout << "Auth table:" << std::endl; - for(const auto &session:ap_hint->second) { - std::cout << Notification.SerialNumber_ << ": Index: " << session.first << ": ID: " << session.second->accountingSessionId << " MID:" << session.second->accountingMultiSessionId << std::endl; - } - } -*/ } std::uint32_t GetUiInt32(const std::uint8_t *buf) { @@ -423,15 +414,15 @@ namespace OpenWifi { } void RADIUSSessionTracker::DisconnectSession(const std::string &SerialNumber) { - poco_information(Logger(),fmt::format("{}: Disconnecting.", SerialNumber)); std::lock_guard Guard(Mutex_); - auto hint = AccountingSessions_.find(SerialNumber); if(hint==end(AccountingSessions_)) { return; } + poco_information(Logger(),fmt::format("{}: Disconnecting.", SerialNumber)); + // we need to go through all sessions and send an accounting stop for(const auto &session:hint->second) { poco_debug(Logger(), fmt::format("Stopping accounting for {}:{}", SerialNumber, session.first )); diff --git a/src/RESTAPI/RESTAPI_blacklist.cpp b/src/RESTAPI/RESTAPI_blacklist.cpp index 42259b88..b4c96c58 100644 --- a/src/RESTAPI/RESTAPI_blacklist.cpp +++ b/src/RESTAPI/RESTAPI_blacklist.cpp @@ -63,7 +63,7 @@ namespace OpenWifi { poco_debug(Logger(), fmt::format("BLACKLIST-POST: {}", D.serialNumber)); Poco::toLowerInPlace(D.serialNumber); - if (StorageService()->IsBlackListed(D.serialNumber)) { + if (StorageService()->IsBlackListed(Utils::MACToInt(D.serialNumber))) { return BadRequest(RESTAPI::Errors::SerialNumberExists); } diff --git a/src/RESTAPI/RESTAPI_device_commandHandler.cpp b/src/RESTAPI/RESTAPI_device_commandHandler.cpp index bc23d40c..84ce8f31 100644 --- a/src/RESTAPI/RESTAPI_device_commandHandler.cpp +++ b/src/RESTAPI/RESTAPI_device_commandHandler.cpp @@ -87,7 +87,7 @@ namespace OpenWifi { poco_debug( Logger_, fmt::format( - "Command rtty TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}", + "Command RTTY TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}", TransactionId_, UUID, RPC, Poco::Thread::current()->id())); return Rtty(UUID, RPC, 60000ms, Restrictions); }; @@ -1169,7 +1169,7 @@ namespace OpenWifi { if (RTTYS_server()->UseInternal()) { std::uint64_t SN = Utils::SerialNumberToInt(SerialNumber_); - bool mTLS = AP_WS_Server()->DeviceRequiresSecureRtty(SN); + bool mTLS = AP_WS_Server()->DeviceRequiresSecureRTTY(SN); auto Hash = Utils::ComputeHash(UserInfo_.webtoken.refresh_token_, Utils::Now()); Rtty.Token = Hash.substr(0, RTTY_DEVICE_TOKEN_LENGTH); if (!RTTYS_server()->CreateEndPoint(Rtty.ConnectionId, Rtty.Token, Requester(), diff --git a/src/RESTAPI/RESTAPI_devices_handler.cpp b/src/RESTAPI/RESTAPI_devices_handler.cpp index 7d67f990..beef733e 100644 --- a/src/RESTAPI/RESTAPI_devices_handler.cpp +++ b/src/RESTAPI/RESTAPI_devices_handler.cpp @@ -175,10 +175,12 @@ namespace OpenWifi { } if(GetBoolParameter("simulatedDevices",false)) { - if(StorageService()->DeleteSimulatedDevice("")) { - return OK(); - } - return NotFound(); + auto F = []() ->void { + StorageService()->DeleteSimulatedDevice(""); + }; + std::thread T(F); + T.detach(); + return OK(); } if(!QB_.Select.empty() && !Utils::ValidSerialNumbers(QB_.Select)) { diff --git a/src/StorageService.h b/src/StorageService.h index a20a9f26..cd03df24 100644 --- a/src/StorageService.h +++ b/src/StorageService.h @@ -16,6 +16,22 @@ namespace OpenWifi { + class LockedDbSession { + public: + explicit LockedDbSession(); + ~LockedDbSession() = default; + inline std::mutex &Mutex() { return *Mutex_; }; + inline Poco::Data::Session &Session() { + if(!Session_->isConnected()) { + Session_->reconnect(); + } + return *Session_; + }; + private: + std::shared_ptr Session_; + std::shared_ptr Mutex_; + }; + class Storage : public StorageClass { public: @@ -90,7 +106,8 @@ namespace OpenWifi { // typedef std::map DeviceCapabilitiesCache; - bool AddLog(const GWObjects::DeviceLog &Log); + bool AddLog(LockedDbSession &Session, const GWObjects::DeviceLog &Log); + bool AddStatisticsData(Poco::Data::Session &Session, const GWObjects::Statistics &Stats); bool AddStatisticsData(const GWObjects::Statistics &Stats); bool GetStatisticsData(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate, uint64_t Offset, uint64_t HowMany, @@ -102,6 +119,7 @@ namespace OpenWifi { std::vector &Stats); bool AddHealthCheckData(const GWObjects::HealthCheck &Check); + bool AddHealthCheckData(LockedDbSession &Session, const GWObjects::HealthCheck &Check); bool GetHealthCheckData(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate, uint64_t Offset, uint64_t HowMany, std::vector &Checks); @@ -115,13 +133,18 @@ namespace OpenWifi { uint64_t &NewUUID); bool RollbackDeviceConfigurationChange(std::string & SerialNumber); + bool CompleteDeviceConfigurationChange(Poco::Data::Session &Session, std::string & SerialNumber); bool CompleteDeviceConfigurationChange(std::string & SerialNumber); - + bool CreateDevice(LockedDbSession &Session, GWObjects::Device &); bool CreateDevice(GWObjects::Device &); - bool CreateDefaultDevice(std::string &SerialNumber, const Config::Capabilities &Caps, + bool CreateDefaultDevice(Poco::Data::Session &Session,std::string &SerialNumber, + const Config::Capabilities &Caps, std::string &Firmware, const Poco::Net::IPAddress &IPAddress, bool simulated); + bool CreateDevice(Poco::Data::Session &Sess, GWObjects::Device &DeviceDetails); + bool GetDevice(LockedDbSession &Session, std::string &SerialNumber, GWObjects::Device &); + bool GetDevice(Poco::Data::Session &Session, std::string &SerialNumber, GWObjects::Device &DeviceDetails); bool GetDevice(std::string &SerialNumber, GWObjects::Device &); bool GetDevices(uint64_t From, uint64_t HowMany, std::vector &Devices, const std::string &orderBy = ""); @@ -132,6 +155,8 @@ namespace OpenWifi { bool DeleteDevices(std::uint64_t OlderContact, bool SimulatedOnly); bool UpdateDevice(GWObjects::Device &); + bool UpdateDevice(LockedDbSession &Session, GWObjects::Device &); + bool UpdateDevice(Poco::Data::Session &Sess, GWObjects::Device &NewDeviceDetails); bool DeviceExists(std::string &SerialNumber); bool SetConnectInfo(std::string &SerialNumber, std::string &Firmware); bool GetDeviceCount(uint64_t &Count); @@ -139,7 +164,7 @@ namespace OpenWifi { std::vector &SerialNumbers, const std::string &orderBy = ""); bool GetDeviceFWUpdatePolicy(std::string &SerialNumber, std::string &Policy); - bool SetDevicePassword(std::string &SerialNumber, std::string &Password); + bool SetDevicePassword(LockedDbSession &Session, std::string &SerialNumber, std::string &Password); bool UpdateSerialNumberCache(); static void GetDeviceDbFieldList(Types::StringVec &Fields); @@ -148,9 +173,11 @@ namespace OpenWifi { bool UpdateDeviceCapabilities(std::string &SerialNumber, const Config::Capabilities &Capabilities); + bool UpdateDeviceCapabilities(Poco::Data::Session &Session, std::string &SerialNumber, + const Config::Capabilities &Capabilities); bool GetDeviceCapabilities(std::string &SerialNumber, GWObjects::Capabilities &); bool DeleteDeviceCapabilities(std::string &SerialNumber); - bool CreateDeviceCapabilities(std::string &SerialNumber, + bool CreateDeviceCapabilities(Poco::Data::Session &Session, std::string &SerialNumber, const Config::Capabilities &Capabilities); bool InitCapabilitiesCache(); @@ -222,15 +249,15 @@ namespace OpenWifi { void RemovedExpiredCommands(); void RemoveTimedOutCommands(); - bool RemoveOldCommands(std::string &SerilNumber, std::string &Command); + bool RemoveOldCommands(std::string &SerialNumber, std::string &Command); bool AddBlackListDevices(std::vector &Devices); bool AddBlackListDevice(GWObjects::BlackListedDevice &Device); bool GetBlackListDevice(std::string &SerialNumber, GWObjects::BlackListedDevice &Device); bool DeleteBlackListDevice(std::string &SerialNumber); - bool IsBlackListed(const std::string &SerialNumber, std::string &reason, + bool IsBlackListed(std::uint64_t SerialNumber, std::string &reason, std::string &author, std::uint64_t &created); - bool IsBlackListed(const std::string &SerialNumber); + bool IsBlackListed(std::uint64_t SerialNumber); bool InitializeBlackListCache(); bool GetBlackListDevices(uint64_t Offset, uint64_t HowMany, std::vector &Devices); @@ -245,7 +272,9 @@ namespace OpenWifi { bool RemoveCommandListRecordsOlderThan(uint64_t Date); bool RemoveUploadedFilesRecordsOlderThan(uint64_t Date); - bool SetDeviceLastRecordedContact(std::string & SeialNumber, std::uint64_t lastRecordedContact); + bool SetDeviceLastRecordedContact(LockedDbSession &Session, std::string & SerialNumber, std::uint64_t lastRecordedContact); + bool SetDeviceLastRecordedContact(std::string & SerialNumber, std::uint64_t lastRecordedContact); + bool SetDeviceLastRecordedContact(Poco::Data::Session & Session, std::string & SerialNumber, std::uint64_t lastRecordedContact); int Create_Tables(); int Create_Statistics(); @@ -265,10 +294,19 @@ namespace OpenWifi { int Start() override; void Stop() override; + inline Poco::Data::Session StartSession() { + return Pool_->get(); + } + private: std::unique_ptr ScriptDB_; }; inline auto StorageService() { return Storage::instance(); } + inline LockedDbSession::LockedDbSession() { + Session_ = std::make_shared(Poco::Data::Session(StorageService()->StartSession())); + Mutex_ = std::make_shared(); + } + } // namespace OpenWifi diff --git a/src/TelemetryStream.h b/src/TelemetryStream.h index e4fbbdcb..d9364e9f 100644 --- a/src/TelemetryStream.h +++ b/src/TelemetryStream.h @@ -23,7 +23,7 @@ #include "framework/SubSystemServer.h" -#include "AP_WS_ReactorPool.h" +#include "AP_WS_Reactor_Pool.h" #include "TelemetryClient.h" namespace OpenWifi { diff --git a/src/framework/EventBusManager.cpp b/src/framework/EventBusManager.cpp index ca28ad94..66774f1e 100644 --- a/src/framework/EventBusManager.cpp +++ b/src/framework/EventBusManager.cpp @@ -9,8 +9,6 @@ namespace OpenWifi { - EventBusManager::EventBusManager(Poco::Logger &L) : Logger_(L) {} - void EventBusManager::run() { Running_ = true; Utils::SetThreadName("fmwk:EventMgr"); diff --git a/src/framework/EventBusManager.h b/src/framework/EventBusManager.h index 9a7316e9..fe8a82cb 100644 --- a/src/framework/EventBusManager.h +++ b/src/framework/EventBusManager.h @@ -12,6 +12,16 @@ namespace OpenWifi { class EventBusManager : public Poco::Runnable { public: + EventBusManager() : + Logger_(Poco::Logger::create( + "EventBusManager", Poco::Logger::root().getChannel(), Poco::Logger::root().getLevel())) { + } + + static auto instance() { + static auto instance_ = new EventBusManager; + return instance_; + } + explicit EventBusManager(Poco::Logger &L); void run() final; void Start(); @@ -24,4 +34,6 @@ namespace OpenWifi { Poco::Logger &Logger_; }; + inline auto EventBusManager() { return EventBusManager::instance(); } + } // namespace OpenWifi diff --git a/src/framework/MicroService.cpp b/src/framework/MicroService.cpp index 5d517d9f..13f89fbf 100644 --- a/src/framework/MicroService.cpp +++ b/src/framework/MicroService.cpp @@ -33,9 +33,23 @@ namespace OpenWifi { void MicroService::Exit(int Reason) { std::exit(Reason); } + static std::string MakeServiceListString(const Types::MicroServiceMetaMap &Services) { + std::string SvcList; + for (const auto &Svc : Services) { + if (SvcList.empty()) + SvcList = Svc.second.Type; + else + SvcList += ", " + Svc.second.Type; + } + return SvcList; + } + void MicroService::BusMessageReceived([[maybe_unused]] const std::string &Key, const std::string &Payload) { std::lock_guard G(InfraMutex_); + + Poco::Logger &BusLogger = EventBusManager()->Logger(); + try { Poco::JSON::Parser P; auto Object = P.parse(Payload).extract(); @@ -55,13 +69,10 @@ namespace OpenWifi { Object->has(KafkaTopics::ServiceEvents::Fields::KEY)) { auto PrivateEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(); - if (Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE && - Services_.find(PrivateEndPoint) != Services_.end()) { - Services_[PrivateEndPoint].LastUpdate = Utils::Now(); - } else if (Event == KafkaTopics::ServiceEvents::EVENT_LEAVE) { + if (Event == KafkaTopics::ServiceEvents::EVENT_LEAVE) { Services_.erase(PrivateEndPoint); - poco_debug( - logger(), + poco_information( + BusLogger, fmt::format( "Service {} ID={} leaving system.", Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE) @@ -69,14 +80,7 @@ namespace OpenWifi { ID)); } else if (Event == KafkaTopics::ServiceEvents::EVENT_JOIN || Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE) { - poco_debug( - logger(), - fmt::format( - "Service {} ID={} joining system.", - Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE) - .toString(), - ID)); - Services_[PrivateEndPoint] = Types::MicroServiceMeta{ + auto ServiceInfo = Types::MicroServiceMeta{ .Id = ID, .Type = Poco::toLower( Object->get(KafkaTopics::ServiceEvents::Fields::TYPE) @@ -94,20 +98,46 @@ namespace OpenWifi { .toString(), .LastUpdate = Utils::Now()}; - std::string SvcList; - for (const auto &Svc : Services_) { - if (SvcList.empty()) - SvcList = Svc.second.Type; - else - SvcList += ", " + Svc.second.Type; + auto s1 = MakeServiceListString(Services_); + auto PreviousSize = Services_.size(); + Services_[PrivateEndPoint] = ServiceInfo; + auto CurrentSize = Services_.size(); + if(Event == KafkaTopics::ServiceEvents::EVENT_JOIN) { + if(!s1.empty()) { + poco_information( + BusLogger, + fmt::format( + "Service {} ID={} is joining the system.", + Object + ->get( + KafkaTopics::ServiceEvents::Fields::PRIVATE) + .toString(), + ID)); + } + std::string SvcList; + for (const auto &Svc : Services_) { + if (SvcList.empty()) + SvcList = Svc.second.Type; + else + SvcList += ", " + Svc.second.Type; + } + poco_information( + BusLogger, + fmt::format("Current list of microservices: {}", SvcList)); + } else if(CurrentSize!=PreviousSize) { + poco_information( + BusLogger, + fmt::format( + "Service {} ID={} is being added back in.", + Object + ->get(KafkaTopics::ServiceEvents::Fields::PRIVATE) + .toString(), + ID)); } - poco_information( - logger(), - fmt::format("Current list of microservices: {}", SvcList)); } } else { - poco_error( - logger(), + poco_information( + BusLogger, fmt::format("KAFKA-MSG: invalid event '{}', missing a field.", Event)); } @@ -118,32 +148,39 @@ namespace OpenWifi { Object->get(KafkaTopics::ServiceEvents::Fields::TOKEN).toString()); #endif } else { - poco_error( - logger(), + poco_information( + BusLogger, fmt::format("KAFKA-MSG: invalid event '{}', missing token", Event)); } } else { - poco_error(logger(), + poco_information(BusLogger, fmt::format("Unknown Event: {} Source: {}", Event, ID)); } } } else { - poco_error(logger(), "Bad bus message."); - std::ostringstream os; - Object->stringify(std::cout); + std::ostringstream os; + Object->stringify(std::cout); + poco_error(BusLogger, fmt::format("Bad bus message: {}", os.str())); } - auto i = Services_.begin(); + auto ServiceHint = Services_.begin(); auto now = Utils::Now(); - for (; i != Services_.end();) { - if ((now - i->second.LastUpdate) > 60) { - i = Services_.erase(i); + auto si1 = Services_.size(); + auto ss1 = MakeServiceListString(Services_); + while(ServiceHint!=Services_.end()) { + if ((now - ServiceHint->second.LastUpdate) > 120) { + poco_information(BusLogger, fmt::format("ZombieService: Removing service {}, ", ServiceHint->second.PublicEndPoint)); + ServiceHint = Services_.erase(ServiceHint); } else - ++i; + ++ServiceHint; } + if(Services_.size() != si1) { + auto ss2 = MakeServiceListString(Services_); + poco_information(BusLogger, fmt::format("Current list of microservices: {} -> {}", ss1, ss2)); + } } catch (const Poco::Exception &E) { - logger().log(E); + BusLogger.log(E); } } @@ -412,7 +449,7 @@ namespace OpenWifi { try { DataDir.createDirectory(); } catch (const Poco::Exception &E) { - logger().log(E); + Logger_.log(E); } } WWWAssetsDir_ = ConfigPath("openwifi.restapi.wwwassets", ""); @@ -530,14 +567,12 @@ namespace OpenWifi { for (auto i : SubSystems_) { i->Start(); } - EventBusManager_ = std::make_unique(Poco::Logger::create( - "EventBusManager", Poco::Logger::root().getChannel(), Poco::Logger::root().getLevel())); - EventBusManager_->Start(); + EventBusManager()->Start(); } void MicroService::StopSubSystemServers() { AddActivity("Stopping"); - EventBusManager_->Stop(); + EventBusManager()->Stop(); for (auto i = SubSystems_.rbegin(); i != SubSystems_.rend(); ++i) { (*i)->Stop(); } @@ -697,7 +732,7 @@ namespace OpenWifi { auto APIKEY = Request.get("X-API-KEY"); return APIKEY == MyHash_; } catch (const Poco::Exception &E) { - logger().log(E); + Logger_.log(E); } return false; } diff --git a/src/framework/MicroService.h b/src/framework/MicroService.h index 00532b47..7290bbbb 100644 --- a/src/framework/MicroService.h +++ b/src/framework/MicroService.h @@ -201,7 +201,6 @@ namespace OpenWifi { Poco::JWT::Signer Signer_; Poco::Logger &Logger_; Poco::ThreadPool TimerPool_{"timer:pool", 2, 32}; - std::unique_ptr EventBusManager_; }; inline MicroService *MicroService::instance_ = nullptr; diff --git a/src/framework/StorageClass.h b/src/framework/StorageClass.h index cfb55304..36751bc6 100644 --- a/src/framework/StorageClass.h +++ b/src/framework/StorageClass.h @@ -47,6 +47,8 @@ namespace OpenWifi { } + Poco::Data::SessionPool &Pool() { return *Pool_; } + private: inline int Setup_SQLite(); inline int Setup_MySQL(); diff --git a/src/framework/orm.h b/src/framework/orm.h index 9e83540f..c0be1373 100644 --- a/src/framework/orm.h +++ b/src/framework/orm.h @@ -576,8 +576,8 @@ namespace ORM { bool UpdateRecord(field_name_t FieldName, const T &Value, const RecordType &R) { try { assert(ValidFieldName(FieldName)); - Poco::Data::Session Session = Pool_.get(); + Session.begin(); Poco::Data::Statement Update(Session); RecordTuple RT; @@ -593,6 +593,7 @@ namespace ORM { Update.execute(); if (Cache_) Cache_->UpdateCache(R); + Session.commit(); return true; } catch (const Poco::Exception &E) { Logger_.log(E); @@ -662,6 +663,7 @@ namespace ORM { assert(ValidFieldName(FieldName)); Poco::Data::Session Session = Pool_.get(); + Session.begin(); Poco::Data::Statement Delete(Session); std::string St = "delete from " + TableName_ + " where " + FieldName + "=?"; @@ -671,6 +673,7 @@ namespace ORM { Delete.execute(); if (Cache_) Cache_->Delete(FieldName, Value); + Session.commit(); return true; } catch (const Poco::Exception &E) { Logger_.log(E); @@ -682,11 +685,13 @@ namespace ORM { try { assert(!WhereClause.empty()); Poco::Data::Session Session = Pool_.get(); + Session.begin(); Poco::Data::Statement Delete(Session); std::string St = "delete from " + TableName_ + " where " + WhereClause; Delete << St; Delete.execute(); + Session.commit(); return true; } catch (const Poco::Exception &E) { Logger_.log(E); diff --git a/src/framework/utils.h b/src/framework/utils.h index d5357de7..b20d32af 100644 --- a/src/framework/utils.h +++ b/src/framework/utils.h @@ -126,20 +126,6 @@ namespace OpenWifi::Utils { [[nodiscard]] std::uint64_t ConvertDate(const std::string &d); - [[nodiscard]] inline uint8_t CalculateMacAddressHash(std::uint64_t value) { - uint8_t hash = 0, i=6; - while(i) { - hash ^= (value & 0xFF) + 1; - value >>= 8; - --i; - } - return hash; - } - - [[nodiscard]] inline uint8_t CalculateMacAddressHash(const std::string & value) { - return CalculateMacAddressHash(MACToInt(value)); - } - template std::string int_to_hex(T i) { std::stringstream stream; stream << std::setfill('0') << std::setw(12) << std::hex << i; @@ -330,5 +316,90 @@ namespace OpenWifi::Utils { uint32_t Port; }; + class CompressedString { + public: + CompressedString() { + DecompressedSize_ = 0; + }; + + explicit CompressedString(const std::string &Data) : DecompressedSize_(Data.size()) { + CompressIt(Data); + } + + CompressedString(const CompressedString &Data) { + this->DecompressedSize_ = Data.DecompressedSize_; + this->CompressedData_ = Data.CompressedData_; + } + + CompressedString& operator=(const CompressedString& rhs) { + if (this != &rhs) { + this->DecompressedSize_ = rhs.DecompressedSize_; + this->CompressedData_ = rhs.CompressedData_; + } + return *this; + } + + CompressedString& operator=(CompressedString&& rhs) { + if (this != &rhs) { + this->DecompressedSize_ = rhs.DecompressedSize_; + this->CompressedData_ = rhs.CompressedData_; + } + return *this; + } + + ~CompressedString() = default; + + operator std::string() const { + return DecompressIt(); + } + + CompressedString &operator=(const std::string &Data) { + DecompressedSize_ = Data.size(); + CompressIt(Data); + return *this; + } + + auto CompressedSize() const { return CompressedData_.size(); } + auto DecompressedSize() const { return DecompressedSize_; } + + private: + std::string CompressedData_; + std::size_t DecompressedSize_; + + inline void CompressIt(const std::string &Data) { + z_stream strm; // = {0}; + CompressedData_.resize(Data.size()); + strm.next_in = (Bytef *)Data.data(); + strm.avail_in = Data.size(); + strm.next_out = (Bytef *)CompressedData_.data(); + strm.avail_out = Data.size(); + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); + deflate(&strm, Z_FINISH); + deflateEnd(&strm); + CompressedData_.resize(strm.total_out); + } + + [[nodiscard]] std::string DecompressIt() const { + std::string Result; + if(DecompressedSize_!=0) { + Result.resize(DecompressedSize_); + z_stream strm ; //= {0}; + strm.next_in = (Bytef *)CompressedData_.data(); + strm.avail_in = CompressedData_.size(); + strm.next_out = (Bytef *)Result.data(); + strm.avail_out = Result.size(); + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + inflateInit2(&strm, 15 + 32); + inflate(&strm, Z_FINISH); + inflateEnd(&strm); + } + return Result; + } + }; } // namespace OpenWifi::Utils diff --git a/src/rttys/RTTYS_server.cpp b/src/rttys/RTTYS_server.cpp index a84d05a6..e71d34b0 100644 --- a/src/rttys/RTTYS_server.cpp +++ b/src/rttys/RTTYS_server.cpp @@ -146,7 +146,7 @@ namespace OpenWifi { auto WebClientSecureContext = new Poco::Net::Context(Poco::Net::Context::SERVER_USE, KeyFileName, - CertFileName, "", Poco::Net::Context::VERIFY_RELAXED); + CertFileName, "", Poco::Net::Context::VERIFY_NONE); Poco::Crypto::X509Certificate WebRoot(RootCaFileName); WebClientSecureContext->addCertificateAuthority(WebRoot); WebClientSecureContext->disableStatelessSessionResumption(); diff --git a/src/storage/storage_blacklist.cpp b/src/storage/storage_blacklist.cpp index e7b2242d..00662415 100644 --- a/src/storage/storage_blacklist.cpp +++ b/src/storage/storage_blacklist.cpp @@ -56,10 +56,10 @@ namespace OpenWifi { struct DeviceDetails { std::string reason; std::string author; - std::uint64_t created; + std::uint64_t created=Utils::Now(); }; - static std::map BlackListDevices; + static std::map BlackListDevices; static std::recursive_mutex BlackListMutex; bool Storage::InitializeBlackListCache() { @@ -78,7 +78,7 @@ namespace OpenWifi { auto Reason = RSet[1].convert(); auto Author = RSet[2].convert(); auto Created = RSet[3].convert(); - BlackListDevices[SerialNumber] = + BlackListDevices[Utils::MACToInt(SerialNumber)] = DeviceDetails{.reason = Reason, .author = Author, .created = Created}; More = RSet.moveNext(); } @@ -93,6 +93,7 @@ namespace OpenWifi { bool Storage::AddBlackListDevice(GWObjects::BlackListedDevice &Device) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Insert(Sess); std::string St{"INSERT INTO BlackList (" + DB_BlackListDeviceSelectFields + ") " + @@ -102,9 +103,9 @@ namespace OpenWifi { ConvertBlackListDeviceRecord(Device, T); Insert << ConvertParams(St), Poco::Data::Keywords::use(T); Insert.execute(); - + Sess.commit(); std::lock_guard G(BlackListMutex); - BlackListDevices[Device.serialNumber] = DeviceDetails{ + BlackListDevices[Utils::MACToInt(Device.serialNumber)] = DeviceDetails{ .reason = Device.reason, .author = Device.author, .created = Device.created}; return true; } catch (const Poco::Exception &E) { @@ -130,6 +131,7 @@ namespace OpenWifi { bool Storage::DeleteBlackListDevice(std::string &SerialNumber) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Delete(Sess); std::string St{"DELETE FROM BlackList WHERE SerialNumber=?"}; @@ -137,9 +139,9 @@ namespace OpenWifi { Poco::toLowerInPlace(SerialNumber); Delete << ConvertParams(St), Poco::Data::Keywords::use(SerialNumber); Delete.execute(); - + Sess.commit(); std::lock_guard G(BlackListMutex); - BlackListDevices.erase(SerialNumber); + BlackListDevices.erase(Utils::MACToInt(SerialNumber)); return true; } catch (const Poco::Exception &E) { poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), @@ -177,6 +179,7 @@ namespace OpenWifi { GWObjects::BlackListedDevice &Device) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Update(Sess); std::string St{"UPDATE BlackList SET " + DB_BlackListDeviceUpdateFields + @@ -187,9 +190,9 @@ namespace OpenWifi { Update << ConvertParams(St), Poco::Data::Keywords::use(T), Poco::Data::Keywords::use(SerialNumber); Update.execute(); - + Sess.commit(); std::lock_guard G(BlackListMutex); - BlackListDevices[Device.serialNumber] = DeviceDetails{ + BlackListDevices[Utils::MACToInt(Device.serialNumber)] = DeviceDetails{ .reason = Device.reason, .author = Device.author, .created = Device.created}; return true; @@ -233,10 +236,10 @@ namespace OpenWifi { return BlackListDevices.size(); } - bool Storage::IsBlackListed(const std::string &SerialNumber, std::string &reason, + bool Storage::IsBlackListed(std::uint64_t SerialNumber, std::string &reason, std::string &author, std::uint64_t &created) { std::lock_guard G(BlackListMutex); - auto DeviceHint = BlackListDevices.find(Poco::toLower(SerialNumber)); + auto DeviceHint = BlackListDevices.find(SerialNumber); if (DeviceHint == end(BlackListDevices)) return false; reason = DeviceHint->second.reason; @@ -245,9 +248,9 @@ namespace OpenWifi { return true; } - bool Storage::IsBlackListed(const std::string &SerialNumber) { + bool Storage::IsBlackListed(std::uint64_t SerialNumber) { std::lock_guard G(BlackListMutex); - auto DeviceHint = BlackListDevices.find(Poco::toLower(SerialNumber)); + auto DeviceHint = BlackListDevices.find(SerialNumber); return DeviceHint != end(BlackListDevices); } } // namespace OpenWifi \ No newline at end of file diff --git a/src/storage/storage_capabilities.cpp b/src/storage/storage_capabilities.cpp index 72d054e4..6ae96330 100644 --- a/src/storage/storage_capabilities.cpp +++ b/src/storage/storage_capabilities.cpp @@ -17,11 +17,11 @@ namespace OpenWifi { - bool Storage::CreateDeviceCapabilities(std::string &SerialNumber, + bool Storage::CreateDeviceCapabilities(Poco::Data::Session &Session, std::string &SerialNumber, const Config::Capabilities &Capabilities) { try { - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement UpSert(Sess); + Session.begin(); + Poco::Data::Statement UpSert(Session); std::string TCaps{Capabilities.AsString()}; uint64_t Now = Utils::Now(); @@ -33,6 +33,7 @@ namespace OpenWifi { Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(TCaps), Poco::Data::Keywords::use(Now); UpSert.execute(); + Session.commit(); return true; } catch (const Poco::Exception &E) { poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), @@ -41,11 +42,11 @@ namespace OpenWifi { return false; } - bool Storage::UpdateDeviceCapabilities(std::string &SerialNumber, + bool Storage::UpdateDeviceCapabilities(Poco::Data::Session &Session, std::string &SerialNumber, const Config::Capabilities &Caps) { try { - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement UpSert(Sess); + Session.begin(); + Poco::Data::Statement UpSert(Session); uint64_t Now = Utils::Now(); if (!Caps.Compatible().empty() && !Caps.Platform().empty()) @@ -61,6 +62,7 @@ namespace OpenWifi { Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(TCaps), Poco::Data::Keywords::use(Now); UpSert.execute(); + Session.commit(); return true; } catch (const Poco::Exception &E) { poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), @@ -99,13 +101,14 @@ namespace OpenWifi { bool Storage::DeleteDeviceCapabilities(std::string &SerialNumber) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Delete(Sess); std::string St{"DELETE FROM Capabilities WHERE SerialNumber=?"}; Delete << ConvertParams(St), Poco::Data::Keywords::use(SerialNumber); Delete.execute(); - + Sess.commit(); return true; } catch (const Poco::Exception &E) { poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), diff --git a/src/storage/storage_command.cpp b/src/storage/storage_command.cpp index b4664a59..d021f16d 100644 --- a/src/storage/storage_command.cpp +++ b/src/storage/storage_command.cpp @@ -105,6 +105,7 @@ namespace OpenWifi { bool Storage::RemoveOldCommands(std::string &SerialNumber, std::string &Command) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Delete(Sess); std::string St{ @@ -112,8 +113,7 @@ namespace OpenWifi { Delete << ConvertParams(St), Poco::Data::Keywords::use(SerialNumber), Poco::Data::Keywords::use(Command); Delete.execute(); - Delete.reset(Sess); - + Sess.commit(); return true; } catch (const Poco::Exception &E) { Logger().log(E); @@ -146,6 +146,7 @@ namespace OpenWifi { RemoveOldCommands(SerialNumber, Command.Command); Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Insert(Sess); std::string St{"INSERT INTO CommandList ( " + DB_Command_SelectFields + " ) VALUES( " + @@ -156,7 +157,7 @@ namespace OpenWifi { Insert << ConvertParams(St), Poco::Data::Keywords::use(R); Insert.execute(); - + Sess.commit(); return true; } catch (const Poco::Exception &E) { @@ -215,6 +216,7 @@ namespace OpenWifi { bool Storage::DeleteCommands(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Delete(Sess); bool DatesIncluded = (FromDate != 0 || ToDate != 0); @@ -237,8 +239,7 @@ namespace OpenWifi { Delete << IntroStatement + DateSelector; Delete.execute(); - Delete.reset(Sess); - + Sess.commit(); return true; } catch (const Poco::Exception &E) { Logger().log(E); @@ -274,7 +275,6 @@ namespace OpenWifi { if (Records.size() < HowMany) Done = true; } - Select.reset(Sess); return true; } catch (const Poco::Exception &E) { Logger().log(E); @@ -286,6 +286,7 @@ namespace OpenWifi { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Update(Sess); std::string St{"UPDATE CommandList SET Status=?, Executed=?, Completed=?, " @@ -299,7 +300,7 @@ namespace OpenWifi { Poco::Data::Keywords::use(Command.ErrorCode), Poco::Data::Keywords::use(UUID); Update.execute(); - + Sess.commit(); return true; } catch (const Poco::Exception &E) { @@ -311,6 +312,7 @@ namespace OpenWifi { bool Storage::SetCommandExecuted(std::string &CommandUUID) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Update(Sess); auto Now = Utils::Now(); @@ -321,6 +323,7 @@ namespace OpenWifi { Update << ConvertParams(St), Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(Status), Poco::Data::Keywords::use(CommandUUID); Update.execute(); + Sess.commit(); return true; } catch (const Poco::Exception &E) { Logger().log(E); @@ -331,6 +334,7 @@ namespace OpenWifi { void Storage::RemovedExpiredCommands() { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Update(Sess); auto Now = Utils::Now(), Window = Now - CommandManager()->CommandTimeout(); @@ -341,8 +345,7 @@ namespace OpenWifi { Update << ConvertParams(St), Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(Status), Poco::Data::Keywords::use(Window); Update.execute(); - Update.reset(Sess); - + Sess.commit(); } catch (const Poco::Exception &E) { Logger().log(E); } @@ -351,6 +354,7 @@ namespace OpenWifi { bool Storage::SetCommandLastTry(std::string &CommandUUID) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Update(Sess); auto Now = Utils::Now(); @@ -359,6 +363,7 @@ namespace OpenWifi { Update << ConvertParams(St), Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(CommandUUID); Update.execute(); + Sess.commit(); return true; } catch (const Poco::Exception &E) { Logger().log(E); @@ -369,6 +374,7 @@ namespace OpenWifi { void Storage::RemoveTimedOutCommands() { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Update(Sess); auto Now = Utils::Now(), Window = Now - CommandManager()->CommandTimeout(); @@ -377,7 +383,7 @@ namespace OpenWifi { Update << ConvertParams(St), Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(Window); Update.execute(); - Update.reset(Sess); + Sess.commit(); } catch (const Poco::Exception &E) { Logger().log(E); } @@ -386,6 +392,7 @@ namespace OpenWifi { bool Storage::SetCommandTimedOut(std::string &CommandUUID) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Update(Sess); auto Now = Utils::Now(); @@ -395,6 +402,7 @@ namespace OpenWifi { Update << ConvertParams(St), Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(Status), Poco::Data::Keywords::use(CommandUUID); Update.execute(); + Sess.commit(); return true; } catch (const Poco::Exception &E) { Logger().log(E); @@ -425,6 +433,7 @@ namespace OpenWifi { bool Storage::DeleteCommand(std::string &UUID) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Delete(Sess); std::string St{"DELETE FROM CommandList WHERE UUID=?"}; @@ -435,8 +444,7 @@ namespace OpenWifi { St = "DELETE FROM FileUploads WHERE UUID=?"; Delete << ConvertParams(St), Poco::Data::Keywords::use(UUID); Delete.execute(); - Delete.reset(Sess); - + Sess.commit(); return true; } catch (const Poco::Exception &E) { Logger().log(E); @@ -510,6 +518,7 @@ namespace OpenWifi { auto Now = Utils::Now(); Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Update(Sess); std::string St{"UPDATE CommandList SET Executed=? WHERE UUID=?"}; @@ -518,7 +527,7 @@ namespace OpenWifi { Poco::Data::Keywords::use(UUID); Update.execute(); - + Sess.commit(); return true; } catch (const Poco::Exception &E) { Logger().log(E); @@ -555,6 +564,7 @@ namespace OpenWifi { } Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Update(Sess); auto Status = to_string(Storage::CommandExecutionType::COMMAND_COMPLETED); @@ -566,6 +576,7 @@ namespace OpenWifi { Poco::Data::Keywords::use(ResultStr), Poco::Data::Keywords::use(Status), Poco::Data::Keywords::use(tET), Poco::Data::Keywords::use(UUID); Update.execute(); + Sess.commit(); return true; } catch (const Poco::Exception &E) { Logger().log(E); @@ -603,6 +614,7 @@ namespace OpenWifi { bool Storage::CancelWaitFile(std::string &UUID, std::string &ErrorText) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); auto Now = Utils::Now(); uint64_t Size = 0, WaitForFile = 0; @@ -616,6 +628,7 @@ namespace OpenWifi { Poco::Data::Keywords::use(ErrorText), Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(UUID); Update.execute(); + Sess.commit(); return true; } catch (const Poco::Exception &E) { Logger().log(E); @@ -631,6 +644,7 @@ namespace OpenWifi { uint64_t Size = FileContent.str().size(); Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Statement(Sess); std::string StatementStr; @@ -644,14 +658,14 @@ namespace OpenWifi { Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(Size), Poco::Data::Keywords::use(UUID); Statement.execute(); - + Sess.commit(); if (Size < FileUploader()->MaxSize()) { Poco::Data::BLOB TheBlob; TheBlob.appendRaw((const unsigned char *)FileContent.str().c_str(), FileContent.str().size()); - + Sess.begin(); Poco::Data::Statement Insert(Sess); std::string FileType{Type}; @@ -662,10 +676,12 @@ namespace OpenWifi { Poco::Data::Keywords::use(FileType), Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(TheBlob); Insert.execute(); - return true; + Sess.commit(); } else { poco_warning(Logger(), fmt::format("File {} is too large.", UUID)); } + Sess.commit(); + return true; } catch (const Poco::Exception &E) { Logger().log(E); } @@ -712,6 +728,7 @@ namespace OpenWifi { bool Storage::SetCommandResult(std::string &UUID, std::string &Result) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Update(Sess); auto Now = Utils::Now(); @@ -722,6 +739,7 @@ namespace OpenWifi { Poco::Data::Keywords::use(Result), Poco::Data::Keywords::use(Status), Poco::Data::Keywords::use(UUID); Update.execute(); + Sess.commit(); return true; } catch (const Poco::Exception &E) { @@ -733,13 +751,14 @@ namespace OpenWifi { bool Storage::RemoveAttachedFile(std::string &UUID) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Delete(Sess); std::string St{"DELETE FROM FileUploads WHERE UUID=?"}; Delete << ConvertParams(St), Poco::Data::Keywords::use(UUID); Delete.execute(); - + Sess.commit(); return true; } catch (const Poco::Exception &E) { @@ -751,11 +770,13 @@ namespace OpenWifi { bool Storage::RemoveUploadedFilesRecordsOlderThan(uint64_t Date) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Delete(Sess); std::string St1{"delete from FileUploads where Createdget(); + Sess.begin(); Poco::Data::Statement Delete(Sess); std::string St1{"delete from CommandList where Submittedget(); + Sess.begin(); Poco::Data::Statement Delete(Sess); Poco::toLowerInPlace(deviceType); @@ -114,7 +117,7 @@ namespace OpenWifi { Delete << ConvertParams(St), Poco::Data::Keywords::use(deviceType); Delete.execute(); - + Sess.commit(); return true; } catch (const Poco::Exception &E) { poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), @@ -125,9 +128,9 @@ namespace OpenWifi { bool Storage::UpdateDefaultFirmware(GWObjects::DefaultFirmware &DefFirmware) { try { + uint64_t Now = Utils::Now(); Poco::Data::Session Sess = Pool_->get(); - - uint64_t Now = time(nullptr); + Sess.begin(); Poco::Data::Statement Update(Sess); DefFirmware.LastModified = Now; Poco::toLowerInPlace(DefFirmware.deviceType); @@ -143,7 +146,7 @@ namespace OpenWifi { Poco::Data::Keywords::use(R), Poco::Data::Keywords::use(DefFirmware.deviceType); Update.execute(); - + Sess.commit(); return true; } catch (const Poco::Exception &E) { poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), diff --git a/src/storage/storage_defconfig.cpp b/src/storage/storage_defconfig.cpp index 7b0f2d39..36f8cc75 100644 --- a/src/storage/storage_defconfig.cpp +++ b/src/storage/storage_defconfig.cpp @@ -72,6 +72,7 @@ namespace OpenWifi { Config::Config Cfg(DefConfig.Configuration); if (Cfg.Valid()) { + Sess.begin(); Poco::Data::Statement Insert(Sess); std::string St{"INSERT INTO DefaultConfigs ( " + DB_DefConfig_SelectFields + @@ -83,6 +84,7 @@ namespace OpenWifi { Convert(DefConfig, R); Insert << ConvertParams(St), Poco::Data::Keywords::use(R); Insert.execute(); + Sess.commit(); return true; } else { poco_warning(Logger(), "Cannot create device: invalid configuration."); @@ -99,13 +101,14 @@ namespace OpenWifi { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Delete(Sess); std::string St{"DELETE FROM DefaultConfigs WHERE Name=?"}; Delete << ConvertParams(St), Poco::Data::Keywords::use(Name); Delete.execute(); - + Sess.commit(); return true; } catch (const Poco::Exception &E) { poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), @@ -117,9 +120,9 @@ namespace OpenWifi { bool Storage::UpdateDefaultConfiguration(std::string &Name, GWObjects::DefaultConfiguration &DefConfig) { try { + uint64_t Now = Utils::Now(); Poco::Data::Session Sess = Pool_->get(); - - uint64_t Now = time(nullptr); + Sess.begin(); Poco::Data::Statement Update(Sess); DefConfig.LastModified = Now; @@ -132,6 +135,7 @@ namespace OpenWifi { Update << ConvertParams(St), Poco::Data::Keywords::use(R), Poco::Data::Keywords::use(Name); Update.execute(); + Sess.commit(); return true; } catch (const Poco::Exception &E) { poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), diff --git a/src/storage/storage_device.cpp b/src/storage/storage_device.cpp index 4e1a0d8a..97882cca 100644 --- a/src/storage/storage_device.cpp +++ b/src/storage/storage_device.cpp @@ -210,7 +210,7 @@ namespace OpenWifi { return false; } - bool Storage::UpdateDeviceConfiguration(std::string &SerialNumber, std::string &Configuration, +/* bool Storage::UpdateDeviceConfiguration(std::string &SerialNumber, std::string &Configuration, uint64_t &NewUUID) { try { @@ -255,7 +255,7 @@ namespace OpenWifi { } return false; } - +*/ bool Storage::RollbackDeviceConfigurationChange(std::string & SerialNumber) { try { GWObjects::Device D; @@ -268,6 +268,7 @@ namespace OpenWifi { ConfigurationCache().Add(Utils::SerialNumberToInt(SerialNumber), D.UUID); Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Update(Sess); DeviceRecordTuple R; @@ -277,6 +278,7 @@ namespace OpenWifi { Update << ConvertParams(St2), Poco::Data::Keywords::use(R), Poco::Data::Keywords::use(SerialNumber); Update.execute(); + Sess.commit(); return true; } catch (const Poco::Exception &E) { Logger().log(E); @@ -285,6 +287,16 @@ namespace OpenWifi { } bool Storage::CompleteDeviceConfigurationChange(std::string & SerialNumber) { + try { + auto Session = Pool_->get(); + return CompleteDeviceConfigurationChange(Session, SerialNumber); + } catch (const Poco::Exception &E) { + Logger().log(E); + } + return false; + } + + bool Storage::CompleteDeviceConfigurationChange(Poco::Data::Session & Session, std::string & SerialNumber) { try { GWObjects::Device D; if (!GetDevice(SerialNumber, D)) @@ -300,8 +312,8 @@ namespace OpenWifi { ConfigurationCache().Add(Utils::SerialNumberToInt(SerialNumber), D.UUID); - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement Update(Sess); + Session.begin(); + Poco::Data::Statement Update(Session); DeviceRecordTuple R; ConvertDeviceRecord(D, R); @@ -310,6 +322,7 @@ namespace OpenWifi { Update << ConvertParams(St2), Poco::Data::Keywords::use(R), Poco::Data::Keywords::use(SerialNumber); Update.execute(); + Session.commit(); return true; } catch (const Poco::Exception &E) { Logger().log(E); @@ -328,13 +341,12 @@ namespace OpenWifi { return false; } - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement Select(Sess); GWObjects::Device D; if (!GetDevice(SerialNumber, D)) return false; + uint64_t Now = time(nullptr); if(NewUUID==0) { D.pendingUUID = NewUUID = (D.LastConfigurationChange == Now ? Now + 1 : Now); @@ -343,6 +355,8 @@ namespace OpenWifi { } if (Cfg.SetUUID(NewUUID)) { + Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Update(Sess); D.pendingConfiguration = Cfg.get(); @@ -353,6 +367,7 @@ namespace OpenWifi { Update << ConvertParams(St2), Poco::Data::Keywords::use(R), Poco::Data::Keywords::use(SerialNumber); Update.execute(); + Sess.commit(); poco_information(Logger(), fmt::format("DEVICE-PENDING-CONFIGURATION-UPDATED({}): New UUID is {}", SerialNumber, NewUUID)); @@ -366,69 +381,95 @@ namespace OpenWifi { return false; } - bool Storage::SetDeviceLastRecordedContact(std::string &SerialNumber, std::uint64_t lastRecordedContact) { + bool Storage::SetDeviceLastRecordedContact(LockedDbSession &Session, std::string &SerialNumber, std::uint64_t lastRecordedContact) { try { - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement Update(Sess); + std::lock_guard Lock(Session.Mutex()); + return SetDeviceLastRecordedContact(Session.Session(), SerialNumber, lastRecordedContact); + } catch (const Poco::Exception &E) { + Logger().log(E); + } + return false; + } + + bool Storage::SetDeviceLastRecordedContact(Poco::Data::Session &Session, std::string &SerialNumber, std::uint64_t lastRecordedContact) { + try { + Session.begin(); + Poco::Data::Statement Update(Session); std::string St{"UPDATE Devices SET lastRecordedContact=? WHERE SerialNumber=?"}; Update << ConvertParams(St), Poco::Data::Keywords::use(lastRecordedContact), Poco::Data::Keywords::use(SerialNumber); Update.execute(); + Session.commit(); return true; + } catch (const Poco::Exception &E) { + Logger().log(E); + } + return false; + } + bool Storage::SetDeviceLastRecordedContact(std::string &SerialNumber, std::uint64_t lastRecordedContact) { + try { + auto Session = Pool_->get(); + return SetDeviceLastRecordedContact(Session, SerialNumber, lastRecordedContact); } catch (const Poco::Exception &E) { Logger().log(E); } return false; } - bool Storage::CreateDevice(GWObjects::Device &DeviceDetails) { + bool Storage::CreateDevice(Poco::Data::Session &Sess, GWObjects::Device &DeviceDetails) { std::string SerialNumber; try { + Config::Config Cfg(DeviceDetails.Configuration); + uint64_t Now = Utils::Now(); - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement Select(Sess); - - std::string St{"SELECT SerialNumber FROM Devices WHERE SerialNumber=?"}; + DeviceDetails.modified = Utils::Now(); + DeviceDetails.CreationTimestamp = DeviceDetails.LastConfigurationDownload = + DeviceDetails.UUID = DeviceDetails.LastConfigurationChange = Now; -// Select << ConvertParams(St), Poco::Data::Keywords::into(SerialNumber), -// Poco::Data::Keywords::use(DeviceDetails.SerialNumber); -// Select.execute(); + if (Cfg.Valid() && Cfg.SetUUID(DeviceDetails.UUID)) { -// if (Select.rowsExtracted() == 0) { - Config::Config Cfg(DeviceDetails.Configuration); - uint64_t Now = Utils::Now(); + DeviceDetails.Configuration = Cfg.get(); + Sess.begin(); + Poco::Data::Statement Insert(Sess); - DeviceDetails.modified = Utils::Now(); - DeviceDetails.CreationTimestamp = DeviceDetails.LastConfigurationDownload = - DeviceDetails.UUID = DeviceDetails.LastConfigurationChange = Now; + std::string St2{"INSERT INTO Devices ( " + DB_DeviceSelectFields + " ) " + + DB_DeviceInsertValues + " ON CONFLICT (SerialNumber) DO NOTHING"}; - if (Cfg.Valid() && Cfg.SetUUID(DeviceDetails.UUID)) { - - DeviceDetails.Configuration = Cfg.get(); - Poco::Data::Statement Insert(Sess); + SetCurrentConfigurationID(DeviceDetails.SerialNumber, DeviceDetails.UUID); + DeviceRecordTuple R; + ConvertDeviceRecord(DeviceDetails, R); + Insert << ConvertParams(St2), Poco::Data::Keywords::use(R); + Insert.execute(); + Sess.commit(); + SetCurrentConfigurationID(DeviceDetails.SerialNumber, DeviceDetails.UUID); + SerialNumberCache()->AddSerialNumber(DeviceDetails.SerialNumber); + } else { + poco_warning(Logger(), "Cannot create device: invalid configuration."); + return false; + } + return true; + } catch (const Poco::Exception &E) { + Logger().log(E); + } + return false; + } - std::string St2{"INSERT INTO Devices ( " + DB_DeviceSelectFields + " ) " + - DB_DeviceInsertValues + " ON CONFLICT (SerialNumber) DO NOTHING"}; + bool Storage::CreateDevice(LockedDbSession &Session, GWObjects::Device &DeviceDetails) { + try { + std::lock_guard Lock(Session.Mutex()); + return CreateDevice(Session.Session(), DeviceDetails); + } catch (const Poco::Exception &E) { + Logger().log(E); + } + return false; + } - SetCurrentConfigurationID(DeviceDetails.SerialNumber, DeviceDetails.UUID); - DeviceRecordTuple R; - ConvertDeviceRecord(DeviceDetails, R); - Insert << ConvertParams(St2), Poco::Data::Keywords::use(R); - Insert.execute(); - SetCurrentConfigurationID(DeviceDetails.SerialNumber, DeviceDetails.UUID); - SerialNumberCache()->AddSerialNumber(DeviceDetails.SerialNumber); - return true; - } else { - poco_warning(Logger(), "Cannot create device: invalid configuration."); - return false; - } -// } else { -// poco_warning(Logger(), fmt::format("Device {} already exists.", SerialNumber)); -// return false; -// } - return true; + bool Storage::CreateDevice(GWObjects::Device &DeviceDetails) { + try { + auto Session = Pool_->get(); + return CreateDevice(Session, DeviceDetails); } catch (const Poco::Exception &E) { Logger().log(E); } @@ -487,16 +528,15 @@ namespace OpenWifi { return true; } -#define __DBGLOG__ std::cout << __LINE__ << std::endl; - - bool Storage::CreateDefaultDevice(std::string &SerialNumber, const Config::Capabilities &Caps, + bool Storage::CreateDefaultDevice(Poco::Data::Session &Session, std::string &SerialNumber, const Config::Capabilities &Caps, std::string &Firmware, const Poco::Net::IPAddress &IPAddress, bool simulated) { GWObjects::Device D; - poco_information(Logger(), fmt::format("AUTO-CREATION({})", SerialNumber)); - uint64_t Now = time(nullptr); + + // poco_information(Logger(), fmt::format("AUTO-CREATION({}): Start.", SerialNumber)); + uint64_t Now = Utils::Now(); GWObjects::DefaultConfiguration DefConfig; if (!Caps.Platform().empty() && !Caps.Compatible().empty()) { @@ -539,12 +579,13 @@ namespace OpenWifi { D.Notes = SecurityObjects::NoteInfoVec{ SecurityObjects::NoteInfo{(uint64_t)Utils::Now(), "", "Auto-provisioned."}}; - CreateDeviceCapabilities(SerialNumber, Caps); - - return CreateDevice(D); + CreateDeviceCapabilities(Session, SerialNumber, Caps); + auto Result = CreateDevice(Session, D); + poco_information(Logger(), fmt::format("AUTO-CREATION({}): Done, Result={}", SerialNumber, Result)); + return Result; } - bool Storage::GetDeviceFWUpdatePolicy(std::string &SerialNumber, std::string &Policy) { +/* bool Storage::GetDeviceFWUpdatePolicy(std::string &SerialNumber, std::string &Policy) { try { Poco::Data::Session Sess = Pool_->get(); Poco::Data::Statement Select(Sess); @@ -559,46 +600,19 @@ namespace OpenWifi { } return false; } - - bool Storage::SetDevicePassword(std::string &SerialNumber, std::string &Password) { +*/ + bool Storage::SetDevicePassword(LockedDbSession &Sess, std::string &SerialNumber, std::string &Password) { try { - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement Update(Sess); + std::lock_guard Lock(Sess.Mutex()); + Sess.Session().begin(); + + Poco::Data::Statement Update(Sess.Session()); std::string St{"UPDATE Devices SET DevicePassword=? WHERE SerialNumber=?"}; Update << ConvertParams(St), Poco::Data::Keywords::use(Password), Poco::Data::Keywords::use(SerialNumber); Update.execute(); - return true; - } catch (const Poco::Exception &E) { - Logger().log(E); - } - return false; - } - - bool Storage::SetConnectInfo(std::string &SerialNumber, std::string &Firmware) { - try { - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement Select(Sess); - - // Get the old version and if they do not match, set the last date - std::string St{"SELECT Firmware FROM Devices WHERE SerialNumber=?"}; - std::string TmpFirmware; - Select << ConvertParams(St), Poco::Data::Keywords::into(TmpFirmware), - Poco::Data::Keywords::use(SerialNumber); - Select.execute(); - - if (TmpFirmware != Firmware) { - Poco::Data::Statement Update(Sess); - std::string St2{ - "UPDATE Devices SET Firmware=?, LastFWUpdate=? WHERE SerialNumber=?"}; - uint64_t Now = Utils::Now(); - - Update << ConvertParams(St2), Poco::Data::Keywords::use(Firmware), - Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(SerialNumber); - Update.execute(); - return true; - } + Sess.Session().commit(); return true; } catch (const Poco::Exception &E) { Logger().log(E); @@ -614,12 +628,14 @@ namespace OpenWifi { for (const auto &tableName : TableNames) { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Delete(Sess); std::string St = fmt::format("DELETE FROM {} WHERE SerialNumber='{}'", tableName, SerialNumber); try { Delete << St; Delete.execute(); + Sess.commit(); } catch (...) { } } @@ -692,11 +708,9 @@ namespace OpenWifi { return false; } - bool Storage::GetDevice(std::string &SerialNumber, GWObjects::Device &DeviceDetails) { + bool Storage::GetDevice(Poco::Data::Session &Session, std::string &SerialNumber, GWObjects::Device &DeviceDetails) { try { - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement Select(Sess); - + Poco::Data::Statement Select(Session); std::string St{"SELECT " + DB_DeviceSelectFields + " FROM Devices WHERE SerialNumber=?"}; @@ -715,6 +729,26 @@ namespace OpenWifi { return false; } + bool Storage::GetDevice(std::string &SerialNumber, GWObjects::Device &DeviceDetails) { + try { + auto Sess = Pool_->get(); + return GetDevice(Sess, SerialNumber, DeviceDetails); + } catch (const Poco::Exception &E) { + Logger().log(E); + } + return false; + } + + bool Storage::GetDevice(LockedDbSession &Session, std::string &SerialNumber, GWObjects::Device &DeviceDetails) { + try { + std::lock_guard Lock(Session.Mutex()); + return GetDevice(Session.Session(), SerialNumber, DeviceDetails); + } catch (const Poco::Exception &E) { + Logger().log(E); + } + return false; + } + bool Storage::DeviceExists(std::string &SerialNumber) { try { Poco::Data::Session Sess = Pool_->get(); @@ -741,6 +775,26 @@ namespace OpenWifi { bool Storage::UpdateDevice(GWObjects::Device &NewDeviceDetails) { try { Poco::Data::Session Sess = Pool_->get(); + return UpdateDevice(Sess, NewDeviceDetails); + } catch (const Poco::Exception &E) { + Logger().log(E); + } + return false; + } + + bool Storage::UpdateDevice(LockedDbSession &Session, GWObjects::Device &NewDeviceDetails) { + try { + std::lock_guard Lock(Session.Mutex()); + return UpdateDevice(Session.Session(), NewDeviceDetails); + } catch (const Poco::Exception &E) { + Logger().log(E); + } + return false; + } + + bool Storage::UpdateDevice(Poco::Data::Session &Sess, GWObjects::Device &NewDeviceDetails) { + try { + Sess.begin(); Poco::Data::Statement Update(Sess); DeviceRecordTuple R; @@ -753,6 +807,7 @@ namespace OpenWifi { Update << ConvertParams(St2), Poco::Data::Keywords::use(R), Poco::Data::Keywords::use(NewDeviceDetails.SerialNumber); Update.execute(); + Sess.commit(); // GetDevice(NewDeviceDetails.SerialNumber,NewDeviceDetails); return true; } catch (const Poco::Exception &E) { diff --git a/src/storage/storage_healthcheck.cpp b/src/storage/storage_healthcheck.cpp index 971bbe7e..2d77f844 100644 --- a/src/storage/storage_healthcheck.cpp +++ b/src/storage/storage_healthcheck.cpp @@ -35,10 +35,11 @@ namespace OpenWifi { R.set<4>(H.Recorded); } - bool Storage::AddHealthCheckData(const GWObjects::HealthCheck &Check) { + bool Storage::AddHealthCheckData(LockedDbSession &Session, const GWObjects::HealthCheck &Check) { try { - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement Insert(Sess); + std::lock_guard Guard(Session.Mutex()); + Session.Session().begin(); + Poco::Data::Statement Insert(Session.Session()); std::string St{"INSERT INTO HealthChecks ( " + DB_HealthCheckSelectFields + " ) VALUES( " + DB_HealthCheckInsertValues + " )"}; @@ -47,6 +48,7 @@ namespace OpenWifi { ConvertHealthCheckRecord(Check, R); Insert << ConvertParams(St), Poco::Data::Keywords::use(R); Insert.execute(); + Session.Session().commit(); return true; } catch (const Poco::Exception &E) { poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), @@ -134,7 +136,7 @@ namespace OpenWifi { uint64_t ToDate) { try { Poco::Data::Session Sess = Pool_->get(); - + Sess.begin(); bool DatesIncluded = (FromDate != 0 || ToDate != 0); std::string Prefix{"DELETE FROM HealthChecks "}; @@ -158,7 +160,7 @@ namespace OpenWifi { Delete << Statement + DateSelector; Delete.execute(); - + Sess.commit(); return true; } catch (const Poco::Exception &E) { poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), @@ -170,11 +172,13 @@ namespace OpenWifi { bool Storage::RemoveHealthChecksRecordsOlderThan(uint64_t Date) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Delete(Sess); std::string St1{"delete from HealthChecks where recorded(Log.UUID); } - bool Storage::AddLog(const GWObjects::DeviceLog &Log) { + bool Storage::AddLog(LockedDbSession &Session, const GWObjects::DeviceLog &Log) { try { - - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement Insert(Sess); + std::lock_guard Guard(Session.Mutex()); + Session.Session().begin(); + Poco::Data::Statement Insert(Session.Session()); std::string St{"INSERT INTO DeviceLogs (" + DB_LogsSelectFields + ") values( " + DB_LogsInsertValues + " )"}; @@ -53,6 +53,7 @@ namespace OpenWifi { Insert << ConvertParams(St), Poco::Data::Keywords::use(R); Insert.execute(); + Session.Session().commit(); return true; } catch (const Poco::Exception &E) { poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), @@ -114,7 +115,7 @@ namespace OpenWifi { uint64_t Type) { try { Poco::Data::Session Sess = Pool_->get(); - + Sess.begin(); bool DatesIncluded = (FromDate != 0 || ToDate != 0); bool HasWhere = DatesIncluded || !SerialNumber.empty(); @@ -141,7 +142,7 @@ namespace OpenWifi { Delete << StatementStr + DateSelector + TypeSelector; Delete.execute(); - Delete.reset(Sess); + Sess.commit(); return true; } catch (const Poco::Exception &E) { @@ -183,11 +184,13 @@ namespace OpenWifi { bool Storage::RemoveDeviceLogsRecordsOlderThan(uint64_t Date) { try { Poco::Data::Session Sess = Pool_->get(); + Sess.begin(); Poco::Data::Statement Delete(Sess); std::string St1{"delete from DeviceLogs where recorded(Stats.Recorded); } - bool Storage::AddStatisticsData(const GWObjects::Statistics &Stats) { + bool Storage::AddStatisticsData(Poco::Data::Session &Session, const GWObjects::Statistics &Stats) { try { - Poco::Data::Session Sess(Pool_->get()); - Poco::Data::Statement Insert(Sess); + Session.begin(); + Poco::Data::Statement Insert(Session); poco_trace(Logger(), fmt::format("{}: Adding stats. Size={}", Stats.SerialNumber, std::to_string(Stats.Data.size()))); @@ -46,6 +45,7 @@ namespace OpenWifi { ConvertStatsRecord(Stats, R); Insert << ConvertParams(St), Poco::Data::Keywords::use(R); Insert.execute(); + Session.commit(); return true; } catch (const Poco::Exception &E) { poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), @@ -167,7 +167,7 @@ namespace OpenWifi { uint64_t ToDate) { try { Poco::Data::Session Sess = Pool_->get(); - + Sess.begin(); bool DatesIncluded = (FromDate != 0 || ToDate != 0); std::string Prefix{"DELETE FROM Statistics "}; @@ -189,7 +189,7 @@ namespace OpenWifi { Poco::Data::Statement Select(Sess); Select << Statement + DateSelector; Select.execute(); - + Sess.commit(); return true; } catch (const Poco::Exception &E) { poco_warning(Logger(), (fmt::format("{}: Failed with: {}", std::string(__func__),