Introduce the XRF peer type

XRF peers can now be defined in the xlxd.interlink file,
allowing linking of a local module to a remote using
the DExtra protocol. XRF peers are shown in the peer list,
along with their XLX siblings.

Changes affect only how the reflector initiates the link,
as xlxd already supports incoming DExtra links.
Each peer is associated internally with a remote client,
so code changes include distinguishing peer connect acks
from non-peer ones and handling timeouts differently for
peer clients to clean up the peer data structure.
The DExtra disconnect packet is now properly implemented.
pull/85/head
Antony Chazapis 8 years ago
parent 4b4658f8c9
commit 49ba30ca25

@ -2,13 +2,15 @@
# XLXD interlink file
#
# one line per entry
# each entry specify a remote XLX to peer with
# each entry specifies a remote XLX or XRF to peer with
# format:
# <callsign> <ip> <list of module shared>
# <XLX callsign> <ip> <list of modules shared>
# <XRF callsign> <ip> <local module><remote module>
# example:
# XLX270 158.64.26.132 ACD
# XRF270 158.64.26.132 BB
#
# note: the remote XLX must list this XLX in it's interlink file
# note: the remote XLX must list this XLX in its interlink file
# for the link to be established
#
#############################################################################

@ -34,7 +34,7 @@ CBmPeer::CBmPeer()
{
}
CBmPeer::CBmPeer(const CCallsign &callsign, const CIp &ip, char *modules, const CVersion &version)
CBmPeer::CBmPeer(const CCallsign &callsign, const CIp &ip, const char *modules, const CVersion &version)
: CPeer(callsign, ip, modules, version)
{
std::cout << "Adding BM peer" << std::endl;

@ -41,7 +41,7 @@ class CBmPeer : public CPeer
public:
// constructors
CBmPeer();
CBmPeer(const CCallsign &, const CIp &, char *, const CVersion &);
CBmPeer(const CCallsign &, const CIp &, const char *, const CVersion &);
CBmPeer(const CBmPeer &);
// destructor

@ -0,0 +1,99 @@
//
// cdextrapeer.cpp
// xlxd
//
// Created by Antony Chazapis (SV9OAN) on 25/2/2018.
// Copyright © 2016 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// xlxd 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 3 of the License, or
// (at your option) any later version.
//
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include "main.h"
#include <string.h>
#include "creflector.h"
#include "cdextrapeer.h"
#include "cdextraclient.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CDextraPeer::CDextraPeer()
{
}
CDextraPeer::CDextraPeer(const CCallsign &callsign, const CIp &ip, const char *modules, const CVersion &version)
: CPeer(callsign, ip, modules, version)
{
std::cout << "Adding DExtra peer" << std::endl;
// and construct the DExtra clients
for ( int i = 0; i < ::strlen(modules); i++ )
{
// create
CDextraClient *client = new CDextraClient(callsign, ip, modules[i], version.GetMajor());
// and append to vector
m_Clients.push_back(client);
}
}
CDextraPeer::CDextraPeer(const CDextraPeer &peer)
: CPeer(peer)
{
for ( int i = 0; i < peer.m_Clients.size(); i++ )
{
CDextraClient *client = new CDextraClient((const CDextraClient &)*(peer.m_Clients[i]));
// grow vector capacity if needed
if ( m_Clients.capacity() == m_Clients.size() )
{
m_Clients.reserve(m_Clients.capacity()+10);
}
// and append
m_Clients.push_back(client);
}
}
////////////////////////////////////////////////////////////////////////////////////////
// destructors
CDextraPeer::~CDextraPeer()
{
}
////////////////////////////////////////////////////////////////////////////////////////
// status
bool CDextraPeer::IsAlive(void) const
{
bool alive = true;
for ( int i = 0; (i < m_Clients.size()) && alive ; i++ )
{
alive &= m_Clients[i]->IsAlive();
}
return alive;
}
////////////////////////////////////////////////////////////////////////////////////////
// revision helper
int CDextraPeer::GetProtocolRevision(const CVersion &version)
{
return version.GetMajor();
}

@ -0,0 +1,61 @@
//
// cdextrapeer.h
// xlxd
//
// Created by Antony Chazapis (SV9OAN) on 25/2/2018.
// Copyright © 2016 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// xlxd 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 3 of the License, or
// (at your option) any later version.
//
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#ifndef cdextrapeer_h
#define cdextrapeer_h
#include "cpeer.h"
#include "cdextraclient.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
////////////////////////////////////////////////////////////////////////////////////////
// class
class CDextraPeer : public CPeer
{
public:
// constructors
CDextraPeer();
CDextraPeer(const CCallsign &, const CIp &, const char *, const CVersion &);
CDextraPeer(const CDextraPeer &);
// destructor
~CDextraPeer();
// status
bool IsAlive(void) const;
// identity
int GetProtocol(void) const { return PROTOCOL_DEXTRA; }
const char *GetProtocolName(void) const { return "DExtra"; }
// revision helper
static int GetProtocolRevision(const CVersion &);
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cdextrapeer_h */

@ -24,6 +24,7 @@
#include "main.h"
#include <string.h>
#include "cdextrapeer.h"
#include "cdextraclient.h"
#include "cdextraprotocol.h"
#include "creflector.h"
@ -52,6 +53,7 @@ bool CDextraProtocol::Init(void)
// update time
m_LastKeepaliveTime.Now();
m_LastPeersLinkTime.Now();
// done
return ok;
@ -114,6 +116,29 @@ void CDextraProtocol::Task(void)
{
// valid module ?
if ( g_Reflector.IsValidModule(ToLinkModule) )
{
// is this an ack for a link request?
CPeerCallsignList *list = g_GateKeeper.GetPeerList();
CCallsignListItem *item = list->FindListItem(Callsign);
if ( item != NULL && Callsign.GetModule() == item->GetModules()[1] && ToLinkModule == item->GetModules()[0] )
{
std::cout << "DExtra ack packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
// already connected ?
CPeers *peers = g_Reflector.GetPeers();
if ( peers->FindPeer(Callsign, Ip, PROTOCOL_DEXTRA) == NULL )
{
// create the new peer
// this also create one client per module
CPeer *peer = new CDextraPeer(Callsign, Ip, std::string(1, ToLinkModule).c_str(), CVersion(2, 0, 0));
// append the peer to reflector peer list
// this also add all new clients to reflector client list
peers->AddPeer(peer);
}
g_Reflector.ReleasePeers();
}
else
{
// acknowledge the request
EncodeConnectAckPacket(&Buffer, ProtRev);
@ -126,6 +151,8 @@ void CDextraProtocol::Task(void)
g_Reflector.GetClients()->AddClient(client);
g_Reflector.ReleaseClients();
}
g_GateKeeper.ReleasePeerList();
}
else
{
std::cout << "DExtra node " << Callsign << " connect attempt on non-existing module" << std::endl;
@ -193,15 +220,25 @@ void CDextraProtocol::Task(void)
// handle queue from reflector
HandleQueue();
// keep client alive
// keep alive
if ( m_LastKeepaliveTime.DurationSinceNow() > DEXTRA_KEEPALIVE_PERIOD )
{
//
// handle keep alives
HandleKeepalives();
// update time
m_LastKeepaliveTime.Now();
}
// peer connections
if ( m_LastPeersLinkTime.DurationSinceNow() > DEXTRA_RECONNECT_PERIOD )
{
// handle remote peers connections
HandlePeerLinks();
// update time
m_LastPeersLinkTime.Now();
}
}
////////////////////////////////////////////////////////////////////////////////////////
@ -275,19 +312,110 @@ void CDextraProtocol::HandleKeepalives(void)
}
// otherwise check if still with us
else if ( !client->IsAlive() )
{
CPeers *peers = g_Reflector.GetPeers();
CPeer *peer = peers->FindPeer(client->GetCallsign(), client->GetIp(), PROTOCOL_DEXTRA);
if ( peer != NULL && peer->GetReflectorModules()[0] == client->GetReflectorModule() )
{
// no, but this is a peer client, so it will be handled below
}
else
{
// no, disconnect
CBuffer disconnect;
EncodeDisconnectPacket(&disconnect);
EncodeDisconnectPacket(&disconnect, client->GetReflectorModule());
m_Socket.Send(disconnect, client->GetIp());
// remove it
std::cout << "DExtra client " << client->GetCallsign() << " keepalive timeout" << std::endl;
clients->RemoveClient(client);
}
g_Reflector.ReleasePeers();
}
}
g_Reflector.ReleaseClients();
// iterate on peers
CPeers *peers = g_Reflector.GetPeers();
index = -1;
CPeer *peer = NULL;
while ( (peer = peers->FindNextPeer(PROTOCOL_DEXTRA, &index)) != NULL )
{
// keepalives are sent between clients
// some client busy or still with us ?
if ( !peer->IsAMaster() && !peer->IsAlive() )
{
// no, disconnect all clients
CBuffer disconnect;
EncodeDisconnectPacket(&disconnect, peer->GetReflectorModules()[0]);
CClients *clients = g_Reflector.GetClients();
for ( int i = 0; i < peer->GetNbClients(); i++ )
{
m_Socket.Send(disconnect, peer->GetClient(i)->GetIp());
}
g_Reflector.ReleaseClients();
// remove it
std::cout << "DExtra peer " << peer->GetCallsign() << " keepalive timeout" << std::endl;
peers->RemovePeer(peer);
}
}
g_Reflector.ReleasePeers();
}
////////////////////////////////////////////////////////////////////////////////////////
// Peers helpers
void CDextraProtocol::HandlePeerLinks(void)
{
CBuffer buffer;
// get the list of peers
CPeerCallsignList *list = g_GateKeeper.GetPeerList();
CPeers *peers = g_Reflector.GetPeers();
// check if all our connected peers are still listed by gatekeeper
// if not, disconnect
int index = -1;
CPeer *peer = NULL;
while ( (peer = peers->FindNextPeer(PROTOCOL_DEXTRA, &index)) != NULL )
{
if ( list->FindListItem(peer->GetCallsign()) == NULL )
{
// send disconnect packet
EncodeDisconnectPacket(&buffer, peer->GetReflectorModules()[0]);
m_Socket.Send(buffer, peer->GetIp());
std::cout << "Sending disconnect packet to XRF peer " << peer->GetCallsign() << std::endl;
// remove client
peers->RemovePeer(peer);
}
}
// check if all ours peers listed by gatekeeper are connected
// if not, connect or reconnect
for ( int i = 0; i < list->size(); i++ )
{
CCallsignListItem *item = &((list->data())[i]);
if ( !item->GetCallsign().HasSameCallsignWithWildcard(CCallsign("XRF*")) )
continue;
if ( strlen(item->GetModules()) != 2 )
continue;
if ( peers->FindPeer(item->GetCallsign(), PROTOCOL_DEXTRA) == NULL )
{
// resolve again peer's IP in case it's a dynamic IP
item->ResolveIp();
// send connect packet to re-initiate peer link
EncodeConnectPacket(&buffer, item->GetModules());
m_Socket.Send(buffer, item->GetIp(), DEXTRA_PORT);
std::cout << "Sending connect packet to XRF peer " << item->GetCallsign() << " @ " << item->GetIp() << " for module " << item->GetModules()[1] << " (module " << item->GetModules()[0] << ")" << std::endl;
}
}
// done
g_Reflector.ReleasePeers();
g_GateKeeper.ReleasePeerList();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -474,6 +602,16 @@ void CDextraProtocol::EncodeKeepAlivePacket(CBuffer *Buffer)
Buffer->Set(GetReflectorCallsign());
}
void CDextraProtocol::EncodeConnectPacket(CBuffer *Buffer, const char *Modules)
{
uint8 lm = (uint8)Modules[0];
uint8 rm = (uint8)Modules[1];
Buffer->Set((uint8 *)(const char *)GetReflectorCallsign(), CALLSIGN_LEN);
Buffer->Append(lm);
Buffer->Append(rm);
Buffer->Append((uint8)0);
}
void CDextraProtocol::EncodeConnectAckPacket(CBuffer *Buffer, int ProtRev)
{
// is it for a XRF or repeater
@ -504,10 +642,12 @@ void CDextraProtocol::EncodeConnectNackPacket(CBuffer *Buffer)
Buffer->Append(tag, sizeof(tag));
}
void CDextraProtocol::EncodeDisconnectPacket(CBuffer *Buffer)
void CDextraProtocol::EncodeDisconnectPacket(CBuffer *Buffer, char Module)
{
uint8 tag[] = { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',0 };
Buffer->Set(tag, sizeof(tag));
uint8 tag[] = { ' ',0 };
Buffer->Set((uint8 *)(const char *)GetReflectorCallsign(), CALLSIGN_LEN);
Buffer->Append((uint8)Module);
Buffer->Append(tag, sizeof(tag));
}
void CDextraProtocol::EncodeDisconnectedPacket(CBuffer *Buffer)

@ -75,6 +75,7 @@ protected:
void HandleQueue(void);
// keepalive helpers
void HandlePeerLinks(void);
void HandleKeepalives(void);
// stream helpers
@ -90,9 +91,10 @@ protected:
// packet encoding helpers
void EncodeKeepAlivePacket(CBuffer *);
void EncodeConnectPacket(CBuffer *, const char *);
void EncodeConnectAckPacket(CBuffer *, int);
void EncodeConnectNackPacket(CBuffer *);
void EncodeDisconnectPacket(CBuffer *);
void EncodeDisconnectPacket(CBuffer *, char);
void EncodeDisconnectedPacket(CBuffer *);
bool EncodeDvHeaderPacket(const CDvHeaderPacket &, CBuffer *) const;
bool EncodeDvFramePacket(const CDvFramePacket &, CBuffer *) const;
@ -101,6 +103,7 @@ protected:
protected:
// time
CTimePoint m_LastKeepaliveTime;
CTimePoint m_LastPeersLinkTime;
};
////////////////////////////////////////////////////////////////////////////////////////

