From d61154d7544e258a49edd498fc6a273f92630650 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Sun, 16 Dec 2018 11:02:59 -0700 Subject: [PATCH] qnrelay and qnitap use unix sockets --- QnetITAP.cpp | 194 +++++++++++++++++--------------------------------- QnetITAP.h | 18 +++-- QnetRelay.cpp | 138 ++++++++++++++++++----------------- QnetRelay.h | 19 +++-- 4 files changed, 163 insertions(+), 206 deletions(-) diff --git a/QnetITAP.cpp b/QnetITAP.cpp index 0176917..f24753e 100644 --- a/QnetITAP.cpp +++ b/QnetITAP.cpp @@ -46,8 +46,9 @@ std::atomic CQnetITAP::keep_running(true); -CQnetITAP::CQnetITAP() : -COUNTER(0) +CQnetITAP::CQnetITAP(int mod) +: assigned_module(mod) +, COUNTER(0) { } @@ -76,6 +77,9 @@ bool CQnetITAP::Initialize(const char *cfgfile) return true; } + if (Gate2Modem.Open(gate2modem.c_str()) || Modem2Gate.Open(modem2gate.c_str())) + return true; + return false; } @@ -120,50 +124,6 @@ int CQnetITAP::OpenITAP() return fd; } -int CQnetITAP::OpenSocket(const std::string &address, const 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(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { - printf("Cannot set the UDP socket %s:%u option, err: %d, %s\n", address.c_str(), port, errno, strerror(errno)); - close(fd); - return -1; - } - - if (::bind(fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { - printf("Cannot bind the UDP socket %s:%u address, err: %d, %s\n", address.c_str(), port, errno, strerror(errno)); - close(fd); - return -1; - } - - return fd; -} - REPLY_TYPE CQnetITAP::GetITAPData(unsigned char *buf) { // Shamelessly adapted from Jonathan G4KLX's CIcomController::GetResponse() @@ -235,20 +195,9 @@ void CQnetITAP::Run(const char *cfgfile) if (serfd < 0) return; - gsock = OpenSocket(G2_INTERNAL_IP, G2_OUT_PORT); - if (gsock < 0) { - ::close(serfd); - return; - } - - vsock = OpenSocket(std::string("0.0.0.0"), MMDVM_OUT_PORT); - if (vsock < 0) { - ::close(serfd); - ::close(gsock); - return; - } - - printf("vsock=%d, gsock=%d serfd=%d\n", vsock, gsock, serfd); + int ug2m = Gate2Modem.GetFD(); + int um2g = Modem2Gate.GetFD(); + printf("gate2modem=%d, modem2gate=%d seral=%d\n", ug2m, um2g, serfd); keep_running = true; unsigned poll_counter = 0; @@ -259,8 +208,8 @@ void CQnetITAP::Run(const char *cfgfile) fd_set readfds; FD_ZERO(&readfds); FD_SET(serfd, &readfds); - FD_SET(gsock, &readfds); - int maxfs = (serfd > gsock) ? serfd : gsock; + FD_SET(ug2m, &readfds); + int maxfs = (serfd > ug2m) ? serfd : ug2m; struct timeval tv; tv.tv_sec = (poll_counter >= 18) ? 1 : 0; @@ -308,20 +257,13 @@ void CQnetITAP::Run(const char *cfgfile) if (rt == RT_TIMEOUT) continue; - } else if (FD_ISSET(gsock, &readfds)) { - sockaddr_in addr; - memset(&addr, 0, sizeof(sockaddr_in)); - socklen_t size = sizeof(sockaddr); - len = ::recvfrom(gsock, buf, 100, 0, (sockaddr *)&addr, &size); + } else if (FD_ISSET(ug2m, &readfds)) { + len = Gate2Modem.Read(buf, 100); if (len < 0) { printf("ERROR: Run: recvfrom(gsock) returned error %d, %s\n", errno, strerror(errno)); break; } - - if (ntohs(addr.sin_port) != G2_IN_PORT) - printf("DEBUG: Run: read from gsock but the port was %u, expected %u\n", ntohs(addr.sin_port), G2_IN_PORT); - } if (rt != RT_NOTHING) { @@ -356,8 +298,8 @@ void CQnetITAP::Run(const char *cfgfile) } ::close(serfd); - ::close(gsock); - ::close(vsock); + Gate2Modem.Close(); + Modem2Gate.Close(); } int CQnetITAP::SendTo(const unsigned char length, const unsigned char *buf) @@ -381,22 +323,6 @@ int CQnetITAP::SendTo(const unsigned char length, const unsigned char *buf) return len; } -int CQnetITAP::SendTo(const int fd, const unsigned char *buf, const int size, const std::string &address, const unsigned short 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); - - int len = ::sendto(fd, buf, size, 0, (sockaddr *)&addr, sizeof(sockaddr_in)); - if (len < 0) - printf("ERROR: SendTo: fd=%d failed sendto %s:%u err: %d, %s\n", fd, address.c_str(), port, errno, strerror(errno)); - else if (len != size) - printf("ERROR: SendTo: fd=%d tried to sendto %s:%u %d bytes, actually sent %d.\n", fd, address.c_str(), port, size, len); - return len; -} - bool CQnetITAP::ProcessGateway(const int len, const unsigned char *raw) { static unsigned char counter = 0; @@ -502,18 +428,18 @@ bool CQnetITAP::ProcessITAP(const unsigned char *buf) memcpy(dstr.vpkt.hdr.my, itap.header.my, 8); memcpy(dstr.vpkt.hdr.nm, itap.header.nm, 4); calcPFCS(dstr.vpkt.hdr.flag, dstr.vpkt.hdr.pfcs); - int ret = SendTo(vsock, dstr.pkt_id, 58, G2_INTERNAL_IP, G2_IN_PORT); + int ret = Modem2Gate.Write(dstr.pkt_id, 58); if (ret != 58) { printf("ERROR: ProcessITAP: Could not write gateway header packet\n"); return true; } if (log_qso) - printf("Sent DSTR to %u, streamid=%04x ur=%.8s r1=%.8s r2=%.8s my=%.8s/%.4s\n", G2_IN_PORT, ntohs(dstr.vpkt.streamid), dstr.vpkt.hdr.ur, dstr.vpkt.hdr.r1, dstr.vpkt.hdr.r2, dstr.vpkt.hdr.my, dstr.vpkt.hdr.nm); + printf("Sent DSTR to gateway, streamid=%04x ur=%.8s r1=%.8s r2=%.8s my=%.8s/%.4s\n", ntohs(dstr.vpkt.streamid), dstr.vpkt.hdr.ur, dstr.vpkt.hdr.r1, dstr.vpkt.hdr.r2, dstr.vpkt.hdr.my, dstr.vpkt.hdr.nm); } else if (16 == len) { // ambe dstr.remaining = 0x16; dstr.vpkt.ctrl = itap.voice.sequence; memcpy(dstr.vpkt.vasd.voice, itap.voice.ambe, 12); - int ret = SendTo(vsock, dstr.pkt_id, 29, G2_INTERNAL_IP, G2_IN_PORT); + int ret = Modem2Gate.Write(dstr.pkt_id, 29); if (ret != 29) { printf("ERROR: ProcessMMDVM: Could not write gateway voice packet\n"); return true; @@ -581,31 +507,33 @@ bool CQnetITAP::ReadConfig(const char *cfgFile) cfg.readFile(cfgFile); } catch(const FileIOException &fioex) { - printf("Can't read %s\n", cfgFile); + fprintf(stderr, "Can't read %s\n", cfgFile); return true; } catch(const ParseException &pex) { - printf("Parse error at %s:%d - %s\n", pex.getFile(), pex.getLine(), pex.getError()); + fprintf(stderr, "Parse error at %s:%d - %s\n", pex.getFile(), pex.getLine(), pex.getError()); return true; } - std::string itap_path, value; - int i; - for (i=0; i<3; i++) { - itap_path = "module."; - itap_path += ('a' + i); - if (cfg.lookupValue(itap_path + ".type", value)) { - if (0 == strcasecmp(value.c_str(), "itap")) - break; + std::string value; + std::string itap_path("module."); + itap_path.append(1, 'a' + assigned_module); + if (cfg.lookupValue(itap_path + ".type", value)) { + if (value.compare("itap")) { + fprintf(stderr, "assigned module %c is not 'itap'\n", 'a' + assigned_module); + return true; } - } - if (i >= 3) { - printf("itap not defined in any module!\n"); + } else { + fprintf(stderr, "assigned module %c not defined\n", 'a' + assigned_module); return true; } - RPTR_MOD = 'A' + i; - int repeater_module = i; - MMDVM_OUT_PORT = (unsigned short int)(i + 19998); + RPTR_MOD = 'A' + assigned_module; + + char unixsockname[16]; + snprintf(unixsockname, 16, "gate2modem%d", assigned_module); + GetValue(cfg, std::string(itap_path+".togateway").c_str(), modem2gate, 1, FILENAME_MAX, unixsockname); + snprintf(unixsockname, 16, "modem2gate%d", assigned_module); + GetValue(cfg, std::string(itap_path+".fromgateway").c_str(), gate2modem, 1, FILENAME_MAX, unixsockname); if (cfg.lookupValue(std::string(itap_path+".callsign").c_str(), value) || cfg.lookupValue("ircddb.login", value)) { int l = value.length(); @@ -613,7 +541,7 @@ bool CQnetITAP::ReadConfig(const char *cfgFile) printf("Call '%s' is invalid length!\n", value.c_str()); return true; } else { - for (i=0; i #include "Random.h" // for streamid generation +#include "UnixDgramSocket.h" using namespace libconfig; @@ -81,7 +82,7 @@ class CQnetITAP { public: // functions - CQnetITAP(); + CQnetITAP(int mod); ~CQnetITAP(); void Run(const char *cfgfile); @@ -89,14 +90,14 @@ public: static std::atomic keep_running; private: + int assigned_module; + unsigned short COUNTER; // functions bool Initialize(const char *cfgfile); static void SignalCatch(const int signum); bool ProcessGateway(const int len, const unsigned char *raw); bool ProcessITAP(const unsigned char *raw); - int OpenSocket(const std::string &address, const unsigned short port); int OpenITAP(); - int SendTo(const int fd, const unsigned char *buf, const int size, const std::string &address, const unsigned short port); int SendTo(const unsigned char length, const unsigned char *buf); REPLY_TYPE GetITAPData(unsigned char *buf); void calcPFCS(const unsigned char *packet, unsigned char *pfcs); @@ -112,15 +113,18 @@ private: char RPTR_MOD; char RPTR[CALL_SIZE + 1]; char OWNER[CALL_SIZE + 1]; - std::string ITAP_DEVICE, G2_INTERNAL_IP; - unsigned short MMDVM_IN_PORT, MMDVM_OUT_PORT, G2_IN_PORT, G2_OUT_PORT; + std::string ITAP_DEVICE; bool log_qso; // parameters - int serfd, gsock, vsock; + int serfd; unsigned char tapcounter; - unsigned short COUNTER; // helpers CRandom random; + + // unix sockets + std::string modem2gate, gate2modem; + CUnixDgramWriter Modem2Gate; + CUnixDgramReader Gate2Modem; }; diff --git a/QnetRelay.cpp b/QnetRelay.cpp index 40a3f41..a0da66c 100644 --- a/QnetRelay.cpp +++ b/QnetRelay.cpp @@ -38,7 +38,8 @@ std::atomic CQnetRelay::keep_running(true); -CQnetRelay::CQnetRelay() : +CQnetRelay::CQnetRelay(int mod) : +assigned_module(mod), seed(time(NULL)), COUNTER(0) { @@ -116,22 +117,21 @@ int CQnetRelay::OpenSocket(const std::string &address, unsigned short port) return fd; } -void CQnetRelay::Run(const char *cfgfile) +bool CQnetRelay::Run(const char *cfgfile) { if (Initialize(cfgfile)) - return; + return true; msock = OpenSocket(MMDVM_IP, MMDVM_OUT_PORT); if (msock < 0) - return; + return true; - gsock = OpenSocket(G2_INTERNAL_IP, G2_OUT_PORT); - if (gsock < 0) { - ::close(msock); - return; - } + if (Gate2Modem.Open(gate2modem.c_str()) || Modem2Gate.Open(modem2gate.c_str())) + return true; - printf("msock=%d, gsock=%d\n", msock, gsock); + int fd = Gate2Modem.GetFD(); + + printf("msock=%d, gateway=%d\n", msock, fd); keep_running = true; @@ -139,8 +139,8 @@ void CQnetRelay::Run(const char *cfgfile) fd_set readfds; FD_ZERO(&readfds); FD_SET(msock, &readfds); - FD_SET(gsock, &readfds); - int maxfs = (msock > gsock) ? msock : gsock; + FD_SET(fd, &readfds); + int maxfs = (msock > fd) ? msock : fd; // don't care about writefds and exceptfds: // and we'll wait as long as needed @@ -163,30 +163,26 @@ void CQnetRelay::Run(const char *cfgfile) len = ::recvfrom(msock, buf, 100, 0, (sockaddr *)&addr, &size); if (len < 0) { - printf("ERROR: Run: recvfrom(mmdvm) return error %d, %s\n", errno, strerror(errno)); + fprintf(stderr, "ERROR: Run: recvfrom(mmdvm) return error %d: %s\n", errno, strerror(errno)); break; } if (ntohs(addr.sin_port) != MMDVM_IN_PORT) - printf("DEBUG: Run: read from msock but port was %u, expected %u.\n", ntohs(addr.sin_port), MMDVM_IN_PORT); + fprintf(stderr, "DEBUG: Run: read from msock but port was %u, expected %u.\n", ntohs(addr.sin_port), MMDVM_IN_PORT); } - if (FD_ISSET(gsock, &readfds)) { - len = ::recvfrom(gsock, buf, 100, 0, (sockaddr *)&addr, &size); + if (FD_ISSET(fd, &readfds)) { + len = Gate2Modem.Read(buf, 100); if (len < 0) { - printf("ERROR: Run: recvfrom(gsock) returned error %d, %s\n", errno, strerror(errno)); + fprintf(stderr, "ERROR: Run: Gate2Modem.Read() returned error %d: %s\n", errno, strerror(errno)); break; } - - if (ntohs(addr.sin_port) != G2_IN_PORT) - printf("DEBUG: Run: read from gsock but the port was %u, expected %u\n", ntohs(addr.sin_port), G2_IN_PORT); - } if (len == 0) { - printf("DEBUG: Run: read zero bytes from %u\n", ntohs(addr.sin_port)); + fprintf(stderr, "DEBUG: Run: read zero bytes from %u\n", ntohs(addr.sin_port)); continue; } @@ -203,12 +199,14 @@ void CQnetRelay::Run(const char *cfgfile) for (int i=0; i<4; i++) title[i] = (buf[i]>=0x20u && buf[i]<0x7fu) ? buf[i] : '.'; title[4] = '\0'; - printf("DEBUG: Run: received unknow packet '%s' len=%d\n", title, (int)len); + fprintf(stderr, "DEBUG: Run: received unknow packet '%s' len=%d\n", title, (int)len); } } ::close(msock); - ::close(gsock); + Gate2Modem.Close(); + Modem2Gate.Close(); + return false; } int CQnetRelay::SendTo(const int fd, const unsigned char *buf, const int size, const std::string &address, const unsigned short port) @@ -320,18 +318,18 @@ bool CQnetRelay::ProcessMMDVM(const int len, const unsigned char *raw) memcpy(dstr.vpkt.hdr.my, dsrp.header.my, 8); memcpy(dstr.vpkt.hdr.nm, dsrp.header.nm, 4); memcpy(dstr.vpkt.hdr.pfcs, dsrp.header.pfcs, 2); - int ret = SendTo(msock, dstr.pkt_id, 58, G2_INTERNAL_IP, G2_IN_PORT); + int ret = Modem2Gate.Write(dstr.pkt_id, 58); if (ret != 58) { printf("ERROR: ProcessMMDVM: Could not write gateway header packet\n"); return true; } if (log_qso) - printf("Sent DSTR to %u, streamid=%04x ur=%.8s r1=%.8s r2=%.8s my=%.8s/%.4s\n", G2_IN_PORT, ntohs(dstr.vpkt.streamid), dstr.vpkt.hdr.ur, dstr.vpkt.hdr.r1, dstr.vpkt.hdr.r2, dstr.vpkt.hdr.my, dstr.vpkt.hdr.nm); + printf("Sent DSTR streamid=%04x ur=%.8s r1=%.8s r2=%.8s my=%.8s/%.4s\n", ntohs(dstr.vpkt.streamid), dstr.vpkt.hdr.ur, dstr.vpkt.hdr.r1, dstr.vpkt.hdr.r2, dstr.vpkt.hdr.my, dstr.vpkt.hdr.nm); } else if (21 == len) { // ambe dstr.remaining = 0x16; dstr.vpkt.ctrl = dsrp.header.seq; memcpy(dstr.vpkt.vasd.voice, dsrp.voice.ambe, 12); - int ret = SendTo(msock, dstr.pkt_id, 29, G2_INTERNAL_IP, G2_IN_PORT); + int ret = Modem2Gate.Write(dstr.pkt_id, 29); if (log_qso && dstr.vpkt.ctrl&0x40) printf("Sent DSTR end of streamid=%04x\n", ntohs(dstr.vpkt.streamid)); @@ -410,30 +408,32 @@ bool CQnetRelay::ReadConfig(const char *cfgFile) return true; } - std::string mmdvm_path, value; - int i; - for (i=0; i<3; i++) { - mmdvm_path = "module."; - mmdvm_path += ('a' + i); - if (cfg.lookupValue(mmdvm_path + ".type", value)) { - if (0 == strcasecmp(value.c_str(), "mmdvm")) - break; + std::string value; + std::string mmdvm_path("module."); + mmdvm_path.append(1, 'a' + assigned_module); + if (cfg.lookupValue(mmdvm_path + ".type", value)) { + if (value.compare("mmdvm")) { + fprintf(stderr, "assigned module is not 'mmdvm' type!\n"); + return true; } - } - if (i >= 3) { - printf("mmdvm not defined in any module!\n"); + } else { + fprintf(stderr, "Module '%c' is not defined.\n", 'a'+assigned_module); return true; } - RPTR_MOD = 'A' + i; - int repeater_module = i; + RPTR_MOD = 'A' + assigned_module; + char unixsockname[16]; + snprintf(unixsockname, 16, "gate2module%d", assigned_module); + GetValue(cfg, std::string(mmdvm_path+".fromgateway").c_str(), gate2modem, 1, FILENAME_MAX, unixsockname); + snprintf(unixsockname, 16, "module2gate%d", assigned_module); + GetValue(cfg, std::string(mmdvm_path+",togateway").c_str(), modem2gate, 1, FILENAME_MAX, unixsockname); if (cfg.lookupValue(std::string(mmdvm_path+".callsign").c_str(), value) || cfg.lookupValue("ircddb.login", value)) { int l = value.length(); if (l<3 || l>CALL_SIZE-2) { - printf("Call '%s' is invalid length!\n", value.c_str()); + fprintf(stderr, "Call '%s' is invalid length!\n", value.c_str()); return true; } else { - for (i=0; iCALL_SIZE-2) { - printf("Call '%s' is invalid length!\n", value.c_str()); + fprintf(stderr, "Call '%s' is invalid length!\n", value.c_str()); return true; } else { - for (i=0; i #include #include - #include +#include "UnixDgramSocket.h" + using namespace libconfig; #define CALL_SIZE 8 @@ -33,9 +34,9 @@ class CQnetRelay { public: // functions - CQnetRelay(); + CQnetRelay(int mod); ~CQnetRelay(); - void Run(const char *cfgfile); + bool Run(const char *cfgfile); // data static std::atomic keep_running; @@ -56,16 +57,22 @@ private: bool GetValue(const Config &cfg, const char *path, bool &value, const bool default_value); bool GetValue(const Config &cfg, const char *path, std::string &value, const int min, const int max, const char *default_value); + // Unix sockets + int assigned_module; + std::string gate2modem, modem2gate; + CUnixDgramWriter Modem2Gate; + CUnixDgramReader Gate2Modem; + // config data char RPTR_MOD; char RPTR[CALL_SIZE + 1]; char OWNER[CALL_SIZE + 1]; - std::string MMDVM_IP, G2_INTERNAL_IP; - unsigned short MMDVM_IN_PORT, MMDVM_OUT_PORT, G2_IN_PORT, G2_OUT_PORT; + std::string MMDVM_IP; + unsigned short MMDVM_IN_PORT, MMDVM_OUT_PORT; bool log_qso; // parameters - int msock, gsock; + int msock; unsigned int seed; unsigned short COUNTER; };