diff --git a/DGWRemoteControl/DGWRemoteControlApp.cpp b/DGWRemoteControl/DGWRemoteControlApp.cpp index d46cc0a..6f8c0fe 100644 --- a/DGWRemoteControl/DGWRemoteControlApp.cpp +++ b/DGWRemoteControl/DGWRemoteControlApp.cpp @@ -22,18 +22,22 @@ #include #include #include +#include +#include #include "DGWRemoteControlApp.h" +#include "DGWRemoteControlConfig.h" #include "Version.h" #include "ProgramArgs.h" -#include "Log.h" #include "DStarDefines.h" +#include "SHA256.h" const std::string NAME_OPTION("name"); const std::string REPEATER_PARAM("Callsign"); const std::string ACTION_PARAM("Action"); const std::string RECONNECT_PARAM("Param1"); const std::string REFLECTOR_PARAM("Param2"); +const std::string CONFIG_FILENAME("dgwremotecontrol.cfg"); int main(int argc, const char* argv[]) { @@ -49,6 +53,118 @@ int main(int argc, const char* argv[]) return 1; } + CDGWRemoteControlConfig config(std::string(CFG_DIR) + "/" + CONFIG_FILENAME); + TRemoteGateway gatewayConfig; + + if(!config.load() || !config.getGateway(name, gatewayConfig)) { + ::fprintf(stderr, "Configuration failed to load\n"); + return 1; + } + + std::string password(gatewayConfig.m_password); + + CRemoteControlRemoteControlHandler handler(gatewayConfig.m_address, gatewayConfig.m_port); + + bool ret = handler.open(); + if (!ret) { + ::fprintf(stderr, "dgwremotecontrol: unable to open the UDP port\n"); + return 1; + } + + ret = handler.login(); + if (!ret) { + handler.close(); + ::fprintf(stderr, "dgwremotecontrol: unable to login to the gateway/starnetserver\n"); + return 1; + } + + unsigned int count = 0U; + while (count < 10U) { + std::this_thread::sleep_for(std::chrono::milliseconds(100U)); + + RC_TYPE type = handler.readType(); + if (type == RCT_RANDOM) + break; + + if (type == RCT_NONE) + handler.retry(); + + count++; + } + + if (count >= 10U) { + handler.close(); + ::fprintf(stderr, "dgwremotecontrol: unable to get a response from the gateway/starnetserver\n"); + return 1; + } + + unsigned int rnd = handler.readRandom(); + sendHash(&handler, password, rnd); + + count = 0U; + while (count < 10U) { + std::this_thread::sleep_for(std::chrono::milliseconds(100U)); + + RC_TYPE type = handler.readType(); + if (type == RCT_ACK) + break; + + if (type == RCT_NAK) { + handler.close(); + ::fprintf(stderr, "dgwremotecontrol: invalid password sent to the gateway/starnetserver\n"); + return 1; + } + + if (type == RCT_NONE) + handler.retry(); + + count++; + } + + if (count >= 10U) { + handler.close(); + ::fprintf(stderr, "dgwremotecontrol: unable to get a response from the gateway/starnetserver\n"); + return 1; + } + + handler.setLoggedIn(true); + + if (actionText == "drop") + handler.logoff(repeater, user); + else + handler.link(repeater, reconnect, reflector); + + count = 0U; + while (count < 10U) { + std::this_thread::sleep_for(std::chrono::milliseconds(100U)); + + RC_TYPE type = handler.readType(); + if (type == RCT_ACK) + break; + + if (type == RCT_NAK) { + handler.close(); + ::fprintf(stderr, "dgwremotecontrol: drop/link/unlink command rejected by the gateway/starnetserver\n"); + return 1; + } + + if (type == RCT_NONE) + handler.retry(); + + count++; + } + + if (count >= 10U) { + handler.close(); + ::fprintf(stderr, "dgwremotecontrol: unable to get a response from the gateway/starnetserver\n"); + return 1; + } + + ::fprintf(stdout, "dgwremotecontrol: command accepted by the gateway/starnetserver\n"); + + handler.logout(); + handler.close(); + return 0; } @@ -76,7 +192,7 @@ bool getCLIParams(int argc, const char* argv[], std::string& name, std::string& actionText = boost::to_lower_copy(positionalArgs[1]); if(actionText != "link") { - CLog::logError("Invalid action %s. Expected link", positionalArgs[1].c_str()); + ::fprintf(stderr, "Invalid action %s. Expected link\n", positionalArgs[1].c_str()); ret = false; } @@ -94,7 +210,7 @@ bool getCLIParams(int argc, const char* argv[], std::string& name, std::string& else if(reconnectText == "180") reconnect = RECONNECT_180MINS; else if(reconnectText == "fixed") reconnect = RECONNECT_FIXED; else { - CLog::logError("Invalid reconnect value %s. Valid values are 5,10,15,20,25,30,60,90,120,180,fixed", positionalArgs[2].c_str()); + ::fprintf(stderr, "Invalid reconnect value %s. Valid values are 5,10,15,20,25,30,60,90,120,180,fixed\n", positionalArgs[2].c_str()); ret = false; } reflector = boost::to_upper_copy(positionalArgs[3]); @@ -105,7 +221,7 @@ bool getCLIParams(int argc, const char* argv[], std::string& name, std::string& repeater = positionalArgs[0]; actionText = boost::to_lower_copy(positionalArgs[1]); if(actionText != "unlink") { - CLog::logError("Invalid action %s. Expected unlink", positionalArgs[1].c_str()); + ::fprintf(stderr, "Invalid action %s. Expected unlink\n", positionalArgs[1].c_str()); ret = false; } reconnect = RECONNECT_NEVER; @@ -117,7 +233,7 @@ bool getCLIParams(int argc, const char* argv[], std::string& name, std::string& actionText = boost::to_lower_copy(positionalArgs[1]); if(actionText != "drop") { - CLog::logError("Invalid action %s. Expected drop", positionalArgs[1].c_str()); + ::fprintf(stderr, "Invalid action %s. Expected drop\n", positionalArgs[1].c_str()); ret = false; } @@ -138,3 +254,24 @@ bool getCLIParams(int argc, const char* argv[], std::string& name, std::string& return ret; } + +void sendHash(CRemoteControlRemoteControlHandler* handler, const std::string& password, unsigned int rnd) +{ + assert(handler != NULL); + + unsigned int len = password.length() + sizeof(unsigned int); + unsigned char* in = new unsigned char[len]; + unsigned char* out = new unsigned char[32U]; + + ::memcpy(in, &rnd, sizeof(unsigned int)); + for (unsigned int i = 0U; i < password.length(); i++) + in[i + sizeof(unsigned int)] = password.at(i); + + CSHA256 sha256; + sha256.buffer(in, len, out); + + handler->sendHash(out, 32U); + + delete[] in; + delete[] out; +} \ No newline at end of file diff --git a/DGWRemoteControl/DGWRemoteControlApp.h b/DGWRemoteControl/DGWRemoteControlApp.h index 39566a7..b23b6a1 100644 --- a/DGWRemoteControl/DGWRemoteControlApp.h +++ b/DGWRemoteControl/DGWRemoteControlApp.h @@ -21,5 +21,7 @@ #include #include "Defs.h" +#include "RemoteControlRemoteControlHandler.h" -bool getCLIParams(int argc, const char* argv[], std::string& name, std::string& repeater, std::string& actionText, RECONNECT& reconnect, std::string& user, std::string& reflector); \ No newline at end of file +bool getCLIParams(int argc, const char* argv[], std::string& name, std::string& repeater, std::string& actionText, RECONNECT& reconnect, std::string& user, std::string& reflector); +void sendHash(CRemoteControlRemoteControlHandler* handler, const std::string& password, unsigned int rnd); \ No newline at end of file diff --git a/DGWRemoteControl/DGWRemoteControlConfig.cpp b/DGWRemoteControl/DGWRemoteControlConfig.cpp index abce0c1..5a881d4 100644 --- a/DGWRemoteControl/DGWRemoteControlConfig.cpp +++ b/DGWRemoteControl/DGWRemoteControlConfig.cpp @@ -17,12 +17,78 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include + #include "DGWRemoteControlConfig.h" #include "Log.h" +#include "StringUtils.h" + +CDGWRemoteControlConfig::CDGWRemoteControlConfig(const std::string& fileName) : +m_fileName(fileName), +m_gateways() +{ + assert(!fileName.empty()); +} + +CDGWRemoteControlConfig::~CDGWRemoteControlConfig() +{ + for(auto gw : m_gateways) { + delete gw; + } + + m_gateways.clear(); +} + +bool CDGWRemoteControlConfig::load() +{ + CConfig cfg(m_fileName); + bool ret = open(cfg); + if(ret) { + ret = loadGateways(cfg) && ret; + } + + return ret; +} -bool load() +bool CDGWRemoteControlConfig::loadGateways(CConfig & cfg) { - return false; + for(unsigned int i = 1U; i <= 4U; i++) { + auto section = CStringUtils::string_format("gateway_%u", i); + TRemoteGateway * gateway = new TRemoteGateway(); + + bool ret = cfg.getValue(section, "name", gateway->m_name, 0U, 1024U, section); + ret = cfg.getValue(section, "address", gateway->m_address, 0U, 1024U, "127.0.0.1") && ret; + ret = cfg.getValue(section, "port", gateway->m_port, 1U, 65535U, 4242U) && ret; + ret = cfg.getValue(section, "password", gateway->m_password, 0U, 1024U, "") && ret; + + if(!ret || gateway->m_password.empty()) { + delete gateway; + continue; + } + + m_gateways.push_back(gateway); + } + + return m_gateways.size() != 0; +} + +bool CDGWRemoteControlConfig::getGateway(const std::string& name, TRemoteGateway& gateway) +{ + if(m_gateways.size() == 0U) + return false; + + for(auto gw : m_gateways) { + if(strcasecmp(name.c_str(), gw->m_name.c_str()) == 0) + { + gateway = *gw; + return true; + } + } + + gateway = *(m_gateways[0]); + + return true; } bool CDGWRemoteControlConfig::open(CConfig & cfg) diff --git a/DGWRemoteControl/DGWRemoteControlConfig.h b/DGWRemoteControl/DGWRemoteControlConfig.h index e587253..ea6ab43 100644 --- a/DGWRemoteControl/DGWRemoteControlConfig.h +++ b/DGWRemoteControl/DGWRemoteControlConfig.h @@ -20,22 +20,29 @@ #pragma once #include +#include #include "Config.h" typedef struct { - std::string callsign; - std::string address; + std::string m_name; + std::string m_address; + unsigned int m_port; + std::string m_password; } TRemoteGateway; class CDGWRemoteControlConfig { public: - CDGWRemoteControlConfig(const std::string& pathName); + CDGWRemoteControlConfig(const std::string& fileName); + ~CDGWRemoteControlConfig(); bool load(); + bool getGateway(const std::string& name, TRemoteGateway& gateway); private: bool open(CConfig& config); + bool loadGateways(CConfig& config); std::string m_fileName; + std::vector m_gateways; }; \ No newline at end of file diff --git a/DGWRemoteControl/dgwremotecontrol_example.cfg b/DGWRemoteControl/example.cfg similarity index 90% rename from DGWRemoteControl/dgwremotecontrol_example.cfg rename to DGWRemoteControl/example.cfg index 40e1395..5077c2b 100644 --- a/DGWRemoteControl/dgwremotecontrol_example.cfg +++ b/DGWRemoteControl/example.cfg @@ -2,11 +2,13 @@ # When invoking dgwremotecontrol without name parameter, the first gateway of the config file is used [gateway_1] +name=hill_top address=127.0.0.1 port=4242 password=CHANGE_ME [gateway_2] +name=city_center address=127.0.0.1 port=4242 password=CHANGE_ME