Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/protos/NetRemoteService.proto
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ service NetRemote
rpc WifiAccessPointsEnumerate (Microsoft.Net.Remote.Wifi.WifiAccessPointsEnumerateRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointsEnumerateResult);
rpc WifiAccessPointEnable (Microsoft.Net.Remote.Wifi.WifiAccessPointEnableRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointEnableResult);
rpc WifiAccessPointDisable (Microsoft.Net.Remote.Wifi.WifiAccessPointDisableRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointDisableResult);
rpc WifiAccessPointTimedEnable (Microsoft.Net.Remote.Wifi.WifiAccessPointTimedEnableRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointTimedEnableResult);
rpc WifiAccessPointTimedDisable (Microsoft.Net.Remote.Wifi.WifiAccessPointTimedDisableRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointTimedDisableResult);
rpc WifiAccessPointSetPhyType (Microsoft.Net.Remote.Wifi.WifiAccessPointSetPhyTypeRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointSetPhyTypeResult);
rpc WifiAccessPointSetFrequencyBands (Microsoft.Net.Remote.Wifi.WifiAccessPointSetFrequencyBandsRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointSetFrequencyBandsResult);
rpc WifiAccessPointSetSsid (Microsoft.Net.Remote.Wifi.WifiAccessPointSetSsidRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointSetSsidResult);
rpc WifiAccessPointSetNetworkBridge (Microsoft.Net.Remote.Wifi.WifiAccessPointSetNetworkBridgeRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointSetNetworkBridgeResult);
rpc WifiAccessPointSetAuthenticationDot1x (Microsoft.Net.Remote.Wifi.WifiAccessPointSetAuthenticationDot1xRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointSetAuthenticationDot1xResult);
rpc WifiAccessPointGetAttributes (Microsoft.Net.Remote.Wifi.WifiAccessPointGetAttributesRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointGetAttributesResult);

}
25 changes: 25 additions & 0 deletions api/protos/NetRemoteWifi.proto
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,28 @@ message WifiAccessPointGetAttributesResult
WifiAccessPointOperationStatus Status = 2;
Microsoft.Net.Wifi.Dot11AccessPointAttributes Attributes = 3;
}

message WifiAccessPointTimedEnableRequest
{
string AccessPointId = 1;
Microsoft.Net.Wifi.Dot11AccessPointConfiguration Configuration = 2;
uint32 DurationSeconds = 3; // Duration in seconds to keep the access point enabled
}

message WifiAccessPointTimedEnableResult
{
string AccessPointId = 1;
WifiAccessPointOperationStatus Status = 2;
}

message WifiAccessPointTimedDisableRequest
{
string AccessPointId = 1;
uint32 DurationSeconds = 2; // Duration in seconds to keep the access point disabled
}

message WifiAccessPointTimedDisableResult
{
string AccessPointId = 1;
WifiAccessPointOperationStatus Status = 2;
}
174 changes: 174 additions & 0 deletions src/common/service/NetRemoteService.cxx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@

#include <algorithm>
#include <atomic>
#include <chrono>
#include <cstddef>
#include <format>
#include <future>
#include <iterator>
#include <memory>
#include <ranges>
#include <string>
#include <string_view>
#include <thread>
#include <utility>
#include <vector>

