rptr_status moved to CQnetDB

pull/14/head
Tom Early 6 years ago
parent ed6d0baca1
commit 9e1a0e43d2

@ -52,8 +52,8 @@ modem : qnmodem
qngateway : QnetGateway.o aprs.o UnixDgramSocket.o TCPReaderWriterClient.o QnetConfigure.o QnetDB.o CacheManager.o DStarDecode.o $(IRCOBJS) qngateway : QnetGateway.o aprs.o UnixDgramSocket.o TCPReaderWriterClient.o QnetConfigure.o QnetDB.o CacheManager.o DStarDecode.o $(IRCOBJS)
g++ $(CPPFLAGS) -o $@ $^ $(LDFLAGS) -l sqlite3 -pthread g++ $(CPPFLAGS) -o $@ $^ $(LDFLAGS) -l sqlite3 -pthread
qnlink : QnetLink.o DPlusAuthenticator.o TCPReaderWriterClient.o UnixDgramSocket.o QnetConfigure.o qnlink : QnetLink.o DPlusAuthenticator.o TCPReaderWriterClient.o UnixDgramSocket.o QnetConfigure.o QnetDB.o
g++ $(CPPFLAGS) -o $@ $^ $(LDFLAGS) -pthread g++ $(CPPFLAGS) -o $@ $^ $(LDFLAGS) -l sqlite3 -pthread
qnrelay : QnetRelay.o UnixDgramSocket.o QnetConfigure.o qnrelay : QnetRelay.o UnixDgramSocket.o QnetConfigure.o
g++ $(CPPFLAGS) -o $@ $^ $(LDFLAGS) g++ $(CPPFLAGS) -o $@ $^ $(LDFLAGS)

@ -21,27 +21,55 @@
bool CQnetDB::Open(const char *name) bool CQnetDB::Open(const char *name)
{ {
if (sqlite3_open(name, &db)) if (sqlite3_open(name, &db)) {
fprintf(stderr, "CQnetDB::Open: can't open %s\n", name);
return true; return true;
} else
return false;
}
std::string sql = "DROP TABLE IF EXISTS LHEARD;"; bool CQnetDB::Init()
{
std::string sql("DROP TABLE IF EXISTS LHEARD;");
char *eMsg; char *eMsg;
if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) { if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) {
fprintf(stderr, "CQnetDB::Open drop table error: %s\n", eMsg); fprintf(stderr, "CQnetDB::Open drop table LHEARD error: %s\n", eMsg);
sqlite3_free(eMsg); sqlite3_free(eMsg);
return true; return true;
} }
sql = "CREATE TABLE LHEARD(" sql.assign("CREATE TABLE LHEARD("
"mycall TEXT PRIMARY KEY, " "mycall TEXT PRIMARY KEY, "
"sfx TEXT, " "sfx TEXT, "
"urcall TEXT, " "urcall TEXT, "
"lasttime INT NOT NULL" "lasttime INT NOT NULL"
") WITHOUT ROWID;"; ") WITHOUT ROWID;");
if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) {
fprintf(stderr, "CQnetDB::Open create table LHEARD error: %s\n", eMsg);
sqlite3_free(eMsg);
return true;
}
sql.assign("DROP TABLE IF EXISTS LINKSTATUS;");
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 LINKSTATUS("
"ip_address TEXT PRIMARY KEY, "
"from_mod TEXT NOT NULL, "
"to_callsign TEXT NOT NULL, "
"to_mod TEXT NOT NULL, "
"linked_time INT NOT NULL"
") WITHOUT ROWID;");
if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) { if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) {
fprintf(stderr, "CQnetDB::Open create table error: %s\n", eMsg); fprintf(stderr, "CQnetDB::Open create table LINKSTATUS error: %s\n", eMsg);
sqlite3_free(eMsg); sqlite3_free(eMsg);
return true; return true;
} }
@ -49,11 +77,11 @@ bool CQnetDB::Open(const char *name)
return false; return false;
} }
bool CQnetDB::Update(const char *mycall, const char *sfx, const char *urcall) bool CQnetDB::UpdateLH(const char *mycall, const char *sfx, const char *urcall)
{ {
if (NULL == db) if (NULL == db)
return false; return false;
std::string sql = "REPLACE INTO LHEARD (mycall,sfx,urcall,lasttime) VALUES ('"; std::string sql("REPLACE INTO LHEARD (mycall,sfx,urcall,lasttime) VALUES ('");
sql.append(mycall); sql.append(mycall);
sql.append("','"); sql.append("','");
sql.append(sfx); sql.append(sfx);
@ -64,10 +92,83 @@ bool CQnetDB::Update(const char *mycall, const char *sfx, const char *urcall)
char *eMsg; char *eMsg;
if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) { if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) {
fprintf(stderr, "CQnetDB::Update error: %s\n", eMsg); fprintf(stderr, "CQnetDB::UpdateLH error: %s\n", eMsg);
sqlite3_free(eMsg); sqlite3_free(eMsg);
return true; return true;
} }
return false; return false;
} }
bool CQnetDB::UpdateLS(const char *address, const char from_mod, const char *to_callsign, const char to_mod, time_t linked_time)
{
if (NULL == db)
return false;
std::string sql = "REPLACE INTO LINKSTATUS (ip_address,from_mod,to_callsign,to_mod,linked_time) VALUES ('";
sql.append(address);
sql.append("','");
sql.append(1, from_mod);
sql.append("','");
sql.append(to_callsign);
sql.append("','");
sql.append(1, to_mod);
sql.append("',");
sql.append(std::to_string(linked_time).c_str());
sql.append(");");
char *eMsg;
if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) {
fprintf(stderr, "CQnetDB::UpdateLS error: %s\n", eMsg);
sqlite3_free(eMsg);
return true;
}
return false;
}
bool CQnetDB::DeleteLS(const char *address)
{
if (NULL == db)
return false;
std::string sql("DELETE FROM LINKSTATUS WHERE ip_address=='");
sql.append(address);
sql.append("';");
char *eMsg;
if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) {
fprintf(stderr, "CQnetDB::DeleteLS error: %s\n", eMsg);
sqlite3_free(eMsg);
return true;
}
return false;
}
bool CQnetDB::FindLS(const char mod, std::list<CLink> &linklist)
{
if (NULL == db)
return false;
std::string sql("SELECT ip_address,to_callsign,to_mod,linked_time FROM LINKSTATUS WHERE from_mod=='");
sql.append(1, mod);
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;
}
while (SQLITE_ROW == sqlite3_step(stmt)) {
std::string cs((const char *)sqlite3_column_text(stmt, 1));
std::string mod((const char *)sqlite3_column_text(stmt, 2));
if (mod.at(0) != 'p') {
cs.resize(7, ' ');
cs.append(mod);
}
linklist.push_back(CLink(cs, sqlite3_column_text(stmt, 0), sqlite3_column_int(stmt, 3)));
}
sqlite3_finalize(stmt);
return false;
}

