From 98f8072a9cd8c48ad79ea1f1d1ee375804b63ed8 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Tue, 14 Apr 2020 14:13:42 -0700 Subject: [PATCH] gateways are now in the database --- .gitignore | 1 + DPlusAuthenticator.cpp | 16 ++-- DPlusAuthenticator.h | 8 +- QnetConfigure.cpp | 2 +- QnetDB.cpp | 84 +++++++++++++++++++++ QnetDB.h | 3 + QnetGateway.cpp | 1 + QnetLink.cpp | 167 +++++++++-------------------------------- QnetLink.h | 4 - 9 files changed, 137 insertions(+), 149 deletions(-) diff --git a/.gitignore b/.gitignore index b52d830..ba0e0c6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.o *.d +*~ *.gch .vscode qn.cfg diff --git a/DPlusAuthenticator.cpp b/DPlusAuthenticator.cpp index 734af7e..b4d2112 100644 --- a/DPlusAuthenticator.cpp +++ b/DPlusAuthenticator.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX - * Copyright (C) 2018-2019 by Thomas A. Early N7TAE + * Copyright (C) 2018-2020 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 @@ -43,7 +43,7 @@ CDPlusAuthenticator::~CDPlusAuthenticator() { } -bool CDPlusAuthenticator::Process(std::map &gwy_map, const bool reflectors, const bool repeaters) +bool CDPlusAuthenticator::Process(CQnetDB &db, const bool reflectors, const bool repeaters) // return true if everything went okay { int result = client.Open(m_address, AF_UNSPEC, "20001"); @@ -51,10 +51,10 @@ bool CDPlusAuthenticator::Process(std::map &gwy_map, c fprintf(stderr, "DPlus Authorization failed: %s\n", gai_strerror(result)); return true; } - return authenticate(gwy_map, reflectors, repeaters); + return authenticate(db, reflectors, repeaters); } -bool CDPlusAuthenticator::authenticate(std::map &gwy_map, const bool reflectors, const bool repeaters) +bool CDPlusAuthenticator::authenticate(CQnetDB &db, const bool reflectors, const bool repeaters) { unsigned char* buffer = new unsigned char[4096U]; ::memset(buffer, ' ', 56U); @@ -77,7 +77,6 @@ bool CDPlusAuthenticator::authenticate(std::map &gwy_m } int ret = client.ReadExact(buffer, 2U); - size_t sofar = gwy_map.size(); unsigned int returned = 0; while (ret == 2) { @@ -100,7 +99,7 @@ bool CDPlusAuthenticator::authenticate(std::map &gwy_m Trim(address); Trim(name); - name.resize(8, ' '); + name.resize(6, ' '); // Get the active flag bool active = (buffer[i + 25U] & 0x80U) == 0x80U; @@ -109,9 +108,9 @@ bool CDPlusAuthenticator::authenticate(std::map &gwy_m if (address.size()>0U && name.size()>0U && active) { returned++; if (reflectors && 0==name.compare(0, 3, "REF")) - gwy_map[name] = address.append(" 20001"); + db.UpdateGW(name.c_str(), address.c_str(), 20001); else if (repeaters && name.compare(0, 3, "REF")) - gwy_map[name] = address.append(" 20001"); + db.UpdateGW(name.c_str(), address.c_str(), 20001); } } @@ -120,7 +119,6 @@ bool CDPlusAuthenticator::authenticate(std::map &gwy_m printf("Probably authorized DPlus on %s using callsign %s\n", m_address.c_str(), m_loginCallsign.c_str()); printf("%s returned %u systems\n", m_address.c_str(), returned); - printf("The gateway map increased by %u additional DPlus gateways\n", (unsigned int)(gwy_map.size() - sofar)); client.Close(); delete[] buffer; diff --git a/DPlusAuthenticator.h b/DPlusAuthenticator.h index f350076..8f8b270 100644 --- a/DPlusAuthenticator.h +++ b/DPlusAuthenticator.h @@ -1,7 +1,7 @@ #pragma once /* * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX - * Copyright (C) 2018-2019 by Thomas A. Early N7TAE + * Copyright (C) 2018-2020 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 @@ -21,14 +21,16 @@ #include #include #include + #include "TCPReaderWriterClient.h" +#include "QnetDB.h" class CDPlusAuthenticator { public: CDPlusAuthenticator(const std::string &loginCallsign, const std::string &address); ~CDPlusAuthenticator(); - bool Process(std::map &gwy_map, const bool reflectors, const bool repeaters); + bool Process(CQnetDB &qn, const bool reflectors, const bool repeaters); private: std::string m_loginCallsign; @@ -36,5 +38,5 @@ private: CTCPReaderWriterClient client; void Trim(std::string &s); - bool authenticate(std::map &gwy_map, const bool reflectors, const bool repeaters); + bool authenticate(CQnetDB &db, const bool reflectors, const bool repeaters); }; diff --git a/QnetConfigure.cpp b/QnetConfigure.cpp index ba46acd..1b264a3 100644 --- a/QnetConfigure.cpp +++ b/QnetConfigure.cpp @@ -129,7 +129,7 @@ bool CQnetConfigure::GetDefaultString(const std::string &path, const std::string search_again = mod; // we're looking from a module value. We may have to look for non-generic module parameters if (0==path.compare(0, 7, "module_") && ('a'==path.at(7) || 'b'==path.at(7) || 'c'==path.at(7)) && '_'==path.at(8)) { // path begins with module_{a|b|c}_ - if (0==mod.compare("dvrptr") || 0==mod.compare("dvap") || 0==mod.compare("mmdvmhost") || 0==mod.compare("mmdvmmodem") || 0==mod.compare("itap")) { + if (0==mod.compare("dvrptr") || 0==mod.compare("dvap") || 0==mod.compare("mmdvmhost") || 0==mod.compare("mmdvmmodem") || 0==mod.compare("itap") || 0==mod.compare("thumbdv")) { // and the module is recognized search = path; search.replace(7, 1, 1, 'x'); diff --git a/QnetDB.cpp b/QnetDB.cpp index af7a72f..05d5760 100644 --- a/QnetDB.cpp +++ b/QnetDB.cpp @@ -75,6 +75,26 @@ bool CQnetDB::Init() return true; } + sql.assign("DROP TABLE IF EXISTS GATEWAYS;"); + + if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) { + fprintf(stderr, "CQnetDB::Open drop table LINKSTATUS error: %s\n", eMsg); + sqlite3_free(eMsg); + return true; + } + + sql.assign("CREATE TABLE GATEWAYS(" + "name TEXT PRIMARY KEY, " + "address TEXT NOT NULL, " + "port INT NOT NULL" + ") WITHOUT ROWID;"); + + if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) { + fprintf(stderr, "CQnetDB::Open create table GATEWAYS error: %s\n", eMsg); + sqlite3_free(eMsg); + return true; + } + return false; } @@ -129,6 +149,30 @@ bool CQnetDB::UpdateLS(const char *address, const char from_mod, const char *to_ return false; } +bool CQnetDB::UpdateGW(const char *name, const char *address, unsigned short port) +{ + if (NULL == db) + return false; + std::string n(name); + n.resize(6, ' '); + std::string sql = "REPLACE INTO GATEWAYS (name,address,port) VALUES ('"; + sql.append(n); + sql.append("','"); + sql.append(address); + sql.append("',"); + sql.append(std::to_string(port)); + sql.append(");"); + + char *eMsg; + if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) { + fprintf(stderr, "CQnetDB::UpdateGW error: %s\n", eMsg); + sqlite3_free(eMsg); + return true; + } + + return false; +} + bool CQnetDB::DeleteLS(const char *address) { if (NULL == db) @@ -175,3 +219,43 @@ bool CQnetDB::FindLS(const char mod, std::list &linklist) sqlite3_finalize(stmt); return false; } + +bool CQnetDB::FindGW(const char *name, std::string &address, unsigned short &port) +{ + if (NULL == db) + return false; + std::string n(name); + n.resize(6, ' '); + std::string sql("SELECT address,port FROM GATEWAYS WHERE name=='"); + sql.append(n); + sql.append("';"); + + sqlite3_stmt *stmt; + int rval = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, 0); + if (SQLITE_OK != rval) { + fprintf(stderr, "CQnetDB::FindLS error: %d\n", rval); + return true; + } + + if (SQLITE_ROW == sqlite3_step(stmt)) { + address.assign((const char *)sqlite3_column_text(stmt, 0)); + port = (unsigned short)(sqlite3_column_int(stmt, 1)); + sqlite3_finalize(stmt); + return false; + } else { + sqlite3_finalize(stmt); + return true; + } +} + +void CQnetDB::ClearGW() +{ + std::string sql("DELETE FROM GATEWAYS;"); + char *eMsg; + + if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) { + fprintf(stderr, "CQnetDB::Open drop table LINKSTATUS error: %s\n", eMsg); + sqlite3_free(eMsg); + } + +} diff --git a/QnetDB.h b/QnetDB.h index 4e3ffd5..dcf0f32 100644 --- a/QnetDB.h +++ b/QnetDB.h @@ -55,8 +55,11 @@ public: bool Init(); bool UpdateLH(const char *callsign, const char *sfx, const char module, const char *reflector); bool UpdateLS(const char *address, const char from_mod, const char *to_callsign, const char to_mod, time_t connect_time); + bool UpdateGW(const char *name, const char *address, unsigned short port); bool DeleteLS(const char *address); bool FindLS(const char mod, std::list &linklist); + bool FindGW(const char *name, std::string &address, unsigned short &port); + void ClearGW(); private: sqlite3 *db; diff --git a/QnetGateway.cpp b/QnetGateway.cpp index 93f3fde..01ad76d 100644 --- a/QnetGateway.cpp +++ b/QnetGateway.cpp @@ -230,6 +230,7 @@ bool CQnetGateway::ReadConfig(char *cfgFile) else if (0 == type.compare("mmdvmhost")) { Rptr.mod[m].package_version.assign(GW_VERSION+".Relay"); } else if (0 == type.compare("mmdvmmodem")) { Rptr.mod[m].package_version.assign(GW_VERSION+".Modem"); } else if (0 == type.compare("itap")) { Rptr.mod[m].package_version.assign(GW_VERSION+".ITAP"); } + else if (0 == type.compare("thumbdv")) { Rptr.mod[m].package_version.assign(GW_VERSION+".ThumbDV"); } else { printf("module type '%s' is invalid\n", type.c_str()); return true; diff --git a/QnetLink.cpp b/QnetLink.cpp index e667cd0..30a34a1 100644 --- a/QnetLink.cpp +++ b/QnetLink.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -51,6 +52,7 @@ #include "DPlusAuthenticator.h" #include "QnetConfigure.h" #include "QnetLink.h" +#include "Utilities.h" #define LINK_VERSION "QnetLink-409" #ifndef BIN_DIR @@ -293,111 +295,37 @@ bool CQnetLink::load_gwys(const std::string &filename) // DPlus Authenticate if (dplus_authorize && !dplus_priority) { CDPlusAuthenticator auth(login_call, std::string("auth.dstargateway.org")); - if (auth.Process(gwy_list, dplus_reflectors, dplus_repeaters)) + if (auth.Process(qnDB, dplus_reflectors, dplus_repeaters)) fprintf(stdout, "DPlus Authorization failed.\n"); else fprintf(stderr, "DPlus Authorization complete!\n"); } - char inbuf[1024]; - const char *delim = " "; - - char call[CALL_SIZE + 1]; - char host[MAXHOSTNAMELEN + 1]; - char port[5 + 1]; - - /* host + space + port + NULL */ - char payload[MAXHOSTNAMELEN + 1 + 5 + 1]; - unsigned short j; - - printf("Trying to open file %s\n", filename.c_str()); - FILE *fp = fopen(filename.c_str(), "r"); - if (fp == NULL) { - printf("Failed to open file %s\n", filename.c_str()); - return false; - } - printf("Opened file %s OK\n", filename.c_str()); - - while (fgets(inbuf, 1020, fp) != NULL) { - char *p = strchr(inbuf, '\r'); - if (p) - *p = '\0'; - - p = strchr(inbuf, '\n'); - if (p) - *p = '\0'; - - p = strchr(inbuf, '#'); - if (p) { - printf("Comment line:[%s]\n", inbuf); - continue; - } - - /* get the call */ - char *tok = strtok(inbuf, delim); - if (!tok) - continue; - if ((strlen(tok) > CALL_SIZE) || (strlen(tok) < 3)) { - printf("Invalid call [%s]\n", tok); - continue; - } - memset(call, ' ', CALL_SIZE); - call[CALL_SIZE] = '\0'; - memcpy(call, tok, strlen(tok)); - for (j = 0; j < strlen(call); j++) - call[j] = toupper(call[j]); - if (strcmp(call, owner.c_str()) == 0) { - printf("Call [%s] will not be loaded\n", call); - continue; - } - - /* get the host */ - tok = strtok(NULL, delim); - if (!tok) { - printf("Call [%s] has no host\n", call); - continue; - } - strncpy(host,tok,MAXHOSTNAMELEN); - host[MAXHOSTNAMELEN] = '\0'; - if (strcmp(host, "0.0.0.0") == 0) { - printf("call %s has invalid host %s\n", call, host); - continue; - } - - /* get the port */ - tok = strtok(NULL, delim); - if (!tok) { - printf("Call [%s] has no port\n", call); - continue; - } - if (strlen(tok) > 5) { - printf("call %s has invalid port [%s]\n", call, tok); - continue; + std::ifstream hostfile(filename); + if (hostfile.is_open()) { + std::string line; + while (std::getline(hostfile, line)) { + trim(line); + if (! line.empty() && ('#' != line.at(0))) { + std::istringstream iss(line); + std::string host, address; + unsigned short port; + iss >> host >> address >> port; + qnDB.UpdateGW(host.c_str(), address.c_str(), port); + } } - strcpy(port, tok); - - /* at this point, we have: call host port */ - /* copy the payload(host port) */ - sprintf(payload, "%s %s", host, port); - - auto gwy_pos = gwy_list.find(call); - if (gwy_pos != gwy_list.end()) - printf("%s %s has been redefined!\n", call, payload); - gwy_list[call] = payload; + hostfile.close(); } - fclose(fp); + // DPlus Authenticate if (dplus_authorize && dplus_priority) { CDPlusAuthenticator auth(login_call, std::string("auth.dstargateway.org")); - if (auth.Process(gwy_list, dplus_reflectors, dplus_repeaters)) + if (auth.Process(qnDB, dplus_reflectors, dplus_repeaters)) fprintf(stdout, "DPlus Authorization failed.\n"); else fprintf(stderr, "DPlus Authorization completed!\n"); } - //for (auto it=gwy_list.begin(); it!=gwy_list.end(); it++) - // printf("%s %s\n", it->first.c_str(), it->second.c_str()); - printf("Added %d gateways from gwys.txt\n", (int)gwy_list.size()); return true; } @@ -714,15 +642,6 @@ void CQnetLink::srv_close() void CQnetLink::g2link(const char from_mod, const char *call, const char to_mod) { char linked_remote_system[CALL_SIZE + 1]; - char *space_p = 0; - - char host[MAXHOSTNAMELEN + 1]; - char port_s[5 + 1]; - unsigned short port_i; - - /* host + space + port + NULL */ - char payload[MAXHOSTNAMELEN + 1 + 5 + 1]; - char *p = NULL; char link_request[519]; @@ -730,10 +649,6 @@ void CQnetLink::g2link(const char from_mod, const char *call, const char to_mod) memset(link_request, 0, sizeof(link_request)); - host[0] = '\0'; - port_s[0] = '\0'; - payload[0] = '\0'; - int i; if (from_mod == 'A') i = 0; @@ -775,31 +690,18 @@ void CQnetLink::g2link(const char from_mod, const char *call, const char to_mod) } } - auto gwy_pos = gwy_list.find(call); - if (gwy_pos == gwy_list.end()) { + std::string address; + unsigned short port; + if (qnDB.FindGW(call, address, port)) { sprintf(notify_msg[i], "%c_gatewaynotfound.dat_GATEWAY_NOT_FOUND", from_mod); printf("%s not found in gwy list\n", call); return; } - strcpy(payload, gwy_pos->second.c_str()); - - /* extract host and port */ - p = strchr(payload, ' '); - if (!p) { - printf("Invalid payload [%s] for call [%s]\n", payload, call); - return; - } - *p = '\0'; - - strcpy(host, payload); - strcpy(port_s, p + 1); - port_i = (unsigned short)atoi(port_s); - - if (host[0] != '\0') { - ok = resolve_rmt(host, port_i, to_remote_g2[i].addr); + if (address.size()) { + ok = resolve_rmt(address.c_str(), port, to_remote_g2[i].addr); if (!ok) { - printf("Call %s is host %s but could not resolve to IP\n", call, host); + printf("Call %s is host %s but could not resolve to IP\n", call, address.c_str()); to_remote_g2[i].addr.Clear(); to_remote_g2[i].countdown = 0; to_remote_g2[i].from_mod = '\0'; @@ -819,17 +721,17 @@ void CQnetLink::g2link(const char from_mod, const char *call, const char to_mod) to_remote_g2[i].in_streamid= 0x0; /* is it XRF? */ - if (port_i == rmt_xrf_port) { + if (port == rmt_xrf_port) { strcpy(link_request, owner.c_str()); link_request[8] = from_mod; link_request[9] = to_mod; link_request[10] = '\0'; - printf("sending link request from mod %c to link with: [%s] mod %c [%s]\n", to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod, payload); + printf("sending link request from mod %c to link with: [%s] mod %c [%s]:%u\n", to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod, address.c_str(), port); for (int j=0; j<5; j++) sendto(xrf_g2_sock, link_request, CALL_SIZE + 3, 0, to_remote_g2[i].addr.GetCPointer(), to_remote_g2[i].addr.GetSize()); - } else if (port_i == rmt_dcs_port) { + } else if (port == rmt_dcs_port) { strcpy(link_request, owner.c_str()); link_request[8] = from_mod; link_request[9] = to_mod; @@ -837,9 +739,9 @@ void CQnetLink::g2link(const char from_mod, const char *call, const char to_mod) memcpy(link_request + 11, to_remote_g2[i].cs, 8); strcpy(link_request + 19, "
REPEATER QnetGateway v1.0+
"); - printf("sending link request from mod %c to link with: [%s] mod %c [%s]\n", to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod, payload); + printf("sending link request from mod %c to link with: [%s] mod %c [%s]:%u\n", to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod, address.c_str(), port); sendto(dcs_g2_sock, link_request, 519, 0, to_remote_g2[i].addr.GetCPointer(), to_remote_g2[i].addr.GetSize()); - } else if (port_i == rmt_ref_port) { + } else if (port == rmt_ref_port) { int counter; for (counter = 0; counter < 3; counter++) { if (counter != i) { @@ -848,7 +750,7 @@ void CQnetLink::g2link(const char from_mod, const char *call, const char to_mod) } } if (counter > 2) { - printf("sending link command from mod %c to: [%s] mod %c [%s]\n", to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod, payload); + printf("sending link command from mod %c to: [%s] mod %c [%s]:%u\n", to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod, address.c_str(), port); queryCommand[0] = 5; queryCommand[1] = 0; @@ -866,7 +768,7 @@ void CQnetLink::g2link(const char from_mod, const char *call, const char to_mod) // announce it here strcpy(linked_remote_system, to_remote_g2[i].cs); - space_p = strchr(linked_remote_system, ' '); + auto space_p = strchr(linked_remote_system, ' '); if (space_p) *space_p = '\0'; sprintf(notify_msg[i], "%c_linked.dat_LINKED_%s_%c", to_remote_g2[i].from_mod, linked_remote_system, to_remote_g2[i].to_mod); @@ -1283,8 +1185,9 @@ void CQnetLink::Process() i = 2; /* Is this repeater listed in gwys.txt? */ - auto gwy_pos = gwy_list.find(call); - if (gwy_pos == gwy_list.end()) { + std::string Address; + unsigned short Port; + if (qnDB.FindGW(call, Address, Port)) { /* We did NOT find this repeater in gwys.txt, reject the incoming link request */ printf("Incoming link from %s,%s but not found in gwys.txt\n", call, ip.c_str()); i = -1; @@ -2839,7 +2742,7 @@ void CQnetLink::Process() } } else if (0==memcmp(dsvt.hdr.urcall, " F", CALL_SIZE) && admin.find(call)!=admin.end()) { // only ADMIN can reload gwys.txt - gwy_list.clear(); + qnDB.ClearGW(); load_gwys(gwys); } } diff --git a/QnetLink.h b/QnetLink.h index 5471edd..e33d76c 100644 --- a/QnetLink.h +++ b/QnetLink.h @@ -160,10 +160,6 @@ private: // Used to validate incoming donglers regex_t preg; - // the map of remotes - // key is the callsign, data is the host - std::map gwy_list; - unsigned char queryCommand[QUERY_SIZE]; // START: TEXT crap