Expand Down Expand Up @@ -279,6 +283,20 @@ NetRemoteService::NetRemoteService(std::shared_ptr<NetworkManager> networkManage
{
}

NetRemoteService::~NetRemoteService()
{
// Signal shutdown to all timer threads
m_shutdown = true;

// Wait for threads to complete outside of the lock
if (m_timedEnableThread && m_timedEnableThread->joinable()) {
m_timedEnableThread->join();
}
if (m_timedDisableThread && m_timedDisableThread->joinable()) {
m_timedDisableThread->join();
}
}

std::shared_ptr<AccessPointManager>
NetRemoteService::GetAccessPointManager() noexcept
{
Expand Down Expand Up @@ -435,6 +453,31 @@ NetRemoteService::WifiAccessPointGetAttributes([[maybe_unused]] grpc::ServerCont
return grpc::Status::OK;
}

grpc::Status
NetRemoteService::WifiAccessPointTimedEnable([[maybe_unused]] grpc::ServerContext* context, const WifiAccessPointTimedEnableRequest* request, WifiAccessPointTimedEnableResult* result)
{
const NetRemoteWifiApiTrace traceMe{ request->accesspointid(), result->mutable_status() };

const auto* dot11AccessPointConfiguration{ request->has_configuration() ? &request->configuration() : nullptr };
auto wifiOperationStatus = WifiAccessPointTimedEnableImpl(request->accesspointid(), dot11AccessPointConfiguration, request->durationseconds());
result->set_accesspointid(request->accesspointid());
*result->mutable_status() = std::move(wifiOperationStatus);

return grpc::Status::OK;
}

grpc::Status
NetRemoteService::WifiAccessPointTimedDisable([[maybe_unused]] grpc::ServerContext* context, const WifiAccessPointTimedDisableRequest* request, WifiAccessPointTimedDisableResult* result)
{
const NetRemoteWifiApiTrace traceMe{ request->accesspointid(), result->mutable_status() };

auto wifiOperationStatus = WifiAccessPointTimedDisableImpl(request->accesspointid(), request->durationseconds());
result->set_accesspointid(request->accesspointid());
*result->mutable_status() = std::move(wifiOperationStatus);

return grpc::Status::OK;
}

AccessPointOperationStatus
NetRemoteService::TryGetAccessPoint(std::string_view accessPointId, std::shared_ptr<IAccessPoint>& accessPoint)
{
Expand Down Expand Up @@ -642,6 +685,137 @@ NetRemoteService::WifiAccessPointDisableImpl(std::string_view accessPointId, std
return wifiOperationStatus;
}

WifiAccessPointOperationStatus
NetRemoteService::WifiAccessPointTimedEnableImpl(std::string_view accessPointId, const Dot11AccessPointConfiguration* dot11AccessPointConfiguration, uint32_t durationSeconds, std::shared_ptr<IAccessPointController> accessPointController)
{
WifiAccessPointOperationStatus wifiOperationStatus{};

// Validate duration - must be greater than 0 and cannot exceed 10 minutes (600 seconds)
constexpr uint32_t MaxDurationSeconds = 600;
if (durationSeconds == 0) {
wifiOperationStatus.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInvalidParameter);
wifiOperationStatus.set_message("Duration must be greater than 0 seconds");
return wifiOperationStatus;
}
if (durationSeconds > MaxDurationSeconds) {
wifiOperationStatus.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInvalidParameter);
wifiOperationStatus.set_message(std::format("Duration {} seconds exceeds maximum allowed duration of {} seconds", durationSeconds, MaxDurationSeconds));
return wifiOperationStatus;
}

// Check if a timed enable operation is already running, create and store the timer thread.
// Right now, this service only supports managing singale access point.
{
std::lock_guard<std::mutex> lock(m_threadsMutex);
if (m_timedEnableThread && m_timedEnableThread->joinable()) {
wifiOperationStatus.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeOperationNotSupported);
wifiOperationStatus.set_message("A timed enable operation is already in progress");
return wifiOperationStatus;
}

// Create and store the timer thread
auto timerThread = std::make_shared<std::thread>([this, accessPointId = std::string(accessPointId), hasConfiguration = (dot11AccessPointConfiguration != nullptr), configurationCopy = dot11AccessPointConfiguration ? *dot11AccessPointConfiguration : Dot11AccessPointConfiguration{}, accessPointController, durationSeconds]() {
// Sleep for the specified duration, checking every second for shutdown signal
uint32_t secondsElapsed = 0;
while (secondsElapsed < durationSeconds && !m_shutdown.load()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
secondsElapsed++;
}

// If we were shutdown, exit early
if (m_shutdown.load()) {
LOGI << std::format("Timed enable operation for access point {} was cancelled due to service shutdown", accessPointId);
return;
}

// Enable the access point after the duration expires
const auto* configPtr = hasConfiguration ? &configurationCopy : nullptr;
auto result = WifiAccessPointEnableImpl(accessPointId, configPtr, accessPointController);
if (result.code() != WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeSucceeded) {
LOGW << std::format("Failed to automatically enable access point {} after {} seconds: {}",
accessPointId,
durationSeconds,
result.message());
} else {
LOGI << std::format("Successfully automatically enabled access point {} after {} seconds",
accessPointId,
durationSeconds);
}
});

m_timedEnableThread = timerThread;
}

LOGI << std::format("Access point {} will be automatically enabled after {} seconds", accessPointId, durationSeconds);
wifiOperationStatus.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeSucceeded);
return wifiOperationStatus;
}

