From 9e44e4ba4fdb4e82f74f6f2f0acff73575b7e0ec Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Fri, 1 May 2020 22:38:45 -0500 Subject: [PATCH] Add server information to user interface and provide buttons to start and stop server, change port --- NetworkServer.cpp | 126 +++++++++++++++++++++--- NetworkServer.h | 18 +++- OpenRGB.pro | 22 ++--- main.cpp | 2 +- qt/OpenRGBDialog2.cpp | 179 ++++++++++++++++++++--------------- qt/OpenRGBDialog2.h | 6 +- qt/OpenRGBServerInfoPage.cpp | 47 ++++++++- qt/OpenRGBServerInfoPage.h | 11 ++- qt/OpenRGBServerInfoPage.ui | 44 +++++++-- 9 files changed, 341 insertions(+), 114 deletions(-) diff --git a/NetworkServer.cpp b/NetworkServer.cpp index 8e015bbd..3b845139 100644 --- a/NetworkServer.cpp +++ b/NetworkServer.cpp @@ -14,11 +14,60 @@ static void Sleep(unsigned int milliseconds) NetworkServer::NetworkServer(std::vector& control) : controllers(control) { - //Start a TCP server and launch threads - port.tcp_server("1337"); + port_num = 1337; + server_online = false; +} - //Start the connection thread - ConnectionThread = new std::thread(&NetworkServer::ConnectionThreadFunction, this); +unsigned short NetworkServer::GetPort() +{ + return port_num; +} + +bool NetworkServer::GetOnline() +{ + return server_online; +} + +void NetworkServer::SetPort(unsigned short new_port) +{ + if(server_online == false) + { + port_num = new_port; + } +} + +void NetworkServer::StartServer() +{ + //Start a TCP server and launch threads + char port_str[6]; + snprintf(port_str, 6, "%d", port_num); + + if(port.tcp_server(port_str)) + { + server_online = true; + + //Start the connection thread + ConnectionThread = new std::thread(&NetworkServer::ConnectionThreadFunction, this); + } +} + +void NetworkServer::StopServer() +{ + server_online = false; + + for(unsigned int client_idx = 0; client_idx < ServerClients.size(); client_idx++) + { + shutdown(*ServerClients[client_idx], SD_RECEIVE); + closesocket(*ServerClients[client_idx]); + ListenThreads[client_idx]->join(); + } + + port.tcp_close(); + + ConnectionThread->join(); + + ServerClients.clear(); + ListenThreads.clear(); } void NetworkServer::ConnectionThreadFunction() @@ -26,7 +75,7 @@ void NetworkServer::ConnectionThreadFunction() //This thread handles client connections printf("Network connection thread started\n"); - while(1) + while(server_online == true) { SOCKET * client_sock = port.tcp_server_listen(); @@ -34,6 +83,39 @@ void NetworkServer::ConnectionThreadFunction() std::thread * NewListenThread = new std::thread(&NetworkServer::ListenThreadFunction, this, client_sock); ListenThreads.push_back(NewListenThread); + ServerClients.push_back(client_sock); + } + + server_online = false; +} + +int NetworkServer::recv_select(SOCKET s, char *buf, int len, int flags) +{ + fd_set set; + struct timeval timeout; + timeout.tv_sec = 5; + timeout.tv_usec = 0; + + while(1) + { + FD_ZERO(&set); /* clear the set */ + FD_SET(s, &set); /* add our file descriptor to the set */ + + int rv = select(s + 1, &set, NULL, NULL, &timeout); + + if(rv == SOCKET_ERROR || server_online == false) + { + return 0; + } + else if(rv == 0) + { + continue; + } + else + { + // socket has something to read + return(recv(s, buf, len, flags)); + } } } @@ -41,14 +123,14 @@ void NetworkServer::ListenThreadFunction(SOCKET * client_sock) { printf("Network server started\n"); //This thread handles messages received from clients - while(1) + while(server_online == true) { NetPacketHeader header; int bytes_read = 0; char * data = NULL; //Read first byte of magic - bytes_read = recv(*client_sock, &header.pkt_magic[0], 1, 0); + bytes_read = recv_select(*client_sock, &header.pkt_magic[0], 1, 0); if(bytes_read == 0) { @@ -62,7 +144,7 @@ void NetworkServer::ListenThreadFunction(SOCKET * client_sock) } //Read second byte of magic - bytes_read = recv(*client_sock, &header.pkt_magic[1], 1, 0); + bytes_read = recv_select(*client_sock, &header.pkt_magic[1], 1, 0); if(bytes_read == 0) { @@ -76,7 +158,7 @@ void NetworkServer::ListenThreadFunction(SOCKET * client_sock) } //Read third byte of magic - bytes_read = recv(*client_sock, &header.pkt_magic[2], 1, 0); + bytes_read = recv_select(*client_sock, &header.pkt_magic[2], 1, 0); if(bytes_read == 0) { @@ -90,7 +172,7 @@ void NetworkServer::ListenThreadFunction(SOCKET * client_sock) } //Read fourth byte of magic - bytes_read = recv(*client_sock, &header.pkt_magic[3], 1, 0); + bytes_read = recv_select(*client_sock, &header.pkt_magic[3], 1, 0); if(bytes_read == 0) { @@ -107,12 +189,18 @@ void NetworkServer::ListenThreadFunction(SOCKET * client_sock) bytes_read = 0; do { - bytes_read += recv(*client_sock, (char *)&header.pkt_dev_idx + bytes_read, sizeof(header) - sizeof(header.pkt_magic) - bytes_read, 0); + int tmp_bytes_read = 0; - if(bytes_read == 0) + tmp_bytes_read = recv_select(*client_sock, (char *)&header.pkt_dev_idx + bytes_read, sizeof(header) - sizeof(header.pkt_magic) - bytes_read, 0); + + bytes_read += tmp_bytes_read; + + if(tmp_bytes_read == 0) { + printf("Server connection closed\r\n"); break; } + } while(bytes_read != sizeof(header) - sizeof(header.pkt_magic)); //printf( "Server: Received header, now receiving data of size %d\r\n", header.pkt_size); @@ -120,13 +208,23 @@ void NetworkServer::ListenThreadFunction(SOCKET * client_sock) //Header received, now receive the data if(header.pkt_size > 0) { - unsigned int bytes_read = 0; + bytes_read = 0; data = new char[header.pkt_size]; do { - bytes_read += recv(*client_sock, &data[bytes_read], header.pkt_size - bytes_read, 0); + int tmp_bytes_read = 0; + + tmp_bytes_read = recv_select(*client_sock, &data[bytes_read], header.pkt_size - bytes_read, 0); + + if(tmp_bytes_read == 0) + { + printf("Server connection closed\r\n"); + return; + } + bytes_read += tmp_bytes_read; + } while (bytes_read < header.pkt_size); } diff --git a/NetworkServer.h b/NetworkServer.h index cd286514..ad7aca85 100644 --- a/NetworkServer.h +++ b/NetworkServer.h @@ -11,18 +11,32 @@ class NetworkServer public: NetworkServer(std::vector& control); - void ConnectionThreadFunction(); - void ListenThreadFunction(SOCKET * client_sock); + unsigned short GetPort(); + bool GetOnline(); + + void SetPort(unsigned short new_port); + + void StartServer(); + void StopServer(); + + void ConnectionThreadFunction(); + void ListenThreadFunction(SOCKET * client_sock); void SendReply_ControllerCount(SOCKET * client_sock); void SendReply_ControllerData(SOCKET * client_sock, unsigned int dev_idx); protected: + unsigned short port_num; + bool server_online; + std::vector& controllers; + std::vector ServerClients; std::vector ListenThreads; std::thread * ConnectionThread; private: net_port port; + + int recv_select(SOCKET s, char *buf, int len, int flags); }; diff --git a/OpenRGB.pro b/OpenRGB.pro index 0a0eb409..7f604cc3 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -79,7 +79,7 @@ SOURCES += \ net_port/net_port.cpp \ qt/OpenRGBDialog2.cpp \ qt/OpenRGBProfileSaveDialog.cpp \ - qt/OpenRGBServerInfoPage.cpp \ + qt/OpenRGBServerInfoPage.cpp \ qt/OpenRGBSoftwareInfoPage.cpp \ qt/OpenRGBSystemInfoPage.cpp \ qt/OpenRGBZoneResizeDialog.cpp \ @@ -192,7 +192,7 @@ HEADERS += \ net_port/net_port.h \ qt/OpenRGBDialog2.h \ qt/OpenRGBProfileSaveDialog.h \ - qt/OpenRGBServerInfoPage.h \ + qt/OpenRGBServerInfoPage.h \ qt/OpenRGBSoftwareInfoPage.h \ qt/OpenRGBSystemInfoPage.h \ qt/OpenRGBZoneResizeDialog.h \ @@ -264,15 +264,15 @@ RESOURCES += \ qt/resources.qrc FORMS += \ - qt/OpenRGBDeviceInfoPage.ui \ - qt/OpenRGBDevicePage.ui \ - qt/OpenRGBDialog.ui \ - qt/OpenRGBDialog2.ui \ - qt/OpenRGBProfileSaveDialog.ui \ - qt/OpenRGBServerInfoPage.ui \ - qt/OpenRGBSoftwareInfoPage.ui \ - qt/OpenRGBSystemInfoPage.ui \ - qt/OpenRGBZoneResizeDialog.ui + qt/OpenRGBDeviceInfoPage.ui \ + qt/OpenRGBDevicePage.ui \ + qt/OpenRGBDialog.ui \ + qt/OpenRGBDialog2.ui \ + qt/OpenRGBProfileSaveDialog.ui \ + qt/OpenRGBServerInfoPage.ui \ + qt/OpenRGBSoftwareInfoPage.ui \ + qt/OpenRGBSystemInfoPage.ui \ + qt/OpenRGBZoneResizeDialog.ui \ #----------------------------------------------- # Windows specific project configuration diff --git a/main.cpp b/main.cpp index f4240697..c7f59eaa 100644 --- a/main.cpp +++ b/main.cpp @@ -52,7 +52,7 @@ int main(int argc, char* argv[]) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication a(argc, argv); - Ui::OpenRGBDialog2 dlg(busses, rgb_controllers, profile_manager); + Ui::OpenRGBDialog2 dlg(busses, rgb_controllers, &profile_manager, &server); dlg.show(); return a.exec(); diff --git a/qt/OpenRGBDialog2.cpp b/qt/OpenRGBDialog2.cpp index 94fb6ca1..b8263b51 100644 --- a/qt/OpenRGBDialog2.cpp +++ b/qt/OpenRGBDialog2.cpp @@ -1,6 +1,7 @@ #include "OpenRGBDialog2.h" #include "OpenRGBDevicePage.h" #include "OpenRGBDeviceInfoPage.h" +#include "OpenRGBServerInfoPage.h" #include "OpenRGBSoftwareInfoPage.h" #include "OpenRGBSystemInfoPage.h" #include "OpenRGBProfileSaveDialog.h" @@ -10,7 +11,7 @@ using namespace Ui; -OpenRGBDialog2::OpenRGBDialog2(std::vector& bus, std::vector& control, ProfileManager& manager, QWidget *parent) : QMainWindow(parent), busses(bus), controllers(control), profile_manager(manager), ui(new OpenRGBDialog2Ui) +OpenRGBDialog2::OpenRGBDialog2(std::vector& bus, std::vector& control, ProfileManager* manager, NetworkServer* server, QWidget *parent) : QMainWindow(parent), busses(bus), controllers(control), profile_manager(manager), network_server(server), ui(new OpenRGBDialog2Ui) { ui->setupUi(this); @@ -242,6 +243,16 @@ OpenRGBDialog2::OpenRGBDialog2(std::vector& bus, std::vec { InformationTabBar->setTabButton(control.size(), QTabBar::LeftSide, SoftwareTabLabel); } + + /*-----------------------------------------------------*\ + | Add server information tab if there is a server | + \*-----------------------------------------------------*/ + if(network_server != NULL) + { + OpenRGBServerInfoPage *ServerInfoPage = new OpenRGBServerInfoPage(network_server); + + ui->MainTabBar->addTab(ServerInfoPage, "SDK Server"); + } } OpenRGBDialog2::~OpenRGBDialog2() @@ -256,26 +267,29 @@ void OpenRGBDialog2::show() void OpenRGBDialog2::RefreshProfileList() { - /*-----------------------------------------------------*\ - | Clear profile combo box and tray icon menu | - \*-----------------------------------------------------*/ - ui->ProfileBox->clear(); - profileMenu->clear(); - - for(std::size_t profile_index = 0; profile_index < profile_manager.profile_list.size(); profile_index++) + if(profile_manager != NULL) { /*-----------------------------------------------------*\ - | Fill in profile combo box | + | Clear profile combo box and tray icon menu | \*-----------------------------------------------------*/ - ui->ProfileBox->addItem(profile_manager.profile_list[profile_index].c_str()); + ui->ProfileBox->clear(); + profileMenu->clear(); - /*-----------------------------------------------------*\ - | Fill in profile tray icon menu | - \*-----------------------------------------------------*/ - QAction* actionProfileSelected = new QAction(profile_manager.profile_list[profile_index].c_str(), this); - actionProfileSelected->setObjectName(profile_manager.profile_list[profile_index].c_str()); - connect(actionProfileSelected, SIGNAL(triggered()), this, SLOT(on_ProfileSelected())); - profileMenu->addAction(actionProfileSelected); + for(std::size_t profile_index = 0; profile_index < profile_manager->profile_list.size(); profile_index++) + { + /*-----------------------------------------------------*\ + | Fill in profile combo box | + \*-----------------------------------------------------*/ + ui->ProfileBox->addItem(profile_manager->profile_list[profile_index].c_str()); + + /*-----------------------------------------------------*\ + | Fill in profile tray icon menu | + \*-----------------------------------------------------*/ + QAction* actionProfileSelected = new QAction(profile_manager->profile_list[profile_index].c_str(), this); + actionProfileSelected->setObjectName(profile_manager->profile_list[profile_index].c_str()); + connect(actionProfileSelected, SIGNAL(triggered()), this, SLOT(on_ProfileSelected())); + profileMenu->addAction(actionProfileSelected); + } } } @@ -336,10 +350,13 @@ void OpenRGBDialog2::on_SetAllDevices(unsigned char red, unsigned char green, un void OpenRGBDialog2::on_SaveSizeProfile() { - /*---------------------------------------------------------*\ - | Save the profile | - \*---------------------------------------------------------*/ - profile_manager.SaveProfile("sizes.ors"); + if(profile_manager != NULL) + { + /*---------------------------------------------------------*\ + | Save the profile | + \*---------------------------------------------------------*/ + profile_manager->SaveProfile("sizes.ors"); + } } void OpenRGBDialog2::on_ShowHide() @@ -356,19 +373,22 @@ void OpenRGBDialog2::on_ShowHide() void Ui::OpenRGBDialog2::on_ProfileSelected() { - /*---------------------------------------------------------*\ - | Get the profile filename from the selected object | - \*---------------------------------------------------------*/ - std::string profile_name = QObject::sender()->objectName().toStdString(); - - /*---------------------------------------------------------*\ - | Load the profile | - \*---------------------------------------------------------*/ - if(profile_manager.LoadProfile(profile_name)) + if(profile_manager != NULL) { - for(int device = 0; device < ui->DevicesTabBar->count(); device++) + /*---------------------------------------------------------*\ + | Get the profile filename from the selected object | + \*---------------------------------------------------------*/ + std::string profile_name = QObject::sender()->objectName().toStdString(); + + /*---------------------------------------------------------*\ + | Load the profile | + \*---------------------------------------------------------*/ + if(profile_manager->LoadProfile(profile_name)) { - qobject_cast(ui->DevicesTabBar->widget(device))->UpdateDevice(); + for(int device = 0; device < ui->DevicesTabBar->count(); device++) + { + qobject_cast(ui->DevicesTabBar->widget(device))->UpdateDevice(); + } } } } @@ -377,64 +397,73 @@ void Ui::OpenRGBDialog2::on_ButtonSaveProfile_clicked() { OpenRGBProfileSaveDialog dialog; - /*---------------------------------------------------------*\ - | Open Profile Name Dialog | - \*---------------------------------------------------------*/ - std::string profile_name = dialog.show(); - - /*---------------------------------------------------------*\ - | Extension .orp - OpenRgb Profile | - \*---------------------------------------------------------*/ - std::string filename = profile_name + ".orp"; - - /*---------------------------------------------------------*\ - | Save the profile | - \*---------------------------------------------------------*/ - if(profile_manager.SaveProfile(filename)) + if(profile_manager != NULL) { - RefreshProfileList(); + /*---------------------------------------------------------*\ + | Open Profile Name Dialog | + \*---------------------------------------------------------*/ + std::string profile_name = dialog.show(); + + /*---------------------------------------------------------*\ + | Extension .orp - OpenRgb Profile | + \*---------------------------------------------------------*/ + std::string filename = profile_name + ".orp"; + + /*---------------------------------------------------------*\ + | Save the profile | + \*---------------------------------------------------------*/ + if(profile_manager->SaveProfile(filename)) + { + RefreshProfileList(); + } } } void Ui::OpenRGBDialog2::on_ButtonLoadProfile_clicked() { - /*---------------------------------------------------------*\ - | Get the profile filename from the profiles list | - \*---------------------------------------------------------*/ - std::string profile_name = ui->ProfileBox->currentText().toStdString(); - - /*---------------------------------------------------------*\ - | Load the profile | - \*---------------------------------------------------------*/ - if(profile_manager.LoadProfile(profile_name)) + if(profile_manager != NULL) { - for(int device = 0; device < ui->DevicesTabBar->count(); device++) + /*---------------------------------------------------------*\ + | Get the profile filename from the profiles list | + \*---------------------------------------------------------*/ + std::string profile_name = ui->ProfileBox->currentText().toStdString(); + + /*---------------------------------------------------------*\ + | Load the profile | + \*---------------------------------------------------------*/ + if(profile_manager->LoadProfile(profile_name)) { - qobject_cast(ui->DevicesTabBar->widget(device))->UpdateDevice(); + for(int device = 0; device < ui->DevicesTabBar->count(); device++) + { + qobject_cast(ui->DevicesTabBar->widget(device))->UpdateDevice(); + } } } } void Ui::OpenRGBDialog2::on_ButtonDeleteProfile_clicked() { - /*---------------------------------------------------------*\ - | Get the profile filename from the profiles list | - \*---------------------------------------------------------*/ - std::string profile_name = ui->ProfileBox->currentText().toStdString(); - - /*---------------------------------------------------------*\ - | Confirm we want to delete the profile | - \*---------------------------------------------------------*/ - QMessageBox::StandardButton reply; - reply = QMessageBox::question(this, "Delete Profile", "Do you really want to delete this profile?", QMessageBox::Yes|QMessageBox::No); - - /*---------------------------------------------------------*\ - | Load the profile | - \*---------------------------------------------------------*/ - if(reply == QMessageBox::Yes) + if(profile_manager != NULL) { - profile_manager.DeleteProfile(profile_name); + /*---------------------------------------------------------*\ + | Get the profile filename from the profiles list | + \*---------------------------------------------------------*/ + std::string profile_name = ui->ProfileBox->currentText().toStdString(); - RefreshProfileList(); + /*---------------------------------------------------------*\ + | Confirm we want to delete the profile | + \*---------------------------------------------------------*/ + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, "Delete Profile", "Do you really want to delete this profile?", QMessageBox::Yes|QMessageBox::No); + + /*---------------------------------------------------------*\ + | Load the profile | + \*---------------------------------------------------------*/ + if(reply == QMessageBox::Yes) + { + profile_manager->DeleteProfile(profile_name); + + RefreshProfileList(); + } } } diff --git a/qt/OpenRGBDialog2.h b/qt/OpenRGBDialog2.h index 87b91365..08cb9f2f 100644 --- a/qt/OpenRGBDialog2.h +++ b/qt/OpenRGBDialog2.h @@ -7,6 +7,7 @@ #include "i2c_smbus.h" #include "RGBController.h" #include "ProfileManager.h" +#include "NetworkServer.h" #include #include @@ -23,7 +24,7 @@ class Ui::OpenRGBDialog2 : public QMainWindow Q_OBJECT public: - explicit OpenRGBDialog2(std::vector& bus, std::vector& control, ProfileManager& manager, QWidget *parent = 0); + explicit OpenRGBDialog2(std::vector& bus, std::vector& control, ProfileManager* manager, NetworkServer* server, QWidget *parent = 0); ~OpenRGBDialog2(); void show(); @@ -32,7 +33,8 @@ public: protected: std::vector& busses; std::vector& controllers; - ProfileManager& profile_manager; + ProfileManager* profile_manager; + NetworkServer* network_server; private: Ui::OpenRGBDialog2Ui *ui; diff --git a/qt/OpenRGBServerInfoPage.cpp b/qt/OpenRGBServerInfoPage.cpp index 0e2cd0d7..c6b68bb5 100644 --- a/qt/OpenRGBServerInfoPage.cpp +++ b/qt/OpenRGBServerInfoPage.cpp @@ -2,14 +2,59 @@ using namespace Ui; -OpenRGBServerInfoPage::OpenRGBServerInfoPage(RGBController *dev, QWidget *parent) : +OpenRGBServerInfoPage::OpenRGBServerInfoPage(NetworkServer * server, QWidget *parent) : QFrame(parent), ui(new Ui::OpenRGBServerInfoPageUi) { + network_server = server; + ui->setupUi(this); + + UpdateInfo(); } OpenRGBServerInfoPage::~OpenRGBServerInfoPage() { delete ui; } + +void OpenRGBServerInfoPage::UpdateInfo() +{ + ui->ServerPortValue->setText(std::to_string(network_server->GetPort()).c_str()); + + if(network_server->GetOnline()) + { + ui->ServerStatusValue->setText("Online"); + ui->ServerStartButton->setEnabled(false); + ui->ServerStopButton->setEnabled(true); + ui->ServerPortValue->setEnabled(false); + } + else + { + ui->ServerStatusValue->setText("Offline"); + ui->ServerStartButton->setEnabled(true); + ui->ServerStopButton->setEnabled(false); + ui->ServerPortValue->setEnabled(true); + } +} + +void Ui::OpenRGBServerInfoPage::on_ServerStartButton_clicked() +{ + if(network_server->GetOnline() == false) + { + network_server->SetPort(ui->ServerPortValue->text().toInt()); + network_server->StartServer(); + + UpdateInfo(); + } +} + +void Ui::OpenRGBServerInfoPage::on_ServerStopButton_clicked() +{ + if(network_server->GetOnline() == true) + { + network_server->StopServer(); + + UpdateInfo(); + } +} diff --git a/qt/OpenRGBServerInfoPage.h b/qt/OpenRGBServerInfoPage.h index 6743eda4..8c72b911 100644 --- a/qt/OpenRGBServerInfoPage.h +++ b/qt/OpenRGBServerInfoPage.h @@ -4,6 +4,7 @@ #include #include "RGBController.h" #include "ui_OpenRGBServerInfoPage.h" +#include "NetworkServer.h" namespace Ui { class OpenRGBServerInfoPage; @@ -14,11 +15,19 @@ class Ui::OpenRGBServerInfoPage : public QFrame Q_OBJECT public: - explicit OpenRGBServerInfoPage(RGBController *dev, QWidget *parent = nullptr); + explicit OpenRGBServerInfoPage(NetworkServer * server, QWidget *parent = nullptr); ~OpenRGBServerInfoPage(); + void UpdateInfo(); + +private slots: + void on_ServerStartButton_clicked(); + + void on_ServerStopButton_clicked(); private: Ui::OpenRGBServerInfoPageUi *ui; + + NetworkServer* network_server; }; #endif // OPENRGBSERVERINFOPAGE_H diff --git a/qt/OpenRGBServerInfoPage.ui b/qt/OpenRGBServerInfoPage.ui index 1ed04331..b7d53447 100644 --- a/qt/OpenRGBServerInfoPage.ui +++ b/qt/OpenRGBServerInfoPage.ui @@ -14,6 +14,19 @@ Frame + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -28,7 +41,21 @@ - + + + + Server Port: + + + + + + + Start Server + + + + @@ -37,17 +64,20 @@ - - + + - Server Port: + Stop Server - - - 0 + + + + 0 + 0 +