diff --git a/Makefile b/Makefile index cba453d..bda8970 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 UDPSocket.o - g++ $(CPPFLAGS) -o mmdvm_modem mmdvm_modem.o UDPSocket.o $(LDFLAGS) +mmdvm_modem : mmdvm_modem.o + g++ $(CPPFLAGS) -o mmdvm_modem mmdvm_modem.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 deleted file mode 100644 index d7c45f3..0000000 --- a/UDPSocket.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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 true on error -{ - m_fd = ::socket(PF_INET, SOCK_DGRAM, 0); - if (m_fd < 0) { - printf("Cannot create the UDP socket, err: %d, %s\n", errno, strerror(errno)); - return true; - } - - 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\n", m_address.c_str()); - return true; - } - } - - int reuse = 1; - if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { - printf("Cannot set the UDP socket (port %u) option, err: %d, %s\n", m_port, errno, strerror(errno)); - return true; - } - - if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { - printf("Cannot bind the UDP (port %u) address, err: %d, %s\n", m_port, errno, strerror(errno)); - return true; - } - } - - return false; -} - -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 if there is nothing for this socket - 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, %s\n", errno, strerror(errno)); - return -1; - } - - if (ret == 0) - return 0; - - if (! FD_ISSET(m_fd, &readFds)) - return 0; // nothing for this socket; - - 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, %s\n", errno, strerror(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, %s\n", errno, strerror(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 deleted file mode 100644 index 580923b..0000000 --- a/UDPSocket.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 b24f199..0d618e2 100644 --- a/mmdvm_modem.cpp +++ b/mmdvm_modem.cpp @@ -65,50 +65,148 @@ bool CMMDVMModem::Initialize(const char *cfgfile) return false; } +int CMMDVMModem::OpenSocket(const std::string &address, unsigned short port) +{ + if (! port) { + printf("ERROR: OpenSocket: non-zero port must be specified.\n"); + return -1; + } + + int fd = ::socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + printf("Cannot create the UDP socket, err: %d, %s\n", errno, strerror(errno)); + return -1; + } + + sockaddr_in addr; + ::memset(&addr, 0, sizeof(sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + if (! address.empty()) { + addr.sin_addr.s_addr = ::inet_addr(address.c_str()); + if (addr.sin_addr.s_addr == INADDR_NONE) { + printf("The local address is invalid - %s\n", address.c_str()); + close(fd); + return -1; + } + } + + int reuse = 1; + if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { + printf("Cannot set the UDP socket %s:%u option, err: %d, %s\n", m_port, errno, strerror(errno)); + close(fd); + return -1; + } + + if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { + printf("Cannot bind the UDP (port %u) address, err: %d, %s\n", m_port, errno, strerror(errno)); + close(fd); + return -1; + } + + return fd; +} + void CMMDVMModem::Run(const char *cfgfile) { if (Initialize(cfgfile)) return; - CUDPSocket MMDVMSock(MMDVM_IP, MMDVM_PORT); - if (MMDVMSock.open()) + int msock = OpenSocket(MMDVM_IP, MMDVM_PORT); + if (msock < 0) return; - CUDPSocket GatewaySock(G2_INTERNAL_IP, G2_INTERNAL_PORT); - if (GatewaySock.open()) { - MMDVMSock.close(); + int gsock = OpenSocket(G2_INTERNAL_IP, G2_INTERNAL_PORT); + if (gsock < 0) { + ::close(fd_m); return; } keep_running = true; - while (keep_running) { - ProcessMMDVM(GatewaySock, MMDVMSock); - if (keep_running) - ProcessGateway(GatewaySock, MMDVMSock); + struct timeval tv; + fd_set readfds; + + tv.tv_sec = 0; + tv.tv_usec = 1000; // wait 1ms for some input + + FD_ZERO(&readfds); + FD_SET(msock, &readfds); + FD_SET(gsock, &readfds); + int maxfd = (msock > gsock) ? msock : gsock; + + // don't care about writefds and exceptfds: + int ret = ::select(maxfd+1, &readfds, NULL, NULL, &tv); + if (ret < 0) + break; + if (ret == 0) + continue; + + // there is something to read! + unsigned char buf[100]; + sockaddr_in addr; + memset(&addr, 0, sizeof(sockaddr_in)); + ssize_t len; + if (FD_ISSET(msock, &readfds)) { + len = ::recvfrom(msock, buf, 100, 0, (sockaddr *)&addr, sizeof(sockaddr_in); + + if (len < 0) { + printf("ERROR: RUN: recvfrom(mmdvm) return error %d, %s\n", errno, strerror(errno)); + break; + } + + if (addr.sin_port == G2_PORT) + printf("DEBUG: Run: reading from fd_m but port was %d.\n", addr.sin_port); + + } else if (FD_ISSET(gsock, &readfds)) { + len = ::recvfrom(fd_g, buf, 100, 0, (sockaddr *)&addr, sizeof(sockaddr_in); + + if (len < 0) { + printf("ERROR: RUN: recvfrom(g2) return error %d, %s\n", errno, strerror(errno)); + break; + } + + if (addr.sin_port == MMDVM_PORT) + printf("DEBUG: Run: reading from fd_g but port was %d.\n", addr.sin_port); + + } else { + printf("ERROR: Run: Input from unknown fd!\n"); + break; + } + if (len == 0) + continue; + + if (addr.sin_port == MMDVM_PORT) { + if (ProcessMMDVM(buf)) + break; + } else if (addr.sin_port == G2_PORT) { + if (ProcessGateway(buf)) + break; + } } - MMDVMSock.close(); - GatewaySock.close(); + ::close(fd_m); + ::close(fd_g); } -void CMMDVMModem::ProcessGateway(CUDPSocket &gsock, CUDPSocket &msock) +int CMMDVMModem::SendTo(const int fd, const unsigned char *buf, const int size, const std::string &address, const unsigned short port) { - SPKT buf; - unsigned int port; - - // read from gateway - int len = gsock.read(buf.pkt_id, 58, g2_internal_addr, port); + sockaddr_in addr; + ::memset(&addr, 0, sizeof(sockaddr_in); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = ::inet_addr(address.c_str()); + addr.sin_port = htons(port); - if (0 == len) - return; + return ::sendto(fd, buf, size, 0, (sockaddr *)&addr, sizeof(sockaddr_in)); +} - if (0 > len) { - printf("ERROR: ProcessGateway: Can't read gateway packet\n"); - keep_running = false; - return; - } +bool CMMDVMModem::ProcessGateway(const int len, const unsigned char *raw) +{ + SPKT buf; + ::memcpy(buf.pkt_id, buf, len); // if there is data, translate it and send it to the MMDVM Modem if (29==len || 58==len) { //here is dstar data @@ -125,10 +223,10 @@ void CMMDVMModem::ProcessGateway(CUDPSocket &gsock, CUDPSocket &msock) printf("DEBUG: ProcessGateway: unexpected voice sequence number %d\n", pkt.voice.seq); memcpy(pkt.voice.ambe, buf.vpkt.vasd.text, 12); - if (false == msock.write(pkt.title, 21, mmdvm_addr, MMDVM_PORT)) { + int ret = SendTo(msock, pkt.title, 21, mmdvm_addr, MMDVM_PORT)) + if (ret != 21) { printf("ERROR: ProcessGateway: Could not write AMBE mmdvm packet\n"); - keep_running = false; - return; + return true; } } else { // write a Header packet pkt.tag = 0x20U; @@ -140,34 +238,21 @@ void CMMDVMModem::ProcessGateway(CUDPSocket &gsock, CUDPSocket &msock) } memcpy(pkt.header.flag, buf.vpkt.hdr.flag, 41); - if (false == msock.write(pkt.title, 49, mmdvm_addr, MMDVM_PORT)) { + int ret = SendTo(msock, pkt.title, 49, mmdvm_addr, MMDVM_PORT); + if (ret != 49) { printf("ERROR: ProcessGateway: Could not write Header mmdvm packet\n"); - keep_running = false; + return true; } } } else printf("DEBUG: ProcessGateway: unusual packet size read len=%d\n", len); + return false; } -void CMMDVMModem::ProcessMMDVM(CUDPSocket &gsock, CUDPSocket &msock) +bool CMMDVMModem::ProcessMMDVM(const int len, const unsigned char *raw) { SMMDVMPKT mpkt; - static SPKT gpkt; // retain some header values for voice data - unsigned int mmdvm_port = MMDVM_PORT; - in_addr addr; - addr.s_addr = mmdvm_addr.s_addr; - - // read from the MMDVM modem - int len = msock.read(mpkt.title, 64, addr, mmdvm_port); - - if (0 == len) // no data available - return; - - if (0 > len) { - printf("ERROR: ProcessMMDVM: Could not read mmdvm packet\n"); - keep_running = false; - return; - } + ::memcopy(mpkt.title, raw, len); // if there is data, translate it and send it to the Gateway if (49 == len) { @@ -185,9 +270,10 @@ void CMMDVMModem::ProcessMMDVM(CUDPSocket &gsock, CUDPSocket &msock) gpkt.vpkt.streamid = (rand_r(&seed) % 65535U) + 1U; gpkt.vpkt.ctrl = mpkt.header.seq; memcpy(gpkt.vpkt.hdr.flag, mpkt.header.flag, 41); - if (false == gsock.write(gpkt.pkt_id, 58, g2_internal_addr, (unsigned int)G2_INTERNAL_PORT)) { + int ret = SendTo(gsock, gpkt.pkt_id, 58, g2_internal_addr, (unsigned int)G2_INTERNAL_PORT); + if (ret != 58) { printf("ERROR: ProcessMMDVM: Could not write gateway header packet\n"); - keep_running = false; + return true; } } else if (21 == len) { // just a few need updating in a voice data frame @@ -195,12 +281,14 @@ void CMMDVMModem::ProcessMMDVM(CUDPSocket &gsock, CUDPSocket &msock) gpkt.remaining = 0x16; gpkt.vpkt.ctrl = mpkt.voice.seq; memcpy(gpkt.vpkt.vasd.text, mpkt.voice.ambe, 12); - if (false == gsock.write(gpkt.pkt_id, 29, g2_internal_addr, (unsigned int)G2_INTERNAL_PORT)) { + int ret = SendTo(gsock, gpkt.pkt_id, 29, g2_internal_addr, (unsigned int)G2_INTERNAL_PORT); + if (ret != 29) { printf("ERROR: ProcessMMDVM: Could not write gateway header packet\n"); - keep_running = false; + return true; } } else printf("DEBUG: ProcessMMDVM: unusual packet size read len=%d\n", len); + return false; } bool CMMDVMModem::GetValue(const Config &cfg, const char *path, int &value, const int min, const int max, const int default_value) diff --git a/mmdvm_modem.h b/mmdvm_modem.h index ecd26f7..867cc8c 100644 --- a/mmdvm_modem.h +++ b/mmdvm_modem.h @@ -46,8 +46,10 @@ private: // functions bool Initialize(const char *cfgfile); static void SignalCatch(int signum); - void ProcessGateway(CUDPSocket &gsock, CUDPSocket &msock); - void ProcessMMDVM(CUDPSocket &gsock, CUDPSocket &msock); + bool ProcessGateway(const int len, const unsigned char *raw); + bool ProcessMMDVM(const int len, const unsigned char *raw); + int OpenSocket(const std::string &address, unsigned short port); + int SendTo(cont int fd, const unsigned char *buf, const int size, const std::string &address, const unsigned short port); // read configuration file bool ReadConfig(const char *); @@ -61,13 +63,12 @@ private: char RPTR[CALL_SIZE + 1]; char OWNER[CALL_SIZE + 1]; std::string MMDVM_IP, G2_INTERNAL_IP; - in_addr mmdvm_addr, g2_internal_addr; unsigned short MMDVM_PORT, G2_INTERNAL_PORT; int WAIT_FOR_PACKETS, DELAY_BEFORE, DELAY_BETWEEN; bool RPTR_ACK; // parameters - int gateway_sock, mmdvm_sock; + int gsock, msock; unsigned int seed; unsigned short COUNTER; };