stephb9959
2024-03-13 14:07:10 -07:00
parent 1a0a6d4a70
commit e75d3cfdbb
14 changed files with 155 additions and 91 deletions

2
.idea/.gitignore generated vendored
View File

@@ -6,3 +6,5 @@
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
# GitHub Copilot persisted chat sessions
/copilot/chatSessions

2
build
View File

@@ -1 +1 @@
89
91

View File

@@ -551,6 +551,12 @@ components:
lastModified:
type: integer
format: int64
platform:
type: string
enum:
- AP
- SWITCH
default: AP
DefaultConfigurationList:
properties:
@@ -1963,15 +1969,6 @@ paths:
schema:
type: string
required: true
- in: query
name: deviceType
schema:
type: string
enum:
- AP
- SWITCH
required: false
default: AP
requestBody:
description: Information used to create the new device
content:
@@ -2018,15 +2015,6 @@ paths:
schema:
type: string
required: true
- in: query
name: deviceType
schema:
type: string
enum:
- AP
- SWITCH
required: false
default: AP
requestBody:
description: Configuration details
content:

View File

@@ -76,15 +76,11 @@ namespace OpenWifi {
}
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));
std::lock_guard G(ConnectionMutex_);
AP_WS_Server()->DecrementConnectionCount();
EndConnection();
poco_debug(Logger_, fmt::format("TERMINATION({}): Session={}, Connection removed.", SerialNumber_,
State_.sessionId));
}
static void NotifyKafkaDisconnect(const std::string &SerialNumber, std::uint64_t uuid) {
@@ -100,7 +96,7 @@ namespace OpenWifi {
}
}
void AP_WS_Connection::EndConnection(bool Clean) {
void AP_WS_Connection::EndConnection() {
bool expectedValue=false;
if (Dead_.compare_exchange_strong(expectedValue,true,std::memory_order_release,std::memory_order_relaxed)) {
@@ -126,9 +122,7 @@ namespace OpenWifi {
if(!SerialNumber_.empty()) {
DeviceDisconnectionCleanup(SerialNumber_, uuid_);
}
if(Clean)
AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
AP_WS_Server()->AddCleanupSession(State_.sessionId, SerialNumberInt_);
}
}

View File

@@ -30,7 +30,7 @@ namespace OpenWifi {
Poco::Logger &L, std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> R);
~AP_WS_Connection();
void EndConnection(bool Clean = true);
void EndConnection();
void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc);
void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
void ProcessIncomingFrame();
@@ -108,7 +108,7 @@ namespace OpenWifi {
void Start();
private:
std::recursive_mutex ConnectionMutex_;
mutable std::recursive_mutex ConnectionMutex_;
std::mutex TelemetryMutex_;
Poco::Logger &Logger_;
std::shared_ptr<Poco::Net::SocketReactor> Reactor_;

View File

@@ -200,9 +200,31 @@ namespace OpenWifi {
Running_ = true;
GarbageCollector_.setName("ws:garbage");
GarbageCollector_.start(*this);
std::thread CleanupThread([this](){ CleanupSessions(); });
CleanupThread.detach();
return 0;
}
void AP_WS_Server::CleanupSessions() {
while(Running_) {
std::this_thread::sleep_for(std::chrono::seconds(10));
while(Running_ && !CleanupSessions_.empty()) {
std::pair<uint64_t, uint64_t> Session;
{
std::lock_guard G(CleanupMutex_);
Session = CleanupSessions_.front();
CleanupSessions_.pop_front();
}
this->Logger().information(fmt::format("Cleaning up session: {} for device: {}", Session.first, Utils::IntToSerialNumber(Session.second)));
EndSession(Session.first, Session.second);
}
}
}
void AP_WS_Server::run() {
uint64_t last_log = Utils::Now(),
last_zombie_run = 0,
@@ -236,29 +258,35 @@ namespace OpenWifi {
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);
continue;
}
auto Device = hint->second;
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) {
total_connected_time +=
(RightNow - Device->State_.started);
++hint;
} else {
++hint;
auto Device = hint->second;
auto RightNow = Utils::Now();
if (Device->Dead_) {
AddCleanupSession(Device->State_.sessionId, Device->SerialNumberInt_);
++hint;
// hint = SerialNumbers_[hashIndex].erase(hint);
} else 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);
AddCleanupSession(Device->State_.sessionId, Device->SerialNumberInt_);
++hint;
} else {
if (Device->State_.Connected) {
total_connected_time +=
(RightNow - Device->State_.started);
}
++hint;
}
}
}
SerialNumbersMutex_[hashIndex].unlock();
@@ -272,8 +300,7 @@ namespace OpenWifi {
}
}
poco_information(LocalLogger,
fmt::format("Garbage collecting zombies... (step 2)"));
poco_information(LocalLogger, fmt::format("Garbage collecting zombies... (step 2)"));
LeftOverSessions_ = 0;
for (int i = 0; i < SessionHash::HashMax(); i++) {
waits = 0;
@@ -285,6 +312,10 @@ namespace OpenWifi {
while (hint != end(Sessions_[i])) {
if (hint->second == nullptr) {
hint = Sessions_[i].erase(hint);
} else if (hint->second->Dead_) {
// hint = Sessions_[i].erase(hint);
AddCleanupSession(hint->second->State_.sessionId, hint->second->SerialNumberInt_);
++hint;
} else if (RightNow > hint->second->LastContact_ &&
(RightNow - hint->second->LastContact_) >
SessionTimeOut_) {
@@ -292,7 +323,9 @@ namespace OpenWifi {
LocalLogger,
fmt::format("{}: Session seems idle. Controller disconnecting device.",
hint->second->SerialNumber_));
hint = Sessions_[i].erase(hint);
AddCleanupSession(hint->second->State_.sessionId, hint->second->SerialNumberInt_);
++hint;
// hint = Sessions_[i].erase(hint);
} else {
++LeftOverSessions_;
++hint;
@@ -309,10 +342,9 @@ namespace OpenWifi {
}
}
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()));
@@ -323,12 +355,11 @@ namespace OpenWifi {
}
}
if(NumberOfConnectedDevices_) {
if (last_garbage_run > 0) {
AverageDeviceConnectionTime_ += (now - last_garbage_run);
}
} else {
AverageDeviceConnectionTime_ = 0;
}
try {
@@ -445,17 +476,21 @@ namespace OpenWifi {
}
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;
std::shared_ptr<AP_WS_Connection> Connection;
{
std::lock_guard SessionLock(SessionMutex_[sessionHash]);
auto SessionHint = Sessions_[sessionHash].find(session_id);
if (SessionHint == end(Sessions_[sessionHash])) {
return;
}
Connection = SessionHint->second;
Sessions_[sessionHash].erase(SessionHint);
} else {
poco_error(Logger(), fmt::format("StartSession: Could not find session '{}'", session_id));
}
auto deviceHash = MACHash::Hash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[deviceHash]);
SerialNumbers_[deviceHash][SerialNumber] = Connection;
}
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t SerialNumber) {

View File

@@ -203,6 +203,13 @@ namespace OpenWifi {
--NumberOfConnectedDevices_;
}
inline void AddCleanupSession(uint64_t session_id, uint64_t SerialNumber) {
std::lock_guard G(CleanupMutex_);
CleanupSessions_.emplace_back(session_id, SerialNumber);
}
void CleanupSessions();
private:
std::array<std::mutex,SessionHashMax> SessionMutex_;
std::array<std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>>,SessionHashMax> Sessions_;
@@ -222,6 +229,10 @@ namespace OpenWifi {
bool SimulatorEnabled_ = false;
bool AllowSerialNumberMismatch_ = true;
Poco::Thread CleanupThread_;
std::mutex CleanupMutex_;
std::deque<std::pair<uint64_t, uint64_t>> CleanupSessions_;
std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_;
std::atomic_bool Running_ = false;

View File

@@ -60,9 +60,13 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::ModelIDListCannotBeEmpty);
}
auto DeviceType = GetParameter("deviceType", "AP");
DefConfig.Platform = DefConfig.Platform.empty() ? "AP" : DefConfig.Platform;
if(DefConfig.Platform != "AP" && DefConfig.Platform != "SWITCH") {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
std::string Error;
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(DeviceType),
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(DefConfig.Platform),
DefConfig.Configuration, Error,
GetBoolParameter("strict", false))) {
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error);
@@ -90,10 +94,20 @@ namespace OpenWifi {
return NotFound();
}
if(Existing.Platform.empty()) {
Existing.Platform = "AP";
}
if(ParsedBody_->has("platform")) {
if(NewConfig.Platform.empty() || (NewConfig.Platform != "AP" && NewConfig.Platform != "SWITCH")) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
Existing.Platform = NewConfig.Platform;
}
if (!NewConfig.Configuration.empty()) {
auto DeviceType = GetParameter("deviceType", "AP");
std::string Error;
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(DeviceType),
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(Existing.Platform),
NewConfig.Configuration, Error,
GetBoolParameter("strict", false))) {
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error);

