From 06be179efe8bbc7e30f17aa6b81b31064f25b8a7 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Fri, 18 Mar 2022 16:36:59 -0400 Subject: [PATCH] re-roll dvmcmd into dvmhost as a proper secondary executable; --- Makefile | 26 ++- remote/DVMCmd.vcxproj | 173 +++++++++++++++++++ remote/DVMCmd.vcxproj.filters | 55 ++++++ remote/RemoteCommand.cpp | 306 ++++++++++++++++++++++++++++++++++ remote/RemoteCommand.h | 60 +++++++ 5 files changed, 613 insertions(+), 7 deletions(-) create mode 100644 remote/DVMCmd.vcxproj create mode 100644 remote/DVMCmd.vcxproj.filters create mode 100644 remote/RemoteCommand.cpp create mode 100644 remote/RemoteCommand.h diff --git a/Makefile b/Makefile index f4383c57..06e81bbc 100644 --- a/Makefile +++ b/Makefile @@ -9,12 +9,13 @@ rpi-armCXX = /opt/tools/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf rpi-armSTRIP= /opt/tools/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip CFLAGS = -g -O3 -Wall -std=c++0x -pthread -I. +CCFLAGS = -I.. EXTFLAGS= LIBS = -lpthread -lutil LDFLAGS = -g -BIN = dvmhost -OBJECTS = \ +HOST_BIN = dvmhost +HOST_OBJECTS = \ edac/AMBEFEC.o \ edac/BCH.o \ edac/BPTC19696.o \ @@ -88,16 +89,27 @@ OBJECTS = \ StopWatch.o \ Utils.o \ HostMain.o +CMD_BIN = dvmcmd +CMD_OBJECTS = \ + remote/RemoteCommand.cmd.o \ + edac/SHA256.cmd.o \ + network/UDPSocket.cmd.o \ + Log.cmd.o -all: dvmhost -dvmhost: $(OBJECTS) - $($(ARCH)CXX) $(OBJECTS) $(CFLAGS) $(EXTFLAGS) $(LIBS) -o $(BIN) +all: dvmhost dvmcmd +dvmhost: $(HOST_OBJECTS) + $($(ARCH)CXX) $(HOST_OBJECTS) $(CFLAGS) $(EXTFLAGS) $(LIBS) -o $(HOST_BIN) +dvmcmd: $(CMD_OBJECTS) + $($(ARCH)CXX) $(CMD_OBJECTS) $(CFLAGS) $(CCFLAGS) $(EXTFLAGS) $(LIBS) -o $(CMD_BIN) %.o: %.cpp $($(ARCH)CXX) $(CFLAGS) $(EXTFLAGS) -c -o $@ $< +%.cmd.o: %.cpp + $($(ARCH)CXX) $(CFLAGS) $(CCFLAGS) $(EXTFLAGS) -c -o $@ $< strip: - $($(ARCH)STRIP) $(BIN) + -$($(ARCH)STRIP) $(HOST_BIN) + -$($(ARCH)STRIP) $(CMD_BIN) clean: - $(RM) $(BIN) $(OBJECTS) *.o *.d *.bak *~ + $(RM) $(HOST_BIN) $(HOST_OBJECTS) $(CMD_BIN) $(CMD_OBJECTS) *.o *.d *.bak *~ $(RM) -r dpkg_build $(RM) dvmhost_1.0.0* dvmhost-dbgsym*.deb diff --git a/remote/DVMCmd.vcxproj b/remote/DVMCmd.vcxproj new file mode 100644 index 00000000..1e186e8f --- /dev/null +++ b/remote/DVMCmd.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {7686FC39-EC3C-4FAC-8C7D-32CF98D14F16} + Win32Proj + DVMCmd + dvmcmd + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir);$(IncludePath) + + + true + $(ProjectDir);$(IncludePath) + + + false + $(ProjectDir);$(IncludePath) + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + true + true + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + true + true + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/remote/DVMCmd.vcxproj.filters b/remote/DVMCmd.vcxproj.filters new file mode 100644 index 00000000..997fd1e5 --- /dev/null +++ b/remote/DVMCmd.vcxproj.filters @@ -0,0 +1,55 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {916a1400-af49-4141-912a-eb51ee88e24a} + + + {364613af-689a-40ff-9eb0-9ed75ec264d0} + + + {cf353bb3-7f93-4b59-98fa-c8c2db8a1afb} + + + {b8c3589b-0d9a-4adf-a14e-45530240b9cb} + + + + + Header Files + + + Header Files\network + + + Header Files + + + Header Files\edac + + + + + Source Files + + + Source Files\network + + + Source Files\edac + + + + + + + + \ No newline at end of file diff --git a/remote/RemoteCommand.cpp b/remote/RemoteCommand.cpp new file mode 100644 index 00000000..c27173e3 --- /dev/null +++ b/remote/RemoteCommand.cpp @@ -0,0 +1,306 @@ +/** +* Digital Voice Modem - Remote Command Client +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Remote Command Client +* +*/ +// +// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost) +// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) +// +/* +* Copyright (C) 2019 by Jonathan Naylor G4KLX +* Copyright (C) 2019 by Bryan Biedenkapp +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include "Defines.h" +#include "edac/SHA256.h" +#include "network/UDPSocket.h" +#include "RemoteCommand.h" +#include "Log.h" + +using namespace network; + +#include +#include +#include +#include + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +#undef __PROG_NAME__ +#define __PROG_NAME__ "Digital Voice Modem (DVM) RCON Tool" +#undef __EXE_NAME__ +#define __EXE_NAME__ "dvmcmd" + +const uint32_t START_OF_TEXT = 0x02; +const uint32_t REC_SEPARATOR = 0x1E; + +const uint32_t RC_BUFFER_LENGTH = 140U; + +// --------------------------------------------------------------------------- +// Macros +// --------------------------------------------------------------------------- +#define IS(s) (::strcmp(argv[i], s) == 0) + +// --------------------------------------------------------------------------- +// Global Variables +// --------------------------------------------------------------------------- + +static std::string g_progExe = std::string(__EXE_NAME__); +static std::string g_remoteAddress = std::string("127.0.0.1"); +static uint32_t g_remotePort = RCON_DEFAULT_PORT; +static std::string g_remotePassword = std::string(); + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +void fatal(const char* message) +{ + ::fprintf(stderr, "%s: %s\n", g_progExe.c_str(), message); + exit(EXIT_FAILURE); +} + +void usage(const char* message, const char* arg) +{ + ::fprintf(stdout, __PROG_NAME__ " %s (built %s)\r\n", __VER__, __BUILD__); + if (message != NULL) { + ::fprintf(stderr, "%s: ", g_progExe.c_str()); + ::fprintf(stderr, message, arg); + ::fprintf(stderr, "\n\n"); + } + + ::fprintf(stdout, "usage: %s [-v] [-a
] [-p ] [-P ] \n\n" + " -a remote modem command address\n" + " -p remote modem command port\n" + " -P remote modem authentication password\n" + "\n" + " -v show version information\n" + " -h show this screen\n" + " -- stop handling options\n", + g_progExe.c_str()); + exit(EXIT_FAILURE); +} + +int checkArgs(int argc, char* argv[]) +{ + int i, p = 0; + + // iterate through arguments + for (i = 1; i <= argc; i++) + { + if (argv[i] == NULL) { + break; + } + + if (*argv[i] != '-') { + continue; + } + else if (IS("--")) { + ++p; + break; + } + else if (IS("-a")) { + if ((argc - 1) <= 0) + usage("error: %s", "must specify the address to connect to"); + g_remoteAddress = std::string(argv[++i]); + + if (g_remoteAddress == "") + usage("error: %s", "remote address cannot be blank!"); + + p += 2; + } + else if (IS("-p")) { + if ((argc - 1) <= 0) + usage("error: %s", "must specify the port to connect to"); + g_remotePort = (uint32_t)::atoi(argv[++i]); + + if (g_remotePort == 0) + usage("error: %s", "remote port number cannot be blank or 0!"); + + p += 2; + } + else if (IS("-P")) { + if ((argc - 1) <= 0) + usage("error: %s", "must specify the auth password"); + g_remotePassword = std::string(argv[++i]); + + if (g_remotePassword == "") + usage("error: %s", "remote auth password cannot be blank!"); + + p += 2; + } + else if (IS("-v")) { + ::fprintf(stdout, __PROG_NAME__ " %s (built %s)\r\n", __VER__, __BUILD__); + if (argc == 2) + exit(EXIT_SUCCESS); + } + else if (IS("-h")) { + usage(NULL, NULL); + if (argc == 2) + exit(EXIT_SUCCESS); + } + else { + usage("unrecognized option `%s'", argv[i]); + } + } + + if (p < 0 || p > argc) { + p = 0; + } + + return ++p; +} + +// --------------------------------------------------------------------------- +// Program Entry Point +// --------------------------------------------------------------------------- + +int main(int argc, char** argv) +{ + if (argv[0] != NULL && *argv[0] != 0) + g_progExe = std::string(argv[0]); + + if (argc < 2) { + usage("error: %s", "must specify the remote command!"); + return EXIT_FAILURE; + } + + if (argc > 1) { + // check arguments + int i = checkArgs(argc, argv); + if (i < argc) { + argc -= i; + argv += i; + } + else { + argc--; + argv++; + } + } + + // process command + std::string cmd = std::string(argv[0]); + for (int i = 1; i < argc; i++) { + cmd += " "; + cmd += std::string(argv[i]); + } + + // initialize system logging + bool ret = ::LogInitialise("", "", 0U, 1U); + if (!ret) { + ::fprintf(stderr, "unable to open the log file\n"); + return 1; + } + + CRemoteCommand* command = new CRemoteCommand(g_remoteAddress, g_remotePort, g_remotePassword); + int retCode = command->send(cmd); + + ::LogFinalise(); + return retCode; +} + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- +/// +/// Initializes a new instance of the CRemoteCommand class. +/// +/// Network Hostname/IP address to connect to. +/// Network port number. +/// Authentication password. +CRemoteCommand::CRemoteCommand(const std::string& address, uint32_t port, const std::string& password) : + m_address(address), + m_port(port), + m_password(password) +{ + assert(!address.empty()); + assert(port > 0U); +} + +/// +/// Finalizes a instance of the CRemoteCommand class. +/// +CRemoteCommand::~CRemoteCommand() +{ + /* stub */ +} + +/// +/// Sends remote control command to the specified modem. +/// +/// Command string to send to remote modem. +/// EXIT_SUCCESS, if command was sent, otherwise EXIT_FAILURE. +int CRemoteCommand::send(const std::string& command) +{ + UDPSocket socket(0U); + + bool ret = socket.open(); + if (!ret) + return EXIT_FAILURE; + + uint8_t buffer[RC_BUFFER_LENGTH]; + ::memset(buffer, 0x00U, RC_BUFFER_LENGTH); + + sockaddr_storage addr; + uint32_t addrLen; + + if (UDPSocket::lookup(m_address, m_port, addr, addrLen) != 0) + addrLen = 0U; + + if (addrLen > 0U) { + return EXIT_FAILURE; + } + + ::LogInfoEx(LOG_HOST, "%s: sending command \"%s\" to %s:%u\r\n", g_progExe.c_str(), command.c_str(), + m_address.c_str(), m_port); + + buffer[0U] = START_OF_TEXT; + + if (!m_password.empty()) { + size_t size = m_password.size(); + + uint8_t* in = new uint8_t[size]; + for (size_t i = 0U; i < size; i++) + in[i] = m_password.at(i); + + uint8_t out[32U]; + ::memset(out, 0x00U, 32U); + + edac::SHA256 sha256; + sha256.buffer(in, (uint32_t)(size), out); + + ::memcpy(buffer + 1U, out, 32U); + } + + buffer[33U] = REC_SEPARATOR; + ::memcpy(buffer + 34U, command.c_str(), command.size()); + + ret = socket.write((uint8_t *)buffer, 34U + command.size(), addr, m_port); + if (!ret) { + socket.close(); + ::LogError(LOG_HOST, "Failed to send command: \"%s\"\r\n", command.c_str()); + return EXIT_FAILURE; + } + + socket.close(); + return EXIT_SUCCESS; +} diff --git a/remote/RemoteCommand.h b/remote/RemoteCommand.h new file mode 100644 index 00000000..6a38631e --- /dev/null +++ b/remote/RemoteCommand.h @@ -0,0 +1,60 @@ +/** +* Digital Voice Modem - Remote Command Client +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Remote Command Client +* +*/ +// +// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost) +// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) +// +/* +* Copyright (C) 2019 by Jonathan Naylor G4KLX +* Copyright (C) 2019 by Bryan Biedenkapp +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#if !defined(__REMOTE_COMMAND_H__) +#define __REMOTE_COMMAND_H__ + +#include "Defines.h" + +#include + +// --------------------------------------------------------------------------- +// Class Declaration +// This class implements the core remote command logic. +// --------------------------------------------------------------------------- + +class HOST_SW_API CRemoteCommand +{ +public: + /// Initializes a new instance of the CRemoteCommand class. + CRemoteCommand(const std::string& address, uint32_t port, const std::string& password); + /// Finalizes a instance of the CRemoteCommand class. + ~CRemoteCommand(); + + /// Sends remote control command to the specified modem. + int send(const std::string& command); + +private: + std::string m_address; + uint32_t m_port; + std::string m_password; +}; + +#endif // __REMOTE_COMMAND_H__