DPlus authorization and "empty txt message" bug

lastudp
Tom Early 7 years ago
parent 0ff3ea12d5
commit e9645fad82

@ -0,0 +1,177 @@
/*
* Copyright (C) 2010-2015 by Jonathan Naylor G4KLX
* 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 <string>
#include <cassert>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include "DPlusAuthenticator.h"
//#include "DStarDefines.h"
//#include "Utils.h"
//#include "Defs.h"
CDPlusAuthenticator::CDPlusAuthenticator(const std::string &loginCallsign, const std::string &address) :
m_loginCallsign(loginCallsign),
m_address(address)
{
assert(loginCallsign.size());
Trim(m_loginCallsign);
}
CDPlusAuthenticator::~CDPlusAuthenticator()
{
}
bool CDPlusAuthenticator::Process(std::map<std::string, std::string> &gwy_map, const bool reflectors, const bool repeaters)
// return true if everything went okay
{
struct addrinfo hints, *infoptr;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET; // AF_INET means IPv4 only addresses
hints.ai_socktype = SOCK_STREAM;
int result = getaddrinfo(m_address.c_str(), NULL, &hints, &infoptr);
if (result) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(result));
return false;
}
struct addrinfo *p;
char host[256];
bool success = false;
for (p = infoptr; p != NULL && !success; p = p->ai_next) {
getnameinfo(p->ai_addr, p->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
printf("Trying %s from %s\n", host, m_address.c_str());
success = authenticate(m_loginCallsign, std::string(host), gwy_map, reflectors, repeaters);
}
freeaddrinfo(infoptr);
return success;
}
bool CDPlusAuthenticator::authenticate(const std::string &callsign, const std::string &hostname, std::map<std::string, std::string> &gwy_map, const bool reflectors, const bool repeaters)
{
CTCPReaderWriterClient socket(hostname, 20001U);
bool ret = socket.open();
if (!ret)
return false;
unsigned char* buffer = new unsigned char[4096U];
::memset(buffer, ' ', 56U);
buffer[0U] = 0x38U;
buffer[1U] = 0xC0U;
buffer[2U] = 0x01U;
buffer[3U] = 0x00U;
::memcpy(buffer+4, callsign.c_str(), callsign.size());
::memcpy(buffer+12, "DV019999", 8);
::memcpy(buffer+28, "W7IB2", 5);
::memcpy(buffer+40, "DHS0257", 7);
ret = socket.write(buffer, 56U);
if (!ret) {
socket.close();
delete[] buffer;
return false;
}
ret = read(socket, buffer, 2U);
while (ret) {
unsigned int len = (buffer[1U] & 0x0FU) * 256U + buffer[0U];
// Ensure that we get exactly len - 2U bytes from the TCP stream
ret = read(socket, buffer + 2U, len - 2U);
if (!ret) {
fprintf(stderr, "Short read from %s:20001", hostname.c_str());
return false;
}
if ((buffer[1U] & 0xC0U) != 0xC0U || buffer[2U] != 0x01U) {
fprintf(stderr, "Invalid packet received from %s:20001", hostname.c_str());
return false;
}
for (unsigned int i = 8U; (i + 25U) < len; i += 26U) {
std::string address((char *)(buffer + i));
std::string name((char *)(buffer + i + 16U));
Trim(address);
Trim(name);
// Get the active flag
bool active = (buffer[i + 25U] & 0x80U) == 0x80U;
// An empty name or IP address or an inactive gateway/reflector is not added
if (address.size()>0U && name.size()>0U && active) {
if (reflectors && 0==name.compare(0, 3, "REF"))
gwy_map[name] = address.append(" 20001");
else if (repeaters && name.compare(0, 3, "REF"))
gwy_map[name] = address.append(" 20001");
}
}
ret = read(socket, buffer, 2U);
}
printf("Authorized DPlus with %s using callsign %s\n", hostname.c_str(), callsign.c_str());
printf("Added %ld DPlus gateways\n", gwy_map.size());
socket.close();
delete[] buffer;
return true;
}
void CDPlusAuthenticator::Trim(std::string &s)
{
auto it = s.begin();
while (it!=s.end() && isspace(*it))
s.erase(it);
auto rit = s.rbegin();
while (rit!=s.rend() && isspace(*rit)) {
s.resize(s.size() - 1);
rit = s.rbegin();
}
}
bool CDPlusAuthenticator::read(CTCPReaderWriterClient &socket, unsigned char *buffer, unsigned int len) const
{
unsigned int offset = 0U;
do {
int n = socket.read(buffer + offset, len - offset, 10U);
if (n < 0)
return false;
offset += n;
} while ((len - offset) > 0U);
return true;
}

@ -0,0 +1,40 @@
#pragma once
/*
* Copyright (C) 2010-2013 by Jonathan Naylor G4KLX
* 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 <netinet/in.h>
#include <map>
#include <string>
#include "TCPReaderWriterClient.h"
class CDPlusAuthenticator {
public:
CDPlusAuthenticator(const std::string &loginCallsign, const std::string &address);
~CDPlusAuthenticator();
bool Process(std::map<std::string, std::string> &gwy_map, const bool reflectors, const bool repeaters);
private:
std::string m_loginCallsign;
std::string m_address;
void Trim(std::string &s);
bool authenticate(const std::string &callsign, const std::string &hostname, std::map<std::string, std::string> &gwy_map, const bool reflectors, const bool repeaters);
bool read(CTCPReaderWriterClient &socket, unsigned char *buffer, unsigned int len) const;
};

@ -30,6 +30,9 @@ your start. On a Raspberry Pi, you can do all of this with the configuration men
USB devices on your system the device might end up somewhere else. Do "ls /dev" USB devices on your system the device might end up somewhere else. Do "ls /dev"
before and after plugging in your cable to figure out where it is. If it's before and after plugging in your cable to figure out where it is. If it's
not on /dev/ttyUSB0, uncomment the device line and put in the correct device. not on /dev/ttyUSB0, uncomment the device line and put in the correct device.
If you are planning on linking to a Trust DPlus (REF) reflector or repeater,
please look over the "dplus" section to enable this. You need to already be
registered (www.dstargateway.org) to do this.
6) You need a gwys.txt file for all the systems to which you may wish to link. 6) You need a gwys.txt file for all the systems to which you may wish to link.
If you want to be able to link to repeaters: ./get_gwy_list.sh If you want to be able to link to repeaters: ./get_gwy_list.sh

@ -59,6 +59,9 @@ disable the serial0 console in the /boot/cmdline.txt file: Remove the reference
12) You need a configuration file called qn.cfg for QnetGateway. A good, nearly 12) You need a configuration file called qn.cfg for QnetGateway. A good, nearly
working config file is qn.mmdvm.cfg. Copy it to qn.cfg and edit it. working config file is qn.mmdvm.cfg. Copy it to qn.cfg and edit it.
If you are planning on linking to a Trust DPlus (REF) reflector or repeater,
please look over the "dplus" section to enable this. You need to already be
registered (www.dstargateway.org) to do this.
13) You need a gwys.txt file for all the systems to which you may wish to link. 13) You need a gwys.txt file for all the systems to which you may wish to link.
If you want to be able to link to repeaters: ./get_gwy_list.sh If you want to be able to link to repeaters: ./get_gwy_list.sh

@ -54,8 +54,8 @@ itap : $(TAP_PROGRAMS)
qngateway : $(IRCOBJS) QnetGateway.o aprs.o qngateway : $(IRCOBJS) QnetGateway.o aprs.o
g++ $(CPPFLAGS) -o qngateway QnetGateway.o aprs.o $(IRCOBJS) $(LDFLAGS) -pthread g++ $(CPPFLAGS) -o qngateway QnetGateway.o aprs.o $(IRCOBJS) $(LDFLAGS) -pthread
qnlink : QnetLink.o Random.o qnlink : QnetLink.o DPlusAuthenticator.o TCPReaderWriterClient.o Random.o
g++ $(CPPFLAGS) -o qnlink QnetLink.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
g++ $(CPPFLAGS) -o qnrelay QnetRelay.o $(LDFLAGS) g++ $(CPPFLAGS) -o qnrelay QnetRelay.o $(LDFLAGS)

@ -814,6 +814,11 @@ void CQnetGateway::ProcessTimeouts()
} }
} }
// new_group is true if we are processing the first voice packet of a 2-voice packet pair. The high order nibble of the first byte of
// this first packet specifed the type of slow data that is being sent.
// the to_print is an integer that counts down how many 2-voice-frame pairs remain to be processed.
// ABC_grp means that we are processing a 20-character message.
// C_seen means that we are processing the last 2-voice-frame packet on a 20 character message.
void CQnetGateway::ProcessSlowData(unsigned char *data, unsigned short sid, unsigned char header_type, bool *new_group, short *to_print, bool *ABC_grp, bool *C_seen) void CQnetGateway::ProcessSlowData(unsigned char *data, unsigned short sid, unsigned char header_type, bool *new_group, short *to_print, bool *ABC_grp, bool *C_seen)
{ {
/* extract 20-byte RADIO ID */ /* extract 20-byte RADIO ID */
@ -829,7 +834,7 @@ void CQnetGateway::ProcessSlowData(unsigned char *data, unsigned short sid, unsi
if (new_group[i]) { if (new_group[i]) {
header_type = c1 & 0xf0; header_type = c1 & 0xf0;
// header squelch // header squelch
if ((header_type == 0x50) || (header_type == 0xc0)) { if ((header_type == 0x50) || (header_type == 0xc0)) {
new_group[i] = false; new_group[i] = false;
to_print[i] = 0; to_print[i] = 0;
@ -933,7 +938,7 @@ void CQnetGateway::ProcessSlowData(unsigned char *data, unsigned short sid, unsi
/* We should NOT see any more text, /* We should NOT see any more text,
if we already processed text, if we already processed text,
so blank out the codes. */ so blank out the codes. */
if (band_txt[i].txt_stats_sent) { if (band_txt[i].sent_key_on_msg) {
data[0] = 0x70; data[0] = 0x70;
data[1] = 0x4f; data[1] = 0x4f;
data[2] = 0x93; data[2] = 0x93;
@ -944,12 +949,26 @@ void CQnetGateway::ProcessSlowData(unsigned char *data, unsigned short sid, unsi
band_txt[i].txt_cnt = 0; band_txt[i].txt_cnt = 0;
} }
} }
else { else { // header type is not header, squelch, gps or message
new_group[i] = false; new_group[i] = false;
to_print[i] = 0; to_print[i] = 0;
ABC_grp[i] = false; ABC_grp[i] = false;
} }
} else { }
else { // not a new_group, this is the second of a two-voice-frame pair
if (! band_txt[i].sent_key_on_msg && vPacketCount > 100) {
// 100 voice packets received and still no 20-char message!
/*** if YRCALL is CQCQCQ, set dest_rptr ***/
band_txt[i].txt[0] = '\0';
if (memcmp(band_txt[i].lh_yrcall, "CQCQCQ", 6) == 0) {
set_dest_rptr(i, 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...
ii->sendHeardWithTXMsg(band_txt[i].lh_mycall, band_txt[i].lh_sfx, (strstr(band_txt[i].lh_yrcall,"REF") == NULL)?band_txt[i].lh_yrcall:"CQCQCQ ", band_txt[i].lh_rpt1, band_txt[i].lh_rpt2, band_txt[i].flags[0], band_txt[i].flags[1], band_txt[i].flags[2], band_txt[i].dest_rptr, band_txt[i].txt);
band_txt[i].sent_key_on_msg = true;
}
if (to_print[i] == 3) { if (to_print[i] == 3) {
if (ABC_grp[i]) { if (ABC_grp[i]) {
band_txt[i].txt[band_txt[i].txt_cnt] = c1; band_txt[i].txt[band_txt[i].txt_cnt] = c1;
@ -964,7 +983,7 @@ void CQnetGateway::ProcessSlowData(unsigned char *data, unsigned short sid, unsi
/* We should NOT see any more text, /* We should NOT see any more text,
if we already processed text, if we already processed text,
so blank out the codes. */ so blank out the codes. */
if (band_txt[i].txt_stats_sent) { if (band_txt[i].sent_key_on_msg) {
data[0] = 0x70; data[0] = 0x70;
data[1] = 0x4f; data[1] = 0x4f;
data[2] = 0x93; data[2] = 0x93;
@ -972,16 +991,16 @@ void CQnetGateway::ProcessSlowData(unsigned char *data, unsigned short sid, unsi
if ((band_txt[i].txt_cnt >= 20) || C_seen[i]) { if ((band_txt[i].txt_cnt >= 20) || C_seen[i]) {
band_txt[i].txt[band_txt[i].txt_cnt] = '\0'; band_txt[i].txt[band_txt[i].txt_cnt] = '\0';
if (!band_txt[i].txt_stats_sent) { 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, band_txt[i].dest_rptr);
if (memcmp(band_txt[i].dest_rptr, "REF", 3) == 0) if (memcmp(band_txt[i].dest_rptr, "REF", 3) == 0)
band_txt[i].dest_rptr[0] = '\0'; band_txt[i].dest_rptr[0] = '\0';
} }
// we have the 20-character message, send it to the server...
ii->sendHeardWithTXMsg(band_txt[i].lh_mycall, band_txt[i].lh_sfx, (strstr(band_txt[i].lh_yrcall,"REF") == NULL)?band_txt[i].lh_yrcall:"CQCQCQ ", band_txt[i].lh_rpt1, band_txt[i].lh_rpt2, band_txt[i].flags[0], band_txt[i].flags[1], band_txt[i].flags[2], band_txt[i].dest_rptr, band_txt[i].txt); ii->sendHeardWithTXMsg(band_txt[i].lh_mycall, band_txt[i].lh_sfx, (strstr(band_txt[i].lh_yrcall,"REF") == NULL)?band_txt[i].lh_yrcall:"CQCQCQ ", band_txt[i].lh_rpt1, band_txt[i].lh_rpt2, band_txt[i].flags[0], band_txt[i].flags[1], band_txt[i].flags[2], band_txt[i].dest_rptr, band_txt[i].txt);
band_txt[i].txt_stats_sent = true; band_txt[i].sent_key_on_msg = true;
} }
band_txt[i].txt_cnt = 0; band_txt[i].txt_cnt = 0;
} }
@ -995,7 +1014,7 @@ void CQnetGateway::ProcessSlowData(unsigned char *data, unsigned short sid, unsi
band_txt[i].temp_line_cnt = 0; band_txt[i].temp_line_cnt = 0;
} }
/* do not copy CR, NL */ /* do not copy carrige return or newline */
if ((c1 != '\r') && (c1 != '\n')) { if ((c1 != '\r') && (c1 != '\n')) {
band_txt[i].temp_line[band_txt[i].temp_line_cnt] = c1; band_txt[i].temp_line[band_txt[i].temp_line_cnt] = c1;
band_txt[i].temp_line_cnt++; band_txt[i].temp_line_cnt++;
@ -1394,7 +1413,7 @@ void CQnetGateway::Process()
} }
if (recvlen == 58) { if (recvlen == 58) {
vPacketCount = 0U;
if (bool_qso_details) if (bool_qso_details)
printf("id=%04x cntr=%04x start RPTR ur=%.8s r1=%.8s r2=%.8s my=%.8s/%.4s ip=%s\n", ntohs(rptrbuf.vpkt.streamid), ntohs(rptrbuf.counter), rptrbuf.vpkt.hdr.ur, rptrbuf.vpkt.hdr.r1, rptrbuf.vpkt.hdr.r2, rptrbuf.vpkt.hdr.my, rptrbuf.vpkt.hdr.nm, inet_ntoa(fromRptr.sin_addr)); printf("id=%04x cntr=%04x start RPTR ur=%.8s r1=%.8s r2=%.8s my=%.8s/%.4s ip=%s\n", ntohs(rptrbuf.vpkt.streamid), ntohs(rptrbuf.counter), rptrbuf.vpkt.hdr.ur, rptrbuf.vpkt.hdr.r1, rptrbuf.vpkt.hdr.r2, rptrbuf.vpkt.hdr.my, rptrbuf.vpkt.hdr.nm, inet_ntoa(fromRptr.sin_addr));
@ -1435,7 +1454,7 @@ void CQnetGateway::Process()
band_txt[i].txt[0] = '\0'; band_txt[i].txt[0] = '\0';
band_txt[i].txt_cnt = 0; band_txt[i].txt_cnt = 0;
band_txt[i].txt_stats_sent = false; band_txt[i].sent_key_on_msg = false;
band_txt[i].dest_rptr[0] = '\0'; band_txt[i].dest_rptr[0] = '\0';
@ -1896,7 +1915,18 @@ void CQnetGateway::Process()
dtmf_counter[i] = 0; dtmf_counter[i] = 0;
dtmf_last_frame[i] = 0; dtmf_last_frame[i] = 0;
} }
if (! band_txt[i].sent_key_on_msg) {
band_txt[i].txt[0] = '\0';
if (memcmp(band_txt[i].lh_yrcall, "CQCQCQ", 6) == 0) {
set_dest_rptr(i, 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...
ii->sendHeardWithTXMsg(band_txt[i].lh_mycall, band_txt[i].lh_sfx, (strstr(band_txt[i].lh_yrcall,"REF") == NULL)?band_txt[i].lh_yrcall:"CQCQCQ ", band_txt[i].lh_rpt1, band_txt[i].lh_rpt2, band_txt[i].flags[0], band_txt[i].flags[1], band_txt[i].flags[2], band_txt[i].dest_rptr, band_txt[i].txt);
band_txt[i].sent_key_on_msg = true;
}
// send the "key off" message, this will end up in the openquad.net Last Heard webpage.
ii->sendHeardWithTXStats(band_txt[i].lh_mycall, band_txt[i].lh_sfx, band_txt[i].lh_yrcall, band_txt[i].lh_rpt1, band_txt[i].lh_rpt2, band_txt[i].flags[0], band_txt[i].flags[1], band_txt[i].flags[2], band_txt[i].num_dv_frames, band_txt[i].num_dv_silent_frames, band_txt[i].num_bit_errors); ii->sendHeardWithTXStats(band_txt[i].lh_mycall, band_txt[i].lh_sfx, band_txt[i].lh_yrcall, band_txt[i].lh_rpt1, band_txt[i].lh_rpt2, band_txt[i].flags[0], band_txt[i].flags[1], band_txt[i].flags[2], band_txt[i].num_dv_frames, band_txt[i].num_dv_silent_frames, band_txt[i].num_bit_errors);
band_txt[i].streamID = 0; band_txt[i].streamID = 0;
@ -1955,8 +1985,8 @@ void CQnetGateway::Process()
break; break;
} }
} }
vPacketCount++;
if (recvlen == 29) if (recvlen == 29) // process the slow data from every voice packet
ProcessSlowData(rptrbuf.vpkt.vasd.text, rptrbuf.vpkt.streamid, header_type, new_group, to_print, ABC_grp, C_seen); ProcessSlowData(rptrbuf.vpkt.vasd.text, rptrbuf.vpkt.streamid, header_type, new_group, to_print, ABC_grp, C_seen);
else else
ProcessSlowData(rptrbuf.vpkt.vasd1.text, rptrbuf.vpkt.streamid, header_type, new_group, to_print, ABC_grp, C_seen); ProcessSlowData(rptrbuf.vpkt.vasd1.text, rptrbuf.vpkt.streamid, header_type, new_group, to_print, ABC_grp, C_seen);
@ -2558,7 +2588,7 @@ int CQnetGateway::Init(char *cfgfile)
band_txt[i].txt[0] = '\0'; band_txt[i].txt[0] = '\0';
band_txt[i].txt_cnt = 0; band_txt[i].txt_cnt = 0;
band_txt[i].txt_stats_sent = false; band_txt[i].sent_key_on_msg = false;
band_txt[i].dest_rptr[0] = '\0'; band_txt[i].dest_rptr[0] = '\0';

@ -58,7 +58,7 @@ typedef struct band_txt_tag {
time_t last_time; time_t last_time;
char txt[64]; // Only 20 are used char txt[64]; // Only 20 are used
unsigned short txt_cnt; unsigned short txt_cnt;
bool txt_stats_sent; bool sent_key_on_msg;
char dest_rptr[CALL_SIZE + 1]; char dest_rptr[CALL_SIZE + 1];
@ -93,6 +93,8 @@ private:
int play_wait, play_delay, echotest_rec_timeout, voicemail_rec_timeout, from_remote_g2_timeout, from_local_rptr_timeout, dtmf_digit; 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; std::map <uint32_t, uint16_t> portmap;
// data needed for aprs login and aprs beacon // data needed for aprs login and aprs beacon

@ -37,7 +37,6 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h> #include <netdb.h>
@ -45,16 +44,13 @@
#include <fstream> #include <fstream>
#include <future> #include <future>
#include <exception> #include <exception>
#include <atomic>
#include <string>
#include <set>
#include <map>
#include <utility> #include <utility>
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#include <libconfig.h++> #include <libconfig.h++>
#include "versions.h" #include "versions.h"
#include "DPlusAuthenticator.h"
#include "QnetLink.h" #include "QnetLink.h"
using namespace libconfig; using namespace libconfig;
@ -315,6 +311,15 @@ void CQnetLink::print_status_file()
/* 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)
{ {
// DPlus Authenticate
if (dplus_authorize) {
CDPlusAuthenticator auth(owner, std::string("auth.dstargateway.org"));
if (auth.Process(gwy_list, dplus_reflectors, dplus_repeaters))
fprintf(stdout, "DPlus Authorization complete.\n");
else
fprintf(stderr, "DPlus Authorization failed!\n");
}
char inbuf[1024]; char inbuf[1024];
const char *delim = " "; const char *delim = " ";
@ -397,11 +402,11 @@ bool CQnetLink::load_gwys(const std::string &filename)
sprintf(payload, "%s %s", host, port); sprintf(payload, "%s %s", host, port);
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())
gwy_list[call] = payload;
printf("Added Call=[%s], payload=[%s]\n",call, payload); printf("Added Call=[%s], payload=[%s]\n",call, payload);
} else else
printf("Call [%s] is duplicate\n", call); printf("%s %s has been redefined!\n", call, payload);
gwy_list[call] = payload;
} }
fclose(fp); fclose(fp);
@ -714,6 +719,10 @@ bool CQnetLink::read_config(const char *cfgFile)
rf_inactivity_timer[i] = timer; rf_inactivity_timer[i] = timer;
} }
get_value(cfg, "dplus.authorize", dplus_authorize, false);
get_value(cfg, "dplus.use_reflectors", dplus_reflectors, true);
get_value(cfg, "dplus.use_repeaters", dplus_repeaters, true);
return false; return false;
} }

@ -19,7 +19,11 @@
*/ */
#include <regex.h> #include <regex.h>
#include <string>
#include <map>
#include <set>
#include <atomic>
#include <netinet/in.h>
#include <libconfig.h++> #include <libconfig.h++>
#include "versions.h" #include "versions.h"
#include "QnetTypeDefs.h" #include "QnetTypeDefs.h"
@ -83,6 +87,7 @@ private:
/* 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, status_file, qnvoice_file, announce_dir;
bool only_admin_login, only_link_unlink, qso_details, bool_rptr_ack, announce; bool only_admin_login, only_link_unlink, qso_details, bool_rptr_ack, announce;
bool dplus_authorize, dplus_reflectors, dplus_repeaters;
int rmt_xrf_port, rmt_ref_port, rmt_dcs_port, my_g2_link_port, to_g2_external_port, delay_between, delay_before; 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]; char link_at_startup[CALL_SIZE+1];
unsigned int max_dongles, saved_max_dongles; unsigned int max_dongles, saved_max_dongles;

@ -0,0 +1,243 @@
/*
* Copyright (C) 2010-2013 by Jonathan Naylor G4KLX
*
* 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 "TCPReaderWriterClient.h"
//#include "UDPReaderWriter.h"
#include <cstdio>
#include <cerrno>
#include <cassert>
#include <cstring>
CTCPReaderWriterClient::CTCPReaderWriterClient(const std::string &address, unsigned int port, const std::string &localAddress) :
m_address(address),
m_port(port),
m_localAddress(localAddress),
m_fd(-1)
{
assert(address.size());
assert(port > 0U);
}
CTCPReaderWriterClient::CTCPReaderWriterClient(int fd) :
m_address(),
m_port(0U),
m_localAddress(),
m_fd(fd)
{
assert(fd >= 0);
}
CTCPReaderWriterClient::CTCPReaderWriterClient() :
m_address(),
m_port(0U),
m_localAddress(),
m_fd(-1)
{
}
CTCPReaderWriterClient::~CTCPReaderWriterClient()
{
}
bool CTCPReaderWriterClient::open(const std::string& address, unsigned int port, const std::string& localAddress)
{
m_address = address;
m_port = port;
m_localAddress = localAddress;
return open();
}
bool CTCPReaderWriterClient::open()
{
if (m_fd != -1)
return true;
if (0 == m_address.size() || m_port == 0U)
return false;
m_fd = ::socket(PF_INET, SOCK_STREAM, 0);
if (m_fd < 0) {
fprintf(stderr, "Cannot create the TCP client socket, err=%d\n", errno);
return false;
}
if (m_localAddress.size()) {
sockaddr_in addr;
::memset(&addr, 0x00, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = 0U;
addr.sin_addr.s_addr = ::inet_addr(m_localAddress.c_str());
if (addr.sin_addr.s_addr == INADDR_NONE) {
fprintf(stderr, "The address is invalid - %s\n", m_localAddress.c_str());
close();
return false;
}
if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
fprintf(stderr, "Cannot bind the TCP client address, err=%d\n", errno);
close();
return false;
}
}
struct sockaddr_in addr;
::memset(&addr, 0x00, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(m_port);
addr.sin_addr = lookup(m_address);
if (addr.sin_addr.s_addr == INADDR_NONE) {
close();
return false;
}
if (::connect(m_fd, (sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1) {
fprintf(stderr, "Cannot connect the TCP client socket, err=%d\n", errno);
close();
return false;
}
int noDelay = 1;
if (::setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&noDelay, sizeof(noDelay)) == -1) {
fprintf(stderr, "Cannot set the TCP client socket option, err=%d\n", errno);
close();
return false;
}
return true;
}
int CTCPReaderWriterClient::read(unsigned char* buffer, unsigned int length, unsigned int secs, unsigned int msecs)
{
assert(buffer != NULL);
assert(length > 0U);
assert(m_fd != -1);
// Check that the recv() won't block
fd_set readFds;
FD_ZERO(&readFds);
FD_SET(m_fd, &readFds);
// Return after timeout
timeval tv;
tv.tv_sec = secs;
tv.tv_usec = msecs * 1000;
int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv);
if (ret < 0) {
fprintf(stderr, "Error returned from TCP client select, err=%d\n", errno);
return -1;
}
if (!FD_ISSET(m_fd, &readFds))
return 0;
ssize_t len = ::recv(m_fd, (char*)buffer, length, 0);
if (len == 0) {
return -2;
} else if (len < 0) {
fprintf(stderr, "Error returned from recv, err=%d\n", errno);
return -1;
}
return len;
}
int CTCPReaderWriterClient::readLine(std::string& line, unsigned int secs)
{
//maybe there is a better way to do this like reading blocks, pushing them for later calls
//Nevermind, we'll read one char at a time for the time being.
unsigned char c;
int resultCode;
int len = 0;
line = "";
do
{
resultCode = read(&c, 1, secs);
if(resultCode == 1){
line += c;
len++;
}
}while(c != '\n' && resultCode == 1);
return resultCode <= 0 ? resultCode : len;
}
bool CTCPReaderWriterClient::write(const unsigned char* buffer, unsigned int length)
{
assert(buffer != NULL);
assert(length > 0U);
assert(m_fd != -1);
ssize_t ret = ::send(m_fd, (char *)buffer, length, 0);
if (ret != ssize_t(length)) {
fprintf(stderr, "Error returned from send, err=%d\n", errno);
return false;
}
return true;
}
bool CTCPReaderWriterClient::writeLine(const std::string& line)
{
std::string lineCopy(line);
if(lineCopy.size() > 0 && lineCopy.at(lineCopy.size() - 1) != '\n')
lineCopy.append("\n");
//stupidly write one char after the other
size_t len = lineCopy.size();
bool result = true;
for(size_t i = 0; i < len && result; i++){
unsigned char c = lineCopy.at(i);
result = write(&c , 1);
}
return result;
}
void CTCPReaderWriterClient::close()
{
if (m_fd != -1) {
::close(m_fd);
m_fd = -1;
}
}
in_addr CTCPReaderWriterClient::lookup(const std::string &hostname)
{
in_addr addr;
in_addr_t address = ::inet_addr(hostname.c_str());
if (address != in_addr_t(-1)) {
addr.s_addr = address;
return addr;
}
struct hostent* hp = ::gethostbyname(hostname.c_str());
if (hp != NULL) {
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
return addr;
}
fprintf(stderr, "Cannot find address for host %s", hostname.c_str());
addr.s_addr = INADDR_NONE;
return addr;
}

@ -0,0 +1,56 @@
#pragma once
/* end of inma once */
/*
* Copyright (C) 2010,2011,2012,2013 by Jonathan Naylor G4KLX
*
* 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 <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string>
class CTCPReaderWriterClient {
public:
CTCPReaderWriterClient(const std::string &address, unsigned int port, const std::string &localAddress = std::string(""));
CTCPReaderWriterClient(int fd);
CTCPReaderWriterClient();
~CTCPReaderWriterClient();
bool open(const std::string &address, unsigned int port, const std::string &localAddress = std::string(""));
bool open();
int read(unsigned char *buffer, unsigned int length, unsigned int secs, unsigned int msecs = 0U);
int readLine(std::string &line, unsigned int secs);
bool write(const unsigned char* buffer, unsigned int length);
bool writeLine(const std::string &line);
in_addr lookup(const std::string &hostname);
void close();
private:
std::string m_address;
unsigned short m_port;
std::string m_localAddress;
int m_fd;
};

@ -30,3 +30,15 @@ link = {
# link to the reflector of your choice. the first character is the module you are linking. # link to the reflector of your choice. the first character is the module you are linking.
# link_at_start = "CREF001C" # link_at_start = "CREF001C"
} }
dplus = {
# The following settings do not affect your ability to use dplus linking to XRF or XLX reflectors!
# You must be registered on the DPlus system, see www.dstargateway.org, otherwise authorization will fail,
# even if QnetLink reports a successful authorization.
# authorize = false # uncomment and set to true if you want to use the closed-source DPlus reflectors and/or repeaters
# use_reflectors = true # uncomment and set to false if you are not going to link to DPlus reflectors
# use_repeaters = true # uncomment and set to false if you are not going to link to DPlus repeaters
# any values specified in you gwys.txt file will override any reflectors or repeaters that DPlus authorization returns.
}

@ -281,6 +281,18 @@ link = {
# max_dongles = 5 # maximum number of linked hot-spots # max_dongles = 5 # maximum number of linked hot-spots
} }
dplus = {
# The following settings do not affect your ability to use dplus linking to XRF or XLX reflectors!
# You must be registered on the DPlus system, see www.dstargateway.org, otherwise authorization will fail,
# even if QnetLink reports a successful authorization.
# authorize = false # uncomment and set to true if you want to use the closed-source DPlus reflectors and/or repeaters
# use_reflectors = true # uncomment and set to false if you are not going to link to DPlus reflectors
# use_repeaters = true # uncomment and set to false if you are not going to link to DPlus repeaters
# any values specified in you gwys.txt file will override any reflectors or repeaters that DPlus authorization returns.
}
file = { file = {
# status = "/usr/local/etc/rptr_status" # where repeater status info is passed between services # status = "/usr/local/etc/rptr_status" # where repeater status info is passed between services
# DTMF = "/tmp" # # DTMF = "/tmp" #

@ -110,6 +110,18 @@ link = {
# max_dongles = 5 # maximum number of linked hotspots # max_dongles = 5 # maximum number of linked hotspots
} }
dplus = {
# The following settings do not affect your ability to use dplus linking to XRF or XLX reflectors!
# You must be registered on the DPlus system, see www.dstargateway.org, otherwise authorization will fail,
# even if QnetLink reports a successful authorization.
# authorize = false # uncomment and set to true if you want to use the closed-source DPlus reflectors and/or repeaters
# use_reflectors = true # uncomment and set to false if you are not going to link to DPlus reflectors
# use_repeaters = true # uncomment and set to false if you are not going to link to DPlus repeaters
# any values specified in you gwys.txt file will override any reflectors or repeaters that DPlus authorization returns.
}
file = { file = {
# status = "/usr/local/etc/rptr_status" # where repeater status info is passed between services # status = "/usr/local/etc/rptr_status" # where repeater status info is passed between services
# DTMF = "/tmp" # # DTMF = "/tmp" #

@ -30,3 +30,15 @@ link = {
# link to the reflector of your choice. the first character is the module you are linking. # link to the reflector of your choice. the first character is the module you are linking.
# link_at_start = "CREF001C" # link_at_start = "CREF001C"
} }
dplus = {
# The following settings do not affect your ability to use dplus linking to XRF or XLX reflectors!
# You must be registered on the DPlus system, see www.dstargateway.org, otherwise authorization will fail,
# even if QnetLink reports a successful authorization.
# authorize = false # uncomment and set to true if you want to use the closed-source DPlus reflectors and/or repeaters
# use_reflectors = true # uncomment and set to false if you are not going to link to DPlus reflectors
# use_repeaters = true # uncomment and set to false if you are not going to link to DPlus repeaters
# any values specified in you gwys.txt file will override any reflectors or repeaters that DPlus authorization returns.
}

@ -41,3 +41,15 @@ link = {
admin = [ "AA0AAA" , "BB1BBB" , "CC3CCC" ] admin = [ "AA0AAA" , "BB1BBB" , "CC3CCC" ]
} }
dplus = {
# The following settings do not affect your ability to use dplus linking to XRF or XLX reflectors!
# You must be registered on the DPlus system, see www.dstargateway.org, otherwise authorization will fail,
# even if QnetLink reports a successful authorization.
# authorize = false # uncomment and set to true if you want to use the closed-source DPlus reflectors and/or repeaters
# use_reflectors = true # uncomment and set to false if you are not going to link to DPlus reflectors
# use_repeaters = true # uncomment and set to false if you are not going to link to DPlus repeaters
# any values specified in you gwys.txt file will override any reflectors or repeaters that DPlus authorization returns.
}

@ -1,6 +1,6 @@
// version strings must be 55 characters or less! // version strings must be 55 characters or less!
#define IRCDDB_VERSION "QnetGateway-7.3.0" #define IRCDDB_VERSION "QnetGateway-7.4.0"
#define LINK_VERSION "QnetLink-6.1.1" #define LINK_VERSION "QnetLink-6.2.0"
#define DVAP_VERSION "QnetDVAP-5.1.2" #define DVAP_VERSION "QnetDVAP-5.1.2"
#define RELAY_VERSION "QnetRelay-0.2.3" #define RELAY_VERSION "QnetRelay-0.2.3"
#define ITAP_VERSION "QnetITAP-0.2.1" #define ITAP_VERSION "QnetITAP-0.2.1"

Loading…
Cancel
Save

Powered by TurnKey Linux.