@ -40,7 +40,7 @@ CPeer::CPeer()
m_LastHeardTime = std::time(NULL);
}
CPeer::CPeer(const CCallsign &callsign, const CIp &ip, char *modules, const CVersion &version)
CPeer::CPeer(const CCallsign &callsign, const CIp &ip, const char *modules, const CVersion &version)
{
m_Callsign = callsign;
m_Ip = ip;

@ -42,7 +42,7 @@ class CPeer
public:
// constructors
CPeer();
CPeer(const CCallsign &, const CIp &, char *, const CVersion &);
CPeer(const CCallsign &, const CIp &, const char *, const CVersion &);
CPeer(const CPeer &);
// destructor
@ -54,7 +54,7 @@ public:
// get
const CCallsign &GetCallsign(void) const { return m_Callsign; }
const CIp &GetIp(void) const { return m_Ip; }
char *GetModulesModules(void) { return m_ReflectorModules; }
char *GetReflectorModules(void) { return m_ReflectorModules; }
// set

@ -106,7 +106,7 @@ void CPeers::RemovePeer(CPeer *peer)
bool found = false;
for ( int i = 0; (i < m_Peers.size()) && !found; i++ )
{
// compare objetc pointers
// compare object pointers
if ( (m_Peers[i]) == peer )
{
// found it !

@ -37,7 +37,7 @@ CXlxPeer::CXlxPeer()
{
}
CXlxPeer::CXlxPeer(const CCallsign &callsign, const CIp &ip, char *modules, const CVersion &version)
CXlxPeer::CXlxPeer(const CCallsign &callsign, const CIp &ip, const char *modules, const CVersion &version)
: CPeer(callsign, ip, modules, version)
{
// get protocol revision

@ -40,7 +40,7 @@ class CXlxPeer : public CPeer
public:
// constructors
CXlxPeer();
CXlxPeer(const CCallsign &, const CIp &, char *, const CVersion &);
CXlxPeer(const CCallsign &, const CIp &, const char *, const CVersion &);
CXlxPeer(const CXlxPeer &);
// destructor

@ -384,6 +384,8 @@ void CXlxProtocol::HandlePeerLinks(void)
for ( int i = 0; i < list->size(); i++ )
{
CCallsignListItem *item = &((list->data())[i]);
if ( item->GetCallsign().HasSameCallsignWithWildcard(CCallsign("XRF*")) )
continue;
if ( peers->FindPeer(item->GetCallsign(), PROTOCOL_XLX) == NULL )
{
// resolve again peer's IP in case it's a dynamic IP

@ -56,7 +56,7 @@ protected:
// queue helper
void HandleQueue(void);
// keepalive helper
// keepalive helpers
void HandlePeerLinks(void);
void HandleKeepalives(void);

@ -80,6 +80,7 @@
#define DEXTRA_PORT 30001 // UDP port
#define DEXTRA_KEEPALIVE_PERIOD 3 // in seconds
#define DEXTRA_KEEPALIVE_TIMEOUT (DEXTRA_KEEPALIVE_PERIOD*10) // in seconds
#define DEXTRA_RECONNECT_PERIOD 5 // in seconds
// DPlus
#define DPLUS_PORT 20001 // UDP port

Loading…
Cancel
Save

Powered by TurnKey Linux.