From 4c1b50a3aca068e21405a9ff78dc8ec867b63832 Mon Sep 17 00:00:00 2001 From: AlexandreRouma Date: Sat, 22 Jan 2022 02:30:08 +0100 Subject: [PATCH] Major bugfix in server --- core/src/gui/main_window.cpp | 4 +- core/src/gui/menus/source.cpp | 2 +- core/src/gui/menus/source.h | 2 +- core/src/gui/smgui.cpp | 23 +++++++++- core/src/server.cpp | 44 +++++++++++++------ core/src/server_protocol.h | 6 ++- make_macos_bundle.sh | 2 + .../sdrpp_server_source/src/main.cpp | 7 +++ .../src/sdrpp_server_client.cpp | 31 ++++++++++--- .../src/sdrpp_server_client.h | 12 ++++- 10 files changed, 104 insertions(+), 29 deletions(-) diff --git a/core/src/gui/main_window.cpp b/core/src/gui/main_window.cpp index de90d994..7e3f02b9 100644 --- a/core/src/gui/main_window.cpp +++ b/core/src/gui/main_window.cpp @@ -75,7 +75,7 @@ void MainWindow::init() { gui::menu.order.push_back(opt); } - gui::menu.registerEntry("Source", sourecmenu::draw, NULL); + gui::menu.registerEntry("Source", sourcemenu::draw, NULL); gui::menu.registerEntry("Sinks", sinkmenu::draw, NULL); gui::menu.registerEntry("Band Plan", bandplanmenu::draw, NULL); gui::menu.registerEntry("Display", displaymenu::draw, NULL); @@ -164,7 +164,7 @@ void MainWindow::init() { gui::waterfall.updatePalletteFromArray(colormaps::maps["Turbo"].map, colormaps::maps["Turbo"].entryCount); - sourecmenu::init(); + sourcemenu::init(); sinkmenu::init(); bandplanmenu::init(); displaymenu::init(); diff --git a/core/src/gui/menus/source.cpp b/core/src/gui/menus/source.cpp index f3b65b51..03124297 100644 --- a/core/src/gui/menus/source.cpp +++ b/core/src/gui/menus/source.cpp @@ -6,7 +6,7 @@ #include #include -namespace sourecmenu { +namespace sourcemenu { int offsetMode = 0; int sourceId = 0; double customOffset = 0.0; diff --git a/core/src/gui/menus/source.h b/core/src/gui/menus/source.h index ac9c7362..83cd5c7b 100644 --- a/core/src/gui/menus/source.h +++ b/core/src/gui/menus/source.h @@ -1,6 +1,6 @@ #pragma once -namespace sourecmenu { +namespace sourcemenu { void init(); void draw(void* ctx); } \ No newline at end of file diff --git a/core/src/gui/smgui.cpp b/core/src/gui/smgui.cpp index 534758af..5cac3122 100644 --- a/core/src/gui/smgui.cpp +++ b/core/src/gui/smgui.cpp @@ -290,6 +290,7 @@ namespace SmGui { // Validate and clear if invalid if (!validate()) { spdlog::error("Drawlist validation failed"); + //elements.clear(); return -1; } @@ -376,7 +377,10 @@ namespace SmGui { va_start(args, n); // Check if enough elements are left - if (elements.size() - firstId < n) { return false; } + if (firstId + n > elements.size()) { + va_end(args); + return false; + } // Check the type of each element for (int i = 0; i < n; i++) { @@ -400,29 +404,46 @@ namespace SmGui { DrawStep step = elements[i++].step; VALIDATE_WIDGET(4, DRAW_STEP_COMBO, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT) + E_VALIDATE_WIDGET(3, DRAW_STEP_BUTTON, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT) + E_VALIDATE_WIDGET(3, DRAW_STEP_COLUMNS, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_BOOL) + E_VALIDATE_WIDGET(2, DRAW_STEP_RADIO_BUTTON, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_BOOL) + E_VALIDATE_WIDGET(1, DRAW_STEP_LEFT_LABEL, DRAW_LIST_ELEM_TYPE_STRING) + E_VALIDATE_WIDGET(6, DRAW_STEP_SLIDER_INT, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT) + E_VALIDATE_WIDGET(6, DRAW_STEP_SLIDER_FLOAT_WITH_STEPS, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_INT) + E_VALIDATE_WIDGET(5, DRAW_STEP_INPUT_INT, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT) + E_VALIDATE_WIDGET(2, DRAW_STEP_CHECKBOX, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_BOOL) + E_VALIDATE_WIDGET(6, DRAW_STEP_SLIDER_FLOAT, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT) + E_VALIDATE_WIDGET(4, DRAW_STEP_INPUT_TEXT, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT) + E_VALIDATE_WIDGET(1, DRAW_STEP_TEXT, DRAW_LIST_ELEM_TYPE_STRING) + E_VALIDATE_WIDGET(5, DRAW_STEP_TEXT_COLORED, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_STRING) + E_VALIDATE_WIDGET(2, DRAW_STEP_OPEN_POPUP, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT) + E_VALIDATE_WIDGET(2, DRAW_STEP_BEGIN_POPUP, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT) + E_VALIDATE_WIDGET(6, DRAW_STEP_BEGIN_TABLE, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT) E_VALIDATE_WIDGET(2, DRAW_STEP_TABLE_NEXT_ROW, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_FLOAT) + E_VALIDATE_WIDGET(1, DRAW_STEP_TABLE_SET_COLUMN_INDEX, DRAW_LIST_ELEM_TYPE_INT) + E_VALIDATE_WIDGET(1, DRAW_STEP_SET_NEXT_ITEM_WIDTH, DRAW_LIST_ELEM_TYPE_FLOAT) } diff --git a/core/src/server.cpp b/core/src/server.cpp index a5b45f55..91074259 100644 --- a/core/src/server.cpp +++ b/core/src/server.cpp @@ -76,6 +76,7 @@ namespace server { std::string modulesDir = core::configManager.conf["modulesDirectory"]; std::vector modules = core::configManager.conf["modules"]; auto modList = core::configManager.conf["moduleInstances"].items(); + std::string sourceName = core::configManager.conf["source"]; core::configManager.release(); modulesDir = std::filesystem::absolute(modulesDir).string(); @@ -136,8 +137,9 @@ namespace server { sourceList.define(name, name); } - // TODO: Load sourceId from config - + // Load sourceId from config + sourceId = 0; + if (sourceList.keyExists(sourceName)) { sourceId = sourceList.keyId(sourceName); } sigpath::sourceManager.selectSource(sourceList[sourceId]); // TODO: Use command line option @@ -151,6 +153,29 @@ namespace server { } void _clientHandler(net::Conn conn, void* ctx) { + // Reject if someone else is already connected + if (client && client->isOpen()) { + spdlog::info("REJECTED Connection from {0}:{1}, another client is already connected.", "TODO", "TODO"); + + // Issue a disconnect command to the client + uint8_t buf[sizeof(PacketHeader) + sizeof(CommandHeader)]; + PacketHeader* tmp_phdr = (PacketHeader*)buf; + CommandHeader* tmp_chdr = (CommandHeader*)&buf[sizeof(PacketHeader)]; + tmp_phdr->size = sizeof(PacketHeader) + sizeof(CommandHeader); + tmp_phdr->type = PACKET_TYPE_COMMAND; + tmp_chdr->cmd = COMMAND_DISCONNECT; + conn->write(tmp_phdr->size, buf); + + // TODO: Find something cleaner + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + conn->close(); + + // Start another async accept + listener->acceptAsync(_clientHandler, NULL); + return; + } + spdlog::info("Connection from {0}:{1}", "TODO", "TODO"); client = std::move(conn); client->readAsync(sizeof(PacketHeader), rbuf, _packetHandler, NULL); @@ -192,17 +217,6 @@ namespace server { client->readAsync(sizeof(PacketHeader), rbuf, _packetHandler, NULL); } - // void _testServerHandler(dsp::complex_t* data, int count, void* ctx) { - // // Build data packet - // PacketHeader* hdr = (PacketHeader*)bbuf; - // hdr->type = PACKET_TYPE_BASEBAND; - // hdr->size = sizeof(PacketHeader) + (count * sizeof(dsp::complex_t)); - // memcpy(&bbuf[sizeof(PacketHeader)], data, count * sizeof(dsp::complex_t)); - - // // Write to network - // if (client && client->isOpen()) { client->write(hdr->size, bbuf); } - // } - void _testServerHandler(uint8_t* data, int count, void* ctx) { // Build data packet PacketHeader* hdr = (PacketHeader*)bbuf; @@ -279,7 +293,9 @@ namespace server { SmGui::ForceSync(); if (SmGui::Combo("##sdrpp_server_src_sel", &sourceId, sourceList.txt)) { sigpath::sourceManager.selectSource(sourceList[sourceId]); - // TODO: Save config + core::configManager.acquire(); + core::configManager.conf["source"] = sourceList.key(sourceId); + core::configManager.release(true); } if (running) { SmGui::EndDisabled(); } diff --git a/core/src/server_protocol.h b/core/src/server_protocol.h index 05649249..cec747d7 100644 --- a/core/src/server_protocol.h +++ b/core/src/server_protocol.h @@ -27,7 +27,8 @@ namespace server { COMMAND_SET_SAMPLE_TYPE, // Server to client - COMMAND_SET_SAMPLERATE = 0x80 + COMMAND_SET_SAMPLERATE = 0x80, + COMMAND_DISCONNECT }; enum Error { @@ -37,7 +38,7 @@ namespace server { ERROR_INVALID_ARGUMENT }; - // TODO: Pack +#pragma pack(push, 1) struct PacketHeader { uint32_t type; uint32_t size; @@ -46,4 +47,5 @@ namespace server { struct CommandHeader { uint32_t cmd; }; +#pragma pack(pop) } \ No newline at end of file diff --git a/make_macos_bundle.sh b/make_macos_bundle.sh index 4c909e64..8ef5bec5 100644 --- a/make_macos_bundle.sh +++ b/make_macos_bundle.sh @@ -38,9 +38,11 @@ bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/hackrf_source/hackrf_source.dylib bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/limesdr_source/limesdr_source.dylib bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/plutosdr_source/plutosdr_source.dylib +bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rfspace_source/rfspace_source.dylib bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rtl_sdr_source/rtl_sdr_source.dylib bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rtl_tcp_source/rtl_tcp_source.dylib bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/sdrplay_source/sdrplay_source.dylib +bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/sdrpp_server_source/sdrpp_server_source.dylib bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/soapy_source/soapy_source.dylib bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/spyserver_source/spyserver_source.dylib diff --git a/source_modules/sdrpp_server_source/src/main.cpp b/source_modules/sdrpp_server_source/src/main.cpp index 7a1c15c3..bfe82188 100644 --- a/source_modules/sdrpp_server_source/src/main.cpp +++ b/source_modules/sdrpp_server_source/src/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #define CONCAT(a, b) ((std::string(a) + b).c_str()) @@ -142,6 +143,10 @@ private: bool connected = (_this->client && _this->client->isOpen()); gui::mainWindow.playButtonLocked = !connected; + ImGui::GenericDialog("##sdrpp_srv_src_err_dialog", _this->serverBusy, GENERIC_DIALOG_BUTTONS_OK, [=](){ + ImGui::Text("This server is already in use."); + }); + if (connected) { style::beginDisabled(); } if (ImGui::InputText(CONCAT("##sdrpp_srv_srv_host_", _this->name), _this->hostname, 1023)) { config.acquire(); @@ -166,6 +171,7 @@ private: } catch (std::exception e) { spdlog::error("Could not connect to SDR: {0}", e.what()); + if (!strcmp(e.what(), "Server busy")) { _this->serverBusy = true; } } } else if (connected && ImGui::Button("Disconnect##sdrpp_srv_source", ImVec2(menuWidth, 0))) { @@ -238,6 +244,7 @@ private: bool running = false; double freq; + bool serverBusy = false; float datarate = 0; float frametimeCounter = 0; diff --git a/source_modules/sdrpp_server_source/src/sdrpp_server_client.cpp b/source_modules/sdrpp_server_source/src/sdrpp_server_client.cpp index 0aeb617d..09c66f2b 100644 --- a/source_modules/sdrpp_server_source/src/sdrpp_server_client.cpp +++ b/source_modules/sdrpp_server_source/src/sdrpp_server_client.cpp @@ -35,11 +35,10 @@ namespace server { // Start readers client->readAsync(sizeof(PacketHeader), rbuffer, tcpHandler, this); - // Default configuration - stop(); - // Ask for a UI - getUI(); + int res = getUI(); + if (res == -1) { throw std::runtime_error("Timed out"); } + else if (res == -2) { throw std::runtime_error("Server busy"); } } ClientClass::~ClientClass() { @@ -153,6 +152,23 @@ namespace server { _this->currentSampleRate = *(double*)_this->r_cmd_data; core::setInputSampleRate(_this->currentSampleRate); } + else if (_this->r_cmd_hdr->cmd == COMMAND_DISCONNECT) { + spdlog::error("Asked to disconnect by the server"); + _this->serverBusy = true; + + // Cancel waiters + std::vector toBeRemoved; + for (auto& [waiter, cmd] : _this->commandAckWaiters) { + waiter->cancel(); + toBeRemoved.push_back(waiter); + } + + // Remove handled waiters + for (auto& waiter : toBeRemoved) { + _this->commandAckWaiters.erase(waiter); + delete waiter; + } + } } else if (_this->r_pkt_hdr->type == PACKET_TYPE_COMMAND_ACK) { // Notify waiters @@ -184,7 +200,7 @@ namespace server { _this->client->readAsync(sizeof(PacketHeader), _this->rbuffer, tcpHandler, _this); } - void ClientClass::getUI() { + int ClientClass::getUI() { auto waiter = awaitCommandAck(COMMAND_GET_UI); sendCommand(COMMAND_GET_UI, 0); if (waiter->await(PROTOCOL_TIMEOUT_MS)) { @@ -192,9 +208,12 @@ namespace server { dl.load(r_cmd_data, r_pkt_hdr->size - sizeof(PacketHeader) - sizeof(CommandHeader)); } else { - spdlog::error("Timeout out after asking for UI"); + if (!serverBusy) { spdlog::error("Timeout out after asking for UI"); }; + waiter->handled(); + return serverBusy ? -2 : -1; } waiter->handled(); + return 0; } void ClientClass::sendPacket(PacketType type, int len) { diff --git a/source_modules/sdrpp_server_source/src/sdrpp_server_client.h b/source_modules/sdrpp_server_source/src/sdrpp_server_client.h index abf34626..172138b5 100644 --- a/source_modules/sdrpp_server_source/src/sdrpp_server_client.h +++ b/source_modules/sdrpp_server_source/src/sdrpp_server_client.h @@ -23,7 +23,7 @@ namespace server { public: bool await(int timeout) { std::unique_lock lck(readyMtx); - return readyCnd.wait_for(lck, std::chrono::milliseconds(timeout), [=](){ return dataReady; }); + return readyCnd.wait_for(lck, std::chrono::milliseconds(timeout), [=](){ return dataReady || canceled; }) && !canceled; } void handled() { @@ -49,16 +49,23 @@ namespace server { } } + void cancel() { + canceled = true; + notify(); + } + void reset() { std::lock_guard lck1(readyMtx); std::lock_guard lck2(handledMtx); dataReady = false; dataHandled = false; + canceled = false; } private: bool dataReady = false; bool dataHandled = false; + bool canceled = 0; std::condition_variable readyCnd; std::condition_variable handledCnd; @@ -86,11 +93,12 @@ namespace server { bool isOpen(); int bytes = 0; + bool serverBusy = false; private: static void tcpHandler(int count, uint8_t* buf, void* ctx); - void getUI(); + int getUI(); void sendPacket(PacketType type, int len); void sendCommand(Command cmd, int len);