@ -19,13 +19,44 @@
#include <stdio.h> #include <stdio.h>
#include <sqlite3.h> #include <sqlite3.h>
#include <string>
#include <list>
class CLink {
public:
CLink(const std::string &call, const unsigned char *addr, time_t ltime) : callsign(call) , address((const char *)addr) , linked_time(ltime) {}
CLink(const CLink &from)
{
callsign.assign(from.callsign);
address.assign(from.address),
linked_time=from.linked_time;
}
CLink &operator=(const CLink &from)
{
callsign.assign(from.callsign);
address.assign(from.address),
linked_time=from.linked_time;
return *this;
}
~CLink() {}
std::string callsign, address;
time_t linked_time;
};
class CQnetDB { class CQnetDB {
public: public:
CQnetDB() : db(NULL) {} CQnetDB() : db(NULL) {}
~CQnetDB() { if (db) sqlite3_close(db); } ~CQnetDB() { if (db) sqlite3_close(db); }
bool Open(const char *name); bool Open(const char *name);
bool Update(const char *mycall, const char *sfx, const char *urcall); bool Init();
bool UpdateLH(const char *mycall, const char *sfx, const char *urcall);
bool UpdateLS(const char *address, const char from_mod, const char *to_callsign, const char to_mod, time_t connect_time);
bool DeleteLS(const char *address);
bool FindLS(const char mod, std::list<CLink> &linklist);
private: private:
sqlite3 *db; sqlite3 *db;

@ -114,42 +114,19 @@ void CQnetGateway::PrintCallsigns(const std::string &key, const std::set<std::st
} }
void CQnetGateway::set_dest_rptr(int mod_ndx, char *dest_rptr) void CQnetGateway::set_dest_rptr(const char mod, std::string &call)
{ {
FILE *statusfp = fopen(FILE_STATUS.c_str(), "r"); std::list<CLink> linklist;
if (statusfp) { if (qnDB.FindLS(mod, linklist))
setvbuf(statusfp, (char *)NULL, _IOLBF, 0); return;
char statusbuf[1024];
while (fgets(statusbuf, 1020, statusfp) != NULL) {
char *p = strchr(statusbuf, '\r');
if (p)
*p = '\0';
p = strchr(statusbuf, '\n');
if (p)
*p = '\0';
const char *delim = ",";
char *saveptr = NULL;
char *status_local_mod = strtok_r(statusbuf, delim, &saveptr);
char *status_remote_stm = strtok_r(NULL, delim, &saveptr);
char *status_remote_mod = strtok_r(NULL, delim, &saveptr);
if (!status_local_mod || !status_remote_stm || !status_remote_mod)
continue;
if ( ((*status_local_mod == 'A') && (mod_ndx == 0)) || auto count = linklist.size();
((*status_local_mod == 'B') && (mod_ndx == 1)) || if (count != 1)
((*status_local_mod == 'C') && (mod_ndx == 2)) ) { printf("set_dest_rptr() returned %d link sets\n", int(count));
strncpy(dest_rptr, status_remote_stm, CALL_SIZE); if (0 == count)
dest_rptr[7] = *status_remote_mod; return;
dest_rptr[CALL_SIZE] = '\0';
break; call.assign(linklist.front().callsign);
}
}
fclose(statusfp);
}
return;
} }
/* compute checksum */ /* compute checksum */
@ -330,7 +307,6 @@ bool CQnetGateway::ReadConfig(char *cfgFile)
path.assign("file_"); path.assign("file_");
cfg.GetValue(path+"echotest", estr, FILE_ECHOTEST, 2, FILENAME_MAX); cfg.GetValue(path+"echotest", estr, FILE_ECHOTEST, 2, FILENAME_MAX);
cfg.GetValue(path+"dtmf", estr, FILE_DTMF, 2, FILENAME_MAX); cfg.GetValue(path+"dtmf", estr, FILE_DTMF, 2, FILENAME_MAX);
cfg.GetValue(path+"status", estr, FILE_STATUS, 2, FILENAME_MAX);
cfg.GetValue(path+"qnvoice_file", estr, FILE_QNVOICE_FILE, 2, FILENAME_MAX); cfg.GetValue(path+"qnvoice_file", estr, FILE_QNVOICE_FILE, 2, FILENAME_MAX);
// timing // timing
@ -805,11 +781,8 @@ void CQnetGateway::ProcessSlowData(unsigned char *data, unsigned short sid)
// 100 voice packets received and still no 20-char message! // 100 voice packets received and still no 20-char message!
/*** if YRCALL is CQCQCQ, set dest_rptr ***/ /*** if YRCALL is CQCQCQ, set dest_rptr ***/
band_txt[i].txt[0] = '\0'; band_txt[i].txt[0] = '\0';
if (memcmp(band_txt[i].lh_yrcall, "CQCQCQ", 6) == 0) { if (memcmp(band_txt[i].lh_yrcall, "CQCQCQ", 6) == 0)
set_dest_rptr(i, band_txt[i].dest_rptr); set_dest_rptr(i+'A', band_txt[i].dest_rptr);
if (memcmp(band_txt[i].dest_rptr, "REF", 3) == 0)
band_txt[i].dest_rptr[0] = '\0';
}
int x = FindIndex(i); int x = FindIndex(i);
if (x >= 0) if (x >= 0)
@ -840,11 +813,9 @@ void CQnetGateway::ProcessSlowData(unsigned char *data, unsigned short sid)
band_txt[i].txt[band_txt[i].txt_cnt] = '\0'; band_txt[i].txt[band_txt[i].txt_cnt] = '\0';
if ( ! band_txt[i].sent_key_on_msg) { if ( ! band_txt[i].sent_key_on_msg) {
/*** if YRCALL is CQCQCQ, set dest_rptr ***/ /*** if YRCALL is CQCQCQ, set dest_rptr ***/
if (memcmp(band_txt[i].lh_yrcall, "CQCQCQ", 6) == 0) { if (memcmp(band_txt[i].lh_yrcall, "CQCQCQ", 6) == 0)
set_dest_rptr(i, band_txt[i].dest_rptr); set_dest_rptr(i+'A', band_txt[i].dest_rptr);
if (memcmp(band_txt[i].dest_rptr, "REF", 3) == 0)
band_txt[i].dest_rptr[0] = '\0';
}
// we have the 20-character message, send it to the server... // we have the 20-character message, send it to the server...
int x = FindIndex(i); int x = FindIndex(i);
if (x >= 0) if (x >= 0)
@ -999,7 +970,7 @@ void CQnetGateway::ProcessG2(const ssize_t g2buflen, const SDSVT &g2buf, const i
std::string urcall((const char *)g2buf.hdr.urcall, 8); std::string urcall((const char *)g2buf.hdr.urcall, 8);
rtrim(mycall); rtrim(mycall);
rtrim(sfx); rtrim(sfx);
qnDB.Update(mycall.c_str(), sfx.c_str(), urcall.c_str()); qnDB.UpdateLH(mycall.c_str(), sfx.c_str(), urcall.c_str());
} }
Gate2Modem[i].Write(g2buf.title, 56); Gate2Modem[i].Write(g2buf.title, 56);
@ -1319,8 +1290,7 @@ void CQnetGateway::ProcessModem()
// The remote repeater has been set, lets fill in the dest_rptr // The remote repeater has been set, lets fill in the dest_rptr
// so that later we can send that to the LIVE web site // so that later we can send that to the LIVE web site
memcpy(band_txt[i].dest_rptr, dsvt.hdr.rpt1, 8); band_txt[i].dest_rptr.assign((char *)dsvt.hdr.rpt1, 8);
band_txt[i].dest_rptr[CALL_SIZE] = '\0';
// send to remote gateway // send to remote gateway
for (int j=0; j<5; j++) for (int j=0; j<5; j++)
@ -1373,8 +1343,7 @@ void CQnetGateway::ProcessModem()
// The remote repeater has been set, lets fill in the dest_rptr // The remote repeater has been set, lets fill in the dest_rptr
// so that later we can send that to the LIVE web site // so that later we can send that to the LIVE web site
memcpy(band_txt[i].dest_rptr, dsvt.hdr.rpt1, 8); band_txt[i].dest_rptr.assign((char *)dsvt.hdr.rpt1, 8);
band_txt[i].dest_rptr[CALL_SIZE] = '\0';
/* send to remote gateway */ /* send to remote gateway */
for (int j=0; j<5; j++) for (int j=0; j<5; j++)
@ -1397,9 +1366,8 @@ void CQnetGateway::ProcessModem()
The remote repeater has been set, lets fill in the dest_rptr The remote repeater has been set, lets fill in the dest_rptr
so that later we can send that to the LIVE web site so that later we can send that to the LIVE web site
*/ */
memcpy(band_txt[i].dest_rptr, dsvt.hdr.rpt2, 8); band_txt[i].dest_rptr.assign((char *)dsvt.hdr.rpt2, 7);
band_txt[i].dest_rptr[7] = rptr.at(7); band_txt[i].dest_rptr.append(1, rptr.at(7));
band_txt[i].dest_rptr[8] = '\0';
i = rptr.at(7) - 'A'; i = rptr.at(7) - 'A';
@ -1557,8 +1525,7 @@ void CQnetGateway::ProcessModem()
if (i>=0 && i<3) { if (i>=0 && i<3) {
// The remote repeater has been set, lets fill in the dest_rptr // The remote repeater has been set, lets fill in the dest_rptr
// so that later we can send that to the LIVE web site // so that later we can send that to the LIVE web site
memcpy(band_txt[i].dest_rptr, dsvt.hdr.rpt2, 8); band_txt[i].dest_rptr.append((char *)dsvt.hdr.rpt2, 8);
band_txt[i].dest_rptr[8] = '\0';
} }
i = dsvt.hdr.rpt2[7] - 'A'; i = dsvt.hdr.rpt2[7] - 'A';
@ -1618,9 +1585,7 @@ void CQnetGateway::ProcessModem()
if (! band_txt[i].sent_key_on_msg) { if (! band_txt[i].sent_key_on_msg) {
band_txt[i].txt[0] = '\0'; band_txt[i].txt[0] = '\0';
if (memcmp(band_txt[i].lh_yrcall, "CQCQCQ", 6) == 0) { if (memcmp(band_txt[i].lh_yrcall, "CQCQCQ", 6) == 0) {
set_dest_rptr(i, band_txt[i].dest_rptr); set_dest_rptr(i+'A', band_txt[i].dest_rptr);
if (memcmp(band_txt[i].dest_rptr, "REF", 3) == 0)
band_txt[i].dest_rptr[0] = '\0';
} }
int x = FindIndex(i); int x = FindIndex(i);
if (x >= 0) if (x >= 0)
@ -2259,8 +2224,29 @@ bool CQnetGateway::Init(char *cfgfile)
std::signal(SIGINT, sigCatch); std::signal(SIGINT, sigCatch);
std::signal(SIGHUP, sigCatch); std::signal(SIGHUP, sigCatch);
for (i = 0; i < 3; i++) for (i=0; i<3; i++) {
memset(&band_txt[0], 0, sizeof(SBANDTXT)); band_txt[i].streamID = 0;
memset(band_txt[i].flags, 0, 3);
memset(band_txt[i].lh_mycall, 0, 9);
memset(band_txt[i].lh_sfx, 0, 5);
memset(band_txt[i].lh_yrcall, 0, 9);
memset(band_txt[i].lh_rpt1, 0, 9);
memset(band_txt[i].lh_rpt2, 0, 9);
band_txt[i].last_time = 0;
memset(band_txt[i].txt, 0, 64); // Only 20 are used
band_txt[i].txt_cnt = 0;
band_txt[i].sent_key_on_msg = false;
band_txt[i].dest_rptr.clear();
memset(band_txt[i].temp_line, 0, 256);
band_txt[i].temp_line_cnt = 0U;
memset(band_txt[i].gprmc, 0, 256);
memset(band_txt[i].gpid, 0, 256);
band_txt[i].is_gps_sent = false;
band_txt[i].gps_last_time = 0;
band_txt[i].num_dv_frames = 0;
band_txt[i].num_dv_silent_frames = 0;
band_txt[i].num_bit_errors = 0;
}
/* process configuration file */ /* process configuration file */
if ( ReadConfig(cfgfile) ) { if ( ReadConfig(cfgfile) ) {
@ -2269,13 +2255,12 @@ bool CQnetGateway::Init(char *cfgfile)
} }
// open database // open database
if (showLastHeard) { std::string fname(CFG_DIR);
std::string dbname(CFG_DIR); fname.append("/");
dbname.append("/"); fname.append(DASH_SQL_NAME);
dbname.append(DASH_SQL_NAME); if (qnDB.Open(fname.c_str()) || qnDB.Init())
if (qnDB.Open(dbname.c_str())) return true;
return true;
}
playNotInCache = false; playNotInCache = false;

@ -61,7 +61,7 @@ using SBANDTXT = struct band_txt_tag {
unsigned short txt_cnt; unsigned short txt_cnt;
bool sent_key_on_msg; bool sent_key_on_msg;
char dest_rptr[CALL_SIZE + 1]; std::string dest_rptr;
// try to process GPS mode: GPRMC and ID // try to process GPS mode: GPRMC and ID
char temp_line[256]; char temp_line[256];
@ -103,7 +103,7 @@ private:
std::string gate2link, link2gate, gate2modem[3], modem2gate; std::string gate2link, link2gate, gate2modem[3], modem2gate;
std::string OWNER, owner, FILE_STATUS, FILE_DTMF, FILE_ECHOTEST, IRCDDB_PASSWORD[2], FILE_QNVOICE_FILE, DASH_SQL_NAME, DASH_SHOW_ORDER; std::string OWNER, owner, FILE_DTMF, FILE_ECHOTEST, IRCDDB_PASSWORD[2], FILE_QNVOICE_FILE, DASH_SQL_NAME, DASH_SHOW_ORDER;
bool GATEWAY_SEND_QRGS_MAP, GATEWAY_HEADER_REGEN, APRS_ENABLE, playNotInCache, showLastHeard; bool GATEWAY_SEND_QRGS_MAP, GATEWAY_HEADER_REGEN, APRS_ENABLE, playNotInCache, showLastHeard;
bool LOG_DEBUG, LOG_IRC, LOG_DTMF, LOG_QSO; bool LOG_DEBUG, LOG_IRC, LOG_DTMF, LOG_QSO;
@ -191,6 +191,6 @@ private:
void qrgs_and_maps(); void qrgs_and_maps();
void set_dest_rptr(int mod_ndx, char *dest_rptr); void set_dest_rptr(const char mod, std::string &call);
bool validate_csum(SBANDTXT &bt, bool is_gps); bool validate_csum(SBANDTXT &bt, bool is_gps);
}; };

@ -52,10 +52,13 @@
#include "QnetConfigure.h" #include "QnetConfigure.h"
#include "QnetLink.h" #include "QnetLink.h"
#define LINK_VERSION "QnetLink-7.3" #define LINK_VERSION "QnetLink-327"
#ifndef BIN_DIR #ifndef BIN_DIR
#define BIN_DIR "/usr/local/bin" #define BIN_DIR "/usr/local/bin"
#endif #endif
#ifndef CFG_DIR
#define CFG_DIR "/usr/local/etc"
#endif
std::atomic<bool> CQnetLink::keep_running(true); std::atomic<bool> CQnetLink::keep_running(true);
@ -121,8 +124,6 @@ bool CQnetLink::resolve_rmt(const char *name, const unsigned short port, CSockAd
/* send keepalive to donglers */ /* send keepalive to donglers */
void CQnetLink::send_heartbeat() void CQnetLink::send_heartbeat()
{ {
bool removed = false;
for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) { for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) {
SINBOUND *inbound = (SINBOUND *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
sendto(ref_g2_sock, REF_ACK, 3, 0, inbound->addr.GetPointer(), inbound->addr.GetSize()); sendto(ref_g2_sock, REF_ACK, 3, 0, inbound->addr.GetPointer(), inbound->addr.GetSize());
@ -131,16 +132,12 @@ void CQnetLink::send_heartbeat()
inbound->countdown --; inbound->countdown --;
if (inbound->countdown < 0) { if (inbound->countdown < 0) {
removed = true;
printf("call=%s timeout, removing %s, users=%d\n", inbound->call, pos->first.c_str(), (int)inbound_list.size() - 1); printf("call=%s timeout, removing %s, users=%d\n", inbound->call, pos->first.c_str(), (int)inbound_list.size() - 1);
qnDB.DeleteLS(pos->first.c_str());
free(pos->second); delete pos->second;
pos->second = NULL;
inbound_list.erase(pos); inbound_list.erase(pos);
} }
} }
if (removed)
print_status_file();
} }
void CQnetLink::rptr_ack(short i) void CQnetLink::rptr_ack(short i)
@ -290,41 +287,6 @@ void CQnetLink::RptrAckThread(char *arg)
} }
} }
void CQnetLink::print_status_file()
{
FILE *statusfp = fopen(status_file.c_str(), "w");
if (!statusfp)
printf("Failed to create status file %s\n", status_file.c_str());
else {
setvbuf(statusfp, (char *)NULL, _IOLBF, 0);
struct tm tm1;
time_t tnow;
const char *fstr = "%c,%s,%c,%s,%02d%02d%02d,%02d:%02d:%02d\n";
time(&tnow);
localtime_r(&tnow, &tm1);
/* print connected donglers */
for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) {
fprintf(statusfp, fstr, 'p', pos->second->call, 'p', pos->first.c_str(), tm1.tm_mon+1,tm1.tm_mday,tm1.tm_year % 100, tm1.tm_hour,tm1.tm_min,tm1.tm_sec);
}
/* print linked repeaters-reflectors */
SLINKFAMILY fam;
memcpy(fam.title, "LINK", 4);
for (int i=0; i<3;i++) {
if (to_remote_g2[i].is_connected) {
fprintf(statusfp, fstr, to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod, to_remote_g2[i].addr.GetAddress(), tm1.tm_mon+1, tm1.tm_mday ,tm1.tm_year % 100, tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
// also inform gateway
fam.family[i] = to_remote_g2[i].addr.GetFamily();
} else {
fam.family[i] = AF_UNSPEC;
}
}
Link2Gate.Write(fam.title, sizeof(SLINKFAMILY));
fclose(statusfp);
}
}
/* Open text file of repeaters, reflectors */ /* Open text file of repeaters, reflectors */
bool CQnetLink::load_gwys(const std::string &filename) bool CQnetLink::load_gwys(const std::string &filename)
{ {
@ -611,7 +573,6 @@ bool CQnetLink::read_config(const char *cfgFile)
key.assign("file_"); key.assign("file_");
cfg.GetValue(key+"gwys", estr, gwys, 2, FILENAME_MAX); cfg.GetValue(key+"gwys", estr, gwys, 2, FILENAME_MAX);
cfg.GetValue(key+"status", estr, status_file, 2, FILENAME_MAX);
cfg.GetValue(key+"qnvoice_file", estr, qnvoice_file, 2, FILENAME_MAX); cfg.GetValue(key+"qnvoice_file", estr, qnvoice_file, 2, FILENAME_MAX);
cfg.GetValue(key+"announce_dir", estr, announce_dir, 2, FILENAME_MAX); cfg.GetValue(key+"announce_dir", estr, announce_dir, 2, FILENAME_MAX);
@ -632,6 +593,8 @@ bool CQnetLink::read_config(const char *cfgFile)
} }
cfg.GetValue(key+"priority", estr, dplus_priority); cfg.GetValue(key+"priority", estr, dplus_priority);
cfg.GetValue("dash_sql_filename", estr, dash_sql_name, 2, 32);
return false; return false;
} }
@ -899,7 +862,6 @@ void CQnetLink::g2link(const char from_mod, const char *call, const char to_mod)
to_remote_g2[i].is_connected = true; to_remote_g2[i].is_connected = true;
printf("Local module %c is also connected to %s %c\n", from_mod, call, to_mod); printf("Local module %c is also connected to %s %c\n", from_mod, call, to_mod);
print_status_file();
tracing[i].last_time = time(NULL); tracing[i].last_time = time(NULL);
// announce it here // announce it here
@ -940,7 +902,7 @@ void CQnetLink::Process()
unsigned char dcs_buf[1000];; unsigned char dcs_buf[1000];;
char call[CALL_SIZE + 1]; char call[CALL_SIZE + 1];
char ip[INET6_ADDRSTRLEN + 1]; std::string ip;
bool found = false; bool found = false;
unsigned char your[3] = { 'C', 'C', 'C' }; unsigned char your[3] = { 'C', 'C', 'C' };
@ -1067,7 +1029,7 @@ void CQnetLink::Process()
printf("Unlinked from [%s] mod %c, TIMEOUT...\n", to_remote_g2[i].cs, to_remote_g2[i].to_mod); printf("Unlinked from [%s] mod %c, TIMEOUT...\n", to_remote_g2[i].cs, to_remote_g2[i].to_mod);
sprintf(notify_msg[i], "%c_unlinked.dat_LINK_TIMEOUT", to_remote_g2[i].from_mod); sprintf(notify_msg[i], "%c_unlinked.dat_LINK_TIMEOUT", to_remote_g2[i].from_mod);
qnDB.DeleteLS(to_remote_g2[i].addr.GetAddress());
if (to_remote_g2[i].auto_link) { if (to_remote_g2[i].auto_link) {
char cs[CALL_SIZE+1]; char cs[CALL_SIZE+1];
memcpy(cs, to_remote_g2[i].cs, CALL_SIZE+1); // call is passed by pointer so we have to copy it memcpy(cs, to_remote_g2[i].cs, CALL_SIZE+1); // call is passed by pointer so we have to copy it
@ -1080,10 +1042,6 @@ void CQnetLink::Process()
to_remote_g2[i].is_connected = false; to_remote_g2[i].is_connected = false;
to_remote_g2[i].in_streamid = 0x0; to_remote_g2[i].in_streamid = 0x0;
} }
print_status_file();
} }
} }
@ -1134,7 +1092,7 @@ void CQnetLink::Process()
for (int j=0; j<2; j++) for (int j=0; j<2; j++)
sendto(dcs_g2_sock, cmd_2_dcs, 19 ,0, to_remote_g2[i].addr.GetPointer(), to_remote_g2[i].addr.GetSize()); sendto(dcs_g2_sock, cmd_2_dcs, 19 ,0, to_remote_g2[i].addr.GetPointer(), to_remote_g2[i].addr.GetSize());
} }
qnDB.DeleteLS(to_remote_g2[i].addr.GetAddress());
sprintf(notify_msg[i], "%c_unlinked.dat_UNLINKED_TIMEOUT", to_remote_g2[i].from_mod); sprintf(notify_msg[i], "%c_unlinked.dat_UNLINKED_TIMEOUT", to_remote_g2[i].from_mod);
to_remote_g2[i].cs[0] = '\0'; to_remote_g2[i].cs[0] = '\0';
@ -1143,8 +1101,6 @@ void CQnetLink::Process()
to_remote_g2[i].countdown = 0; to_remote_g2[i].countdown = 0;
to_remote_g2[i].is_connected = false; to_remote_g2[i].is_connected = false;
to_remote_g2[i].in_streamid = 0x0; to_remote_g2[i].in_streamid = 0x0;
print_status_file();
} }
} }
} }
@ -1188,8 +1144,7 @@ void CQnetLink::Process()
unsigned char buf[100]; unsigned char buf[100];
int length = recvfrom(xrf_g2_sock, buf, 100, 0, fromDst4.GetPointer(), &fromlen); int length = recvfrom(xrf_g2_sock, buf, 100, 0, fromDst4.GetPointer(), &fromlen);
strncpy(ip, fromDst4.GetAddress(), INET6_ADDRSTRLEN); ip.assign(fromDst4.GetAddress());
ip[INET6_ADDRSTRLEN] = '\0';
memcpy(call, buf, CALL_SIZE); memcpy(call, buf, CALL_SIZE);
call[CALL_SIZE] = '\0'; call[CALL_SIZE] = '\0';
@ -1207,7 +1162,6 @@ void CQnetLink::Process()
to_remote_g2[i].is_connected = true; to_remote_g2[i].is_connected = true;
printf("Connected from: %.*s\n", length - 1, buf); printf("Connected from: %.*s\n", length - 1, buf);
print_status_file();
strcpy(linked_remote_system, to_remote_g2[i].cs); strcpy(linked_remote_system, to_remote_g2[i].cs);
space_p = strchr(linked_remote_system, ' '); space_p = strchr(linked_remote_system, ' ');
@ -1231,7 +1185,7 @@ void CQnetLink::Process()
to_remote_g2[i].is_connected = true; to_remote_g2[i].is_connected = true;
printf("Connected from: [%s] %c\n", to_remote_g2[i].cs, to_remote_g2[i].to_mod); printf("Connected from: [%s] %c\n", to_remote_g2[i].cs, to_remote_g2[i].to_mod);
print_status_file(); qnDB.UpdateLS(fromDst4.GetAddress(), to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod, time(NULL));
strcpy(linked_remote_system, to_remote_g2[i].cs); strcpy(linked_remote_system, to_remote_g2[i].cs);
space_p = strchr(linked_remote_system, ' '); space_p = strchr(linked_remote_system, ' ');
@ -1250,8 +1204,6 @@ void CQnetLink::Process()
to_remote_g2[i].countdown = 0; to_remote_g2[i].countdown = 0;
to_remote_g2[i].is_connected = false; to_remote_g2[i].is_connected = false;
to_remote_g2[i].in_streamid = 0x0; to_remote_g2[i].in_streamid = 0x0;
print_status_file();
} }
} }
} }
@ -1267,7 +1219,7 @@ void CQnetLink::Process()
if (buf[9] == ' ') { if (buf[9] == ' ') {
printf("Received: %.*s\n", length - 1, buf); printf("Received: %.*s\n", length - 1, buf);
printf("Module %c to [%s] %c is unlinked\n", to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod); printf("Module %c to [%s] %c is unlinked\n", to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod);
qnDB.DeleteLS(to_remote_g2[i].addr.GetAddress());
sprintf(notify_msg[i], "%c_unlinked.dat_UNLINKED", to_remote_g2[i].from_mod); sprintf(notify_msg[i], "%c_unlinked.dat_UNLINKED", to_remote_g2[i].from_mod);
to_remote_g2[i].cs[0] = '\0'; to_remote_g2[i].cs[0] = '\0';
@ -1276,8 +1228,6 @@ void CQnetLink::Process()
to_remote_g2[i].countdown = 0; to_remote_g2[i].countdown = 0;
to_remote_g2[i].is_connected = false; to_remote_g2[i].is_connected = false;
to_remote_g2[i].in_streamid = 0x0; to_remote_g2[i].in_streamid = 0x0;
print_status_file();
} else } else
/* link request from a remote repeater that we know */ /* link request from a remote repeater that we know */
if ((i==0 && buf[9]=='A') || (i==1 && buf[9]=='B') || (i==2 && buf[9]=='C')) { if ((i==0 && buf[9]=='A') || (i==1 && buf[9]=='B') || (i==2 && buf[9]=='C')) {
@ -1302,7 +1252,7 @@ void CQnetLink::Process()
tracing[i].last_time = time(NULL); tracing[i].last_time = time(NULL);
print_status_file();
/* send back an ACK */ /* send back an ACK */
memcpy(buf + 10, "ACK", 4); memcpy(buf + 10, "ACK", 4);
@ -1336,12 +1286,12 @@ void CQnetLink::Process()
auto gwy_pos = gwy_list.find(call); auto gwy_pos = gwy_list.find(call);
if (gwy_pos == gwy_list.end()) { if (gwy_pos == gwy_list.end()) {
/* We did NOT find this repeater in gwys.txt, reject the incoming link request */ /* 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); printf("Incoming link from %s,%s but not found in gwys.txt\n", call, ip.c_str());
i = -1; i = -1;
} else { } else {
int rc = regexec(&preg, call, 0, NULL, 0); int rc = regexec(&preg, call, 0, NULL, 0);
if (rc != 0) { if (rc != 0) {
printf("Invalid repeater %s,%s requesting to link\n", call, ip); printf("Invalid repeater %s,%s requesting to link\n", call, ip.c_str());
i = -1; i = -1;
} }
} }
@ -1366,9 +1316,8 @@ void CQnetLink::Process()
to_remote_g2[i].is_connected = true; to_remote_g2[i].is_connected = true;
to_remote_g2[i].in_streamid = 0x0; to_remote_g2[i].in_streamid = 0x0;
print_status_file();
tracing[i].last_time = time(NULL); tracing[i].last_time = time(NULL);
qnDB.UpdateLS(to_remote_g2[i].addr.GetAddress(), to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod, tracing[i].last_time);
printf("Received: %.*s\n", length - 1, buf); printf("Received: %.*s\n", length - 1, buf);
printf("Module %c to [%s] %c linked\n", to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod); printf("Module %c to [%s] %c linked\n", to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod);
@ -1494,7 +1443,9 @@ void CQnetLink::Process()
/* no changes here */ /* no changes here */
for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) { for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) {
SINBOUND *inbound = (SINBOUND *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
if (! (fromDst4 == inbound->addr)) { if (fromDst4 == inbound->addr) {
inbound->mod = dsvt.hdr.rpt1[7];
} else {
SREFDSVT rdsvt; SREFDSVT rdsvt;
rdsvt.head[0] = (unsigned char)(58 & 0xFF); rdsvt.head[0] = (unsigned char)(58 & 0xFF);
rdsvt.head[1] = (unsigned char)(58 >> 8 & 0x1F); rdsvt.head[1] = (unsigned char)(58 >> 8 & 0x1F);
@ -1502,8 +1453,7 @@ void CQnetLink::Process()
memcpy(rdsvt.dsvt.title, dsvt.title, 56); memcpy(rdsvt.dsvt.title, dsvt.title, 56);
sendto(ref_g2_sock, rdsvt.head, 58, 0, inbound->addr.GetPointer(), inbound->addr.GetSize()); sendto(ref_g2_sock, rdsvt.head, 58, 0, inbound->addr.GetPointer(), inbound->addr.GetSize());
} else }
inbound->mod = dsvt.hdr.rpt1[7];
} }
/* send the data to the repeater/reflector that is linked to our RPT1 */ /* send the data to the repeater/reflector that is linked to our RPT1 */
@ -1737,8 +1687,7 @@ void CQnetLink::Process()
unsigned char buf[100]; unsigned char buf[100];
int length = recvfrom(ref_g2_sock, buf, 100, 0, (struct sockaddr *)&fromDst4,&fromlen); int length = recvfrom(ref_g2_sock, buf, 100, 0, (struct sockaddr *)&fromDst4,&fromlen);
strncpy(ip, fromDst4.GetAddress(), INET6_ADDRSTRLEN+1); ip.assign(fromDst4.GetAddress());
ip[INET_ADDRSTRLEN] = '\0';
found = false; found = false;
@ -2052,14 +2001,13 @@ void CQnetLink::Process()
auto pos = inbound_list.find(ip); auto pos = inbound_list.find(ip);
if (pos != inbound_list.end()) { if (pos != inbound_list.end()) {
SINBOUND *inbound = (SINBOUND *)pos->second; qnDB.DeleteLS(pos->first.c_str());
SINBOUND *inbound = pos->second;
if (memcmp(inbound->call, "1NFO", 4) != 0) if (memcmp(inbound->call, "1NFO", 4) != 0)
printf("Call %s disconnected\n", inbound->call); printf("Call %s disconnected\n", inbound->call);
free(pos->second); delete pos->second;
pos->second = NULL;
inbound_list.erase(pos); inbound_list.erase(pos);
} }
print_status_file();
} }
for (int i=0; i<3; i++) { for (int i=0; i<3; i++) {
@ -2100,9 +2048,9 @@ void CQnetLink::Process()
to_remote_g2[i].is_connected = true; to_remote_g2[i].is_connected = true;
to_remote_g2[i].countdown = TIMEOUT; to_remote_g2[i].countdown = TIMEOUT;
printf("Login OK to call %s mod %c\n", to_remote_g2[i].cs, to_remote_g2[i].to_mod); printf("Login OK to call %s mod %c\n", to_remote_g2[i].cs, to_remote_g2[i].to_mod);
print_status_file();
tracing[i].last_time = time(NULL); tracing[i].last_time = time(NULL);
qnDB.UpdateLS(to_remote_g2[i].addr.GetAddress(), to_remote_g2[i].from_mod, linked_remote_system, to_remote_g2[i].to_mod, tracing[i].last_time);
strcpy(linked_remote_system, to_remote_g2[i].cs); strcpy(linked_remote_system, to_remote_g2[i].cs);
space_p = strchr(linked_remote_system, ' '); space_p = strchr(linked_remote_system, ' ');
@ -2173,7 +2121,7 @@ void CQnetLink::Process()
*/ */
if (length==5 && buf[0]==5 && buf[1]==0 && buf[2]==24 && buf[3]==0 && buf[4]==1) { if (length==5 && buf[0]==5 && buf[1]==0 && buf[2]==24 && buf[3]==0 && buf[4]==1) {
if ((inbound_list.size() + 1) > max_dongles) if ((inbound_list.size() + 1) > max_dongles)
printf("Inbound DONGLE-p connection from %s but over the max_dongles limit of %d\n", ip, (int)inbound_list.size()); printf("Inbound DONGLE-p connection from %s but over the max_dongles limit of %d\n", ip.c_str(), (int)inbound_list.size());
else else
sendto(ref_g2_sock, buf, 5, 0, (struct sockaddr *)&fromDst4, sizeof(fromDst4)); sendto(ref_g2_sock, buf, 5, 0, (struct sockaddr *)&fromDst4, sizeof(fromDst4));
} else if (length==28 && buf[0]==28 && buf[1]==192 && buf[2]==4 && buf[3]==0) { } else if (length==28 && buf[0]==28 && buf[1]==192 && buf[2]==4 && buf[3]==0) {
@ -2188,14 +2136,14 @@ void CQnetLink::Process()
} }
if (memcmp(call, "1NFO", 4)) if (memcmp(call, "1NFO", 4))
printf("Inbound DONGLE-p CALL=%s, ip=%s, DV=%.8s\n", call, ip, buf + 20); printf("Inbound DONGLE-p CALL=%s, ip=%s, DV=%.8s\n", call, ip.c_str(), buf + 20);
if ((inbound_list.size() + 1) > max_dongles) if ((inbound_list.size() + 1) > max_dongles)
printf("Inbound DONGLE-p connection from %s but over the max_dongles limit of %d\n", ip, (int)inbound_list.size()); printf("Inbound DONGLE-p connection from %s but over the max_dongles limit of %d\n", ip.c_str(), (int)inbound_list.size());
//else if (admin.size() && (admin.find(call) == admin.end())) //else if (admin.size() && (admin.find(call) == admin.end()))
// printf("Incoming call [%s] from %s not an ADMIN\n", call, ip); // printf("Incoming call [%s] from %s not an ADMIN\n", call, ip.c_str());
else if (regexec(&preg, call, 0, NULL, 0) != 0) { else if (regexec(&preg, call, 0, NULL, 0) != 0) {
printf("Invalid dongle callsign: CALL=%s,ip=%s\n", call, ip); printf("Invalid dongle callsign: CALL=%s,ip=%s\n", call, ip.c_str());
buf[0] = 8; buf[0] = 8;
buf[4] = 70; buf[4] = 70;
@ -2206,7 +2154,7 @@ void CQnetLink::Process()
sendto(ref_g2_sock, buf, 8, 0, (struct sockaddr *)&fromDst4, sizeof(fromDst4)); sendto(ref_g2_sock, buf, 8, 0, (struct sockaddr *)&fromDst4, sizeof(fromDst4));
} else { } else {
/* add the dongle to the inbound list */ /* add the dongle to the inbound list */
SINBOUND *inbound = (SINBOUND *)malloc(sizeof(SINBOUND)); SINBOUND *inbound = new SINBOUND;
if (inbound) { if (inbound) {
inbound->countdown = TIMEOUT; inbound->countdown = TIMEOUT;
inbound->addr = fromDst4; inbound->addr = fromDst4;
@ -2224,38 +2172,28 @@ void CQnetLink::Process()
auto insert_pair = inbound_list.insert(std::pair<std::string, SINBOUND *>(ip, inbound)); auto insert_pair = inbound_list.insert(std::pair<std::string, SINBOUND *>(ip, inbound));
if (insert_pair.second) { if (insert_pair.second) {
if (memcmp(inbound->call, "1NFO", 4) != 0) if (memcmp(inbound->call, "1NFO", 4) != 0)
printf("new CALL=%s, DONGLE-p, ip=%s, users=%d\n", inbound->call,ip, (int)inbound_list.size()); printf("new CALL=%s, DONGLE-p, ip=%s, users=%d\n", inbound->call, ip.c_str(), (int)inbound_list.size());
buf[0] = 8; buf[0] = 8;
buf[4] = 79; memcpy(buf+4, "OKAY", 4);
buf[5] = 75;
buf[6] = 82;
buf[7] = 87;
sendto(ref_g2_sock, buf, 8, 0, (struct sockaddr *)&fromDst4, sizeof(fromDst4)); sendto(ref_g2_sock, buf, 8, 0, (struct sockaddr *)&fromDst4, sizeof(fromDst4));
print_status_file(); qnDB.UpdateLS(ip.c_str(), 'p', inbound->call, 'p', time(NULL));
} else { } else {
printf("failed to add CALL=%s,ip=%s\n",inbound->call,ip); printf("failed to add CALL=%s,ip=%s\n", inbound->call, ip.c_str());
free(inbound); delete inbound;
inbound = NULL;
buf[0] = 8; buf[0] = 8;
buf[4] = 70; memcpy(buf+4, "FAIL", 4);
buf[5] = 65;
buf[6] = 73;
buf[7] = 76;
sendto(ref_g2_sock, buf, 8, 0, (struct sockaddr *)&fromDst4, sizeof(fromDst4)); sendto(ref_g2_sock, buf, 8, 0, (struct sockaddr *)&fromDst4, sizeof(fromDst4));
} }
} else { } else {
printf("malloc() failed for call=%s,ip=%s\n",call,ip); printf("new SINBOUND failed for call=%s,ip=%s\n", call, ip.c_str());
buf[0] = 8; buf[0] = 8;
buf[4] = 70; memcpy(buf+4, "FAIL", 4);
buf[5] = 65;
buf[6] = 73;
buf[7] = 76;
sendto(ref_g2_sock, buf, 8, 0, (struct sockaddr *)&fromDst4, sizeof(fromDst4)); sendto(ref_g2_sock, buf, 8, 0, (struct sockaddr *)&fromDst4, sizeof(fromDst4));
} }
@ -2378,10 +2316,10 @@ void CQnetLink::Process()
/* send the data to the donglers */ /* send the data to the donglers */
for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) { for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) {
SINBOUND *inbound = (SINBOUND *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
if (! (fromDst4 == inbound->addr)) { if (fromDst4 == inbound->addr)
sendto(ref_g2_sock, rdsvt.head, 58, 0, inbound->addr.GetPointer(), inbound->addr.GetSize());
} else
inbound->mod = rdsvt.dsvt.hdr.rpt1[7]; inbound->mod = rdsvt.dsvt.hdr.rpt1[7];
else
sendto(ref_g2_sock, rdsvt.head, 58, 0, inbound->addr.GetPointer(), inbound->addr.GetSize());
} }
if ((! (to_remote_g2[i].addr==fromDst4)) && to_remote_g2[i].is_connected) { if ((! (to_remote_g2[i].addr==fromDst4)) && to_remote_g2[i].is_connected) {
@ -2493,8 +2431,7 @@ void CQnetLink::Process()
socklen_t fromlen = sizeof(struct sockaddr_in); socklen_t fromlen = sizeof(struct sockaddr_in);
int length = recvfrom(dcs_g2_sock, dcs_buf, 1000, 0, (struct sockaddr *)&fromDst4, &fromlen); int length = recvfrom(dcs_g2_sock, dcs_buf, 1000, 0, (struct sockaddr *)&fromDst4, &fromlen);
strncpy(ip, fromDst4.GetAddress(), INET6_ADDRSTRLEN); ip.assign(fromDst4.GetAddress());
ip[INET6_ADDRSTRLEN] = '\0';
/* header, audio */ /* header, audio */
if (dcs_buf[0]=='0' && dcs_buf[1]=='0' && dcs_buf[2]=='0' && dcs_buf[3]=='1') { if (dcs_buf[0]=='0' && dcs_buf[1]=='0' && dcs_buf[2]=='0' && dcs_buf[3]=='1') {
@ -2658,7 +2595,7 @@ void CQnetLink::Process()
to_remote_g2[i].is_connected = true; to_remote_g2[i].is_connected = true;
printf("Connected from: %.*s\n", 8, dcs_buf); printf("Connected from: %.*s\n", 8, dcs_buf);
print_status_file(); qnDB.UpdateLS(to_remote_g2[i].addr.GetAddress(), to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod, tracing[i].last_time);
strcpy(linked_remote_system, to_remote_g2[i].cs); strcpy(linked_remote_system, to_remote_g2[i].cs);
space_p = strchr(linked_remote_system, ' '); space_p = strchr(linked_remote_system, ' ');
@ -2689,7 +2626,7 @@ void CQnetLink::Process()
to_remote_g2[i].is_connected = true; to_remote_g2[i].is_connected = true;
printf("Connected from: %.*s\n", 8, to_remote_g2[i].cs); printf("Connected from: %.*s\n", 8, to_remote_g2[i].cs);
print_status_file(); qnDB.UpdateLS(to_remote_g2[i].addr.GetAddress(), to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].from_mod, tracing[i].last_time);
strcpy(linked_remote_system, to_remote_g2[i].cs); strcpy(linked_remote_system, to_remote_g2[i].cs);
space_p = strchr(linked_remote_system, ' '); space_p = strchr(linked_remote_system, ' ');
@ -2701,15 +2638,13 @@ void CQnetLink::Process()
printf("Link module %c to [%s] %c is unlinked\n", to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod); printf("Link module %c to [%s] %c is unlinked\n", to_remote_g2[i].from_mod, to_remote_g2[i].cs, to_remote_g2[i].to_mod);
sprintf(notify_msg[i], "%c_failed_link.dat_UNLINKED", to_remote_g2[i].from_mod); sprintf(notify_msg[i], "%c_failed_link.dat_UNLINKED", to_remote_g2[i].from_mod);
qnDB.DeleteLS(to_remote_g2[i].addr.GetAddress());
to_remote_g2[i].cs[0] = '\0'; to_remote_g2[i].cs[0] = '\0';
to_remote_g2[i].addr.Clear(); to_remote_g2[i].addr.Clear();
to_remote_g2[i].from_mod = to_remote_g2[i].to_mod = ' '; to_remote_g2[i].from_mod = to_remote_g2[i].to_mod = ' ';
to_remote_g2[i].countdown = 0; to_remote_g2[i].countdown = 0;
to_remote_g2[i].is_connected = false; to_remote_g2[i].is_connected = false;
to_remote_g2[i].in_streamid = 0x0; to_remote_g2[i].in_streamid = 0x0;
print_status_file();
} }
} }
} }
@ -2854,7 +2789,7 @@ void CQnetLink::Process()
printf("Unlinked from [%s] mod %c\n", to_remote_g2[i].cs, to_remote_g2[i].to_mod); printf("Unlinked from [%s] mod %c\n", to_remote_g2[i].cs, to_remote_g2[i].to_mod);
sprintf(notify_msg[i], "%c_unlinked.dat_UNLINKED", to_remote_g2[i].from_mod); sprintf(notify_msg[i], "%c_unlinked.dat_UNLINKED", to_remote_g2[i].from_mod);
qnDB.DeleteLS(to_remote_g2[i].addr.GetAddress());
/* now zero out this entry */ /* now zero out this entry */
to_remote_g2[i].cs[0] = '\0'; to_remote_g2[i].cs[0] = '\0';
to_remote_g2[i].addr.Clear(); to_remote_g2[i].addr.Clear();
@ -2862,8 +2797,6 @@ void CQnetLink::Process()
to_remote_g2[i].countdown = 0; to_remote_g2[i].countdown = 0;
to_remote_g2[i].is_connected = false; to_remote_g2[i].is_connected = false;
to_remote_g2[i].in_streamid = 0x0; to_remote_g2[i].in_streamid = 0x0;
print_status_file();
} else { } else {
sprintf(notify_msg[i], "%c_already_unlinked.dat_UNLINKED", dsvt.hdr.rpt1[7]); sprintf(notify_msg[i], "%c_already_unlinked.dat_UNLINKED", dsvt.hdr.rpt1[7]);
} }
@ -3423,7 +3356,12 @@ bool CQnetLink::Init(const char *cfgfile)
printf("Failed to process config file %s\n", cfgfile); printf("Failed to process config file %s\n", cfgfile);
return true; return true;
} }
print_status_file(); // open sqlite
std::string fname(CFG_DIR);
fname.append("/");
fname.append(dash_sql_name);
if (qnDB.Open(fname.c_str()))
return true;
/* Open DB */ /* Open DB */
if (!load_gwys(gwys)) if (!load_gwys(gwys))
@ -3503,11 +3441,11 @@ void CQnetLink::Shutdown()
/* tell inbound dongles we are down */ /* tell inbound dongles we are down */
for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) { for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) {
SINBOUND *inbound = (SINBOUND *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
qnDB.DeleteLS(pos->first.c_str());
sendto(ref_g2_sock, queryCommand, 5, 0, inbound->addr.GetPointer(), inbound->addr.GetSize()); sendto(ref_g2_sock, queryCommand, 5, 0, inbound->addr.GetPointer(), inbound->addr.GetSize());
} }
inbound_list.clear(); inbound_list.clear();
print_status_file();
srv_close(); srv_close();
return; return;