WifiAccessPointOperationStatus
NetRemoteService::WifiAccessPointTimedDisableImpl(std::string_view accessPointId, uint32_t durationSeconds, std::shared_ptr<IAccessPointController> accessPointController)
{
WifiAccessPointOperationStatus wifiOperationStatus{};

// Validate duration - must be greater than 0 and cannot exceed 10 minutes (600 seconds)
constexpr uint32_t MaxDurationSeconds = 600;
if (durationSeconds == 0) {
wifiOperationStatus.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInvalidParameter);
wifiOperationStatus.set_message("Duration must be greater than 0 seconds");
return wifiOperationStatus;
}
if (durationSeconds > MaxDurationSeconds) {
wifiOperationStatus.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInvalidParameter);
wifiOperationStatus.set_message(std::format("Duration {} seconds exceeds maximum allowed duration of {} seconds", durationSeconds, MaxDurationSeconds));
return wifiOperationStatus;
}

// Check if a timed disable operation is already running, if not, create and store the timer thread.
// Right now, this service only supports managing singale access point.
{
std::lock_guard<std::mutex> lock(m_threadsMutex);
if (m_timedDisableThread && m_timedDisableThread->joinable()) {
wifiOperationStatus.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeOperationNotSupported);
wifiOperationStatus.set_message("A timed disable operation is already in progress");
return wifiOperationStatus;
}

// Create and store the timer thread
auto timerThread = std::make_shared<std::thread>([this, accessPointId = std::string(accessPointId), accessPointController, durationSeconds]() {
// Sleep for the specified duration, checking every second for shutdown signal
uint32_t secondsElapsed = 0;
while (secondsElapsed < durationSeconds && !m_shutdown.load()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
secondsElapsed++;
}

// If we were shutdown, exit early
if (m_shutdown.load()) {
LOGI << std::format("Timed disable operation for access point {} was cancelled due to service shutdown", accessPointId);
return;
}

// Disable the access point using the existing implementation
auto result = WifiAccessPointDisableImpl(accessPointId, accessPointController);
if (result.code() != WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeSucceeded) {
LOGW << std::format("Failed to automatically disable access point {} after {} seconds: {}",
accessPointId,
durationSeconds,
result.message());
} else {
LOGI << std::format("Successfully automatically disabled access point {} after {} seconds",
accessPointId,
durationSeconds);
}
});

m_timedDisableThread = timerThread;
}

LOGI << std::format("Access point {} will be automatically disabled after {} seconds", accessPointId, durationSeconds);
wifiOperationStatus.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeSucceeded);
return wifiOperationStatus;
}

WifiAccessPointOperationStatus
NetRemoteService::WifiAccessPointSetPhyTypeImpl(std::string_view accessPointId, Dot11PhyType dot11PhyType, std::shared_ptr<IAccessPointController> accessPointController)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
#ifndef NET_REMOTE_SERVICE_HXX
#define NET_REMOTE_SERVICE_HXX

#include <atomic>
#include <memory>
#include <mutex>
#include <string>
#include <string_view>
#include <thread>
#include <unordered_map>

#include <google/protobuf/map.h>
#include <grpcpp/server_context.h>
Expand Down Expand Up @@ -37,6 +41,11 @@ public:
*/
explicit NetRemoteService(std::shared_ptr<Microsoft::Net::NetworkManager> networkManager) noexcept;