View File

@@ -184,15 +184,6 @@ namespace OpenWifi::GWObjects {
return false;
}
void DefaultConfiguration::to_json(Poco::JSON::Object &Obj) const {
EmbedDocument("configuration", Obj, Configuration);
field_to_json(Obj, "name", Name);
field_to_json(Obj, "modelIds", Models);
field_to_json(Obj, "description", Description);
field_to_json(Obj, "created", Created);
field_to_json(Obj, "lastModified", LastModified);
}
void DefaultFirmware::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "deviceType", deviceType);
field_to_json(Obj, "description", Description);
@@ -240,12 +231,25 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "deferred", deferred);
}
void DefaultConfiguration::to_json(Poco::JSON::Object &Obj) const {
EmbedDocument("configuration", Obj, Configuration);
field_to_json(Obj, "name", Name);
field_to_json(Obj, "modelIds", Models);
field_to_json(Obj, "description", Description);
field_to_json(Obj, "created", Created);
field_to_json(Obj, "lastModified", LastModified);
field_to_json(Obj, "Platform", Platform);
}
bool DefaultConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "name", Name);
field_from_json(Obj, "configuration", Configuration);
field_from_json(Obj, "name", Name);
field_from_json(Obj, "modelIds", Models);
field_from_json(Obj, "description", Description);
field_from_json(Obj, "created", Created);
field_from_json(Obj, "lastModified", LastModified);
field_from_json(Obj, "Platform", Platform);
return true;
} catch (const Poco::Exception &E) {
}