@ -32,6 +32,7 @@
#include "UnixDgramSocket.h" #include "UnixDgramSocket.h"
#include "SockAddress.h" #include "SockAddress.h"
#include "Timer.h" #include "Timer.h"
#include "QnetDB.h"
/*** version number must be x.xx ***/ /*** version number must be x.xx ***/
#define CALL_SIZE 8 #define CALL_SIZE 8
@ -66,6 +67,12 @@ using SINBOUND = struct inbound_tag {
char client; // dvap, dvdongle char client; // dvap, dvdongle
}; };
using STRACING = struct tracing_tag {
unsigned short streamid;
time_t last_time; // last time RF user talked
};
class CQnetLink { class CQnetLink {
public: public:
// functions // functions
@ -86,7 +93,6 @@ private:
void srv_close(); void srv_close();
static void sigCatch(int signum); static void sigCatch(int signum);
void g2link(const char from_mod, const char *call, const char to_mod); void g2link(const char from_mod, const char *call, const char to_mod);
void print_status_file();
void send_heartbeat(); void send_heartbeat();
bool resolve_rmt(const char *name, const unsigned short port, CSockAddress &addr); bool resolve_rmt(const char *name, const unsigned short port, CSockAddress &addr);
void rptr_ack(short i); void rptr_ack(short i);
@ -95,7 +101,7 @@ private:
void RptrAckThread(char *arg); void RptrAckThread(char *arg);
/* configuration data */ /* configuration data */
std::string login_call, owner, to_g2_external_ip, my_g2_link_ip, gwys, status_file, qnvoice_file, announce_dir; std::string login_call, owner, to_g2_external_ip, my_g2_link_ip, gwys, dash_sql_name, qnvoice_file, announce_dir;
bool only_admin_login, only_link_unlink, qso_details, log_debug, bool_rptr_ack, announce; bool only_admin_login, only_link_unlink, qso_details, log_debug, bool_rptr_ack, announce;
bool dplus_authorize, dplus_reflectors, dplus_repeaters, dplus_priority; bool dplus_authorize, dplus_reflectors, dplus_repeaters, dplus_priority;
unsigned short rmt_xrf_port, rmt_ref_port, rmt_dcs_port, my_g2_link_port, to_g2_external_port; unsigned short rmt_xrf_port, rmt_ref_port, rmt_dcs_port, my_g2_link_port, to_g2_external_port;
@ -132,10 +138,7 @@ private:
SDSVT fromrptr_torptr_brd; SDSVT fromrptr_torptr_brd;
short brd_from_rptr_idx; short brd_from_rptr_idx;
struct tracing_tag { STRACING tracing[3];
unsigned short streamid;
time_t last_time; // last time RF user talked
} tracing[3];
// input from remote // input from remote
int xrf_g2_sock, ref_g2_sock, dcs_g2_sock; int xrf_g2_sock, ref_g2_sock, dcs_g2_sock;
@ -178,6 +181,6 @@ private:
} old_sid[3]; } old_sid[3];
CRandom Random; CRandom Random;
CQnetDB qnDB;
std::vector<unsigned long> speak; std::vector<unsigned long> speak;
}; };

