qngateway uses unix sockets

pull/12/head
Tom Early 7 years ago
parent b5fa2eca2e
commit 51a929ce54

@ -54,22 +54,22 @@ itap : $(TAP_PROGRAMS)
qnigateway : $(IRCOBJS) QnetIcomGateway.o aprs.o qnigateway : $(IRCOBJS) QnetIcomGateway.o aprs.o
g++ $(CPPFLAGS) -o qnigateway QnetIcomGateway.o aprs.o $(IRCOBJS) $(LDFLAGS) -pthread g++ $(CPPFLAGS) -o qnigateway QnetIcomGateway.o aprs.o $(IRCOBJS) $(LDFLAGS) -pthread
qngateway : $(IRCOBJS) QnetGateway.o aprs.o qngateway : $(IRCOBJS) QnetGateway.o aprs.o UnixDgramSocket.o
g++ $(CPPFLAGS) -o qngateway QnetGateway.o aprs.o $(IRCOBJS) $(LDFLAGS) -pthread g++ $(CPPFLAGS) -o qngateway QnetGateway.o aprs.o UnixDgramSocket.o $(IRCOBJS) $(LDFLAGS) -pthread
qnlink : QnetLink.o DPlusAuthenticator.o TCPReaderWriterClient.o Random.o qnlink : QnetLink.o DPlusAuthenticator.o TCPReaderWriterClient.o Random.o UnixDgramSocket.o
g++ $(CPPFLAGS) -o qnlink QnetLink.o DPlusAuthenticator.o TCPReaderWriterClient.o Random.o $(LDFLAGS) -pthread g++ $(CPPFLAGS) -o qnlink QnetLink.o DPlusAuthenticator.o TCPReaderWriterClient.o Random.o $(LDFLAGS) -pthread
qnrelay : QnetRelay.o qnrelay : QnetRelay.o UnixDgramSocket.o
g++ $(CPPFLAGS) -o qnrelay QnetRelay.o $(LDFLAGS) g++ $(CPPFLAGS) -o qnrelay QnetRelay.o $(LDFLAGS)
qnitap : QnetITAP.o Random.o qnitap : QnetITAP.o Random.o UnixDgramSocket.o
g++ $(CPPFLAGS) -o qnitap QnetITAP.o Random.o $(LDFLAGS) g++ $(CPPFLAGS) -o qnitap QnetITAP.o Random.o $(LDFLAGS)
qndvap : QnetDVAP.o DVAPDongle.o Random.o $(DSTROBJS) qndvap : QnetDVAP.o DVAPDongle.o Random.o $(DSTROBJS) UnixDgramSocket.o
g++ $(CPPFLAGS) -o qndvap QnetDVAP.o DVAPDongle.o Random.o $(DSTROBJS) $(LDFLAGS) -pthread g++ $(CPPFLAGS) -o qndvap QnetDVAP.o DVAPDongle.o Random.o $(DSTROBJS) $(LDFLAGS) -pthread
qndvrptr : QnetDVRPTR.o $(DSTROBJS) Random.o qndvrptr : QnetDVRPTR.o $(DSTROBJS) Random.o UnixDgramSocket.o
g++ $(CPPFLAGS) -o qndvrptr QnetDVRPTR.o Random.o $(DSTROBJS) $(LDFLAGS) g++ $(CPPFLAGS) -o qndvrptr QnetDVRPTR.o Random.o $(DSTROBJS) $(LDFLAGS)
qnremote : QnetRemote.o Random.o qnremote : QnetRemote.o Random.o

