mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
synced 2026-03-20 03:41:02 +00:00
https://telecominfraproject.atlassian.net/browse/WIFI-14521 Summary of changes: - Updated code to add certificates from clientcas to trust chain and validate client certificates against it. Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
264 lines
9.4 KiB
C++
264 lines
9.4 KiB
C++
//
|
|
// License type: BSD 3-Clause License
|
|
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
|
//
|
|
// Created by Stephane Bourque on 2021-03-04.
|
|
// Arilia Wireless Inc.
|
|
//
|
|
|
|
#pragma once
|
|
|
|
#include <array>
|
|
#include <ctime>
|
|
#include <mutex>
|
|
#include <thread>
|
|
|
|
#include "Poco/AutoPtr.h"
|
|
#include "Poco/Net/HTTPRequestHandler.h"
|
|
#include "Poco/Net/HTTPRequestHandlerFactory.h"
|
|
#include "Poco/Net/HTTPServer.h"
|
|
#include "Poco/Net/HTTPServerRequest.h"
|
|
#include "Poco/Net/ParallelSocketAcceptor.h"
|
|
#include "Poco/Net/SocketAcceptor.h"
|
|
#include "Poco/Net/SocketReactor.h"
|
|
#include "Poco/Timer.h"
|
|
|
|
#include "AP_WS_Connection.h"
|
|
#include "AP_WS_Reactor_Pool.h"
|
|
|
|
#include "framework/SubSystemServer.h"
|
|
#include "framework/utils.h"
|
|
|
|
namespace OpenWifi {
|
|
|
|
constexpr uint MACHashMax = 256;
|
|
constexpr uint MACHashMask = MACHashMax-1;
|
|
class MACHash {
|
|
public:
|
|
[[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;
|
|
}
|
|
|
|
[[nodiscard]] static inline uint16_t Hash(const std::string & value) {
|
|
return Hash(Utils::MACToInt(value));
|
|
}
|
|
|
|
[[nodiscard]] static inline uint16_t HashMax() {
|
|
return MACHashMax;
|
|
}
|
|
};
|
|
|
|
constexpr uint SessionHashMax = 256;
|
|
constexpr uint SessionHashMask = SessionHashMax-1;
|
|
class SessionHash {
|
|
public:
|
|
[[nodiscard]] static inline uint16_t Hash(std::uint64_t value) {
|
|
return (value & SessionHashMask);
|
|
}
|
|
|
|
[[nodiscard]] static inline uint16_t HashMax() {
|
|
return SessionHashMax;
|
|
}
|
|
};
|
|
|
|
|
|
class AP_WS_Server : public SubSystemServer, public Poco::Runnable {
|
|
public:
|
|
static auto instance() {
|
|
static auto instance_ = new AP_WS_Server;
|
|
return instance_;
|
|
}
|
|
|
|
int Start() override;
|
|
void Stop() override;
|
|
bool IsCertOk() { return IssuerCert_ != nullptr; }
|
|
bool ValidateCertificate(const std::string &ConnectionId,
|
|
const Poco::Crypto::X509Certificate &Certificate);
|
|
|
|
inline bool IsSimSerialNumber(const std::string &SerialNumber) const {
|
|
return IsSim(SerialNumber) &&
|
|
SerialNumber == SimulatorId_;
|
|
}
|
|
|
|
inline static bool IsSim(const std::string &SerialNumber) {
|
|
return SerialNumber.substr(0, 6) == "53494d";
|
|
}
|
|
|
|
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<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> NextReactor() {
|
|
return Reactor_pool_->NextReactor();
|
|
}
|
|
|
|
inline void AddConnection(std::shared_ptr<AP_WS_Connection> Connection) {
|
|
std::uint64_t sessionHash = SessionHash::Hash(Connection->State_.sessionId);
|
|
std::lock_guard SessionLock(SessionMutex_[sessionHash]);
|
|
if(Sessions_[sessionHash].find(Connection->State_.sessionId)==end(Sessions_[sessionHash])) {
|
|
Sessions_[sessionHash][Connection->State_.sessionId] = std::move(Connection);
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] inline bool DeviceRequiresSecureRTTY(uint64_t serialNumber) const {
|
|
std::shared_ptr<AP_WS_Connection> Connection;
|
|
{
|
|
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;
|
|
Connection = DeviceHint->second;
|
|
}
|
|
return Connection->RTTYMustBeSecure_;
|
|
}
|
|
|
|
inline bool GetStatistics(const std::string &SerialNumber, std::string &Statistics) const {
|
|
return GetStatistics(Utils::SerialNumberToInt(SerialNumber), Statistics);
|
|
}
|
|
[[nodiscard]] bool GetStatistics(uint64_t SerialNumber, std::string &Statistics) const;
|
|
|
|
inline bool GetState(const std::string &SerialNumber,
|
|
GWObjects::ConnectionState &State) const {
|
|
return GetState(Utils::SerialNumberToInt(SerialNumber), State);
|
|
}
|
|
bool GetState(uint64_t SerialNumber, GWObjects::ConnectionState &State) const;
|
|
|
|
inline bool GetHealthcheck(const std::string &SerialNumber,
|
|
GWObjects::HealthCheck &CheckData) const {
|
|
return GetHealthcheck(Utils::SerialNumberToInt(SerialNumber), CheckData);
|
|
}
|
|
bool GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck &CheckData) const;
|
|
|
|
bool Connected(uint64_t SerialNumber, GWObjects::DeviceRestrictions &Restrictions) const;
|
|
bool Connected(uint64_t SerialNumber) const;
|
|
bool Disconnect(uint64_t SerialNumber);
|
|
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,
|
|
std::size_t size);
|
|
bool SendRadiusCoAData(const std::string &SerialNumber, const unsigned char *buffer,
|
|
std::size_t size);
|
|
|
|
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<std::string> &TelemetryTypes);
|
|
void StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber);
|
|
void SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval,
|
|
uint64_t Lifetime,
|
|
const std::vector<std::string> &TelemetryTypes);
|
|
void StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber);
|
|
void GetTelemetryParameters(uint64_t SerialNumber, bool &TelemetryRunning,
|
|
uint64_t &TelemetryInterval, uint64_t &TelemetryWebSocketTimer,
|
|
uint64_t &TelemetryKafkaTimer,
|
|
uint64_t &TelemetryWebSocketCount,
|
|
uint64_t &TelemetryKafkaCount,
|
|
uint64_t &TelemetryWebSocketPackets,
|
|
uint64_t &TelemetryKafkaPackets);
|
|
|
|
bool GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector<std::string> & 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 {
|
|
Connections = NumberOfConnectedDevices_;
|
|
AverageConnectionTime = AverageDeviceConnectionTime_;
|
|
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) {
|
|
RX_ += bytes;
|
|
}
|
|
|
|
inline void AddTX(std::uint64_t bytes) {
|
|
TX_ += bytes;
|
|
}
|
|
|
|
inline void GetTotalDataStatistics(std::uint64_t &TX, std::uint64_t &RX) const {
|
|
TX = TX_;
|
|
RX = RX_;
|
|
}
|
|
|
|
bool KafkaDisableState() const { return KafkaDisableState_; }
|
|
bool KafkaDisableHealthChecks() const { return KafkaDisableHealthChecks_; }
|
|
|
|
inline void IncrementConnectionCount() {
|
|
++NumberOfConnectedDevices_;
|
|
}
|
|
|
|
inline void DecrementConnectionCount() {
|
|
--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_;
|
|
using SerialNumberMap = std::map<uint64_t /* serial number */,
|
|
std::shared_ptr<AP_WS_Connection>>;
|
|
std::array<SerialNumberMap,MACHashMax> SerialNumbers_;
|
|
mutable std::array<std::mutex,MACHashMax> SerialNumbersMutex_;
|
|
|
|
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
|
|
std::vector<Poco::Crypto::X509Certificate> ClientCasCerts_;
|
|
std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
|
|
Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 4, 256};
|
|
Poco::Net::SocketReactor Reactor_;
|
|
Poco::Thread ReactorThread_;
|
|
std::string SimulatorId_;
|
|
bool LookAtProvisioning_ = false;
|
|
bool UseDefaultConfig_ = true;
|
|
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;
|
|
|
|
std::uint64_t MismatchDepth_ = 2;
|
|
|
|
std::atomic_uint64_t NumberOfConnectedDevices_ = 0;
|
|
std::atomic_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::atomic_bool KafkaDisableState_=false,
|
|
KafkaDisableHealthChecks_=false;
|
|
|
|
Poco::Thread GarbageCollector_;
|
|
|
|
AP_WS_Server() noexcept
|
|
: SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {}
|
|
};
|
|
|
|
inline auto AP_WS_Server() { return AP_WS_Server::instance(); }
|
|
|
|
} // namespace OpenWifi
|