mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2026-09-13 13:47:02 -04:00
When a connection dropped, the listener thread deleted all of that server's controllers immediately, before anything else was notified, so the GUI, ResourceManager, and plugins kept dereferencing freed controllers. Clicking Disconnect had the same problem and also ran the teardown inline on the GUI thread, where UpdateDeviceList's DEVICE_LIST_UPDATED is a BlockingQueuedConnection back to that thread, so the device pages were not torn down before the controllers were freed and a later queued onDetectionEnded dereferenced them. Neither path frees controllers inline now. NetworkClient moves them to an orphaned list and a dedicated teardown thread frees them: plugins are warned first, then the same DETECTION_STARTED, UpdateDeviceList, DETECTION_COMPLETE sequence a rescan runs tears down the device pages that still reference the controllers, and only then are they freed, so a controller always outlives its page. Both the connection-loss path and the disconnect button queue to that thread, so the blocking handler runs on the GUI thread while the controllers are still alive, and StopClient's join stays off the GUI and listener threads.
322 lines
19 KiB
C++
322 lines
19 KiB
C++
/*---------------------------------------------------------*\
|
|
| NetworkClient.h |
|
|
| |
|
|
| OpenRGB SDK network client |
|
|
| |
|
|
| Adam Honse (CalcProgrammer1) 09 May 2020 |
|
|
| |
|
|
| This file is part of the OpenRGB project |
|
|
| SPDX-License-Identifier: GPL-2.0-or-later |
|
|
\*---------------------------------------------------------*/
|
|
|
|
#pragma once
|
|
|
|
#include <condition_variable>
|
|
#include <list>
|
|
#include <mutex>
|
|
#include <queue>
|
|
#include <thread>
|
|
#include <condition_variable>
|
|
#include "i2c_smbus.h"
|
|
#include "ResourceManager.h"
|
|
#include "RGBController.h"
|
|
#include "NetworkProtocol.h"
|
|
#include "net_port.h"
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Callback Types |
|
|
\*---------------------------------------------------------*/
|
|
typedef void (*NetworkClientCallback)(void*, unsigned int);
|
|
|
|
/*---------------------------------------------------------*\
|
|
| NetworkClient Update Reason Codes |
|
|
\*---------------------------------------------------------*/
|
|
enum
|
|
{
|
|
NETWORKCLIENT_UPDATE_REASON_CLIENT_STARTED, /* Client started */
|
|
NETWORKCLIENT_UPDATE_REASON_CLIENT_STOPPED, /* Client stopped */
|
|
NETWORKCLIENT_UPDATE_REASON_CLIENT_CONNECTED, /* Client connectedd */
|
|
NETWORKCLIENT_UPDATE_REASON_CLIENT_DISCONNECTED, /* Client disconnected */
|
|
NETWORKCLIENT_UPDATE_REASON_SERVER_STRING_RECEIVED, /* Server string received */
|
|
NETWORKCLIENT_UPDATE_REASON_PROTOCOL_NEGOTIATED, /* Protocol version negotiated */
|
|
NETWORKCLIENT_UPDATE_REASON_DEVICE_LIST_UPDATED, /* Device list updated */
|
|
NETWORKCLIENT_UPDATE_REASON_DETECTION_STARTED, /* Detection started */
|
|
NETWORKCLIENT_UPDATE_REASON_DETECTION_PROGRESS_CHANGED, /* Detection progress changed */
|
|
NETWORKCLIENT_UPDATE_REASON_DETECTION_COMPLETE, /* Detection completed */
|
|
NETWORKCLIENT_UPDATE_REASON_PROFILEMANAGER_PROFILE_LIST_UPDATED, /* Profile list updated */
|
|
NETWORKCLIENT_UPDATE_REASON_PROFILEMANAGER_ACTIVE_PROFILE_CHANGED, /* Active profile changed */
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
NetPacketHeader header;
|
|
unsigned char* data;
|
|
} NetworkClientListenerThreadQueueEntry;
|
|
|
|
typedef struct
|
|
{
|
|
unsigned int id;
|
|
unsigned int index;
|
|
std::queue<NetworkClientListenerThreadQueueEntry> queue;
|
|
std::mutex queue_mutex;
|
|
std::mutex start_mutex;
|
|
std::condition_variable start_cv;
|
|
std::thread* thread;
|
|
std::atomic<bool> online;
|
|
} NetworkClientListenerThread;
|
|
|
|
class NetworkClient
|
|
{
|
|
public:
|
|
NetworkClient();
|
|
~NetworkClient();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Client Information functions |
|
|
\*-----------------------------------------------------*/
|
|
bool GetConnected();
|
|
std::string GetIP();
|
|
bool GetLocal();
|
|
unsigned short GetPort();
|
|
unsigned int GetProtocolVersion();
|
|
bool GetOnline();
|
|
std::string GetServerName();
|
|
bool GetSupportsRGBControllerAPI();
|
|
bool GetSupportsLogManagerAPI();
|
|
bool GetSupportsProfileManagerAPI();
|
|
bool GetSupportsPluginManagerAPI();
|
|
bool GetSupportsSettingsManagerAPI();
|
|
bool GetSupportsDetectionAPI();
|
|
bool GetSupportsDeviceInfoAPI();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Client Control functions |
|
|
\*-----------------------------------------------------*/
|
|
void RequestLocalClient(bool request_local);
|
|
void SetIP(std::string new_ip);
|
|
void SetName(std::string new_name);
|
|
void SetPort(unsigned short new_port);
|
|
|
|
void StartClient();
|
|
void StopClient();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Controller teardown functions |
|
|
\*-----------------------------------------------------*/
|
|
void DeleteOrphanedControllers();
|
|
void TakeOrphanedControllers(std::vector<RGBController*>& orphaned);
|
|
|
|
void SendRequest_ControllerData(unsigned int dev_id);
|
|
void SendRequest_RescanDevices();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Client Callback functions |
|
|
\*-----------------------------------------------------*/
|
|
void ClearCallbacks();
|
|
void RegisterNetworkClientCallback(NetworkClientCallback new_callback, void* new_callback_arg);
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Device Info Functions |
|
|
\*-----------------------------------------------------*/
|
|
std::vector<HIDDeviceInfo> GetHIDDeviceInfo();
|
|
std::vector<i2c_smbus_info> GetI2CBusInfo();
|
|
std::vector<std::string> GetSerialPorts();
|
|
std::vector<USBDeviceInfo> GetUSBDeviceInfo();
|
|
std::vector<SerialDeviceInfo> GetUSBSerialPorts();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| DetectionManager functions |
|
|
\*-----------------------------------------------------*/
|
|
unsigned int DetectionManager_GetDetectionPercent();
|
|
std::string DetectionManager_GetDetectionString();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| LogManager functions |
|
|
\*-----------------------------------------------------*/
|
|
void LogManager_ClearLogBuffer();
|
|
void LogManager_GetLogBuffer();
|
|
unsigned int LogManager_GetLogLevel();
|
|
void LogManager_SetLogLevel(unsigned int log_level);
|
|
|
|
/*-----------------------------------------------------*\
|
|
| ProfileManager functions |
|
|
\*-----------------------------------------------------*/
|
|
void ProfileManager_GetProfileList();
|
|
void ProfileManager_LoadProfile(std::string profile_name);
|
|
void ProfileManager_SaveProfile(std::string profile_name);
|
|
void ProfileManager_DeleteProfile(std::string profile_name);
|
|
void ProfileManager_UploadProfile(std::string profile_json_str);
|
|
std::string ProfileManager_DownloadProfile(std::string profile_name);
|
|
std::string ProfileManager_GetActiveProfile();
|
|
void ProfileManager_ClearActiveProfile();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| SettingsManager functions |
|
|
\*-----------------------------------------------------*/
|
|
std::string SettingsManager_GetSettings(std::string settings_key);
|
|
std::string SettingsManager_GetSettingsSchema(std::string settings_key);
|
|
void SettingsManager_ModifySettings(std::string settings_json_str);
|
|
void SettingsManager_SaveSettings();
|
|
void SettingsManager_SetSettings(std::string settings_json_str);
|
|
|
|
/*-----------------------------------------------------*\
|
|
| RGBController functions |
|
|
\*-----------------------------------------------------*/
|
|
std::vector<RGBController*>& GetRGBControllers();
|
|
|
|
void SendRequest_RGBController_ClearSegments(unsigned int dev_idx, int zone);
|
|
void SendRequest_RGBController_AddSegment(unsigned int dev_idx, unsigned char* data_ptr, unsigned int data_size);
|
|
void SendRequest_RGBController_ConfigureZone(unsigned int dev_idx, unsigned char* data_ptr, unsigned int data_size);
|
|
void SendRequest_RGBController_ResizeZone(unsigned int dev_idx, int zone, int new_size);
|
|
void SendRequest_RGBController_ConfigureDevice(unsigned int dev_idx, unsigned char* data_ptr, unsigned int data_size);
|
|
void SendRequest_RGBController_SetHidden(unsigned int dev_idx, bool hidden);
|
|
|
|
void SendRequest_RGBController_UpdateLEDs(unsigned int dev_idx, unsigned char* data_ptr, unsigned int data_size);
|
|
void SendRequest_RGBController_UpdateZoneLEDs(unsigned int dev_idx, unsigned char* data_ptr, unsigned int data_size);
|
|
void SendRequest_RGBController_UpdateSingleLED(unsigned int dev_idx, unsigned char* data_ptr, unsigned int data_size);
|
|
|
|
void SendRequest_RGBController_SetCustomMode(unsigned int dev_idx);
|
|
|
|
void SendRequest_RGBController_UpdateMode(unsigned int dev_idx, unsigned char* data_ptr, unsigned int data_size);
|
|
void SendRequest_RGBController_UpdateZoneMode(unsigned int dev_idx, unsigned char* data_ptr, unsigned int data_size);
|
|
void SendRequest_RGBController_SaveMode(unsigned int dev_idx, unsigned char* data_ptr, unsigned int data_size);
|
|
|
|
void SendRequest_RGBController_SetDeviceSpecificConfiguration(unsigned int dev_idx, unsigned char* data_ptr, unsigned int data_size);
|
|
void SendRequest_RGBController_SetDeviceSpecificZoneConfiguration(unsigned int dev_idx, unsigned char* data_ptr, unsigned int data_size);
|
|
|
|
void WaitOnControllerData();
|
|
|
|
private:
|
|
/*-----------------------------------------------------*\
|
|
| Client state variables |
|
|
\*-----------------------------------------------------*/
|
|
std::atomic<bool> client_active;
|
|
bool client_flags_sent;
|
|
bool client_is_local_client;
|
|
bool client_string_sent;
|
|
bool controller_data_received;
|
|
bool controller_data_requested;
|
|
bool protocol_initialized;
|
|
unsigned int protocol_version;
|
|
bool change_in_progress;
|
|
unsigned int requested_controller_index;
|
|
std::mutex send_in_progress;
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Response queue |
|
|
\*-----------------------------------------------------*/
|
|
std::list<NetworkClientListenerThreadQueueEntry>
|
|
response_queue;
|
|
std::mutex response_queue_mutex;
|
|
std::condition_variable response_queue_cv;
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Client information |
|
|
\*-----------------------------------------------------*/
|
|
unsigned int client_flags;
|
|
std::string client_name;
|
|
SOCKET client_sock;
|
|
net_port port;
|
|
std::string port_ip;
|
|
unsigned short port_num;
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Server information |
|
|
\*-----------------------------------------------------*/
|
|
unsigned int server_flags;
|
|
bool server_flags_initialized;
|
|
std::string server_name;
|
|
bool server_connected;
|
|
bool server_initialized;
|
|
bool server_reinitialize;
|
|
bool server_controller_ids_requested;
|
|
bool server_controller_ids_received;
|
|
unsigned int server_protocol_version;
|
|
bool server_protocol_version_received;
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Client threads |
|
|
\*-----------------------------------------------------*/
|
|
std::mutex connection_mutex;
|
|
std::condition_variable connection_cv;
|
|
std::thread * ConnectionThread;
|
|
std::thread * ListenThread;
|
|
NetworkClientListenerThread* profilemanager_thread;
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Callbacks |
|
|
\*-----------------------------------------------------*/
|
|
std::mutex NetworkClientCallbackMutex;
|
|
std::vector<NetworkClientCallback> NetworkClientCallbacks;
|
|
std::vector<void *> NetworkClientCallbackArgs;
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Controller list |
|
|
\*-----------------------------------------------------*/
|
|
std::mutex ControllerListMutex;
|
|
std::vector<RGBController*> server_controllers;
|
|
std::vector<RGBController*> orphaned_controllers;
|
|
std::vector<unsigned int> server_controller_ids;
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Detection variables |
|
|
\*-----------------------------------------------------*/
|
|
unsigned int detection_percent;
|
|
std::string detection_string;
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Client callback signal functions |
|
|
\*-----------------------------------------------------*/
|
|
void SignalNetworkClientUpdate(unsigned int update_reason);
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Client thread functions |
|
|
\*-----------------------------------------------------*/
|
|
void ConnectionThreadFunction();
|
|
void ListenThreadFunction();
|
|
void ProfileManagerListenThread(NetworkClientListenerThread* this_thread);
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Private Client functions |
|
|
\*-----------------------------------------------------*/
|
|
void ProcessReply_ControllerData(unsigned int data_size, unsigned char* data_ptr, unsigned int dev_id);
|
|
void ProcessReply_ControllerIDs(unsigned int data_size, unsigned char* data_ptr);
|
|
void ProcessReply_ProtocolVersion(unsigned int data_size, unsigned char* data_ptr);
|
|
void ProcessRequest_DetectionProgressChanged(unsigned int data_size, unsigned char* data_ptr);
|
|
void ProcessRequest_DeviceListChanged();
|
|
void ProcessRequest_RGBController_SignalUpdate(unsigned int data_size, unsigned char* data_ptr, unsigned int dev_id);
|
|
void ProcessRequest_ServerFlags(unsigned int data_size, unsigned char* data_ptr);
|
|
void ProcessRequest_ServerString(unsigned int data_size, unsigned char* data_ptr);
|
|
|
|
void ProcessRequest_LogManager_LoggedEntry(unsigned int data_size, unsigned char* data_ptr);
|
|
|
|
void ProcessRequest_ProfileManager_ActiveProfileChanged(unsigned int data_size, unsigned char* data_ptr);
|
|
void ProcessRequest_ProfileManager_ProfileAboutToLoad();
|
|
void ProcessRequest_ProfileManager_ProfileListUpdated(unsigned int data_size, unsigned char* data_ptr);
|
|
void ProcessRequest_ProfileManager_ProfileLoaded(unsigned int data_size, unsigned char* data_ptr);
|
|
|
|
void SendData_ClientFlags();
|
|
void SendData_ClientString();
|
|
void SendRequest_ControllerIDs();
|
|
void SendRequest_ProtocolVersion();
|
|
|
|
void UpdateDeviceList(RGBController* new_controller);
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Private ProfileManager functions |
|
|
\*-----------------------------------------------------*/
|
|
std::vector<std::string>* ProcessReply_ProfileList(unsigned int data_size, unsigned char* data_ptr);
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Response queue helper |
|
|
\*-----------------------------------------------------*/
|
|
NetworkClientListenerThreadQueueEntry
|
|
WaitForResponse(unsigned int expected_pkt_id);
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Private helper functions |
|
|
\*-----------------------------------------------------*/
|
|
RGBController * controller_from_id(unsigned int id);
|
|
int recv_select(SOCKET s, char *buf, int len, int flags);
|
|
};
|