QnetLink in a class

pull/5/head
Tom Early 8 years ago
parent 0baae420ff
commit 26b52b66df

@ -44,7 +44,6 @@
#include <future> #include <future>
#include <exception> #include <exception>
#include <atomic> #include <atomic>
/* Required for Binary search trees using C++ STL */
#include <string> #include <string>
#include <set> #include <set>
#include <map> #include <map>
@ -53,169 +52,24 @@
#include <chrono> #include <chrono>
#include <libconfig.h++> #include <libconfig.h++>
#include "versions.h" #include "versions.h"
#include "QnetLink.h"
using namespace libconfig; using namespace libconfig;
/*** version number must be x.xx ***/ std::atomic<bool> CQnetLink::keep_running(true);
#define VERSION LINK_VERSION
#define CALL_SIZE 8 CQnetLink::CQnetLink()
#define IP_SIZE 15 {
#define QUERY_SIZE 56 memset(tracing, 0, 3 * sizeof(struct tracing_tag));
#define MAXHOSTNAMELEN 64 memset(dtmf_mycall, 0, 3 * (CALL_SIZE+1));
#define TIMEOUT 50 memset(old_sid, 0, 6);
}
/* configuration data */
static std::string login_call; CQnetLink::~CQnetLink()
static std::string owner; {
static std::string to_g2_external_ip; }
static std::string my_g2_link_ip;
static std::string gwys; bool CQnetLink::resolve_rmt(char *name, int type, struct sockaddr_in *addr)
static std::string status_file;
static std::string announce_dir;
static bool qso_details;
static bool bool_rptr_ack;
static bool announce;
static int rmt_xrf_port;
static int rmt_ref_port;
static int rmt_dcs_port;
static int my_g2_link_port;
static int to_g2_external_port;
static int delay_between;
static int delay_before;
static char link_at_startup[CALL_SIZE+1];
static unsigned int max_dongles;
static unsigned int saved_max_dongles;
static long rf_inactivity_timer[3];
static unsigned char REF_ACK[3] = { 3, 96, 0 };
// This is the data payload in the map: inbound_list
// This is for inbound dongles
struct inbound {
char call[CALL_SIZE + 1]; // the callsign of the remote
struct sockaddr_in sin; // IP and port of remote
short countdown; // if countdown expires, the connection is terminated
char mod; // A B C This user talked on this module
char client; // dvap, dvdongle
};
// the Key in this inbound_list map is the unique IP address of the remote
static std::map<std::string, inbound *> inbound_list;
static std::set<std::string> admin;
static std::set<std::string> link_unlink_user;
static std::set<std::string> link_blacklist;
#define LH_MAX_SIZE 39
typedef std::map<std::string, std::string> dt_lh_type;
static dt_lh_type dt_lh_list;
static struct {
char to_call[CALL_SIZE + 1];
struct sockaddr_in toDst4;
char from_mod;
char to_mod;
short countdown;
bool is_connected;
unsigned char in_streamid[2]; // incoming from remote systems
unsigned char out_streamid[2]; // outgoing to remote systems
} to_remote_g2[3];
// broadcast for data arriving from xrf to local rptr
static struct {
unsigned char xrf_streamid[2]; // streamid from xrf
unsigned char rptr_streamid[2][2]; // generated streamid to rptr(s)
} brd_from_xrf;
static unsigned char from_xrf_torptr_brd[56];
static short brd_from_xrf_idx = 0;
// broadcast for data arriving from local rptr to xrf
static struct {
unsigned char from_rptr_streamid[2];
unsigned char to_rptr_streamid[2][2];
} brd_from_rptr;
static unsigned char fromrptr_torptr_brd[56];
static short brd_from_rptr_idx = 0;
static struct {
unsigned char streamid[2];
time_t last_time; // last time RF user talked
} tracing[3] = {
{ {0,0}, 0 },
{ {0,0}, 0 },
{ {0,0}, 0 }
};
// input from remote
static int xrf_g2_sock = -1;
static int ref_g2_sock = -1;
static int dcs_g2_sock = -1;
static struct sockaddr_in fromDst4;
// After we receive it from remote g2,
// we must feed it to our local repeater.
static struct sockaddr_in toLocalg2;
// input from our own local repeater
static int rptr_sock = -1;
static struct sockaddr_in fromRptr;
static fd_set fdset;
static struct timeval tv;
static std::atomic<bool> keep_running(true);
// Used to validate incoming donglers
static regex_t preg;
const char* G2_html = "<table border=\"0\" width=\"95%\"><tr>"
"<td width=\"4%\"><img border=\"0\" src=g2ircddb.jpg></td>"
"<td width=\"96%\"><font size=\"2\">"
"<b>REPEATER</b> QnetGateway v1.0+"
"</font></td>"
"</tr></table>";
// the map of remotes
// key is the callsign, data is the host
typedef std::map<std::string, std::string> gwy_list_type;
static gwy_list_type gwy_list;
static unsigned char queryCommand[QUERY_SIZE];
// START: TEXT crap
static char dtmf_mycall[3][CALL_SIZE + 1] = { {""}, {""}, {""} };
static bool new_group[3] = { true, true, true };
static int header_type = 0;
static bool GPS_seen[3] = { false, false, false };
unsigned char tmp_txt[3];
static char *p_tmp2 = NULL;
// END: TEXT crap
// this is used for the "dashboard and qso_details" to avoid processing multiple headers
static struct {
unsigned char sid[2];
} old_sid[3] = {
{ {0x00, 0x00} },
{ {0x00, 0x00} },
{ {0x00, 0x00} }
};
static bool load_gwys(const std::string &filename);
static void calcPFCS(unsigned char *packet, int len);
static bool read_config(char *);
static bool srv_open();
static void srv_close();
static void sigCatch(int signum);
static void g2link(char from_mod, char *call, char to_mod);
static void runit();
static void print_status_file();
static void send_heartbeat();
static bool resolve_rmt(char *name, int type, struct sockaddr_in *addr);
static void audio_notify(char *notify_msg);
static void rptr_ack(short i);
static void AudioNotifyThread(char *arg);
static void RptrAckThread(char *arg);
static bool resolve_rmt(char *name, int type, struct sockaddr_in *addr)
{ {
struct addrinfo hints; struct addrinfo hints;
struct addrinfo *res; struct addrinfo *res;
@ -245,21 +99,20 @@ static bool resolve_rmt(char *name, int type, struct sockaddr_in *addr)
} }
/* send keepalive to donglers */ /* send keepalive to donglers */
static void send_heartbeat() void CQnetLink::send_heartbeat()
{ {
inbound *inbound_ptr;
bool removed = false; 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++) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
sendto(ref_g2_sock, REF_ACK, 3, 0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); sendto(ref_g2_sock, REF_ACK, 3, 0, (struct sockaddr *)&(inbound->sin), sizeof(struct sockaddr_in));
if (inbound_ptr->countdown >= 0) if (inbound->countdown >= 0)
inbound_ptr->countdown --; inbound->countdown --;
if (inbound_ptr->countdown < 0) { if (inbound->countdown < 0) {
removed = true; removed = true;
printf("call=%s timeout, removing %s, users=%d\n", inbound_ptr->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);
free(pos->second); free(pos->second);
pos->second = NULL; pos->second = NULL;
@ -270,7 +123,7 @@ static void send_heartbeat()
print_status_file(); print_status_file();
} }
static void rptr_ack(short i) void CQnetLink::rptr_ack(short i)
{ {
static char mod_and_RADIO_ID[3][22]; static char mod_and_RADIO_ID[3][22];
@ -296,14 +149,14 @@ static void rptr_ack(short i)
memcpy(mod_and_RADIO_ID[i] + 1, "NOT LINKED", 10); memcpy(mod_and_RADIO_ID[i] + 1, "NOT LINKED", 10);
} }
try { try {
std::async(std::launch::async, RptrAckThread, mod_and_RADIO_ID[i]); std::async(std::launch::async, &CQnetLink::RptrAckThread, this, mod_and_RADIO_ID[i]);
} catch (const std::exception &e) { } catch (const std::exception &e) {
printf("Failed to start RptrAckThread(). Exception: %s\n", e.what()); printf("Failed to start RptrAckThread(). Exception: %s\n", e.what());
} }
return; return;
} }
static void RptrAckThread(char *arg) void CQnetLink::RptrAckThread(char *arg)
{ {
char from_mod = arg[0]; char from_mod = arg[0];
char RADIO_ID[21]; char RADIO_ID[21];
@ -435,7 +288,7 @@ static void RptrAckThread(char *arg)
} }
} }
static void print_status_file() void CQnetLink::print_status_file()
{ {
FILE *statusfp = fopen(status_file.c_str(), "w"); FILE *statusfp = fopen(status_file.c_str(), "w");
if (!statusfp) if (!statusfp)
@ -450,8 +303,8 @@ static void print_status_file()
/* print connected donglers */ /* print connected donglers */
for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) { for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) {
inbound *inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
fprintf(statusfp, fstr, 'p', inbound_ptr->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); fprintf(statusfp, fstr, 'p', inbound->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 */ /* print linked repeaters-reflectors */
@ -466,7 +319,7 @@ static void print_status_file()
} }
/* Open text file of repeaters, reflectors */ /* Open text file of repeaters, reflectors */
static bool load_gwys(const std::string &filename) bool CQnetLink::load_gwys(const std::string &filename)
{ {
char inbuf[1024]; char inbuf[1024];
const char *delim = " "; const char *delim = " ";
@ -479,9 +332,6 @@ static bool load_gwys(const std::string &filename)
char payload[MAXHOSTNAMELEN + 1 + 5 + 1]; char payload[MAXHOSTNAMELEN + 1 + 5 + 1];
unsigned short j; unsigned short j;
gwy_list_type::iterator gwy_pos;
std::pair<gwy_list_type::iterator,bool> gwy_insert_pair;
printf("Trying to open file %s\n", filename.c_str()); printf("Trying to open file %s\n", filename.c_str());
FILE *fp = fopen(filename.c_str(), "r"); FILE *fp = fopen(filename.c_str(), "r");
if (fp == NULL) { if (fp == NULL) {
@ -552,13 +402,10 @@ static bool load_gwys(const std::string &filename)
/* copy the payload(host port) */ /* copy the payload(host port) */
sprintf(payload, "%s %s", host, port); sprintf(payload, "%s %s", host, port);
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()) {
gwy_insert_pair = gwy_list.insert(std::pair<std::string,std::string>(call,payload)); gwy_list[call] = payload;
if (gwy_insert_pair.second) printf("Added Call=[%s], payload=[%s]\n",call, payload);
printf("Added Call=[%s], payload=[%s]\n",call, payload);
else
printf("Failed to add: Call=[%s], payload=[%s]\n",call, payload);
} else } else
printf("Call [%s] is duplicate\n", call); printf("Call [%s] is duplicate\n", call);
} }
@ -569,7 +416,7 @@ static bool load_gwys(const std::string &filename)
} }
/* compute checksum */ /* compute checksum */
static void calcPFCS(unsigned char *packet, int len) void CQnetLink::calcPFCS(unsigned char *packet, int len)
{ {
unsigned short crc_tabccitt[256] = { unsigned short crc_tabccitt[256] = {
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7, 0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
@ -621,7 +468,7 @@ static void calcPFCS(unsigned char *packet, int len)
return; return;
} }
bool get_value(const Config &cfg, const char *path, int &value, int min, int max, int default_value) bool CQnetLink::get_value(const Config &cfg, const char *path, int &value, int min, int max, int default_value)
{ {
if (cfg.lookupValue(path, value)) { if (cfg.lookupValue(path, value)) {
if (value < min || value > max) if (value < min || value > max)
@ -632,7 +479,7 @@ bool get_value(const Config &cfg, const char *path, int &value, int min, int max
return true; return true;
} }
bool get_value(const Config &cfg, const char *path, double &value, double min, double max, double default_value) bool CQnetLink::get_value(const Config &cfg, const char *path, double &value, double min, double max, double default_value)
{ {
if (cfg.lookupValue(path, value)) { if (cfg.lookupValue(path, value)) {
if (value < min || value > max) if (value < min || value > max)
@ -643,7 +490,7 @@ bool get_value(const Config &cfg, const char *path, double &value, double min, d
return true; return true;
} }
bool get_value(const Config &cfg, const char *path, bool &value, bool default_value) bool CQnetLink::get_value(const Config &cfg, const char *path, bool &value, bool default_value)
{ {
if (! cfg.lookupValue(path, value)) if (! cfg.lookupValue(path, value))
value = default_value; value = default_value;
@ -651,7 +498,7 @@ bool get_value(const Config &cfg, const char *path, bool &value, bool default_va
return true; return true;
} }
bool get_value(const Config &cfg, const char *path, std::string &value, int min, int max, const char *default_value) bool CQnetLink::get_value(const Config &cfg, const char *path, std::string &value, int min, int max, const char *default_value)
{ {
if (cfg.lookupValue(path, value)) { if (cfg.lookupValue(path, value)) {
int l = value.length(); int l = value.length();
@ -666,7 +513,7 @@ bool get_value(const Config &cfg, const char *path, std::string &value, int min,
} }
/* process configuration file */ /* process configuration file */
static bool read_config(char *cfgFile) bool CQnetLink::read_config(const char *cfgFile)
{ {
unsigned short i; unsigned short i;
Config cfg; Config cfg;
@ -678,11 +525,11 @@ static bool read_config(char *cfgFile)
} }
catch(const FileIOException &fioex) { catch(const FileIOException &fioex) {
printf("Can't read %s\n", cfgFile); printf("Can't read %s\n", cfgFile);
return false; return true;
} }
catch(const ParseException &pex) { catch(const ParseException &pex) {
printf("Parse error at %s:%d - %s\n", pex.getFile(), pex.getLine(), pex.getError()); printf("Parse error at %s:%d - %s\n", pex.getFile(), pex.getLine(), pex.getError());
return false; return true;
} }
std::string value; std::string value;
@ -691,7 +538,7 @@ static bool read_config(char *cfgFile)
int l = login_call.length(); int l = login_call.length();
if (l<3 || l>CALL_SIZE-2) { if (l<3 || l>CALL_SIZE-2) {
printf("Call '%s' is invalid length!\n", login_call.c_str()); printf("Call '%s' is invalid length!\n", login_call.c_str());
return false; return true;
} else { } else {
for (i=0; i<l; i++) { for (i=0; i<l; i++) {
if (islower(login_call[i])) if (islower(login_call[i]))
@ -702,7 +549,7 @@ static bool read_config(char *cfgFile)
} }
} else { } else {
printf("%s is not defined.\n", key.c_str()); printf("%s is not defined.\n", key.c_str());
return false; return true;
} }
key = "link.admin"; key = "link.admin";
@ -727,7 +574,7 @@ static bool read_config(char *cfgFile)
} }
} else { } else {
printf("%s is not an array!\n", key.c_str()); printf("%s is not an array!\n", key.c_str());
return false; return true;
} }
printf("%s = [ ", key.c_str()); printf("%s = [ ", key.c_str());
for (auto pos=admin.begin(); pos!=admin.end(); pos++) { for (auto pos=admin.begin(); pos!=admin.end(); pos++) {
@ -760,7 +607,7 @@ static bool read_config(char *cfgFile)
} }
} else { } else {
printf("%s is not an array!\n", key.c_str()); printf("%s is not an array!\n", key.c_str());
return false; return true;
} }
printf("%s = [ ", key.c_str()); printf("%s = [ ", key.c_str());
for (auto pos=link_blacklist.begin(); pos!=link_blacklist.end(); pos++) { for (auto pos=link_blacklist.begin(); pos!=link_blacklist.end(); pos++) {
@ -792,7 +639,7 @@ static bool read_config(char *cfgFile)
} }
} else { } else {
printf("%s is not an array!\n", key.c_str()); printf("%s is not an array!\n", key.c_str());
return false; return true;
} }
printf("%s = [ ", key.c_str()); printf("%s = [ ", key.c_str());
for (auto pos=link_unlink_user.begin(); pos!=link_unlink_user.end(); pos++) { for (auto pos=link_unlink_user.begin(); pos!=link_unlink_user.end(); pos++) {
@ -816,7 +663,7 @@ static bool read_config(char *cfgFile)
printf("%s = [%s]\n", key.c_str(), owner.c_str()); printf("%s = [%s]\n", key.c_str(), owner.c_str());
} else { } else {
printf("%s '%s' is wrong size.\n", key.c_str(), owner.c_str()); printf("%s '%s' is wrong size.\n", key.c_str(), owner.c_str());
return false; return true;
} }
} }
@ -825,20 +672,20 @@ static bool read_config(char *cfgFile)
get_value(cfg, "link.dcs_port", rmt_dcs_port, 10000, 65535, 30051); get_value(cfg, "link.dcs_port", rmt_dcs_port, 10000, 65535, 30051);
if (! get_value(cfg, "link.incoming_ip", my_g2_link_ip, 7, IP_SIZE, "0.0.0.0")) if (! get_value(cfg, "link.incoming_ip", my_g2_link_ip, 7, IP_SIZE, "0.0.0.0"))
return false; return true;
get_value(cfg, "link.port", my_g2_link_port, 10000, 65535, 18997); get_value(cfg, "link.port", my_g2_link_port, 10000, 65535, 18997);
if (! get_value(cfg, "gateway.internal.ip", to_g2_external_ip, 7, IP_SIZE, "0.0.0.0")) if (! get_value(cfg, "gateway.internal.ip", to_g2_external_ip, 7, IP_SIZE, "0.0.0.0"))
return false; return true;
get_value(cfg, "gateway.external.port", to_g2_external_port, 1024, 65535, 40000); get_value(cfg, "gateway.external.port", to_g2_external_port, 1024, 65535, 40000);
get_value(cfg, "gateway.log.qso", qso_details, true); get_value(cfg, "gateway.log.qso", qso_details, true);
if (! get_value(cfg, "file.gwys", gwys, 2, FILENAME_MAX, "/usr/local/etc/gwys.txt")) if (! get_value(cfg, "file.gwys", gwys, 2, FILENAME_MAX, "/usr/local/etc/gwys.txt"))
return false; return true;
if (! get_value(cfg, "file.status", status_file, 2, FILENAME_MAX, "/usr/local/etc/RPTR_STATUS.txt")) if (! get_value(cfg, "file.status", status_file, 2, FILENAME_MAX, "/usr/local/etc/RPTR_STATUS.txt"))
return false; return true;
get_value(cfg, "timing.play.delay", delay_between, 9, 25, 19); get_value(cfg, "timing.play.delay", delay_between, 9, 25, 19);
@ -847,7 +694,7 @@ static bool read_config(char *cfgFile)
get_value(cfg, "link.announce", announce, true); get_value(cfg, "link.announce", announce, true);
if (! get_value(cfg, "file.announce_dir", announce_dir, 2, FILENAME_MAX, "/usr/local/etc")) if (! get_value(cfg, "file.announce_dir", announce_dir, 2, FILENAME_MAX, "/usr/local/etc"))
return false; return true;
get_value(cfg, "timing.play.wait", delay_before, 1, 10, 2); get_value(cfg, "timing.play.wait", delay_before, 1, 10, 2);
@ -856,7 +703,7 @@ static bool read_config(char *cfgFile)
if (strcasecmp(value.c_str(), "none")) if (strcasecmp(value.c_str(), "none"))
strcpy(link_at_startup, value.c_str()); strcpy(link_at_startup, value.c_str());
} else } else
return false; return true;
int maxdongle; int maxdongle;
get_value(cfg, "link.max_dongles", maxdongle, 0, 10, 5); get_value(cfg, "link.max_dongles", maxdongle, 0, 10, 5);
@ -871,11 +718,11 @@ static bool read_config(char *cfgFile)
rf_inactivity_timer[i] = timer; rf_inactivity_timer[i] = timer;
} }
return true; return false;
} }
/* create our server */ /* create our server */
static bool srv_open() bool CQnetLink::srv_open()
{ {
struct sockaddr_in sin; struct sockaddr_in sin;
short i; short i;
@ -992,7 +839,7 @@ static bool srv_open()
} }
/* destroy our server */ /* destroy our server */
static void srv_close() void CQnetLink::srv_close()
{ {
if (xrf_g2_sock != -1) { if (xrf_g2_sock != -1) {
close(xrf_g2_sock); close(xrf_g2_sock);
@ -1018,7 +865,7 @@ static void srv_close()
} }
/* find the repeater IP by callsign and link to it */ /* find the repeater IP by callsign and link to it */
static void g2link(char from_mod, char *call, char to_mod) void CQnetLink::g2link(char from_mod, char *call, char to_mod)
{ {
short i,j, counter; short i,j, counter;
@ -1034,7 +881,6 @@ static void g2link(char from_mod, char *call, char to_mod)
char payload[MAXHOSTNAMELEN + 1 + 5 + 1]; char payload[MAXHOSTNAMELEN + 1 + 5 + 1];
char *p = NULL; char *p = NULL;
gwy_list_type::iterator gwy_pos;
char link_request[519]; char link_request[519];
bool ok = false; bool ok = false;
@ -1077,7 +923,7 @@ static void g2link(char from_mod, char *call, char to_mod)
} }
} }
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()) {
printf("%s not found in gwy list\n", call); printf("%s not found in gwy list\n", call);
return; return;
@ -1132,7 +978,7 @@ static void g2link(char from_mod, char *call, char to_mod)
link_request[9] = to_mod; link_request[9] = to_mod;
link_request[10] = '\0'; link_request[10] = '\0';
memcpy(link_request + 11, to_remote_g2[i].to_call, 8); memcpy(link_request + 11, to_remote_g2[i].to_call, 8);
strcpy(link_request + 19, G2_html); strcpy(link_request + 19, "<table border=\"0\" width=\"95%\"><tr><td width=\"4%\"><img border=\"0\" src=g2ircddb.jpg></td><td width=\"96%\"><font size=\"2\"><b>REPEATER</b> QnetGateway v1.0+</font></td></tr></table>");
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].to_call, to_remote_g2[i].to_mod, payload); 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].to_call, to_remote_g2[i].to_mod, payload);
sendto(dcs_g2_sock, link_request, 519, 0, (struct sockaddr *)&(to_remote_g2[i].toDst4), sizeof(to_remote_g2[i].toDst4)); sendto(dcs_g2_sock, link_request, 519, 0, (struct sockaddr *)&(to_remote_g2[i].toDst4), sizeof(to_remote_g2[i].toDst4));
@ -1178,7 +1024,7 @@ static void g2link(char from_mod, char *call, char to_mod)
} }
/* signal catching function */ /* signal catching function */
static void sigCatch(int signum) void CQnetLink::sigCatch(int signum)
{ {
/* do NOT do any serious work here */ /* do NOT do any serious work here */
if ((signum == SIGTERM) || (signum == SIGINT)) if ((signum == SIGTERM) || (signum == SIGINT))
@ -1186,7 +1032,7 @@ static void sigCatch(int signum)
return; return;
} }
static void runit() void CQnetLink::Process()
{ {
socklen_t fromlen; socklen_t fromlen;
int recvlen; int recvlen;
@ -1214,7 +1060,6 @@ static void runit()
char call[CALL_SIZE + 1]; char call[CALL_SIZE + 1];
char ip[IP_SIZE + 1]; char ip[IP_SIZE + 1];
inbound *inbound_ptr;
bool found = false; bool found = false;
char cmd_2_dcs[23]; char cmd_2_dcs[23];
@ -1263,8 +1108,7 @@ static void runit()
if (dcs_g2_sock > max_nfds) if (dcs_g2_sock > max_nfds)
max_nfds = dcs_g2_sock; max_nfds = dcs_g2_sock;
printf("xrf=%d, dcs=%d, ref=%d, rptr=%d, MAX+1=%d\n", printf("xrf=%d, dcs=%d, ref=%d, rptr=%d, MAX+1=%d\n", xrf_g2_sock, dcs_g2_sock, ref_g2_sock, rptr_sock, max_nfds + 1);
xrf_g2_sock, dcs_g2_sock, ref_g2_sock, rptr_sock, max_nfds + 1);
if (strlen(link_at_startup) >= 8) { if (strlen(link_at_startup) >= 8) {
if ((link_at_startup[0] == 'A') || (link_at_startup[0] == 'B') || (link_at_startup[0] == 'C')) { if ((link_at_startup[0] == 'A') || (link_at_startup[0] == 'B') || (link_at_startup[0] == 'C')) {
@ -1814,16 +1658,16 @@ static void runit()
/* send data to donglers */ /* send data to donglers */
/* 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++) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
if (fromDst4.sin_addr.s_addr != inbound_ptr->sin.sin_addr.s_addr) { if (fromDst4.sin_addr.s_addr != inbound->sin.sin_addr.s_addr) {
readBuffer[0] = (unsigned char)(58 & 0xFF); readBuffer[0] = (unsigned char)(58 & 0xFF);
readBuffer[1] = (unsigned char)(58 >> 8 & 0x1F); readBuffer[1] = (unsigned char)(58 >> 8 & 0x1F);
readBuffer[1] = (unsigned char)(readBuffer[1] | 0xFFFFFF80); readBuffer[1] = (unsigned char)(readBuffer[1] | 0xFFFFFF80);
memcpy(readBuffer + 2, readBuffer2, 56); memcpy(readBuffer + 2, readBuffer2, 56);
sendto(ref_g2_sock, readBuffer, 58, 0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); sendto(ref_g2_sock, readBuffer, 58, 0, (struct sockaddr *)&(inbound->sin), sizeof(struct sockaddr_in));
} else } else
inbound_ptr->mod = readBuffer2[25]; inbound->mod = readBuffer2[25];
} }
/* 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 */
@ -1974,15 +1818,15 @@ static void runit()
/* send data to donglers */ /* send data to donglers */
/* 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++) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
if (fromDst4.sin_addr.s_addr != inbound_ptr->sin.sin_addr.s_addr) { if (fromDst4.sin_addr.s_addr != inbound->sin.sin_addr.s_addr) {
readBuffer[0] = (unsigned char)(29 & 0xFF); readBuffer[0] = (unsigned char)(29 & 0xFF);
readBuffer[1] = (unsigned char)(29 >> 8 & 0x1F); readBuffer[1] = (unsigned char)(29 >> 8 & 0x1F);
readBuffer[1] = (unsigned char)(readBuffer[1] | 0xFFFFFF80); readBuffer[1] = (unsigned char)(readBuffer[1] | 0xFFFFFF80);
memcpy(readBuffer + 2, readBuffer2, 27); memcpy(readBuffer + 2, readBuffer2, 27);
sendto(ref_g2_sock, readBuffer, 29, 0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); sendto(ref_g2_sock, readBuffer, 29, 0, (struct sockaddr *)&(inbound->sin), sizeof(struct sockaddr_in));
} }
} }
@ -2091,7 +1935,7 @@ static void runit()
auto pos = inbound_list.find(ip); auto pos = inbound_list.find(ip);
if (pos != inbound_list.end()) { if (pos != inbound_list.end()) {
inbound_ptr = (inbound *)pos->second; //SINBOUND *inbound = (SINBOUND *)pos->second;
// printf("Remote station %s %s requested LH list\n", inbound_ptr->call, ip); // printf("Remote station %s %s requested LH list\n", inbound_ptr->call, ip);
/* header is 10 bytes */ /* header is 10 bytes */
@ -2177,7 +2021,7 @@ static void runit()
auto pos = inbound_list.find(ip); auto pos = inbound_list.find(ip);
if (pos != inbound_list.end()) { if (pos != inbound_list.end()) {
inbound_ptr = (inbound *)pos->second; //SINBOUND *inbound = (SINBOUND *)pos->second;
// printf("Remote station %s %s requested linked repeaters list\n", inbound_ptr->call, ip); // printf("Remote station %s %s requested linked repeaters list\n", inbound_ptr->call, ip);
/* header is 8 bytes */ /* header is 8 bytes */
@ -2268,7 +2112,6 @@ static void runit()
auto pos = inbound_list.find(ip); auto pos = inbound_list.find(ip);
if (pos != inbound_list.end()) { if (pos != inbound_list.end()) {
inbound_ptr = (inbound *)pos->second;
// printf("Remote station %s %s requested connected user list\n", inbound_ptr->call, ip); // printf("Remote station %s %s requested connected user list\n", inbound_ptr->call, ip);
/* header is 8 bytes */ /* header is 8 bytes */
@ -2286,14 +2129,14 @@ static void runit()
for (pos = inbound_list.begin(), i_idx = 0; pos != inbound_list.end(); pos++, i_idx++) { for (pos = inbound_list.begin(), i_idx = 0; pos != inbound_list.end(); pos++, i_idx++) {
/* each entry has 20 bytes */ /* each entry has 20 bytes */
readBuffer2[8 + (20 * j_idx)] = ' '; readBuffer2[8 + (20 * j_idx)] = ' ';
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
readBuffer2[8 + (20 * j_idx)] = inbound_ptr->mod; readBuffer2[8 + (20 * j_idx)] = inbound->mod;
strcpy((char *)readBuffer2 + 9 + (20 * j_idx), inbound_ptr->call); strcpy((char *)readBuffer2 + 9 + (20 * j_idx), inbound->call);
readBuffer2[17 + (20 * j_idx)] = 0; readBuffer2[17 + (20 * j_idx)] = 0;
/* readBuffer2[18 + (20 * j_idx)] = 0; */ /* readBuffer2[18 + (20 * j_idx)] = 0; */
readBuffer2[18 + (20 * j_idx)] = inbound_ptr->client; readBuffer2[18 + (20 * j_idx)] = inbound->client;
readBuffer2[19 + (20 * j_idx)] = 0; readBuffer2[19 + (20 * j_idx)] = 0;
readBuffer2[20 + (20 * j_idx)] = 0x0d; readBuffer2[20 + (20 * j_idx)] = 0x0d;
readBuffer2[21 + (20 * j_idx)] = 0x4d; readBuffer2[21 + (20 * j_idx)] = 0x4d;
@ -2351,7 +2194,7 @@ static void runit()
auto pos = inbound_list.find(ip); auto pos = inbound_list.find(ip);
if (pos != inbound_list.end()) { if (pos != inbound_list.end()) {
inbound_ptr = (inbound *)pos->second; //SINBOUND *inbound = (SINBOUND *)pos->second;
// printf("Remote station %s %s requested date\n", inbound_ptr->call, ip); // printf("Remote station %s %s requested date\n", inbound_ptr->call, ip);
time(&ltime); time(&ltime);
@ -2381,7 +2224,7 @@ static void runit()
(readBuffer2[3] == 0)) { (readBuffer2[3] == 0)) {
auto pos = inbound_list.find(ip); auto pos = inbound_list.find(ip);
if (pos != inbound_list.end()) { if (pos != inbound_list.end()) {
inbound_ptr = (inbound *)pos->second; //SINBOUND *inbound = (SINBOUND *)pos->second;
// printf("Remote station %s %s requested version\n", inbound_ptr->call, ip); // printf("Remote station %s %s requested version\n", inbound_ptr->call, ip);
readBuffer2[0] = 9; readBuffer2[0] = 9;
@ -2420,9 +2263,9 @@ static void runit()
auto pos = inbound_list.find(ip); auto pos = inbound_list.find(ip);
if (pos != inbound_list.end()) { if (pos != inbound_list.end()) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
if (memcmp(inbound_ptr->call, "1NFO", 4) != 0) if (memcmp(inbound->call, "1NFO", 4) != 0)
printf("Call %s disconnected\n", inbound_ptr->call); printf("Call %s disconnected\n", inbound->call);
free(pos->second); free(pos->second);
pos->second = NULL; pos->second = NULL;
inbound_list.erase(pos); inbound_list.erase(pos);
@ -2566,9 +2409,9 @@ static void runit()
/* find out if it is a connected dongle */ /* find out if it is a connected dongle */
auto pos = inbound_list.find(ip); auto pos = inbound_list.find(ip);
if (pos != inbound_list.end()) { if (pos != inbound_list.end()) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
found = true; found = true;
inbound_ptr->countdown = TIMEOUT; inbound->countdown = TIMEOUT;
/*** ip is same, do not update port /*** ip is same, do not update port
memcpy((char *)&(inbound_ptr->sin),(char *)&fromDst4, sizeof(struct sockaddr_in)); memcpy((char *)&(inbound_ptr->sin),(char *)&fromDst4, sizeof(struct sockaddr_in));
***/ ***/
@ -2625,25 +2468,25 @@ static void runit()
sendto(ref_g2_sock, readBuffer2, 8, 0, (struct sockaddr *)&fromDst4, sizeof(fromDst4)); sendto(ref_g2_sock, readBuffer2, 8, 0, (struct sockaddr *)&fromDst4, sizeof(fromDst4));
} else { } else {
/* add the dongle to the inbound list */ /* add the dongle to the inbound list */
inbound_ptr = (inbound *)malloc(sizeof(inbound)); SINBOUND *inbound = (SINBOUND *)malloc(sizeof(SINBOUND));
if (inbound_ptr) { if (inbound) {
inbound_ptr->countdown = TIMEOUT; inbound->countdown = TIMEOUT;
memcpy((char *)&(inbound_ptr->sin),(char *)&fromDst4, sizeof(struct sockaddr_in)); memcpy((char *)&(inbound->sin),(char *)&fromDst4, sizeof(struct sockaddr_in));
strcpy(inbound_ptr->call, call); strcpy(inbound->call, call);
inbound_ptr->mod = ' '; inbound->mod = ' ';
if (memcmp(readBuffer2 + 20, "AP", 2) == 0) if (memcmp(readBuffer2 + 20, "AP", 2) == 0)
inbound_ptr->client = 'A'; /* dvap */ inbound->client = 'A'; /* dvap */
else if (memcmp(readBuffer2 + 20, "DV019999", 8) == 0) else if (memcmp(readBuffer2 + 20, "DV019999", 8) == 0)
inbound_ptr->client = 'H'; /* spot */ inbound->client = 'H'; /* spot */
else else
inbound_ptr->client = 'D'; /* dongle */ inbound->client = 'D'; /* dongle */
auto insert_pair = inbound_list.insert(std::pair<std::string, inbound *>(ip, inbound_ptr)); auto insert_pair = inbound_list.insert(std::pair<std::string, SINBOUND *>(ip, inbound));
if (insert_pair.second) { if (insert_pair.second) {
if (memcmp(inbound_ptr->call, "1NFO", 4) != 0) if (memcmp(inbound->call, "1NFO", 4) != 0)
printf("new CALL=%s, DONGLE-p, ip=%s, users=%d\n", inbound_ptr->call,ip, (int)inbound_list.size()); printf("new CALL=%s, DONGLE-p, ip=%s, users=%d\n", inbound->call,ip, (int)inbound_list.size());
readBuffer2[0] = 8; readBuffer2[0] = 8;
readBuffer2[4] = 79; readBuffer2[4] = 79;
@ -2656,9 +2499,9 @@ static void runit()
print_status_file(); print_status_file();
} else { } else {
printf("failed to add CALL=%s,ip=%s\n",inbound_ptr->call,ip); printf("failed to add CALL=%s,ip=%s\n",inbound->call,ip);
free(inbound_ptr); free(inbound);
inbound_ptr = NULL; inbound = NULL;
readBuffer2[0] = 8; readBuffer2[0] = 8;
readBuffer2[4] = 70; readBuffer2[4] = 70;
@ -2702,8 +2545,8 @@ static void runit()
if (!found) { if (!found) {
auto pos = inbound_list.find(ip); auto pos = inbound_list.find(ip);
if (pos != inbound_list.end()) { if (pos != inbound_list.end()) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
inbound_ptr->countdown = TIMEOUT; inbound->countdown = TIMEOUT;
found = true; found = true;
} }
} }
@ -2750,8 +2593,8 @@ static void runit()
if (i == 3) { if (i == 3) {
pos = inbound_list.find(ip); pos = inbound_list.find(ip);
if (pos != inbound_list.end()) { if (pos != inbound_list.end()) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
memcpy(source_stn, inbound_ptr->call, 8); memcpy(source_stn, inbound->call, 8);
} }
} }
@ -2813,11 +2656,11 @@ static void runit()
/* 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++) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
if (fromDst4.sin_addr.s_addr != inbound_ptr->sin.sin_addr.s_addr) { if (fromDst4.sin_addr.s_addr != inbound->sin.sin_addr.s_addr) {
sendto(ref_g2_sock, readBuffer2, 58, 0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); sendto(ref_g2_sock, readBuffer2, 58, 0, (struct sockaddr *)&(inbound->sin), sizeof(struct sockaddr_in));
} else } else
inbound_ptr->mod = readBuffer2[27]; inbound->mod = readBuffer2[27];
} }
if ((to_remote_g2[i].toDst4.sin_addr.s_addr != fromDst4.sin_addr.s_addr) && if ((to_remote_g2[i].toDst4.sin_addr.s_addr != fromDst4.sin_addr.s_addr) &&
@ -2861,8 +2704,7 @@ static void runit()
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
if (memcmp(old_sid[i].sid, readBuffer2 + 14, 2) == 0) { if (memcmp(old_sid[i].sid, readBuffer2 + 14, 2) == 0) {
if (qso_details) if (qso_details)
printf("END from remote g2: streamID=%d,%d, %d bytes from IP=%s\n", printf("END from remote g2: streamID=%d,%d, %d bytes from IP=%s\n", readBuffer2[14], readBuffer2[15], recvlen2, inet_ntoa(fromDst4.sin_addr));
readBuffer2[14],readBuffer2[15],recvlen2,inet_ntoa(fromDst4.sin_addr));
memset(old_sid[i].sid, 0x00, 2); memset(old_sid[i].sid, 0x00, 2);
@ -2876,9 +2718,9 @@ static void runit()
/* send the data to the donglers */ /* send the data to the donglers */
for (pos = inbound_list.begin(); pos != inbound_list.end(); pos++) { for (pos = inbound_list.begin(); pos != inbound_list.end(); pos++) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
if (fromDst4.sin_addr.s_addr != inbound_ptr->sin.sin_addr.s_addr) { if (fromDst4.sin_addr.s_addr != inbound->sin.sin_addr.s_addr) {
sendto(ref_g2_sock, readBuffer2, 29, 0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); sendto(ref_g2_sock, readBuffer2, 29, 0, (struct sockaddr *)&(inbound->sin), sizeof(struct sockaddr_in));
} }
} }
@ -3043,9 +2885,9 @@ static void runit()
/* 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++) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
for (j=0; j<5; j++) for (j=0; j<5; j++)
sendto(ref_g2_sock, readBuffer2, 58, 0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); sendto(ref_g2_sock, readBuffer2, 58, 0, (struct sockaddr *)&(inbound->sin), sizeof(struct sockaddr_in));
} }
} }
@ -3081,16 +2923,15 @@ static void runit()
/* 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++) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
sendto(ref_g2_sock, readBuffer2, 29, 0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); sendto(ref_g2_sock, readBuffer2, 29, 0, (struct sockaddr *)&(inbound->sin), sizeof(struct sockaddr_in));
} }
if ((dcs_buf[45] & 0x40) != 0) { if ((dcs_buf[45] & 0x40) != 0) {
memset(old_sid[i].sid, 0x00, 2); memset(old_sid[i].sid, 0x00, 2);
if (qso_details) if (qso_details)
printf("END from dcs: streamID=%d,%d, %d bytes from IP=%s\n", printf("END from dcs: streamID=%d,%d, %d bytes from IP=%s\n", dcs_buf[43],dcs_buf[44], recvlen2, inet_ntoa(fromDst4.sin_addr));
dcs_buf[43],dcs_buf[44], recvlen2,inet_ntoa(fromDst4.sin_addr));
to_remote_g2[i].in_streamid[0] = 0x00; to_remote_g2[i].in_streamid[0] = 0x00;
to_remote_g2[i].in_streamid[1] = 0x00; to_remote_g2[i].in_streamid[1] = 0x00;
@ -3446,9 +3287,9 @@ static void runit()
memcpy(&readBuffer2[36], "CQCQCQ ", 8); memcpy(&readBuffer2[36], "CQCQCQ ", 8);
for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) { for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
for (j=0; j<5; j++) for (j=0; j<5; j++)
sendto(ref_g2_sock, readBuffer2, 58, 0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); sendto(ref_g2_sock, readBuffer2, 58, 0, (struct sockaddr *)&(inbound->sin), sizeof(struct sockaddr_in));
} }
} }
@ -3582,8 +3423,8 @@ static void runit()
memcpy(readBuffer2 + 17, readBuffer + 20, 12); memcpy(readBuffer2 + 17, readBuffer + 20, 12);
for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) { for (auto pos = inbound_list.begin(); pos != inbound_list.end(); pos++) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
sendto(ref_g2_sock, readBuffer2, 29, 0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); sendto(ref_g2_sock, readBuffer2, 29, 0, (struct sockaddr *)&(inbound->sin), sizeof(struct sockaddr_in));
} }
} }
@ -3774,7 +3615,7 @@ static void runit()
} }
} }
void audio_notify(char *msg) void CQnetLink::audio_notify(char *msg)
{ {
if (!announce) if (!announce)
return; return;
@ -3791,14 +3632,14 @@ void audio_notify(char *msg)
strcpy(notify_msg[i], msg); strcpy(notify_msg[i], msg);
try { try {
std::async(std::launch::async, AudioNotifyThread, notify_msg[i]); std::async(std::launch::async, &CQnetLink::AudioNotifyThread, this, notify_msg[i]);
} catch (const std::exception &e) { } catch (const std::exception &e) {
printf ("Failed to start AudioNotifyThread(). Exception: %s\n", e.what()); printf ("Failed to start AudioNotifyThread(). Exception: %s\n", e.what());
} }
return; return;
} }
static void AudioNotifyThread(char *arg) void CQnetLink::AudioNotifyThread(char *arg)
{ {
char notify_msg[64]; char notify_msg[64];
@ -4001,27 +3842,18 @@ static void AudioNotifyThread(char *arg)
return; return;
} }
int main(int argc, char **argv) bool CQnetLink::Init(const char *cfgfile)
{ {
short i, j;
struct sigaction act; struct sigaction act;
char unlink_request[CALL_SIZE + 3];
inbound *inbound_ptr;
char cmd_2_dcs[19];
tzset(); tzset();
setvbuf(stdout, (char *)NULL, _IOLBF, 0); setvbuf(stdout, (char *)NULL, _IOLBF, 0);
if (argc != 2) {
printf("Usage: ./g2_link g2_link.cfg\n");
return 1;
}
int rc = regcomp(&preg, "^(([1-9][A-Z])|([A-Z][0-9])|([A-Z][A-Z][0-9]))[0-9A-Z]*[A-Z][ ]*[ A-RT-Z]$", REG_EXTENDED | REG_NOSUB); int rc = regcomp(&preg, "^(([1-9][A-Z])|([A-Z][0-9])|([A-Z][A-Z][0-9]))[0-9A-Z]*[A-Z][ ]*[ A-RT-Z]$", REG_EXTENDED | REG_NOSUB);
if (rc != 0) { if (rc != 0) {
printf("The IRC regular expression is NOT valid\n"); printf("The IRC regular expression is NOT valid\n");
return 1; return true;
} }
act.sa_handler = sigCatch; act.sa_handler = sigCatch;
@ -4029,14 +3861,14 @@ int main(int argc, char **argv)
act.sa_flags = SA_RESTART; act.sa_flags = SA_RESTART;
if (sigaction(SIGTERM, &act, 0) != 0) { if (sigaction(SIGTERM, &act, 0) != 0) {
printf("sigaction-TERM failed, error=%d\n", errno); printf("sigaction-TERM failed, error=%d\n", errno);
return 1; return true;
} }
if (sigaction(SIGINT, &act, 0) != 0) { if (sigaction(SIGINT, &act, 0) != 0) {
printf("sigaction-INT failed, error=%d\n", errno); printf("sigaction-INT failed, error=%d\n", errno);
return 1; return true;
} }
for (i = 0; i < 3; i++) { for (int i=0; i<3; i++) {
to_remote_g2[i].to_call[0] = '\0'; to_remote_g2[i].to_call[0] = '\0';
memset(&(to_remote_g2[i].toDst4),0,sizeof(struct sockaddr_in)); memset(&(to_remote_g2[i].toDst4),0,sizeof(struct sockaddr_in));
to_remote_g2[i].to_mod = ' '; to_remote_g2[i].to_mod = ' ';
@ -4059,30 +3891,29 @@ int main(int argc, char **argv)
brd_from_rptr.to_rptr_streamid[1][0] = brd_from_rptr.to_rptr_streamid[1][1] = 0x00; brd_from_rptr.to_rptr_streamid[1][0] = brd_from_rptr.to_rptr_streamid[1][1] = 0x00;
brd_from_rptr_idx = 0; brd_from_rptr_idx = 0;
do { /* process configuration file */
/* process configuration file */ if (read_config(cfgfile)) {
if (!read_config(argv[1])) { printf("Failed to process config file %s\n", cfgfile);
printf("Failed to process config file %s\n", argv[1]); return true;
break; }
} print_status_file();
print_status_file();
/* Open DB */
if (!load_gwys(gwys))
break;
/* create our server */
if (!srv_open()) {
printf("srv_open() failed\n");
break;
}
printf("g2_link %s initialized...entering processing loop\n", VERSION); /* Open DB */
runit(); if (!load_gwys(gwys))
printf("Leaving processing loop...\n"); return true;
} while (false); /* create our server */
if (!srv_open()) {
printf("srv_open() failed\n");
return true;
}
return false;
}
void CQnetLink::Shutdown()
{
char unlink_request[CALL_SIZE + 3];
char cmd_2_dcs[19];
/* Clear connections */ /* Clear connections */
queryCommand[0] = 5; queryCommand[0] = 5;
@ -4090,7 +3921,7 @@ int main(int argc, char **argv)
queryCommand[2] = 24; queryCommand[2] = 24;
queryCommand[3] = 0; queryCommand[3] = 0;
queryCommand[4] = 0; queryCommand[4] = 0;
for (i = 0; i < 3; i++) { for (int i=0; i<3; i++) {
if (to_remote_g2[i].to_call[0] != '\0') { if (to_remote_g2[i].to_call[0] != '\0') {
if (to_remote_g2[i].toDst4.sin_port == htons(rmt_ref_port)) if (to_remote_g2[i].toDst4.sin_port == htons(rmt_ref_port))
sendto(ref_g2_sock, queryCommand, 5, 0, (struct sockaddr *)&(to_remote_g2[i].toDst4), sizeof(to_remote_g2[i].toDst4)); sendto(ref_g2_sock, queryCommand, 5, 0, (struct sockaddr *)&(to_remote_g2[i].toDst4), sizeof(to_remote_g2[i].toDst4));
@ -4099,7 +3930,7 @@ int main(int argc, char **argv)
unlink_request[8] = to_remote_g2[i].from_mod; unlink_request[8] = to_remote_g2[i].from_mod;
unlink_request[9] = ' '; unlink_request[9] = ' ';
unlink_request[10] = '\0'; unlink_request[10] = '\0';
for (j=0; j<5; j++) for (int j=0; j<5; j++)
sendto(xrf_g2_sock, unlink_request, CALL_SIZE+3, 0, (struct sockaddr *)&(to_remote_g2[i].toDst4), sizeof(to_remote_g2[i].toDst4)); sendto(xrf_g2_sock, unlink_request, CALL_SIZE+3, 0, (struct sockaddr *)&(to_remote_g2[i].toDst4), sizeof(to_remote_g2[i].toDst4));
} else { } else {
strcpy(cmd_2_dcs, owner.c_str()); strcpy(cmd_2_dcs, owner.c_str());
@ -4108,7 +3939,7 @@ int main(int argc, char **argv)
cmd_2_dcs[10] = '\0'; cmd_2_dcs[10] = '\0';
memcpy(cmd_2_dcs + 11, to_remote_g2[i].to_call, 8); memcpy(cmd_2_dcs + 11, to_remote_g2[i].to_call, 8);
for (j=0; j<5; j++) for (int j=0; j<5; j++)
sendto(dcs_g2_sock, cmd_2_dcs, 19, 0, (struct sockaddr *)&(to_remote_g2[i].toDst4), sizeof(to_remote_g2[i].toDst4)); sendto(dcs_g2_sock, cmd_2_dcs, 19, 0, (struct sockaddr *)&(to_remote_g2[i].toDst4), sizeof(to_remote_g2[i].toDst4));
} }
} }
@ -4126,14 +3957,28 @@ int main(int argc, char **argv)
/* 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++) {
inbound_ptr = (inbound *)pos->second; SINBOUND *inbound = (SINBOUND *)pos->second;
sendto(ref_g2_sock, queryCommand, 5, 0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); sendto(ref_g2_sock, queryCommand, 5, 0, (struct sockaddr *)&(inbound->sin), sizeof(struct sockaddr_in));
} }
inbound_list.clear(); inbound_list.clear();
print_status_file(); print_status_file();
srv_close(); srv_close();
printf("g2_link exiting\n");
return 0; return;
}
int main(int argc, char **argv)
{
if (argc != 2) {
printf("Usage: ./g2_link g2_link.cfg\n");
return 1;
}
CQnetLink qnlink;
if (qnlink.Init(argv[1]))
return 1;
printf("g2_link %s initialized...entering processing loop\n", VERSION);
qnlink.Process();
printf("g2_link exiting\n");
qnlink.Shutdown();
} }

@ -0,0 +1,161 @@
#pragma once
/*
* 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 <regex.h>
#include <libconfig.h++>
#include "versions.h"
using namespace libconfig;
/*** version number must be x.xx ***/
#define VERSION LINK_VERSION
#define CALL_SIZE 8
#define IP_SIZE 15
#define QUERY_SIZE 56
#define MAXHOSTNAMELEN 64
#define TIMEOUT 50
#define LH_MAX_SIZE 39
// This is the data payload in the map: inbound_list
// This is for inbound dongles
typedef struct inbound_tag {
char call[CALL_SIZE + 1]; // the callsign of the remote
struct sockaddr_in sin; // IP and port of remote
short countdown; // if countdown expires, the connection is terminated
char mod; // A B C This user talked on this module
char client; // dvap, dvdongle
} SINBOUND;
class CQnetLink {
public:
// functions
CQnetLink();
~CQnetLink();
bool Init(const char *cfgfile);
void Process();
void Shutdown();
private:
// functions
bool load_gwys(const std::string &filename);
void calcPFCS(unsigned char *packet, int len);
bool read_config(const char *);
bool srv_open();
void srv_close();
static void sigCatch(int signum);
void g2link(char from_mod, char *call, char to_mod);
void print_status_file();
void send_heartbeat();
bool resolve_rmt(char *name, int type, struct sockaddr_in *addr);
void audio_notify(char *notify_msg);
void rptr_ack(short i);
void AudioNotifyThread(char *arg);
void RptrAckThread(char *arg);
bool get_value(const Config &cfg, const char *path, int &value, int min, int max, int default_value);
bool get_value(const Config &cfg, const char *path, double &value, double min, double max, double default_value);
bool get_value(const Config &cfg, const char *path, bool &value, bool default_value);
bool get_value(const Config &cfg, const char *path, std::string &value, int min, int max, const char *default_value);
/* configuration data */
std::string login_call, owner, to_g2_external_ip, my_g2_link_ip, gwys, status_file, announce_dir;
bool only_admin_login, only_link_unlink, qso_details, bool_rptr_ack, announce;
int rmt_xrf_port, rmt_ref_port, rmt_dcs_port, my_g2_link_port, to_g2_external_port, delay_between, delay_before;
char link_at_startup[CALL_SIZE+1];
unsigned int max_dongles, saved_max_dongles;
long rf_inactivity_timer[3];
const unsigned char REF_ACK[3] = { 3, 96, 0 };
// the Key in this inbound_list map is the unique IP address of the remote
std::map<std::string, SINBOUND *> inbound_list;
std::set<std::string> admin, link_unlink_user, link_blacklist;
std::map<std::string, std::string> dt_lh_list;
struct to_remote_g2_tag {
char to_call[CALL_SIZE + 1];
struct sockaddr_in toDst4;
char from_mod;
char to_mod;
short countdown;
bool is_connected;
unsigned char in_streamid[2]; // incoming from remote systems
unsigned char out_streamid[2]; // outgoing to remote systems
} to_remote_g2[3];
// broadcast for data arriving from xrf to local rptr
struct brd_from_xrf_tag {
unsigned char xrf_streamid[2]; // streamid from xrf
unsigned char rptr_streamid[2][2]; // generated streamid to rptr(s)
} brd_from_xrf;
unsigned char from_xrf_torptr_brd[56];
short brd_from_xrf_idx;
// broadcast for data arriving from local rptr to xrf
struct brd_from_rptr_tag {
unsigned char from_rptr_streamid[2];
unsigned char to_rptr_streamid[2][2];
} brd_from_rptr;
unsigned char fromrptr_torptr_brd[56];
short brd_from_rptr_idx;
struct tracing_tag {
unsigned char streamid[2];
time_t last_time; // last time RF user talked
} tracing[3];
// input from remote
int xrf_g2_sock, ref_g2_sock, dcs_g2_sock, rptr_sock;
struct sockaddr_in fromDst4;
// After we receive it from remote g2,
// we must feed it to our local repeater.
struct sockaddr_in toLocalg2;
// input from our own local repeater
struct sockaddr_in fromRptr;
fd_set fdset;
struct timeval tv;
static std::atomic<bool> keep_running;
// Used to validate incoming donglers
regex_t preg;
// the map of remotes
// key is the callsign, data is the host
std::map<std::string, std::string> gwy_list;
unsigned char queryCommand[QUERY_SIZE];
// START: TEXT crap
char dtmf_mycall[3][CALL_SIZE + 1];
bool new_group[3];
int header_type;
bool GPS_seen[3];
unsigned char tmp_txt[3];
char *p_tmp2;
// END: TEXT crap
// this is used for the "dashboard and qso_details" to avoid processing multiple headers
struct old_sid_tag {
unsigned char sid[2];
} old_sid[3];
};
Loading…
Cancel
Save

Powered by TurnKey Linux.