View File

@@ -186,6 +186,7 @@ namespace OpenWifi::GWObjects {
std::string Description;
uint64_t Created;
uint64_t LastModified;
std::string Platform;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};

View File

@@ -200,6 +200,7 @@ namespace OpenWifi {
bool GetDefaultConfigurations(uint64_t From, uint64_t HowMany,
std::vector<GWObjects::DefaultConfiguration> &Devices);
bool FindDefaultConfigurationForModel(const std::string &Model,
const std::string &Platform,
GWObjects::DefaultConfiguration &DefConfig);
uint64_t GetDefaultConfigurationsCount();
bool DefaultConfigurationAlreadyExists(std::string &Name);

View File

@@ -19,18 +19,18 @@ namespace OpenWifi {
"Models TEXT, "
"Description TEXT, "
"Created BIGINT , "
"LastModified BIGINT)"};
"LastModified BIGINT, Platform TEXT )"};
const static std::string DB_DefConfig_SelectFields{"Name, "
"Configuration, "
"Models, "
"Description, "
"Created, "
"LastModified "};
"LastModified, Platform "};
const static std::string DB_DefConfig_InsertValues{"?,?,?,?,?,?"};
const static std::string DB_DefConfig_InsertValues{"?,?,?,?,?,?,?"};
typedef Poco::Tuple<std::string, std::string, std::string, std::string, uint64_t, uint64_t>
typedef Poco::Tuple<std::string, std::string, std::string, std::string, uint64_t, uint64_t, std::string>
DefConfigRecordTuple;
typedef std::vector<DefConfigRecordTuple> DefConfigRecordList;
@@ -41,6 +41,7 @@ namespace OpenWifi {
T.Description = R.get<3>();
T.Created = R.get<4>();
T.LastModified = R.get<5>();
T.Platform = R.get<6>();
}
void Convert(const GWObjects::DefaultConfiguration &R, DefConfigRecordTuple &T) {
@@ -50,6 +51,7 @@ namespace OpenWifi {
T.set<3>(R.Description);
T.set<4>(R.Created);
T.set<5>(R.LastModified);
T.set<6>(R.Platform);
}
bool Storage::CreateDefaultConfiguration(std::string &Name,
@@ -127,7 +129,7 @@ namespace OpenWifi {
DefConfig.LastModified = Now;
std::string St{"UPDATE DefaultConfigs SET Name=?, Configuration=?, Models=?, "
"Description=?, Created=? , LastModified=? WHERE Name=?"};
"Description=?, Created=? , LastModified=? , Platform=? WHERE Name=?"};
DefConfigRecordTuple R;
Convert(DefConfig, R);
@@ -219,7 +221,7 @@ namespace OpenWifi {
return false;
}
bool Storage::FindDefaultConfigurationForModel(const std::string &Model,
bool Storage::FindDefaultConfigurationForModel(const std::string &Model, const std::string &Platform,
GWObjects::DefaultConfiguration &DefConfig) {
try {
DefConfigRecordList Records;
@@ -235,7 +237,7 @@ namespace OpenWifi {
GWObjects::DefaultConfiguration Config;
Convert(i, Config);
for (const auto &j : Config.Models) {
if (j == "*" || j == Model) {
if ((j == "*" || j == Model) && (Poco::toUpper(Config.Platform) == Poco::toUpper(Platform))){
DefConfig = Config;
return true;
}

View File

@@ -578,11 +578,11 @@ namespace OpenWifi {
}
if (!Found && AP_WS_Server()->UseDefaults() &&
FindDefaultConfigurationForModel(Caps.Compatible(), DefConfig)) {
FindDefaultConfigurationForModel(Caps.Compatible(), Caps.Platform(), DefConfig)) {
Config::Config NewConfig(DefConfig.Configuration);
NewConfig.SetUUID(Now);
D.Configuration = NewConfig.get();
} else if (!Found) {
} else if (!Found && Caps.Platform()=="AP") {
Config::Config NewConfig;
NewConfig.SetUUID(Now);
D.Configuration = NewConfig.get();

View File

@@ -275,9 +275,21 @@ namespace OpenWifi {
"Models TEXT, "
"Description TEXT, "
"Created BIGINT , "
"LastModified BIGINT)",
"LastModified BIGINT, Platform TEXT)",
Poco::Data::Keywords::now;
}
std::vector<std::string> Script{
"alter table DefaultConfigs add column Platform text"
};
for (const auto &i : Script) {
try {
Sess << i, Poco::Data::Keywords::now;
} catch (...) {
}
}
return 0;
} catch (const Poco::Exception &E) {
Logger().log(E);