/**
* @brief Destructor that waits for all timer threads to complete.
*/
~NetRemoteService();

/**
* @brief Get the AccessPointManager object for this service.
*
Expand Down Expand Up @@ -159,6 +168,28 @@ private:
::grpc::Status
WifiAccessPointGetAttributes(grpc::ServerContext* context, const Microsoft::Net::Remote::Wifi::WifiAccessPointGetAttributesRequest* request, Microsoft::Net::Remote::Wifi::WifiAccessPointGetAttributesResult* result) override;

/**
* @brief Enable an access point after a specified duration.
*
* @param context
* @param request
* @param result
* @return ::grpc::Status
*/
::grpc::Status
WifiAccessPointTimedEnable(grpc::ServerContext* context, const Microsoft::Net::Remote::Wifi::WifiAccessPointTimedEnableRequest* request, Microsoft::Net::Remote::Wifi::WifiAccessPointTimedEnableResult* result) override;

/**
* @brief Disable an access point after a specified duration.
*
* @param context
* @param request
* @param result
* @return ::grpc::Status
*/
::grpc::Status
WifiAccessPointTimedDisable(grpc::ServerContext* context, const Microsoft::Net::Remote::Wifi::WifiAccessPointTimedDisableRequest* request, Microsoft::Net::Remote::Wifi::WifiAccessPointTimedDisableResult* result) override;

protected:
/**
* @brief Attempt to obtain an IAccessPoint instance for the specified access point identifier.
Expand Down Expand Up @@ -211,6 +242,29 @@ protected:
Microsoft::Net::Remote::Wifi::WifiAccessPointOperationStatus
WifiAccessPointDisableImpl(std::string_view accessPointId, std::shared_ptr<Microsoft::Net::Wifi::IAccessPointController> accessPointController = nullptr);

/**
* @brief Enable an access point after a specified duration.
*
* @param accessPointId The access point identifier.
* @param dot11AccessPointConfiguration The access point configuration to apply (optional).
* @param durationSeconds The duration in seconds to enable the access point.
* @param accessPointController The access point controller for the specified access point (optional).
* @return Microsoft::Net::Remote::Wifi::WifiAccessPointOperationStatus
*/
Microsoft::Net::Remote::Wifi::WifiAccessPointOperationStatus
WifiAccessPointTimedEnableImpl(std::string_view accessPointId, const Microsoft::Net::Wifi::Dot11AccessPointConfiguration* dot11AccessPointConfiguration, uint32_t durationSeconds, std::shared_ptr<Microsoft::Net::Wifi::IAccessPointController> accessPointController = nullptr);

/**
* @brief Disable an access point after a specified duration.
*
* @param accessPointId The access point identifier.
* @param durationSeconds The duration in seconds to disable the access point.
* @param accessPointController The access point controller for the specified access point (optional).
* @return Microsoft::Net::Remote::Wifi::WifiAccessPointOperationStatus
*/
Microsoft::Net::Remote::Wifi::WifiAccessPointOperationStatus
WifiAccessPointTimedDisableImpl(std::string_view accessPointId, uint32_t durationSeconds, std::shared_ptr<Microsoft::Net::Wifi::IAccessPointController> accessPointController = nullptr);

/**
* @brief Set the active PHY type of the access point. The access point must be enabled. This will cause
* the access point to temporarily go offline while the change is being applied.
Expand Down Expand Up @@ -329,6 +383,12 @@ protected:
private:
std::shared_ptr<Microsoft::Net::NetworkManager> m_networkManager;
std::shared_ptr<Microsoft::Net::Wifi::AccessPointManager> m_accessPointManager;

// Thread management for timed operations
std::mutex m_threadsMutex;
std::atomic<bool> m_shutdown{ false };
std::shared_ptr<std::thread> m_timedEnableThread;
std::shared_ptr<std::thread> m_timedDisableThread;
};
} // namespace Microsoft::Net::Remote::Service

Expand Down
Loading
Loading