@ -193,7 +193,6 @@ dplus_priority_d=true # set to true if you want DPlus reflector read after
# #
# FILE - where important QnetGateway files and directories are found. # FILE - where important QnetGateway files and directories are found.
# #
file_status_d='/usr/local/etc/rptr_status' # where repeater status info is passed between services
file_dtmf_d='/tmp' # where DTMF is decoded file_dtmf_d='/tmp' # where DTMF is decoded
file_echotest_d='/var/local' # echo dat files will end up here file_echotest_d='/var/local' # echo dat files will end up here
file_qnvoice_file_d='/tmp/qnvoice.txt' # where qnvoice will create the play command file_qnvoice_file_d='/tmp/qnvoice.txt' # where qnvoice will create the play command

@ -58,23 +58,6 @@ function GetIP(string $type)
return $ip; return $ip;
} }
function GetStatus(string $mod, array &$kv)
{
$mod = strtoupper(substr($mod, 0, 1));
if (array_key_exists('file_status', $kv))
$file = $kv['file_status'];
else
$file = '/usr/local/etc/rptr_status';
if ($lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)) {
foreach ($lines as $line) {
$words = explode(',', $line);
if ($words[0] == $mod)
return $words;
}
}
return explode(',', ',,,,,');
}
function SecToString(int $sec) { function SecToString(int $sec) {
if ($sec >= 86400) if ($sec >= 86400)
return sprintf("%0.2f days", $sec/86400); return sprintf("%0.2f days", $sec/86400);
@ -194,33 +177,53 @@ foreach($showlist as $section) {
break; break;
case 'MO': case 'MO':
echo 'Modules:<br>', "\n"; echo 'Modules:<br>', "\n";
$dbname = $cfgdir.'/'.GetCFGValues('dash_sql_filename');
$db = new SQLiet3($dbname, SQLITE3_OPEN_READ_ONLY);
echo "<table cellpadding='1' border='1' style='font-family: monospace'>\n"; echo "<table cellpadding='1' border='1' style='font-family: monospace'>\n";
echo '<tr><td style="text-align:center">Module</td><td style="text-align:center">Modem</td><td style="text-align:center">Frequency</td><td style="text-align:center">Link</td><td style="text-align:center">Link IP</td></tr>', "\n"; echo '<tr><td style="text-align:center">Module</td><td style="text-align:center">Modem</td><td style="text-align:center">Frequency</td><td style="text-align:center">Link</td><td style="text-align:center">Linked Time</td><td style="text-align:center">Link IP</td></tr>', "\n";
foreach (array('a', 'b', 'c') as $mod) { foreach (array('a', 'b', 'c') as $mod) {
$module = 'module_'.$mod; $module = 'module_'.$mod;
if (array_key_exists($module, $cfg)) { if (array_key_exists($module, $cfg)) {
$configured[] = strtoupper($mod);
$freq = 0.0; $freq = 0.0;
if (array_key_exists($module.'_tx_frequency', $cfg)) if (array_key_exists($module.'_tx_frequency', $cfg))
$freq = $cfg[$module.'_tx_frequency']; $freq = $cfg[$module.'_tx_frequency'];
else if (array_key_exists($module.'_frequency', $cfg)) else if (array_key_exists($module.'_frequency', $cfg))
$freq = $cfg[$module.'_frequency']; $freq = $cfg[$module.'_frequency'];
$stat = GetStatus($mod, $cfg); $ss = 'SELECT ip_address,to_callsign,to_mod,strftime("%s","now")-link_time FROM LINKSTATUS WHERE from_mod=' . "'" . strtoupper($mod) . "';";
if (8==strlen($stat[1]) && 1==strlen($stat[2])) if ($stmnt = $db->prepare($ss)) {
$linkstatus = substr($stat[1], 0, 7).$stat[2]; if ($result = $stmnt->execute()) {
else if ($row = $result->FetchArray(SQLITE3_NUM)) {
$linkstatus = 'Unlinked'; $linkstatus = str_pad(trim($row[1]), 7).$row[2];
echo '<tr><td style="text-align:center">',strtoupper($mod),'</td><td style="text-align:center">',$cfg[$module],'</td><td style="text-align:center">',$freq,'</td><td style="text-align:center">',$linkstatus,'</td><td style="text-align:center">',$stat[3],'</td></tr>',"\n"; $address = $row[0];
$ctime = SecToString(intval($row[3]));
} else {
$linkstatus = 'Unlinked';
$address = '';
$ctime = '';
}
$result->finalize();
}
$stmnt->close();
}
echo '<tr><td style="text-align:center">', strtoupper($mod), '</td><td style="text-align:center">',$cfg[$module], '</td><td style="text-align:center">', $freq, '</td><td style="text-align:center">', $linkstatus, '</td><td style="text-align:right">', $ctime, '</td><td style="text-align:center">', $address, '</td></tr>', "\n";
} }
} }
echo '</table><br>', "\n"; echo '</table><br>', "\n";
$db->close();
break; break;
case 'UR': case 'UR':
echo 'Send URCall:<br>', "\n"; echo 'Send URCall:<br>', "\n";
echo '<form method="post">', "\n"; echo '<form method="post">', "\n";
if (count($configured) > 1) { $mods = array();
foreach (array('a', 'b', 'c') as $mod) {
$module = 'module_'.$mod;
if (array_key_exists($module, $cfg)) {
$mods[] = strtoupper($mod);
}
}
if (count($mods) > 1) {
echo 'Module: ', "\n"; echo 'Module: ', "\n";
foreach ($configured as $mod) { foreach ($mods as $mod) {
echo '<input type="radio" name="fmodule"', (isset($fmodule) && $fmodule==$mod) ? '"checked"' : '', ' value="$mod">', $mod, '<br>', "\n"; echo '<input type="radio" name="fmodule"', (isset($fmodule) && $fmodule==$mod) ? '"checked"' : '', ' value="$mod">', $mod, '<br>', "\n";
} }
} else } else

Loading…
Cancel
Save

Powered by TurnKey Linux.