From 398a4fdb87b3f7fa64b7025d724a112c4b8937b8 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Thu, 5 Apr 2018 10:58:21 -0700 Subject: [PATCH] no threads in mmdvm service --- Makefile | 4 +- UDPSocket.cpp | 172 ++++++++++++++++++++++++++++++++++++++++++++++++ UDPSocket.h | 53 +++++++++++++++ mmdvm_modem.cpp | 58 ++++++++++------ mmdvm_modem.h | 16 ++--- 5 files changed, 271 insertions(+), 32 deletions(-) create mode 100644 UDPSocket.cpp create mode 100644 UDPSocket.h diff --git a/Makefile b/Makefile index 98313fe..cba453d 100644 --- a/Makefile +++ b/Makefile @@ -42,8 +42,8 @@ g2_ircddb : $(IRCOBJS) g2_ircddb.o aprs.o g2_link : g2_link.o g++ $(CPPFLAGS) -o g2_link g2_link.o $(LDFLAGS) -pthread -mmdvm_modem : mmdvm_modem.o - g++ $(CPPFLAGS) -o mmdvm_modem mmdvm_modem.o $(LDFLAGS) -pthread +mmdvm_modem : mmdvm_modem.o UDPSocket.o + g++ $(CPPFLAGS) -o mmdvm_modem mmdvm_modem.o UDPSocket.o $(LDFLAGS) dvap_rptr : dvap_rptr.o DVAPDongle.o $(DSTROBJS) g++ $(CPPFLAGS) -o dvap_rptr dvap_rptr.o DVAPDongle.o $(DSTROBJS) $(LDFLAGS) -pthread diff --git a/UDPSocket.cpp b/UDPSocket.cpp new file mode 100644 index 0000000..3d4b8f2 --- /dev/null +++ b/UDPSocket.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2006-2016 by Jonathan Naylor G4KLX + * Copyright (c) 2018 by Thomas A. Early N7TAE + * + * 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 "UDPSocket.h" + +#include +#include + +#include +#include + + +CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) : +m_address(address), +m_port(port), +m_fd(-1) +{ +} + +CUDPSocket::CUDPSocket(unsigned int port) : +m_address(), +m_port(port), +m_fd(-1) +{ +} + +CUDPSocket::~CUDPSocket() +{ +} + +in_addr CUDPSocket::lookup(const std::string& hostname) +{ + in_addr addr; + in_addr_t address = ::inet_addr(hostname.c_str()); + if (address != in_addr_t(-1)) { + addr.s_addr = address; + return addr; + } + + struct hostent* hp = ::gethostbyname(hostname.c_str()); + if (hp != NULL) { + ::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr)); + return addr; + } + + printf("Cannot find address for host %s", hostname.c_str()); + + addr.s_addr = INADDR_NONE; + return addr; +} + +bool CUDPSocket::open() // returns false on error +{ + m_fd = ::socket(PF_INET, SOCK_DGRAM, 0); + if (m_fd < 0) { + printf("Cannot create the UDP socket, err: %d", errno); + return false; + } + + if (m_port > 0U) { + sockaddr_in addr; + ::memset(&addr, 0x00, sizeof(sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(m_port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + if (!m_address.empty()) { + addr.sin_addr.s_addr = ::inet_addr(m_address.c_str()); + if (addr.sin_addr.s_addr == INADDR_NONE) { + printf("The local address is invalid - %s", m_address.c_str()); + return false; + } + } + + int reuse = 1; + if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { + printf("Cannot set the UDP socket option, err: %d", errno); + return false; + } + + if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { + printf("Cannot bind the UDP address, err: %d", errno); + return false; + } + } + + return true; +} + +int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port) +{ + assert(buffer != NULL); + assert(length > 0U); + + // Check that the readfrom() won't block + fd_set readFds; + FD_ZERO(&readFds); + FD_SET(m_fd, &readFds); + + // Return immediately + timeval tv; + tv.tv_sec = 0L; + tv.tv_usec = 0L; + + int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv); + if (ret < 0) { + printf("Error returned from UDP select, err: %d", errno); + return -1; + } + + if (ret == 0) + return 0; + + sockaddr_in addr; + socklen_t size = sizeof(sockaddr_in); + + ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size); + if (len <= 0) { + printf("Error returned from recvfrom, err: %d", errno); + return -1; + } + + address = addr.sin_addr; + port = ntohs(addr.sin_port); + + return len; +} + +bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port) +{ + assert(buffer != NULL); + assert(length > 0U); + + sockaddr_in addr; + ::memset(&addr, 0x00, sizeof(sockaddr_in)); + + addr.sin_family = AF_INET; + addr.sin_addr = address; + addr.sin_port = htons(port); + + ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in)); + if (ret < 0) { + printf("Error returned from sendto, err: %d", errno); + return false; + } + + if (ret != ssize_t(length)) + return false; + + return true; +} + +void CUDPSocket::close() +{ + ::close(m_fd); +} diff --git a/UDPSocket.h b/UDPSocket.h new file mode 100644 index 0000000..580923b --- /dev/null +++ b/UDPSocket.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2009-2011,2013,2015,2016 by Jonathan Naylor G4KLX + * Copyright (c) 2018 by Thomas A. Early N7TAE + * + * 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. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +class CUDPSocket { +public: + CUDPSocket(const std::string& address, unsigned int port = 0U); + CUDPSocket(unsigned int port = 0U); + ~CUDPSocket(); + + bool open(); + + int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port); + bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port); + + void close(); + + static in_addr lookup(const std::string& hostName); + +private: + std::string m_address; + unsigned short m_port; + int m_fd; +}; + diff --git a/mmdvm_modem.cpp b/mmdvm_modem.cpp index 7563419..cbd9752 100644 --- a/mmdvm_modem.cpp +++ b/mmdvm_modem.cpp @@ -25,6 +25,7 @@ #include "versions.h" #include "mmdvm_modem.h" +#include "UDPSocket.h" std::atomic CMMDVMModem::keep_running(true); @@ -57,25 +58,48 @@ bool CMMDVMModem::Initialize(const char *cfgfile) return true; } -// dstar_dv_init(); + return false; +} - try { - mmdvm_future = std::async(std::launch::async, &CMMDVMModem::ProcessMMDVM, this); - } catch (const std::exception &e) { - printf("Unable to start ReadDVAPThread(). Exception: %s\n", e.what()); - keep_running = false; +void CMMDVMModem::Run(const char *cfgfile) +{ + if (Initialize(cfgfile)) + return; + + CUDPSocket GatewaySock(G2_INTERNAL_IP, G2_PORT); + if (GatewaySock.open()) + return; + + CUDPSocket MMDVMSock(MMDVM_IP, MMDVM_PORT); + if (MMDVMSock.open()) { + GatewaySock.close(); + return; } - printf("Started ProcessMMDVM() thread\n"); - return false; + keep_running = true; + + + while (keep_running) { + ProcessMMDVM(); + ProcessGateway(); + } + + MMDVMSock.close(); + GatewaySock.close(); } void CMMDVMModem::ProcessGateway() { + // read from gateway + + // if there is data, translate it and send it to the MMDVM Modem } void CMMDVMModem::ProcessMMDVM() { + // read from the MMDVM modem + + // if there is data, translate it and send it to the Gateway } bool CMMDVMModem::GetValue(const Config &cfg, const char *path, int &value, const int min, const int max, const int default_value) @@ -195,15 +219,15 @@ bool CMMDVMModem::ReadConfig(const char *cfgFile) } if (GetValue(cfg, std::string(mmdvm_path+".internal_ip").c_str(), value, 7, IP_SIZE, "0.0.0.0")) - strcpy(RPTR_VIRTUAL_IP, value.c_str()); + MMDVM_IP = value; else return true; GetValue(cfg, std::string(mmdvm_path+".port").c_str(), i, 10000, 65535, 20010); - RPTR_PORT = (unsigned short)i; + MMDVM_PORT = (unsigned short)i; if (GetValue(cfg, "gateway.ip", value, 7, IP_SIZE, "127.0.0.1")) - strcpy(G2_INTERNAL_IP, value.c_str()); + G2_INTERNAL_IP = value; else return true; @@ -246,17 +270,9 @@ int main(int argc, const char **argv) CMMDVMModem mmdvm; - if (mmdvm.Initialize(argv[1])) { - printf("ERROR: Failed to process %s\n", argv[0]); - return 1; - } - - while (mmdvm.keep_running) { - mmdvm.ProcessGateway(); - } + mmdvm.Run(argv[1]); - mmdvm.mmdvm_future.get(); - printf("%s is closed.\n", argv[0]); + printf("%s is closing.\n", argv[0]); return 0; } diff --git a/mmdvm_modem.h b/mmdvm_modem.h index fcd0e9c..38d8916 100644 --- a/mmdvm_modem.h +++ b/mmdvm_modem.h @@ -20,8 +20,6 @@ #include #include -#include - #include using namespace libconfig; @@ -35,17 +33,17 @@ public: // functions CMMDVMModem(); ~CMMDVMModem(); - bool Initialize(const char *cfgfile); - void ProcessGateway(); + void Run(const char *cfgfile); // data static std::atomic keep_running; - std::future mmdvm_future; private: // functions - void ProcessMMDVM(); + bool Initialize(const char *cfgfile); static void SignalCatch(int signum); + void ProcessGateway(); + void ProcessMMDVM(); // read configuration file bool ReadConfig(const char *); @@ -58,11 +56,11 @@ private: char RPTR_MOD; char RPTR[CALL_SIZE + 1]; char OWNER[CALL_SIZE + 1]; - char RPTR_VIRTUAL_IP[IP_SIZE + 1]; - char G2_INTERNAL_IP[IP_SIZE + 1]; - unsigned short RPTR_PORT, G2_PORT; + std::string MMDVM_IP, G2_INTERNAL_IP; + unsigned short MMDVM_PORT, G2_PORT; int WAIT_FOR_PACKETS, DELAY_BEFORE, DELAY_BETWEEN; bool RPTR_ACK; // parameters + int gateway_sock, mmdvm_sock; };