diff --git a/config/xlxd.interlink b/config/xlxd.interlink index fdba77c..b77ce32 100644 --- a/config/xlxd.interlink +++ b/config/xlxd.interlink @@ -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: -# +# +# # 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 # ############################################################################# diff --git a/src/cbmpeer.cpp b/src/cbmpeer.cpp index 36c38fb..cef9661 100644 --- a/src/cbmpeer.cpp +++ b/src/cbmpeer.cpp @@ -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; diff --git a/src/cbmpeer.h b/src/cbmpeer.h index b92d238..ee90a9b 100644 --- a/src/cbmpeer.h +++ b/src/cbmpeer.h @@ -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 diff --git a/src/cdextrapeer.cpp b/src/cdextrapeer.cpp new file mode 100644 index 0000000..e6a13e6 --- /dev/null +++ b/src/cdextrapeer.cpp @@ -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 . +// ---------------------------------------------------------------------------- + +#include "main.h" +#include +#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(); +} + diff --git a/src/cdextrapeer.h b/src/cdextrapeer.h new file mode 100644 index 0000000..ff3b24e --- /dev/null +++ b/src/cdextrapeer.h @@ -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 . +// ---------------------------------------------------------------------------- + +#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 */ diff --git a/src/cdextraprotocol.cpp b/src/cdextraprotocol.cpp index 8aa88ab..c8c887c 100644 --- a/src/cdextraprotocol.cpp +++ b/src/cdextraprotocol.cpp @@ -24,6 +24,7 @@ #include "main.h" #include +#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; @@ -115,16 +117,41 @@ void CDextraProtocol::Task(void) // valid module ? if ( g_Reflector.IsValidModule(ToLinkModule) ) { - // acknowledge the request - EncodeConnectAckPacket(&Buffer, ProtRev); - m_Socket.Send(Buffer, Ip); - - // create the client - CDextraClient *client = new CDextraClient(Callsign, Ip, ToLinkModule, ProtRev); - - // and append - g_Reflector.GetClients()->AddClient(client); - g_Reflector.ReleaseClients(); + // 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); + m_Socket.Send(Buffer, Ip); + + // create the client + CDextraClient *client = new CDextraClient(Callsign, Ip, ToLinkModule, ProtRev); + + // and append + g_Reflector.GetClients()->AddClient(client); + g_Reflector.ReleaseClients(); + } + g_GateKeeper.ReleasePeerList(); } else { @@ -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(); + } } //////////////////////////////////////////////////////////////////////////////////////// @@ -257,7 +294,7 @@ void CDextraProtocol::HandleKeepalives(void) // so, send keepalives to all CBuffer keepalive; EncodeKeepAlivePacket(&keepalive); - + // iterate on clients CClients *clients = g_Reflector.GetClients(); int index = -1; @@ -276,18 +313,109 @@ void CDextraProtocol::HandleKeepalives(void) // otherwise check if still with us else if ( !client->IsAlive() ) { - // no, disconnect + 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, 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); - m_Socket.Send(disconnect, client->GetIp()); + 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 client " << client->GetCallsign() << " keepalive timeout" << std::endl; - clients->RemoveClient(client); + 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); } - } - g_Reflector.ReleaseClients(); + + // 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(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -388,7 +516,7 @@ bool CDextraProtocol::IsValidDisconnectPacket(const CBuffer &Buffer, CCallsign * { callsign->SetCallsign(Buffer.data(), 8); callsign->SetModule(Buffer.data()[8]); - valid = callsign->IsValid(); + valid = callsign->IsValid(); } return valid; } @@ -471,12 +599,22 @@ CDvLastFramePacket *CDextraProtocol::IsValidDvLastFramePacket(const CBuffer &Buf void CDextraProtocol::EncodeKeepAlivePacket(CBuffer *Buffer) { - Buffer->Set(GetReflectorCallsign()); + 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 + // is it for a XRF or repeater if ( ProtRev == 2 ) { // XRFxxx @@ -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) diff --git a/src/cdextraprotocol.h b/src/cdextraprotocol.h index 3c623fc..4512295 100644 --- a/src/cdextraprotocol.h +++ b/src/cdextraprotocol.h @@ -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; }; //////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/cpeer.cpp b/src/cpeer.cpp index 037325e..96f9c9a 100644 --- a/src/cpeer.cpp +++ b/src/cpeer.cpp @@ -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; diff --git a/src/cpeer.h b/src/cpeer.h index ffb68a5..dc1a7b9 100644 --- a/src/cpeer.h +++ b/src/cpeer.h @@ -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 diff --git a/src/cpeers.cpp b/src/cpeers.cpp index 35c5547..0a83cdb 100644 --- a/src/cpeers.cpp +++ b/src/cpeers.cpp @@ -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 ! diff --git a/src/cxlxpeer.cpp b/src/cxlxpeer.cpp index aa214c4..264d1f6 100644 --- a/src/cxlxpeer.cpp +++ b/src/cxlxpeer.cpp @@ -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 diff --git a/src/cxlxpeer.h b/src/cxlxpeer.h index 482f3ec..497d7f2 100644 --- a/src/cxlxpeer.h +++ b/src/cxlxpeer.h @@ -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 diff --git a/src/cxlxprotocol.cpp b/src/cxlxprotocol.cpp index f01fb9a..c347275 100644 --- a/src/cxlxprotocol.cpp +++ b/src/cxlxprotocol.cpp @@ -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 diff --git a/src/cxlxprotocol.h b/src/cxlxprotocol.h index 1b8d8d9..c9b66a1 100644 --- a/src/cxlxprotocol.h +++ b/src/cxlxprotocol.h @@ -56,7 +56,7 @@ protected: // queue helper void HandleQueue(void); - // keepalive helper + // keepalive helpers void HandlePeerLinks(void); void HandleKeepalives(void); diff --git a/src/main.h b/src/main.h index 7127e39..30c056d 100755 --- a/src/main.h +++ b/src/main.h @@ -86,6 +86,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