@ -252,7 +252,7 @@ bool CQnetGateway::read_config(char *cfgFile)
return true; return true;
// module // module
for (short int m=0; m<3; m++) { for (int m=0; m<3; m++) {
std::string path = "module."; std::string path = "module.";
path += m + 'a'; path += m + 'a';
path += '.'; path += '.';
@ -276,9 +276,11 @@ bool CQnetGateway::read_config(char *cfgFile)
return true; return true;
} }
if (! get_value(cfg, std::string(path+"ip").c_str(), rptr.mod[m].portip.ip, 7, IP_SIZE, "127.0.0.1")) char unixsockname[16];
return true; snprintf(unixsockname, 16, "modem2gate%d", m);
get_value(cfg, std::string(path+"port").c_str(), rptr.mod[m].portip.port, 16000, 65535, 19998+m); get_value(cfg, path+"togateway", modem2gate[m], 1, FILENAME_MAX, unixsockname);
snprintf(unixsockname, 16, "gate2modem%d", m);
get_value(cfg, path+"fromgateway", gate2modem[m], 1, FILENAME_MAX, unixsockname);
get_value(cfg, std::string(path+"frequency").c_str(), rptr.mod[m].frequency, 0.0, 1.0e12, 0.0); get_value(cfg, std::string(path+"frequency").c_str(), rptr.mod[m].frequency, 0.0, 1.0e12, 0.0);
get_value(cfg, std::string(path+"offset").c_str(), rptr.mod[m].offset, -1.0e12, 1.0e12, 0.0); get_value(cfg, std::string(path+"offset").c_str(), rptr.mod[m].offset, -1.0e12, 1.0e12, 0.0);
get_value(cfg, std::string(path+"range").c_str(), rptr.mod[m].range, 0.0, 1609344.0, 0.0); get_value(cfg, std::string(path+"range").c_str(), rptr.mod[m].range, 0.0, 1609344.0, 0.0);
@ -318,17 +320,15 @@ bool CQnetGateway::read_config(char *cfgFile)
get_value(cfg, path+"external.port", g2_external.port, 1024, 65535, 40000); get_value(cfg, path+"external.port", g2_external.port, 1024, 65535, 40000);
if (! get_value(cfg, path+"internal.ip", g2_internal.ip, 7, IP_SIZE, "0.0.0.0"))
return true;
get_value(cfg, path+"internal.port", g2_internal.port, 16000, 65535, 19000);
get_value(cfg, path+"regen_header", bool_regen_header, true); get_value(cfg, path+"regen_header", bool_regen_header, true);
get_value(cfg, path+"aprs_send", bool_send_aprs, true); get_value(cfg, path+"aprs_send", bool_send_aprs, true);
get_value(cfg, path+"send_qrgs_maps", bool_send_qrgs, true); get_value(cfg, path+"send_qrgs_maps", bool_send_qrgs, true);
get_value(cfg, path+"tolink", gate2link, 1, FILENAME_MAX, "gate2link");
get_value(cfg, path+"fromlink", link2gate, 1, FILENAME_MAX, "link2gate");
// APRS // APRS
path = "aprs."; path = "aprs.";
if (! get_value(cfg, path+"host", rptr.aprs.ip, 7, MAXHOSTNAMELEN, "rotate.aprs.net")) if (! get_value(cfg, path+"host", rptr.aprs.ip, 7, MAXHOSTNAMELEN, "rotate.aprs.net"))
@ -348,8 +348,6 @@ bool CQnetGateway::read_config(char *cfgFile)
get_value(cfg, path+"irc", bool_irc_debug, false); get_value(cfg, path+"irc", bool_irc_debug, false);
get_value(cfg, path+"dtmf", bool_dtmf_debug, false); get_value(cfg, path+"dtmf", bool_dtmf_debug, false);
if (! get_value(cfg, "link.outgoing_ip", g2_link.ip, 7, IP_SIZE, "127.0.0.1"))
return true;
// file // file
path = "file."; path = "file.";
@ -365,13 +363,6 @@ bool CQnetGateway::read_config(char *cfgFile)
if (! get_value(cfg, path+"qnvoicefile", qnvoicefile, 2, FILENAME_MAX, "/tmp/qnvoice.txt")) if (! get_value(cfg, path+"qnvoicefile", qnvoicefile, 2, FILENAME_MAX, "/tmp/qnvoice.txt"))
return true; return true;
// link
path = "link.";
get_value(cfg, path+"port", g2_link.port, 16000, 65535, 18997);
if (! get_value(cfg, path+"ip", g2_link.ip, 7, 15, "127.0.0.1"))
return true;
// timing // timing
path = "timing.play."; path = "timing.play.";
get_value(cfg, path+"wait", play_wait, 1, 10, 1); get_value(cfg, path+"wait", play_wait, 1, 10, 1);
@ -732,7 +723,7 @@ void CQnetGateway::ProcessTimeouts()
end_of_audio.vpkt.ctrl = toRptr[i].sequence | 0x40; end_of_audio.vpkt.ctrl = toRptr[i].sequence | 0x40;
for (int j=0; j<2; j++) for (int j=0; j<2; j++)
sendto(srv_sock, end_of_audio.pkt_id, 29, 0, (struct sockaddr *)&toRptr[i].band_addr, sizeof(struct sockaddr_in)); Gate2Modem[i].Write(end_of_audio.pkt_id, 29);
toRptr[i].streamid = 0; toRptr[i].streamid = 0;
@ -1091,79 +1082,10 @@ void CQnetGateway::ProcessSlowData(unsigned char *data, unsigned short sid)
} }
} }
/* run the main loop for QnetGateway */ void CQnetGateway::ProcessG2(ssize_t g2buflen, SDSVT &g2buf)
void CQnetGateway::Process()
{ {
// dtmf stuff
int dtmf_buf_count[3] = {0, 0, 0};
char dtmf_buf[3][MAX_DTMF_BUF + 1] = { {""}, {""}, {""} };
int dtmf_last_frame[3] = { 0, 0, 0 };
unsigned int dtmf_counter[3] = { 0, 0, 0 };
dstar_dv_init();
int max_nfds = 0;
if (g2_sock > max_nfds)
max_nfds = g2_sock;
if (srv_sock > max_nfds)
max_nfds = srv_sock;
printf("g2=%d, srv=%d, MAX+1=%d\n", g2_sock, srv_sock, max_nfds + 1);
std::future<void> aprs_future, irc_data_future;
if (bool_send_aprs) { // start the beacon thread
try {
aprs_future = std::async(std::launch::async, &CQnetGateway::APRSBeaconThread, this);
} catch (const std::exception &e) {
printf("Failed to start the APRSBeaconThread. Exception: %s\n", e.what());
}
if (aprs_future.valid())
printf("APRS beacon thread started\n");
}
try { // start the IRC read thread
irc_data_future = std::async(std::launch::async, &CQnetGateway::GetIRCDataThread, this);
} catch (const std::exception &e) {
printf("Failed to start GetIRCDataThread. Exception: %s\n", e.what());
keep_running = false;
}
if (keep_running)
printf("get_irc_data thread started\n");
ii->kickWatchdog(IRCDDB_VERSION);
while (keep_running) {
ProcessTimeouts();
// wait 20 ms max
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(g2_sock, &fdset);
FD_SET(srv_sock, &fdset);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 20000; // 20 ms
(void)select(max_nfds + 1, &fdset, 0, 0, &tv);
// process packets coming from remote G2
if (FD_ISSET(g2_sock, &fdset)) {
SDSVT g2buf;
socklen_t fromlen = sizeof(struct sockaddr_in);
int g2buflen = recvfrom(g2_sock, g2buf.title, 56, 0, (struct sockaddr *)&fromDst4, &fromlen);
// save incoming port for mobile systems
if (portmap.end() == portmap.find(fromDst4.sin_addr.s_addr)) {
printf("New g2 contact at %s on port %u\n", inet_ntoa(fromDst4.sin_addr), ntohs(fromDst4.sin_port));
portmap[fromDst4.sin_addr.s_addr] = ntohs(fromDst4.sin_port);
} else {
if (ntohs(fromDst4.sin_port) != portmap[fromDst4.sin_addr.s_addr]) {
printf("New g2 port from %s is now %u, it was %u\n", inet_ntoa(fromDst4.sin_addr), ntohs(fromDst4.sin_port), portmap[fromDst4.sin_addr.s_addr]);
portmap[fromDst4.sin_addr.s_addr] = ntohs(fromDst4.sin_port);
}
}
if ( (g2buflen==56 || g2buflen==27) && 0==memcmp(g2buf.title, "DSVT", 4) && (g2buf.config==0x10 || g2buf.config==0x20) && g2buf.id==0x20) { if ( (g2buflen==56 || g2buflen==27) && 0==memcmp(g2buf.title, "DSVT", 4) && (g2buf.config==0x10 || g2buf.config==0x20) && g2buf.id==0x20) {
if (g2buflen == 56) { if (g2buflen == 56) {
// Find out the local repeater module IP/port to send the data to // Find out the local repeater module IP/port to send the data to
int i = g2buf.hdr.rpt1[7] - 'A'; int i = g2buf.hdr.rpt1[7] - 'A';
@ -1196,7 +1118,7 @@ void CQnetGateway::Process()
memcpy(rptrbuf.vpkt.hdr.nm, g2buf.hdr.sfx, 4); memcpy(rptrbuf.vpkt.hdr.nm, g2buf.hdr.sfx, 4);
memcpy(rptrbuf.vpkt.hdr.pfcs, g2buf.hdr.pfcs, 2); memcpy(rptrbuf.vpkt.hdr.pfcs, g2buf.hdr.pfcs, 2);
sendto(srv_sock, rptrbuf.pkt_id, 58, 0, (struct sockaddr *)&toRptr[i].band_addr, sizeof(struct sockaddr_in)); Gate2Modem[i].Write(rptrbuf.pkt_id, 58);
/* save the header */ /* save the header */
memcpy(toRptr[i].saved_hdr, rptrbuf.pkt_id, 58); memcpy(toRptr[i].saved_hdr, rptrbuf.pkt_id, 58);
@ -1230,7 +1152,7 @@ void CQnetGateway::Process()
rptrbuf.vpkt.icm_id = 0x20; rptrbuf.vpkt.icm_id = 0x20;
memcpy(&rptrbuf.vpkt.dst_rptr_id, g2buf.flagb, 18); memcpy(&rptrbuf.vpkt.dst_rptr_id, g2buf.flagb, 18);
sendto(srv_sock, rptrbuf.pkt_id, 29, 0, (struct sockaddr *)&toRptr[i].band_addr, sizeof(struct sockaddr_in)); Gate2Modem[i].Write(rptrbuf.pkt_id, 29);
/* timeit */ /* timeit */
time(&toRptr[i].last_time); time(&toRptr[i].last_time);
@ -1270,7 +1192,7 @@ void CQnetGateway::Process()
toRptr[i].saved_hdr[5] = (unsigned char)((toRptr[i].G2_COUNTER++) & 0xff); toRptr[i].saved_hdr[5] = (unsigned char)((toRptr[i].G2_COUNTER++) & 0xff);
/* re-generate/send the header */ /* re-generate/send the header */
sendto(srv_sock, toRptr[i].saved_hdr, 58, 0, (struct sockaddr *)&toRptr[i].band_addr, sizeof(struct sockaddr_in)); Gate2Modem[i].Write(toRptr[i].saved_hdr, 58);
/* send this audio packet to repeater */ /* send this audio packet to repeater */
memcpy(rptrbuf.pkt_id, "DSTR", 4); memcpy(rptrbuf.pkt_id, "DSTR", 4);
@ -1282,7 +1204,7 @@ void CQnetGateway::Process()
rptrbuf.vpkt.icm_id = 0x20; rptrbuf.vpkt.icm_id = 0x20;
memcpy(&rptrbuf.vpkt.dst_rptr_id, g2buf.flagb, 18); memcpy(&rptrbuf.vpkt.dst_rptr_id, g2buf.flagb, 18);
sendto(srv_sock, rptrbuf.pkt_id, 29, 0, (struct sockaddr *)&toRptr[i].band_addr, sizeof(struct sockaddr_in)); Gate2Modem[i].Write(rptrbuf.pkt_id, 29);
/* make sure that any more audio arriving will be accepted */ /* make sure that any more audio arriving will be accepted */
toRptr[i].streamid = g2buf.streamid; toRptr[i].streamid = g2buf.streamid;
@ -1301,24 +1223,20 @@ void CQnetGateway::Process()
} }
} }
} }
FD_CLR (g2_sock,&fdset); }
}
// process packets coming from local repeater modules void CQnetGateway::ProcessModem(int mod)
if (FD_ISSET(srv_sock, &fdset)) { {
char temp_radio_user[CALL_SIZE + 1]; char temp_radio_user[CALL_SIZE + 1];
char temp_mod; char temp_mod;
char arearp_cs[CALL_SIZE + 1]; char arearp_cs[CALL_SIZE + 1];
char zonerp_cs[CALL_SIZE + 1]; char zonerp_cs[CALL_SIZE + 1];
char ip[IP_SIZE + 1]; char ip[IP_SIZE + 1];
char tempfile[FILENAME_MAX + 1]; char tempfile[FILENAME_MAX + 1];
SDSVT g2buf; SDSVT g2buf;
socklen_t fromlen = sizeof(struct sockaddr_in); int recvlen = Modem2Gate[mod].Read(rptrbuf.pkt_id, 58);
int recvlen = recvfrom(srv_sock, rptrbuf.pkt_id, 58, 0, (struct sockaddr *)&fromRptr, &fromlen);
if (0 == memcmp(rptrbuf.pkt_id, "DSTR", 4)) { if (0 == memcmp(rptrbuf.pkt_id, "DSTR", 4)) {
if ( (recvlen==58 || recvlen==29 || recvlen==32) && rptrbuf.flag[0]==0x73 && rptrbuf.flag[1]==0x12 && rptrbuf.flag[2]==0x0 && rptrbuf.vpkt.icm_id==0x20 && (rptrbuf.remaining==0x30 || rptrbuf.remaining==0x13 || rptrbuf.remaining==0x16) ) { if ( (recvlen==58 || recvlen==29 || recvlen==32) && rptrbuf.flag[0]==0x73 && rptrbuf.flag[1]==0x12 && rptrbuf.flag[2]==0x0 && rptrbuf.vpkt.icm_id==0x20 && (rptrbuf.remaining==0x30 || rptrbuf.remaining==0x13 || rptrbuf.remaining==0x16) ) {
@ -1409,7 +1327,7 @@ void CQnetGateway::Process()
/* send data qnlink */ /* send data qnlink */
if (mycall_valid == REG_NOERROR) if (mycall_valid == REG_NOERROR)
sendto(srv_sock, rptrbuf.pkt_id, recvlen, 0, (struct sockaddr *)&plug, sizeof(struct sockaddr_in)); Gate2Link.Write(rptrbuf.pkt_id, recvlen);
if ( mycall_valid==REG_NOERROR && if ( mycall_valid==REG_NOERROR &&
memcmp(rptrbuf.vpkt.hdr.ur, "XRF", 3) && // not a reflector memcmp(rptrbuf.vpkt.hdr.ur, "XRF", 3) && // not a reflector
@ -1600,7 +1518,7 @@ void CQnetGateway::Process()
rptrbuf.vpkt.hdr.r1[7] = 'G'; rptrbuf.vpkt.hdr.r1[7] = 'G';
calcPFCS(rptrbuf.pkt_id, 58); calcPFCS(rptrbuf.pkt_id, 58);
sendto(srv_sock, rptrbuf.pkt_id, 58, 0, (struct sockaddr *)&toRptr[i].band_addr, sizeof(struct sockaddr_in)); Gate2Modem[i].Write(rptrbuf.pkt_id, 58);
/* This is the active streamid */ /* This is the active streamid */
toRptr[i].streamid = rptrbuf.vpkt.streamid; toRptr[i].streamid = rptrbuf.vpkt.streamid;
@ -1771,7 +1689,7 @@ void CQnetGateway::Process()
rptrbuf.vpkt.hdr.r1[7] = 'G'; rptrbuf.vpkt.hdr.r1[7] = 'G';
calcPFCS(rptrbuf.pkt_id, 58); calcPFCS(rptrbuf.pkt_id, 58);
sendto(srv_sock, rptrbuf.pkt_id, 58, 0, (struct sockaddr *)&toRptr[i].band_addr, sizeof(struct sockaddr_in)); Gate2Modem[i].Write(rptrbuf.pkt_id, 58);
/* This is the active streamid */ /* This is the active streamid */
toRptr[i].streamid = rptrbuf.vpkt.streamid; toRptr[i].streamid = rptrbuf.vpkt.streamid;
@ -1903,7 +1821,7 @@ void CQnetGateway::Process()
ProcessSlowData(rptrbuf.vpkt.vasd1.text, rptrbuf.vpkt.streamid); ProcessSlowData(rptrbuf.vpkt.vasd1.text, rptrbuf.vpkt.streamid);
/* send data to qnlink */ /* send data to qnlink */
sendto(srv_sock, rptrbuf.pkt_id, recvlen, 0, (struct sockaddr *)&plug, sizeof(struct sockaddr_in)); Gate2Link.Write(rptrbuf.pkt_id, recvlen);
/* aprs processing */ /* aprs processing */
if (bool_send_aprs) if (bool_send_aprs)
@ -1941,25 +1859,11 @@ void CQnetGateway::Process()
else if (recd[i].fd>=0 && recd[i].streamid==rptrbuf.vpkt.streamid) { // Is the data to be recorded for echotest else if (recd[i].fd>=0 && recd[i].streamid==rptrbuf.vpkt.streamid) { // Is the data to be recorded for echotest
time(&recd[i].last_time); time(&recd[i].last_time);
//memcpy(recbuf.title, "DSVT", 4);
//recbuf.config = 0x20;
//recbuf.id = rptrbuf.vpkt.icm_id;
//recbuf.flaga[0] = recbuf.flaga[1] = recbuf.flaga[20] = 0;
//recbuf.flagb[0] = rptrbuf.vpkt.dst_rptr_id;
//recbuf.flagb[1] = rptrbuf.vpkt.snd_rptr_id;
//recbuf.flagb[2] = rptrbuf.vpkt.snd_term_id;
//memcpy(&recbuf.streamid, &rptrbuf.vpkt.streamid, 3);
if (recvlen == 29) if (recvlen == 29)
//memcpy(recbuf.vasd.voice, rptrbuf.vpkt.vasd.voice, 12);
(void)write(recd[i].fd, rptrbuf.vpkt.vasd.voice, 9); (void)write(recd[i].fd, rptrbuf.vpkt.vasd.voice, 9);
else else
//memcpy(recbuf.vasd.voice, rptrbuf.vpkt.vasd1.voice, 12);
(void)write(recd[i].fd, rptrbuf.vpkt.vasd1.voice, 9); (void)write(recd[i].fd, rptrbuf.vpkt.vasd1.voice, 9);
//rec_len = 27;
//(void)write(recd[i].fd, &rec_len, 2);
//(void)write(recd[i].fd, &recbuf, rec_len);
if ((rptrbuf.vpkt.ctrl & 0x40) != 0) { if ((rptrbuf.vpkt.ctrl & 0x40) != 0) {
recd[i].streamid = 0; recd[i].streamid = 0;
recd[i].last_time = 0; recd[i].last_time = 0;
@ -1982,25 +1886,11 @@ void CQnetGateway::Process()
else if ((vm[i].fd >= 0) && (vm[i].streamid==rptrbuf.vpkt.streamid)) { // Is the data to be recorded for voicemail else if ((vm[i].fd >= 0) && (vm[i].streamid==rptrbuf.vpkt.streamid)) { // Is the data to be recorded for voicemail
time(&vm[i].last_time); time(&vm[i].last_time);
//memcpy(recbuf.title, "DSVT", 4);
//recbuf.config = 0x20;
//recbuf.flaga[0] = recbuf.flaga[1] = recbuf.flaga[2] = 0;
//recbuf.id = rptrbuf.vpkt.icm_id;
//recbuf.flagb[0] = rptrbuf.vpkt.dst_rptr_id;
//recbuf.flagb[1] = rptrbuf.vpkt.snd_rptr_id;
//recbuf.flagb[2] = rptrbuf.vpkt.snd_term_id;
//memcpy(&recbuf.streamid, &rptrbuf.vpkt.streamid, 3);
if (recvlen == 29) if (recvlen == 29)
//memcpy(recbuf.vasd.voice, rptrbuf.vpkt.vasd.voice, 12);
(void)write(vm[i].fd, rptrbuf.vpkt.vasd.voice, 9); (void)write(vm[i].fd, rptrbuf.vpkt.vasd.voice, 9);
else else
//memcpy(recbuf.vasd.voice, rptrbuf.vpkt.vasd1.voice, 12);
(void)write(vm[i].fd, rptrbuf.vpkt.vasd1.voice, 9); (void)write(vm[i].fd, rptrbuf.vpkt.vasd1.voice, 9);
//rec_len = 27;
//(void)write(vm[i].fd, &rec_len, 2);
//(void)write(vm[i].fd, &recbuf, rec_len);
if ((rptrbuf.vpkt.ctrl & 0x40) != 0) { if ((rptrbuf.vpkt.ctrl & 0x40) != 0) {
vm[i].streamid = 0; vm[i].streamid = 0;
vm[i].last_time = 0; vm[i].last_time = 0;
@ -2011,7 +1901,7 @@ void CQnetGateway::Process()
break; break;
} }
else if ((toRptr[i].streamid==rptrbuf.vpkt.streamid) && (toRptr[i].adr == fromRptr.sin_addr.s_addr)) { // or maybe this is cross-banding data else if ((toRptr[i].streamid==rptrbuf.vpkt.streamid) && (toRptr[i].adr == fromRptr.sin_addr.s_addr)) { // or maybe this is cross-banding data
sendto(srv_sock, rptrbuf.pkt_id, 29, 0, (struct sockaddr *)&toRptr[i].band_addr, sizeof(struct sockaddr_in)); Gate2Modem[i].Write(rptrbuf.pkt_id, 29);
/* timeit */ /* timeit */
time(&toRptr[i].last_time); time(&toRptr[i].last_time);
@ -2036,7 +1926,100 @@ void CQnetGateway::Process()
} }
} }
} }
FD_CLR (srv_sock,&fdset); }
void CQnetGateway::AddFDSet(int &max, int newfd, fd_set *set)
{
if (newfd > max)
max = newfd;
FD_SET(newfd, set);
}
/* run the main loop for QnetGateway */
void CQnetGateway::Process()
{
// dtmf stuff initialize
for (int i=0; i<3; i++) {
dtmf_buf_count[i] = 0;
dtmf_buf[i][0] = '\0';
dtmf_last_frame[i] = 0;
dtmf_counter[i] = 0U;
}
dstar_dv_init();
std::future<void> aprs_future, irc_data_future;
if (bool_send_aprs) { // start the beacon thread
try {
aprs_future = std::async(std::launch::async, &CQnetGateway::APRSBeaconThread, this);
} catch (const std::exception &e) {
printf("Failed to start the APRSBeaconThread. Exception: %s\n", e.what());
}
if (aprs_future.valid())
printf("APRS beacon thread started\n");
}
try { // start the IRC read thread
irc_data_future = std::async(std::launch::async, &CQnetGateway::GetIRCDataThread, this);
} catch (const std::exception &e) {
printf("Failed to start GetIRCDataThread. Exception: %s\n", e.what());
keep_running = false;
}
if (keep_running)
printf("get_irc_data thread started\n");
ii->kickWatchdog(IRCDDB_VERSION);
while (keep_running) {
ProcessTimeouts();
// wait 20 ms max
int max_nfds = 0;
fd_set fdset;
FD_ZERO(&fdset);
AddFDSet(max_nfds, g2_sock, &fdset);
AddFDSet(max_nfds, Link2Gate.GetFD(), &fdset);
for (int i=0; i<3; i++)
if (rptr.mod[i].defined)
AddFDSet(max_nfds, Modem2Gate[i].GetFD(), &fdset);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 20000; // 20 ms
(void)select(max_nfds + 1, &fdset, 0, 0, &tv);
// process packets coming from remote G2 or g2_link
if (FD_ISSET(g2_sock, &fdset)) {
SDSVT g2buf;
socklen_t fromlen = sizeof(struct sockaddr_in);
ssize_t g2buflen = recvfrom(g2_sock, g2buf.title, 56, 0, (struct sockaddr *)&fromDst4, &fromlen);
// save incoming port for mobile systems
if (portmap.end() == portmap.find(fromDst4.sin_addr.s_addr)) {
printf("New g2 contact at %s on port %u\n", inet_ntoa(fromDst4.sin_addr), ntohs(fromDst4.sin_port));
portmap[fromDst4.sin_addr.s_addr] = ntohs(fromDst4.sin_port);
} else {
if (ntohs(fromDst4.sin_port) != portmap[fromDst4.sin_addr.s_addr]) {
printf("New g2 port from %s is now %u, it was %u\n", inet_ntoa(fromDst4.sin_addr), ntohs(fromDst4.sin_port), portmap[fromDst4.sin_addr.s_addr]);
portmap[fromDst4.sin_addr.s_addr] = ntohs(fromDst4.sin_port);
}
}
ProcessG2(g2buflen, g2buf);
FD_CLR(g2_sock, &fdset);
}
if (FD_ISSET(Link2Gate.GetFD(), &fdset)) {
SDSVT g2buf;
ssize_t g2buflen = Link2Gate.Read(g2buf.title, 56);
ProcessG2(g2buflen, g2buf);
FD_CLR(Link2Gate.GetFD(), &fdset);
}
// process packets coming from local repeater modules
for (int mod=0; mod<3; mod++) {
if (rptr.mod[mod].defined && FD_ISSET(Modem2Gate[mod].GetFD(), &fdset)) {
ProcessModem(mod);
FD_CLR (Modem2Gate[mod].GetFD(), &fdset);
}
} }
} }
@ -2333,7 +2316,7 @@ void CQnetGateway::PlayFileThread(SECHO &edata)
memcpy(dstr.vpkt.hdr.nm, edata.header.hdr.sfx, 4); memcpy(dstr.vpkt.hdr.nm, edata.header.hdr.sfx, 4);
calcPFCS(dstr.pkt_id, 58); calcPFCS(dstr.pkt_id, 58);
sendto(srv_sock, dstr.pkt_id, 58, 0, (struct sockaddr *)&toRptr[mod].band_addr, sizeof(struct sockaddr_in)); Gate2Modem[mod].Write(dstr.pkt_id, 58);
dstr.remaining = 0x13U; dstr.remaining = 0x13U;
@ -2395,7 +2378,7 @@ void CQnetGateway::PlayFileThread(SECHO &edata)
if (i+1 == ambeblocks) if (i+1 == ambeblocks)
dstr.vpkt.ctrl |= 0x40U; dstr.vpkt.ctrl |= 0x40U;
sendto(srv_sock, dstr.pkt_id, 29, 0, (struct sockaddr *)&toRptr[mod].band_addr, sizeof(struct sockaddr_in)); Gate2Modem[mod].Write(dstr.pkt_id, 29);
std::this_thread::sleep_for(std::chrono::milliseconds(play_delay)); std::this_thread::sleep_for(std::chrono::milliseconds(play_delay));
} }
@ -2561,16 +2544,17 @@ int CQnetGateway::Init(char *cfgfile)
return 1; return 1;
} }
// Open G2 INTERNAL: // Open unix sockets between qngateway and qnlink
// default non-icom 127.0.0.1:19000 if (Gate2Link.Open(gate2link.c_str()))
// default icom 172.16.0.20:20000 return 1;
srv_sock = open_port(g2_internal); if (Link2Gate.Open(link2gate.c_str()))
if (0 > srv_sock) {
printf("Can't open %s:%d\n", g2_internal.ip.c_str(), g2_internal.port);
return 1; return 1;
}
for (i = 0; i < 3; i++) { for (i=0; i<3; i++) {
if (rptr.mod[i].defined) { // open unix sockets between qngateway and each defined modem
if (Gate2Modem[i].Open(gate2modem[i].c_str()) || Modem2Gate[i].Open(modem2gate[i].c_str()))
return 1;
}
// recording for echotest on local repeater modules // recording for echotest on local repeater modules
recd[i].last_time = 0; recd[i].last_time = 0;
recd[i].streamid = 0; recd[i].streamid = 0;
@ -2633,12 +2617,6 @@ int CQnetGateway::Init(char *cfgfile)
to_remote_g2[i].last_time = 0; to_remote_g2[i].last_time = 0;
} }
/* where to send packets to qnlink */
memset(&plug, 0, sizeof(struct sockaddr_in));
plug.sin_family = AF_INET;
plug.sin_port = htons(g2_link.port);
plug.sin_addr.s_addr = inet_addr(g2_link.ip.c_str());
printf("QnetGateway...entering processing loop\n"); printf("QnetGateway...entering processing loop\n");
if (bool_send_qrgs) if (bool_send_qrgs)
@ -2652,9 +2630,11 @@ CQnetGateway::CQnetGateway()
CQnetGateway::~CQnetGateway() CQnetGateway::~CQnetGateway()
{ {
if (srv_sock != -1) { Gate2Link.Close();
close(srv_sock); Link2Gate.Close();
printf("Closed G2_INTERNAL_PORT\n"); for (int i=0; i<3; i++) {
Gate2Modem[i].Close();
Modem2Gate[i].Close();
} }
if (g2_sock != -1) { if (g2_sock != -1) {

@ -19,7 +19,7 @@
#include <libconfig.h++> #include <libconfig.h++>
#include "QnetTypeDefs.h" #include "QnetTypeDefs.h"
#include "SEcho.h" #include "SEcho.h"
#include "UnixDgramSocket.h"
#include "aprs.h" #include "aprs.h"
using namespace libconfig; using namespace libconfig;
@ -91,7 +91,12 @@ private:
bool ABC_grp[3] = { false, false, false }; bool ABC_grp[3] = { false, false, false };
bool C_seen[3] = { false, false, false }; bool C_seen[3] = { false, false, false };
SPORTIP g2_internal, g2_external, g2_link, ircddb; SPORTIP g2_external, ircddb;
CUnixDgramReader Link2Gate, Modem2Gate[3];
CUnixDgramWriter Gate2Link, Gate2Modem[3];
std::string gate2link, link2gate, gate2modem[3], modem2gate[3];
std::string OWNER, owner, local_irc_ip, status_file, dtmf_dir, dtmf_file, echotest_dir, irc_pass, qnvoicefile; std::string OWNER, owner, local_irc_ip, status_file, dtmf_dir, dtmf_file, echotest_dir, irc_pass, qnvoicefile;
@ -124,7 +129,6 @@ private:
STOREPEATER toRptr[3]; // 0=A, 1=B, 2=C STOREPEATER toRptr[3]; // 0=A, 1=B, 2=C
// input from our own local repeater modules // input from our own local repeater modules
int srv_sock = -1;
SDSTR rptrbuf; // 58 or 29 or 32, max is 58 SDSTR rptrbuf; // 58 or 29 or 32, max is 58
struct sockaddr_in fromRptr; struct sockaddr_in fromRptr;
@ -151,6 +155,13 @@ private:
pthread_mutex_t irc_data_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t irc_data_mutex = PTHREAD_MUTEX_INITIALIZER;
// dtmf stuff
int dtmf_buf_count[3];
char dtmf_buf[3][MAX_DTMF_BUF + 1];
int dtmf_last_frame[3];
unsigned int dtmf_counter[3];
void AddFDSet(int &max, int newfd, fd_set *set);
int open_port(const SPORTIP &pip); int open_port(const SPORTIP &pip);
void calcPFCS(unsigned char *packet, int len); void calcPFCS(unsigned char *packet, int len);
void GetIRCDataThread(); void GetIRCDataThread();
@ -161,6 +172,8 @@ private:
void APRSBeaconThread(); void APRSBeaconThread();
void ProcessTimeouts(); void ProcessTimeouts();
void ProcessSlowData(unsigned char *data, unsigned short sid); void ProcessSlowData(unsigned char *data, unsigned short sid);
void ProcessG2(ssize_t g2buflen, SDSVT &g2buf);
void ProcessModem(int mod);
bool Flag_is_ok(unsigned char flag); bool Flag_is_ok(unsigned char flag);
// read configuration file // read configuration file

@ -56,7 +56,7 @@
#include "IRCDDB.h" #include "IRCDDB.h"
#include "IRCutils.h" #include "IRCutils.h"
#include "versions.h" #include "versions.h"
#include "QnetGateway.h" #include "QnetIcomGateway.h"
extern void dstar_dv_init(); extern void dstar_dv_init();

@ -0,0 +1,182 @@
/*
* Copyright (C) 2018 by Thomas 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 <libconfig.h++>
#include "QnetTypeDefs.h"
#include "SEcho.h"
#include "aprs.h"
using namespace libconfig;
#define IP_SIZE 15
#define MAXHOSTNAMELEN 64
#define CALL_SIZE 8
#define MAX_DTMF_BUF 32
typedef struct to_remote_g2_tag {
unsigned short streamid;
struct sockaddr_in toDst4;
time_t last_time;
} STOREMOTEG2;
typedef struct torepeater_tag {
// help with header re-generation
unsigned char saved_hdr[58]; // repeater format
uint32_t saved_adr;
unsigned short streamid;
uint32_t adr;
struct sockaddr_in band_addr;
time_t last_time;
std::atomic<unsigned short> G2_COUNTER;
unsigned char sequence;
} STOREPEATER;
typedef struct band_txt_tag {
unsigned short streamID;
unsigned char flags[3];
char lh_mycall[CALL_SIZE + 1];
char lh_sfx[5];
char lh_yrcall[CALL_SIZE + 1];
char lh_rpt1[CALL_SIZE + 1];
char lh_rpt2[CALL_SIZE + 1];
time_t last_time;
char txt[64]; // Only 20 are used
unsigned short txt_cnt;
bool sent_key_on_msg;
char dest_rptr[CALL_SIZE + 1];
// try to process GPS mode: GPRMC and ID
char temp_line[256];
unsigned short temp_line_cnt;
char gprmc[256];
char gpid[256];
bool is_gps_sent;
time_t gps_last_time;
int num_dv_frames;
int num_dv_silent_frames;
int num_bit_errors;
} SBANDTXT;
class CQnetGateway {
public:
CQnetGateway();
~CQnetGateway();
void Process();
int Init(char *cfgfile);
private:
// text stuff
bool new_group[3] = { true, true, true };
unsigned char header_type = 0;
short to_print[3] = { 0, 0, 0 };
bool ABC_grp[3] = { false, false, false };
bool C_seen[3] = { false, false, false };
SPORTIP g2_internal, g2_external, g2_link, ircddb;
std::string OWNER, owner, local_irc_ip, status_file, dtmf_dir, dtmf_file, echotest_dir, irc_pass, qnvoicefile;
bool bool_send_qrgs, bool_irc_debug, bool_dtmf_debug, bool_regen_header, bool_qso_details, bool_send_aprs, playNotInCache;
int play_wait, play_delay, echotest_rec_timeout, voicemail_rec_timeout, from_remote_g2_timeout, from_local_rptr_timeout, dtmf_digit;
unsigned int vPacketCount;
std::map <uint32_t, uint16_t> portmap;
// data needed for aprs login and aprs beacon
// RPTR defined in aprs.h
SRPTR rptr;
// local repeater modules being recorded
// This is for echotest and voicemail
SECHO recd[3], vm[3];
SDSVT recbuf; // 56 or 27, max is 56
// the streamids going to remote Gateways from each local module
STOREMOTEG2 to_remote_g2[3]; // 0=A, 1=B, 2=C
// input from remote G2 gateway
int g2_sock = -1;
struct sockaddr_in fromDst4;
// Incoming data from remote systems
// must be fed into our local repeater modules.
STOREPEATER toRptr[3]; // 0=A, 1=B, 2=C
// input from our own local repeater modules
int srv_sock = -1;
SDSTR rptrbuf; // 58 or 29 or 32, max is 58
struct sockaddr_in fromRptr;
SDSTR end_of_audio;
// send packets to g2_link
struct sockaddr_in plug;
// for talking with the irc server
CIRCDDB *ii;
// for handling APRS stuff
CAPRS *aprs;
// text coming from local repeater bands
SBANDTXT band_txt[3]; // 0=A, 1=B, 2=C
/* Used to validate MYCALL input */
regex_t preg;
// CACHE used to cache users, repeaters,
// gateways, IP numbers coming from the irc server
std::map<std::string, std::string> user2rptr_map, rptr2gwy_map, gwy2ip_map;
pthread_mutex_t irc_data_mutex = PTHREAD_MUTEX_INITIALIZER;
int open_port(const SPORTIP &pip);
void calcPFCS(unsigned char *packet, int len);
void GetIRCDataThread();
int get_yrcall_rptr_from_cache(char *call, char *arearp_cs, char *zonerp_cs, char *mod, char *ip, char RoU);
bool get_yrcall_rptr(char *call, char *arearp_cs, char *zonerp_cs, char *mod, char *ip, char RoU);
void PlayFileThread(SECHO &edata);
void compute_aprs_hash();
void APRSBeaconThread();
void ProcessTimeouts();
void ProcessSlowData(unsigned char *data, unsigned short sid);
bool Flag_is_ok(unsigned char flag);
// read configuration file
bool read_config(char *);
bool get_value(const Config &cfg, const std::string path, int &value, int min, int max, int default_value);
bool get_value(const Config &cfg, const std::string path, double &value, double min, double max, double default_value);
bool get_value(const Config &cfg, const std::string path, bool &value, bool default_value);
bool get_value(const Config &cfg, const std::string path, std::string &value, int min, int max, const char *default_value);
/* aprs functions, borrowed from my retired IRLP node 4201 */
void gps_send(short int rptr_idx);
bool verify_gps_csum(char *gps_text, char *csum_text);
void build_aprs_from_gps_and_send(short int rptr_idx);
void qrgs_and_maps();
void set_dest_rptr(int mod_ndx, char *dest_rptr);
bool validate_csum(SBANDTXT &bt, bool is_gps);
};

@ -0,0 +1,125 @@
/*
* Copyright (C) 2018 by Thomas 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 <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include "UnixDgramSocket.h"
CUnixDgramReader::CUnixDgramReader() : fd(-1) {}
CUnixDgramReader::~CUnixDgramReader()
{
Close();
}
bool CUnixDgramReader::Open(const char *path) // returns true on failure
{
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (fd < 0) {
fprintf(stderr, "CUnixDgramReader::Open: socket() failed: %s\n", strerror(errno));
return true;
}
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path+1, path, sizeof(addr.sun_path)-2);
int rval = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if (rval < 0) {
fprintf(stderr, "CUnixDgramReader::Open: bind() failed: %s\n", strerror(errno));
close(fd);
fd = -1;
return true;
}
return false;
}
ssize_t CUnixDgramReader::Read(void *buf, size_t size)
{
if (fd >= 0)
return read(fd, buf, size);
return -1;
}
void CUnixDgramReader::Close()
{
if (fd >= 0)
close(fd);
fd = -1;
}
int CUnixDgramReader::GetFD()
{
return fd;
}
CUnixDgramWriter::CUnixDgramWriter() : fd(-1) {}
CUnixDgramWriter::~CUnixDgramWriter()
{
Close();
}
bool CUnixDgramWriter::Open(const char *path) // returns true on failure
{
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (fd < 0) {
fprintf(stderr, "CUnixDgramWriter::Open: socket() failed: %s\n", strerror(errno));
return true;
}
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path+1, path, sizeof(addr.sun_path)-2);
int rval = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
if (rval < 0) {
fprintf(stderr, "CUnixDgramWriter::Open: connect() failed: %s\n", strerror(errno));
close(fd);
fd = -1;
return true;
}
return false;
}
ssize_t CUnixDgramWriter::Write(void *buf, size_t size)
{
if (fd >= 0)
return write(fd, buf, size);
return -1;
}
void CUnixDgramWriter::Close()
{
if (fd >= 0)
close(fd);
fd = -1;
}
int CUnixDgramWriter::GetFD()
{
return fd;
}

@ -0,0 +1,46 @@
#pragma once
/*
* Copyright (C) 2018 by Thomas 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 <stdlib.h>
class CUnixDgramReader
{
public:
CUnixDgramReader();
~CUnixDgramReader();
bool Open(const char *path);
ssize_t Read(void *buf, size_t size);
void Close();
int GetFD();
private:
int fd;
};
class CUnixDgramWriter
{
public:
CUnixDgramWriter();
~CUnixDgramWriter();
bool Open(const char *path);
ssize_t Write(void *buf, size_t size);
void Close();
int GetFD();
private:
int fd;
};
Loading…
Cancel
Save

Powered by TurnKey Linux.