From 32a437c138ddf97440790bd67a70e9a7b15d6698 Mon Sep 17 00:00:00 2001 From: LX3JL Date: Fri, 12 Jan 2018 09:30:59 +0100 Subject: [PATCH] xlxd 2.2.1 * auto-reload of deride DB * interlink protocol v2.0 --- src/ccallsign.cpp | 49 ++++-- src/ccallsignlist.cpp | 2 +- src/cdmriddir.cpp | 300 +++++++++++-------------------------- src/cdmriddir.h | 37 +++-- src/cdmriddirfile.cpp | 165 ++++++++++++++++++++ src/cdmriddirfile.h | 59 ++++++++ src/cdmriddirhttp.cpp | 182 ++++++++++++++++++++++ src/cdmriddirhttp.h | 52 +++++++ src/cdvframepacket.cpp | 14 ++ src/cdvframepacket.h | 1 + src/cdvlastframepacket.cpp | 10 ++ src/cdvlastframepacket.h | 1 + src/cpacket.cpp | 10 ++ src/cpacket.h | 1 + src/cpeer.cpp | 5 +- src/cpeer.h | 4 +- src/creflector.cpp | 5 +- src/ctranscoder.cpp | 6 - src/ctranscoder.h | 3 + src/cversion.cpp | 87 +++++++++++ src/cversion.h | 64 ++++++++ src/cxlxclient.cpp | 26 +++- src/cxlxclient.h | 12 +- src/cxlxpeer.cpp | 28 +++- src/cxlxpeer.h | 10 +- src/cxlxprotocol.cpp | 190 +++++++++++++++++++---- src/cxlxprotocol.h | 26 ++-- src/main.cpp | 3 + src/main.h | 18 ++- 29 files changed, 1072 insertions(+), 298 deletions(-) create mode 100644 src/cdmriddirfile.cpp create mode 100644 src/cdmriddirfile.h create mode 100644 src/cdmriddirhttp.cpp create mode 100644 src/cdmriddirhttp.h create mode 100644 src/cversion.cpp create mode 100644 src/cversion.h diff --git a/src/ccallsign.cpp b/src/ccallsign.cpp index af04e58..23cdb3e 100644 --- a/src/ccallsign.cpp +++ b/src/ccallsign.cpp @@ -25,7 +25,8 @@ #include "main.h" #include #include -#include "cdmriddir.h" +#include "cdmriddirfile.h" +#include "cdmriddirhttp.h" #include "ccallsign.h" //////////////////////////////////////////////////////////////////////////////////////// @@ -60,16 +61,24 @@ CCallsign::CCallsign(const char *sz, uint32 dmrid) // dmrid ok ? if ( m_uiDmrid == 0 ) { - m_uiDmrid = g_DmridDir.FindDmrid(*this); + g_DmridDir.Lock(); + { + m_uiDmrid = g_DmridDir.FindDmrid(*this); + } + g_DmridDir.Unlock(); } } else if ( m_uiDmrid != 0 ) { - const CCallsign *callsign = g_DmridDir.FindCallsign(m_uiDmrid); - if ( callsign != NULL ) - { - ::memcpy(m_Callsign, callsign->m_Callsign, sizeof(m_Callsign)); - } + g_DmridDir.Lock(); + { + const CCallsign *callsign = g_DmridDir.FindCallsign(m_uiDmrid); + if ( callsign != NULL ) + { + ::memcpy(m_Callsign, callsign->m_Callsign, sizeof(m_Callsign)); + } + } + g_DmridDir.Unlock(); } } @@ -151,7 +160,11 @@ void CCallsign::SetCallsign(const char *sz, bool UpdateDmrid) // and update dmrid if ( UpdateDmrid ) { - m_uiDmrid = g_DmridDir.FindDmrid(*this); + g_DmridDir.Lock(); + { + m_uiDmrid = g_DmridDir.FindDmrid(*this); + } + g_DmridDir.Unlock(); } } @@ -174,7 +187,11 @@ void CCallsign::SetCallsign(const uint8 *buffer, int len, bool UpdateDmrid) } if ( UpdateDmrid ) { - m_uiDmrid = g_DmridDir.FindDmrid(*this); + g_DmridDir.Lock(); + { + m_uiDmrid = g_DmridDir.FindDmrid(*this); + } + g_DmridDir.Unlock(); } } @@ -183,11 +200,15 @@ void CCallsign::SetDmrid(uint32 dmrid, bool UpdateCallsign) m_uiDmrid = dmrid; if ( UpdateCallsign ) { - const CCallsign *callsign = g_DmridDir.FindCallsign(dmrid); - if ( callsign != NULL ) - { - ::memcpy(m_Callsign, callsign->m_Callsign, sizeof(m_Callsign)); - } + g_DmridDir.Lock(); + { + const CCallsign *callsign = g_DmridDir.FindCallsign(dmrid); + if ( callsign != NULL ) + { + ::memcpy(m_Callsign, callsign->m_Callsign, sizeof(m_Callsign)); + } + } + g_DmridDir.Unlock(); } } diff --git a/src/ccallsignlist.cpp b/src/ccallsignlist.cpp index 5d68b93..dfd9d35 100644 --- a/src/ccallsignlist.cpp +++ b/src/ccallsignlist.cpp @@ -34,7 +34,7 @@ CCallsignList::CCallsignList() { m_Filename = NULL; - ::memset(&m_LastModTime, 0, sizeof(CCallsignList)); + ::memset(&m_LastModTime, 0, sizeof(time_t)); } //////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/cdmriddir.cpp b/src/cdmriddir.cpp index 21f9347..5d62db3 100644 --- a/src/cdmriddir.cpp +++ b/src/cdmriddir.cpp @@ -26,9 +26,95 @@ #include "main.h" #include "creflector.h" #include "cdmriddir.h" +#include "cdmriddirfile.h" +#include "cdmriddirhttp.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// constructor & destructor + +CDmridDir::CDmridDir() +{ + m_bStopThread = false; + m_pThread = NULL; +} + +CDmridDir::~CDmridDir() +{ + // kill threads + m_bStopThread = true; + if ( m_pThread != NULL ) + { + m_pThread->join(); + delete m_pThread; + } +} -CDmridDir g_DmridDir; +//////////////////////////////////////////////////////////////////////////////////////// +// init & close + +bool CDmridDir::Init(void) +{ + // load content + Reload(); + + // reset stop flag + m_bStopThread = false; + + // start thread; + m_pThread = new std::thread(CDmridDir::Thread, this); + + return true; +} + +void CDmridDir::Close(void) +{ + m_bStopThread = true; + if ( m_pThread != NULL ) + { + m_pThread->join(); + delete m_pThread; + m_pThread = NULL; + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +// thread + +void CDmridDir::Thread(CDmridDir *This) +{ + while ( !This->m_bStopThread ) + { + // Wait 30 seconds + CTimePoint::TaskSleepFor(DMRIDDB_REFRESH_RATE * 60000); + + // have lists files changed ? + if ( This->NeedReload() ) + { + This->Reload(); + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +// Reload + +bool CDmridDir::Reload(void) +{ + CBuffer buffer; + bool ok = false; + + if ( LoadContent(&buffer) ) + { + Lock(); + { + ok = RefreshContent(buffer); + } + Unlock(); + } + return ok; +} + //////////////////////////////////////////////////////////////////////////////////////// // find @@ -53,218 +139,6 @@ uint32 CDmridDir::FindDmrid(const CCallsign &callsign) return 0; } -//////////////////////////////////////////////////////////////////////////////////////// -// refresh - -#if (DMRIDDB_USE_RLX_SERVER == 1) -bool CDmridDir::RefreshContent(void) -{ - bool ok = true; - CBuffer buffer; - - // get file from xlxapi server - if ( (ok = HttpGet("xlxapi.rlx.lu", "api/exportdmr.php", 80, &buffer)) ) - { - // clear directory - m_CallsignMap.clear(); - m_DmridMap.clear(); - - // scan file - if ( buffer.size() > 0 ) - { - char *ptr1 = (char *)buffer.data(); - char *ptr2; - // get next line - while ( (ptr2 = ::strchr(ptr1, '\n')) != NULL ) - { - *ptr2 = 0; - // get items - char *dmrid; - char *callsign; - if ( ((dmrid = ::strtok(ptr1, ";")) != NULL) && IsValidDmrid(dmrid) ) - { - if ( ((callsign = ::strtok(NULL, ";")) != NULL) ) - { - // new entry - uint32 ui = atoi(dmrid); - CCallsign cs(callsign, ui); - if ( cs.IsValid() ) - { - m_CallsignMap.insert(std::pair(ui, cs)); - m_DmridMap.insert(std::pair(cs,ui)); - } - } - } - // next line - ptr1 = ptr2+1; - } - // done - ok = true; - } - } - - // report - std::cout << "Read " << m_DmridMap.size() << " DMR id from online database " << std::endl; - - // done - return ok; -} -#else -bool CDmridDir::RefreshContent(void) -{ - bool ok = true; - CBuffer buffer; - std::ifstream file; - std::streampos size; - - // open file - file.open(DMRIDDB_PATH, std::ios::in | std::ios::binary | std::ios::ate); - if ( file.is_open() ) - { - // clear directory - m_CallsignMap.clear(); - m_DmridMap.clear(); - - // scan file - size = file.tellg(); - if ( size > 0 ) - { - // read file into buffer - buffer.resize((int)size+1); - file.seekg (0, std::ios::beg); - file.read((char *)buffer.data(), (int)size); - - // close file - file.close(); - - // crack it - char *ptr1 = (char *)buffer.data(); - char *ptr2; - // get next line - while ( (ptr2 = ::strchr(ptr1, '\n')) != NULL ) - { - *ptr2 = 0; - // get items - char *dmrid; - char *callsign; - if ( ((dmrid = ::strtok(ptr1, ";")) != NULL) && IsValidDmrid(dmrid) ) - { - if ( ((callsign = ::strtok(NULL, ";")) != NULL) ) - { - // new entry - uint32 ui = atoi(dmrid); - CCallsign cs(callsign, ui); - if ( cs.IsValid() ) - { - m_CallsignMap.insert(std::pair(ui, cs)); - m_DmridMap.insert(std::pair(cs,ui)); - } - } - } - // next line - ptr1 = ptr2+1; - } - // done - ok = true; - } - } - - // report - std::cout << "Read " << m_DmridMap.size() << " DMR id from online database " << std::endl; - - // done - return ok; -} -#endif - -//////////////////////////////////////////////////////////////////////////////////////// -// httpd helpers - -#define DMRID_HTTPGET_SIZEMAX (256) -#define DMRID_TEXTFILE_SIZEMAX (10*1024*1024) - -bool CDmridDir::HttpGet(const char *hostname, const char *filename, int port, CBuffer *buffer) -{ - bool ok = false; - int sock_id; - - // open socket - if ( (sock_id = ::socket(AF_INET, SOCK_STREAM, 0)) >= 0 ) - { - // get hostname address - struct sockaddr_in servaddr; - struct hostent *hp; - ::memset(&servaddr,0,sizeof(servaddr)); - if( (hp = gethostbyname(hostname)) != NULL ) - { - // dns resolved - ::memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length); - servaddr.sin_port = htons(port); - servaddr.sin_family = AF_INET; - - // connect - if ( ::connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0) - { - // send the GET request - char request[DMRID_HTTPGET_SIZEMAX]; - ::sprintf(request, "GET /%s HTTP/1.0\r\nFrom: %s\r\nUser-Agent: xlxd\r\n\r\n", - filename, (const char *)g_Reflector.GetCallsign()); - ::write(sock_id, request, strlen(request)); - - // config receive timeouts - fd_set read_set; - struct timeval timeout; - timeout.tv_sec = 5; - timeout.tv_usec = 0; - FD_ZERO(&read_set); - FD_SET(sock_id, &read_set); - - // get the reply back - buffer->clear(); - bool done = false; - do - { - char buf[1440]; - ssize_t len = 0; - select(sock_id+1, &read_set, NULL, NULL, &timeout); - //if ( (ret > 0) || ((ret < 0) && (errno == EINPROGRESS)) ) - //if ( ret >= 0 ) - //{ - usleep(5000); - len = read(sock_id, buf, 1440); - if ( len > 0 ) - { - buffer->Append((uint8 *)buf, (int)len); - ok = true; - } - //} - done = (len <= 0); - - } while (!done); - buffer->Append((uint8)0); - - // and disconnect - close(sock_id); - } - else - { - std::cout << "Cannot establish connection with host " << hostname << std::endl; - } - } - else - { - std::cout << "Host " << hostname << " not found" << std::endl; - } - - } - else - { - std::cout << "Failed to open wget socket" << std::endl; - } - - // done - return ok; -} //////////////////////////////////////////////////////////////////////////////////////// // syntax helpers diff --git a/src/cdmriddir.h b/src/cdmriddir.h index 83f25b1..1e0d9ed 100644 --- a/src/cdmriddir.h +++ b/src/cdmriddir.h @@ -32,7 +32,6 @@ #include "cbuffer.h" #include "ccallsign.h" - // compare function for std::map::find struct CallsignCompare @@ -48,31 +47,49 @@ class CDmridDir { public: // constructor - CDmridDir() {} + CDmridDir(); // destructor - ~CDmridDir() {} + ~CDmridDir(); + + // init & close + virtual bool Init(void); + virtual void Close(void); + + // locks + void Lock(void) { m_Mutex.lock(); } + void Unlock(void) { m_Mutex.unlock(); } // refresh - bool RefreshContent(void); + virtual bool LoadContent(CBuffer *) { return false; } + virtual bool RefreshContent(const CBuffer &) { return false; } // find const CCallsign *FindCallsign(uint32); uint32 FindDmrid(const CCallsign &); protected: - // httpd helpers - bool HttpGet(const char *, const char *, int, CBuffer *); - - // syntax helpers + // thread + static void Thread(CDmridDir *); + + // reload helpers + bool Reload(void); + virtual bool NeedReload(void) { return false; } bool IsValidDmrid(const char *); protected: - // directory + // data std::map m_CallsignMap; std::map m_DmridMap; + + // Lock() + std::mutex m_Mutex; + + // thread + bool m_bStopThread; + std::thread *m_pThread; + }; //////////////////////////////////////////////////////////////////////////////////////// - #endif /* cdmriddir_h */ diff --git a/src/cdmriddirfile.cpp b/src/cdmriddirfile.cpp new file mode 100644 index 0000000..0efb26e --- /dev/null +++ b/src/cdmriddirfile.cpp @@ -0,0 +1,165 @@ +// +// cdmriddirfile.cpp +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 29/12/2017. +// Copyright © 2015 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 +#include +#include +#include "main.h" +#include "cdmriddirfile.h" + + +#if (DMRIDDB_USE_RLX_SERVER == 0) +CDmridDirFile g_DmridDir; +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// constructor & destructor + +CDmridDirFile::CDmridDirFile() +{ + ::memset(&m_LastModTime, 0, sizeof(time_t)); +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// init & close + +bool CDmridDirFile::Init(void) +{ + return CDmridDir::Init(); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// refresh + +bool CDmridDirFile::NeedReload(void) +{ + bool needReload = false; + + time_t time; + if ( GetLastModTime(&time) ) + { + needReload = time != m_LastModTime; + } + return needReload; +} + +bool CDmridDirFile::LoadContent(CBuffer *buffer) +{ + bool ok = false; + std::ifstream file; + std::streampos size; + + // open file + file.open(DMRIDDB_PATH, std::ios::in | std::ios::binary | std::ios::ate); + if ( file.is_open() ) + { + // read file + size = file.tellg(); + if ( size > 0 ) + { + // read file into buffer + buffer->resize((int)size+1); + file.seekg (0, std::ios::beg); + file.read((char *)buffer->data(), (int)size); + + // close file + file.close(); + + // update time + GetLastModTime(&m_LastModTime); + + // done + ok = true; + } + } + + // done + return ok; +} + +bool CDmridDirFile::RefreshContent(const CBuffer &buffer) +{ + bool ok = false; + + // clear directory + m_CallsignMap.clear(); + m_DmridMap.clear(); + + // scan buffer + if ( buffer.size() > 0 ) + { + // crack it + char *ptr1 = (char *)buffer.data(); + char *ptr2; + + // get next line + while ( (ptr2 = ::strchr(ptr1, '\n')) != NULL ) + { + *ptr2 = 0; + // get items + char *dmrid; + char *callsign; + if ( ((dmrid = ::strtok(ptr1, ";")) != NULL) && IsValidDmrid(dmrid) ) + { + if ( ((callsign = ::strtok(NULL, ";")) != NULL) ) + { + // new entry + uint32 ui = atoi(dmrid); + CCallsign cs(callsign, ui); + if ( cs.IsValid() ) + { + m_CallsignMap.insert(std::pair(ui, cs)); + m_DmridMap.insert(std::pair(cs,ui)); + } + } + } + // next line + ptr1 = ptr2+1; + } + + // done + ok = true; + } + + // report + std::cout << "Read " << m_DmridMap.size() << " DMR id from file " << DMRIDDB_PATH << std::endl; + + // done + return ok; +} + + +bool CDmridDirFile::GetLastModTime(time_t *time) +{ + bool ok = false; + + struct stat fileStat; + if( ::stat(DMRIDDB_PATH, &fileStat) != -1 ) + { + *time = fileStat.st_mtime; + ok = true; + } + return ok; +} diff --git a/src/cdmriddirfile.h b/src/cdmriddirfile.h new file mode 100644 index 0000000..8466068 --- /dev/null +++ b/src/cdmriddirfile.h @@ -0,0 +1,59 @@ +// +// cdmrididirfile.h +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 29/12/2017. +// Copyright © 2015 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 cdmrididirfile_h +#define cdmrididirfile_h + +#include "cdmriddir.h" + +//////////////////////////////////////////////////////////////////////////////////////// + +class CDmridDirFile : public CDmridDir +{ +public: + // constructor + CDmridDirFile(); + + // destructor + ~CDmridDirFile() {} + + // init & close + bool Init(void); + + // refresh + bool LoadContent(CBuffer *); + bool RefreshContent(const CBuffer &); + +protected: + // reload helpers + bool NeedReload(void); + bool GetLastModTime(time_t *); + +protected: + // data + time_t m_LastModTime; + }; + +//////////////////////////////////////////////////////////////////////////////////////// +#endif /* cdmrididirfile_h */ diff --git a/src/cdmriddirhttp.cpp b/src/cdmriddirhttp.cpp new file mode 100644 index 0000000..12f21a0 --- /dev/null +++ b/src/cdmriddirhttp.cpp @@ -0,0 +1,182 @@ +// +// cdmriddirhttp.cpp +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 29/12/2017. +// Copyright © 2015 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 +#include "main.h" +#include "creflector.h" +#include "cdmriddirhttp.h" + +#if (DMRIDDB_USE_RLX_SERVER == 1) +CDmridDirHttp g_DmridDir; +#endif + + + + +//////////////////////////////////////////////////////////////////////////////////////// +// refresh + +bool CDmridDirHttp::LoadContent(CBuffer *buffer) +{ + // get file from xlxapi server + return HttpGet("xlxapi.rlx.lu", "api/exportdmr.php", 80, buffer); +} + +bool CDmridDirHttp::RefreshContent(const CBuffer &buffer) +{ + bool ok = false; + + // clear directory + m_CallsignMap.clear(); + m_DmridMap.clear(); + + // scan file + if ( buffer.size() > 0 ) + { + char *ptr1 = (char *)buffer.data(); + char *ptr2; + // get next line + while ( (ptr2 = ::strchr(ptr1, '\n')) != NULL ) + { + *ptr2 = 0; + // get items + char *dmrid; + char *callsign; + if ( ((dmrid = ::strtok(ptr1, ";")) != NULL) && IsValidDmrid(dmrid) ) + { + if ( ((callsign = ::strtok(NULL, ";")) != NULL) ) + { + // new entry + uint32 ui = atoi(dmrid); + CCallsign cs(callsign, ui); + if ( cs.IsValid() ) + { + m_CallsignMap.insert(std::pair(ui, cs)); + m_DmridMap.insert(std::pair(cs,ui)); + } + } + } + // next line + ptr1 = ptr2+1; + } + // done + ok = true; + } + + // report + std::cout << "Read " << m_DmridMap.size() << " DMR id from xlxapi.rlx.lu database " << std::endl; + + // done + return ok; +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// httpd helpers + +#define DMRID_HTTPGET_SIZEMAX (256) +#define DMRID_TEXTFILE_SIZEMAX (10*1024*1024) + +bool CDmridDirHttp::HttpGet(const char *hostname, const char *filename, int port, CBuffer *buffer) +{ + bool ok = false; + int sock_id; + + // open socket + if ( (sock_id = ::socket(AF_INET, SOCK_STREAM, 0)) >= 0 ) + { + // get hostname address + struct sockaddr_in servaddr; + struct hostent *hp; + ::memset(&servaddr,0,sizeof(servaddr)); + if( (hp = gethostbyname(hostname)) != NULL ) + { + // dns resolved + ::memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length); + servaddr.sin_port = htons(port); + servaddr.sin_family = AF_INET; + + // connect + if ( ::connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0) + { + // send the GET request + char request[DMRID_HTTPGET_SIZEMAX]; + ::sprintf(request, "GET /%s HTTP/1.0\r\nFrom: %s\r\nUser-Agent: xlxd\r\n\r\n", + filename, (const char *)g_Reflector.GetCallsign()); + ::write(sock_id, request, strlen(request)); + + // config receive timeouts + fd_set read_set; + struct timeval timeout; + timeout.tv_sec = 5; + timeout.tv_usec = 0; + FD_ZERO(&read_set); + FD_SET(sock_id, &read_set); + + // get the reply back + buffer->clear(); + bool done = false; + do + { + char buf[1440]; + ssize_t len = 0; + select(sock_id+1, &read_set, NULL, NULL, &timeout); + //if ( (ret > 0) || ((ret < 0) && (errno == EINPROGRESS)) ) + //if ( ret >= 0 ) + //{ + usleep(5000); + len = read(sock_id, buf, 1440); + if ( len > 0 ) + { + buffer->Append((uint8 *)buf, (int)len); + ok = true; + } + //} + done = (len <= 0); + + } while (!done); + buffer->Append((uint8)0); + + // and disconnect + close(sock_id); + } + else + { + std::cout << "Cannot establish connection with host " << hostname << std::endl; + } + } + else + { + std::cout << "Host " << hostname << " not found" << std::endl; + } + + } + else + { + std::cout << "Failed to open wget socket" << std::endl; + } + + // done + return ok; +} diff --git a/src/cdmriddirhttp.h b/src/cdmriddirhttp.h new file mode 100644 index 0000000..1d90ec1 --- /dev/null +++ b/src/cdmriddirhttp.h @@ -0,0 +1,52 @@ +// +// cdmriddirhttp.h +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 29/12/2017. +// Copyright © 2015 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 cdmriddirhttp_h +#define cdmriddirhttp_h + +#include "cdmriddir.h" + +//////////////////////////////////////////////////////////////////////////////////////// + +class CDmridDirHttp : public CDmridDir +{ +public: + // constructor + CDmridDirHttp() {} + + // destructor + ~CDmridDirHttp() {} + + // refresh + bool LoadContent(CBuffer *); + bool RefreshContent(const CBuffer &); + +protected: + // reload helpers + bool NeedReload(void) { return true; } + bool HttpGet(const char *, const char *, int, CBuffer *); +}; + +//////////////////////////////////////////////////////////////////////////////////////// +#endif /* cdmriddirhttp_h */ diff --git a/src/cdvframepacket.cpp b/src/cdvframepacket.cpp index aa0e7bf..113aba4 100644 --- a/src/cdvframepacket.cpp +++ b/src/cdvframepacket.cpp @@ -61,6 +61,20 @@ CDvFramePacket::CDvFramePacket(const uint8 *ambe, const uint8 *sync, uint16 sid, ::memset(m_uiDvData, 0, sizeof(m_uiDvData)); } +// dstar + dmr constructor + +CDvFramePacket::CDvFramePacket + (uint16 sid, + uint8 dstarpid, const uint8 *dstarambe, const uint8 *dstardvdata, + uint8 dmrpid, uint8 dprspid, const uint8 *dmrambe, const uint8 *dmrsync) +: CPacket(sid, dstarpid, dmrpid, dprspid) +{ + ::memcpy(m_uiAmbe, dstarambe, sizeof(m_uiAmbe)); + ::memcpy(m_uiDvData, dstardvdata, sizeof(m_uiDvData)); + ::memcpy(m_uiAmbePlus, dmrambe, sizeof(m_uiAmbePlus)); + ::memcpy(m_uiDvSync, dmrsync, sizeof(m_uiDvSync)); +} + // copy constructor CDvFramePacket::CDvFramePacket(const CDvFramePacket &DvFrame) diff --git a/src/cdvframepacket.h b/src/cdvframepacket.h index 555770d..69917b7 100644 --- a/src/cdvframepacket.h +++ b/src/cdvframepacket.h @@ -55,6 +55,7 @@ public: CDvFramePacket(); CDvFramePacket(const struct dstar_dvframe *, uint16, uint8); CDvFramePacket(const uint8 *, const uint8 *, uint16, uint8, uint8); + CDvFramePacket(uint16, uint8, const uint8 *, const uint8 *, uint8, uint8, const uint8 *, const uint8 *); CDvFramePacket(const CDvFramePacket &); // destructor diff --git a/src/cdvlastframepacket.cpp b/src/cdvlastframepacket.cpp index 46673f3..5908303 100644 --- a/src/cdvlastframepacket.cpp +++ b/src/cdvlastframepacket.cpp @@ -47,6 +47,16 @@ CDvLastFramePacket::CDvLastFramePacket(const uint8 *ambe, const uint8 *sync, uin { } +// dstar + dmr constructor + +CDvLastFramePacket::CDvLastFramePacket + (uint16 sid, + uint8 dstarpid, const uint8 *dstarambe, const uint8 *dstardvdata, + uint8 dmrpid, uint8 dprspid, const uint8 *dmrambe, const uint8 *dmrsync) + : CDvFramePacket(sid, dstarpid, dstarambe, dstardvdata, dmrpid, dprspid, dmrambe, dmrsync) +{ +} + // copy constructor CDvLastFramePacket::CDvLastFramePacket(const CDvLastFramePacket &DvFrame) diff --git a/src/cdvlastframepacket.h b/src/cdvlastframepacket.h index d561fc6..685e9d4 100644 --- a/src/cdvlastframepacket.h +++ b/src/cdvlastframepacket.h @@ -42,6 +42,7 @@ public: CDvLastFramePacket(); CDvLastFramePacket(const struct dstar_dvframe *, uint16, uint8); CDvLastFramePacket(const uint8 *, const uint8 *, uint16, uint8, uint8); + CDvLastFramePacket(uint16, uint8, const uint8 *, const uint8 *, uint8, uint8, const uint8 *, const uint8 *); CDvLastFramePacket(const CDvLastFramePacket &); // destructor diff --git a/src/cpacket.cpp b/src/cpacket.cpp index b93d603..02b8931 100644 --- a/src/cpacket.cpp +++ b/src/cpacket.cpp @@ -59,6 +59,16 @@ CPacket::CPacket(uint16 sid, uint8 dmrpid, uint8 dmrspid) m_uiOriginId = ORIGIN_LOCAL; }; +CPacket::CPacket(uint16 sid, uint8 dstarpid, uint8 dmrpid, uint8 dmrsubpid) +{ + m_uiStreamId = sid; + m_uiDstarPacketId = dstarpid; + m_uiDmrPacketId = dmrpid; + m_uiDmrPacketSubid = dmrsubpid; + m_uiModuleId = ' '; + m_uiOriginId = ORIGIN_LOCAL; +} + //////////////////////////////////////////////////////////////////////////////////////// // virtual duplication diff --git a/src/cpacket.h b/src/cpacket.h index b762896..30280b5 100644 --- a/src/cpacket.h +++ b/src/cpacket.h @@ -42,6 +42,7 @@ public: CPacket(); CPacket(uint16 sid, uint8 dstarpid); CPacket(uint16 sid, uint8 dmrpid, uint8 dmrsubpid); + CPacket(uint16 sid, uint8 dstarpid, uint8 dmrpid, uint8 dmrsubpid); // destructor virtual ~CPacket() {}; diff --git a/src/cpeer.cpp b/src/cpeer.cpp index d1db483..037325e 100644 --- a/src/cpeer.cpp +++ b/src/cpeer.cpp @@ -40,12 +40,13 @@ CPeer::CPeer() m_LastHeardTime = std::time(NULL); } -CPeer::CPeer(const CCallsign &callsign, const CIp &ip, char *modules) +CPeer::CPeer(const CCallsign &callsign, const CIp &ip, char *modules, const CVersion &version) { m_Callsign = callsign; m_Ip = ip; ::memset(m_ReflectorModules, 0, sizeof(m_ReflectorModules)); ::strncpy(m_ReflectorModules, modules, sizeof(m_ReflectorModules)-1); + m_Version = version; m_LastKeepaliveTime.Now(); m_ConnectTime = std::time(NULL); m_LastHeardTime = std::time(NULL); @@ -56,6 +57,7 @@ CPeer::CPeer(const CPeer &peer) m_Callsign = peer.m_Callsign; m_Ip = peer.m_Ip; ::memcpy(m_ReflectorModules, peer.m_ReflectorModules, sizeof(m_ReflectorModules)); + m_Version = peer.m_Version; m_LastKeepaliveTime = peer.m_LastKeepaliveTime; m_ConnectTime = peer.m_ConnectTime; m_LastHeardTime = peer.m_LastHeardTime; @@ -82,6 +84,7 @@ bool CPeer::operator ==(const CPeer &peer) const same &= (peer.m_Callsign == m_Callsign); same &= (peer.m_Ip == m_Ip); + same &= (peer.m_Version == m_Version); for ( int i = 0; (i < m_Clients.size()) && same ; i++ ) { same &= (peer.m_Clients[i] == m_Clients[i]); diff --git a/src/cpeer.h b/src/cpeer.h index 92dcdc6..ffb68a5 100644 --- a/src/cpeer.h +++ b/src/cpeer.h @@ -25,6 +25,7 @@ #ifndef cpeer_h #define cpeer_h +#include "cversion.h" #include "ctimepoint.h" #include "cip.h" #include "ccallsign.h" @@ -41,7 +42,7 @@ class CPeer public: // constructors CPeer(); - CPeer(const CCallsign &, const CIp &, char *); + CPeer(const CCallsign &, const CIp &, char *, const CVersion &); CPeer(const CPeer &); // destructor @@ -82,6 +83,7 @@ protected: CCallsign m_Callsign; CIp m_Ip; char m_ReflectorModules[NB_MODULES_MAX+1]; + CVersion m_Version; std::vector m_Clients; // status diff --git a/src/creflector.cpp b/src/creflector.cpp index 9ede4fc..ed6ba58 100644 --- a/src/creflector.cpp +++ b/src/creflector.cpp @@ -26,7 +26,8 @@ #include #include "creflector.h" #include "cgatekeeper.h" -#include "cdmriddir.h" +#include "cdmriddirfile.h" +#include "cdmriddirhttp.h" #include "ctranscoder.h" //////////////////////////////////////////////////////////////////////////////////////// @@ -102,7 +103,7 @@ bool CReflector::Start(void) ok &= g_GateKeeper.Init(); // init dmrid directory - g_DmridDir.RefreshContent(); + g_DmridDir.Init(); // init the transcoder g_Transcoder.Init(); diff --git a/src/ctranscoder.cpp b/src/ctranscoder.cpp index ff378c7..6b810c9 100644 --- a/src/ctranscoder.cpp +++ b/src/ctranscoder.cpp @@ -188,12 +188,6 @@ void CTranscoder::Task(void) } - // handle end of streaming timeout - //CheckStreamsTimeout(); - - // handle queue from reflector - //HandleQueue(); - // keep client alive if ( m_LastKeepaliveTime.DurationSinceNow() > TRANSCODER_KEEPALIVE_PERIOD ) { diff --git a/src/ctranscoder.h b/src/ctranscoder.h index b45b727..7d54c58 100644 --- a/src/ctranscoder.h +++ b/src/ctranscoder.h @@ -55,6 +55,9 @@ public: void Lock(void) { m_Mutex.lock(); } void Unlock(void) { m_Mutex.unlock(); } + // status + bool IsConnected(void) const { return m_bConnected; } + // manage streams CCodecStream *GetStream(CPacketStream *, uint8); void ReleaseStream(CCodecStream *); diff --git a/src/cversion.cpp b/src/cversion.cpp new file mode 100644 index 0000000..8452e0b --- /dev/null +++ b/src/cversion.cpp @@ -0,0 +1,87 @@ +// +// cversion.cpp +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 05/01/2018. +// Copyright © 2015 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 "cversion.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// constructor + +CVersion::CVersion() +{ + m_iMajor = 0; + m_iMinor = 0; + m_iRevision = 0; +} + +CVersion::CVersion(int iMajor, int iMinor, int iRevision) +{ + m_iMajor = iMajor; + m_iMinor = iMinor; + m_iRevision = iRevision; +} + +CVersion::CVersion(const CVersion &Version) +{ + m_iMajor = Version.m_iMajor; + m_iMinor = Version.m_iMinor; + m_iRevision = Version.m_iRevision; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// comparaison + +bool CVersion::IsEqualOrHigherTo(const CVersion &version) const +{ + if ( m_iMajor > version.m_iMajor ) + { + return true; + } + else if ( m_iMajor == version.m_iMajor ) + { + if ( m_iMinor > version.m_iMinor ) + { + return true; + } + else if ( m_iMinor == version.m_iMinor ) + { + if ( m_iRevision >= version.m_iRevision ) + { + return true; + } + } + } + return false; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// operator + +bool CVersion::operator ==(const CVersion &Version) const +{ + return ( (Version.m_iMajor == m_iMajor) && + (Version.m_iMinor == m_iMinor) && + (Version.m_iRevision == m_iRevision )) ; +} + diff --git a/src/cversion.h b/src/cversion.h new file mode 100644 index 0000000..a5e931a --- /dev/null +++ b/src/cversion.h @@ -0,0 +1,64 @@ +// +// cversion.h +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 05/01/2018. +// Copyright © 2015 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 cversion_h +#define cversion_h + + +//////////////////////////////////////////////////////////////////////////////////////// +// class + +class CVersion +{ +public: + // constructor + CVersion(); + CVersion(int, int, int); + CVersion(const CVersion &); + + // destructor + virtual ~CVersion() {} + + // get + int GetMajor(void) const { return m_iMajor; } + int GetMinor(void) const { return m_iMinor; } + int GetRevision(void) const { return m_iRevision; } + + // comparaison + bool IsEqualOrHigherTo(const CVersion &) const; + + // operator + bool operator ==(const CVersion &) const; + +protected: + // data + int m_iMajor; + int m_iMinor; + int m_iRevision; +}; + + +//////////////////////////////////////////////////////////////////////////////////////// +#endif /* cversion_h */ diff --git a/src/cxlxclient.cpp b/src/cxlxclient.cpp index 63d51d8..2d32b29 100644 --- a/src/cxlxclient.cpp +++ b/src/cxlxclient.cpp @@ -32,16 +32,40 @@ CXlxClient::CXlxClient() { + m_ProtRev = XLX_PROTOCOL_REVISION_0; } -CXlxClient::CXlxClient(const CCallsign &callsign, const CIp &ip, char reflectorModule) +CXlxClient::CXlxClient(const CCallsign &callsign, const CIp &ip, char reflectorModule, int protRev) : CClient(callsign, ip, reflectorModule) { + m_ProtRev = protRev; } CXlxClient::CXlxClient(const CXlxClient &client) : CClient(client) { + m_ProtRev = client.m_ProtRev; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// identity + +int CXlxClient::GetCodec(void) const +{ + int codec; + + switch ( GetProtocolRevision() ) + { + case XLX_PROTOCOL_REVISION_0: + case XLX_PROTOCOL_REVISION_1: + default: + codec = CODEC_AMBEPLUS; + break; + case XLX_PROTOCOL_REVISION_2: + codec = CODEC_NONE; + break; + } + return codec; } //////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/cxlxclient.h b/src/cxlxclient.h index 503df40..ae15045 100644 --- a/src/cxlxclient.h +++ b/src/cxlxclient.h @@ -31,6 +31,10 @@ //////////////////////////////////////////////////////////////////////////////////////// // define +#define XLX_PROTOCOL_REVISION_0 0 // AMBE only, original connect mechanism +#define XLX_PROTOCOL_REVISION_1 1 // AMBE only, revised connect mechanism +#define XLX_PROTOCOL_REVISION_2 2 // Transcoded AMBE+AMBE2 interlink + //////////////////////////////////////////////////////////////////////////////////////// // class @@ -40,7 +44,7 @@ class CXlxClient : public CClient public: // constructors CXlxClient(); - CXlxClient(const CCallsign &, const CIp &, char = ' '); + CXlxClient(const CCallsign &, const CIp &, char = ' ', int = XLX_PROTOCOL_REVISION_0); CXlxClient(const CXlxClient &); // destructor @@ -48,7 +52,9 @@ public: // identity int GetProtocol(void) const { return PROTOCOL_XLX; } + int GetProtocolRevision(void) const { return m_ProtRev; } const char *GetProtocolName(void) const { return "XLX"; } + int GetCodec(void) const; bool IsPeer(void) const { return true; } // status @@ -56,6 +62,10 @@ public: // reporting void WriteXml(std::ofstream &) {} + +protected: + // data + int m_ProtRev; }; //////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/cxlxpeer.cpp b/src/cxlxpeer.cpp index d96fbaa..aa214c4 100644 --- a/src/cxlxpeer.cpp +++ b/src/cxlxpeer.cpp @@ -37,14 +37,18 @@ CXlxPeer::CXlxPeer() { } -CXlxPeer::CXlxPeer(const CCallsign &callsign, const CIp &ip, char *modules) -: CPeer(callsign, ip, modules) +CXlxPeer::CXlxPeer(const CCallsign &callsign, const CIp &ip, char *modules, const CVersion &version) +: CPeer(callsign, ip, modules, version) { + // get protocol revision + int protrev = GetProtocolRevision(version); + //std::cout << "Adding XLX peer with protocol revision " << protrev << std::endl; + // and construct all xlx clients for ( int i = 0; i < ::strlen(modules); i++ ) { // create - CXlxClient *client = new CXlxClient(callsign, ip, modules[i]); + CXlxClient *client = new CXlxClient(callsign, ip, modules[i], protrev); // and append to vector m_Clients.push_back(client); } @@ -82,3 +86,21 @@ bool CXlxPeer::IsAlive(void) const return (m_LastKeepaliveTime.DurationSinceNow() < XLX_KEEPALIVE_TIMEOUT); } +//////////////////////////////////////////////////////////////////////////////////////// +// revision helper + +int CXlxPeer::GetProtocolRevision(const CVersion &version) +{ + int protrev = XLX_PROTOCOL_REVISION_0; + + if ( version.IsEqualOrHigherTo(CVersion(2,2,0)) ) + { + protrev = XLX_PROTOCOL_REVISION_2; + } + else if ( version.IsEqualOrHigherTo(CVersion(1,4,0)) ) + { + protrev = XLX_PROTOCOL_REVISION_1; + } + return protrev; +} + diff --git a/src/cxlxpeer.h b/src/cxlxpeer.h index 1ced2ad..482f3ec 100644 --- a/src/cxlxpeer.h +++ b/src/cxlxpeer.h @@ -26,9 +26,11 @@ #define cxlxpeer_h #include "cpeer.h" +#include "cxlxclient.h" //////////////////////////////////////////////////////////////////////////////////////// -// +// define + //////////////////////////////////////////////////////////////////////////////////////// // class @@ -38,7 +40,7 @@ class CXlxPeer : public CPeer public: // constructors CXlxPeer(); - CXlxPeer(const CCallsign &, const CIp &, char *); + CXlxPeer(const CCallsign &, const CIp &, char *, const CVersion &); CXlxPeer(const CXlxPeer &); // destructor @@ -46,9 +48,13 @@ public: // status bool IsAlive(void) const; + // identity int GetProtocol(void) const { return PROTOCOL_XLX; } const char *GetProtocolName(void) const { return "XLX"; } + + // revision helper + static int GetProtocolRevision(const CVersion &); }; //////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/cxlxprotocol.cpp b/src/cxlxprotocol.cpp index c6f645a..0a6dd7c 100644 --- a/src/cxlxprotocol.cpp +++ b/src/cxlxprotocol.cpp @@ -67,10 +67,10 @@ void CXlxProtocol::Task(void) CIp Ip; CCallsign Callsign; char Modules[NB_MODULES_MAX+1]; + CVersion Version; CDvHeaderPacket *Header; CDvFramePacket *Frame; CDvLastFramePacket *LastFrame; - uint8 Major, Minor, Revision; // any incoming packet ? if ( m_Socket.Receive(&Buffer, &Ip, 20) != -1 ) @@ -106,34 +106,41 @@ void CXlxProtocol::Task(void) // handle it OnDvLastFramePacketIn(LastFrame, &Ip); } - else if ( IsValidConnectPacket(Buffer, &Callsign, Modules, &Major, &Minor, &Revision) ) + else if ( IsValidConnectPacket(Buffer, &Callsign, Modules, &Version) ) { - std::cout << "XLX (" << (int)Major << "." << (int)Minor << "." << (int)Revision + std::cout << "XLX (" + << Version.GetMajor() << "." << Version.GetMinor() << "." << Version.GetRevision() << ") connect packet for modules " << Modules << " from " << Callsign << " at " << Ip << std::endl; // callsign authorized? if ( g_GateKeeper.MayLink(Callsign, Ip, PROTOCOL_XLX, Modules) ) { + // acknowledge connecting request // following is version dependent - // for backward compatibility, only send ACK once - if ( (Major == 1) && (Minor < 4) ) + switch ( CXlxPeer::GetProtocolRevision(Version) ) { - // already connected ? - CPeers *peers = g_Reflector.GetPeers(); - if ( peers->FindPeer(Callsign, Ip, PROTOCOL_XLX) == NULL ) - { + case XLX_PROTOCOL_REVISION_0: + { + // already connected ? + CPeers *peers = g_Reflector.GetPeers(); + if ( peers->FindPeer(Callsign, Ip, PROTOCOL_XLX) == NULL ) + { + // acknowledge the request + EncodeConnectAckPacket(&Buffer, Modules); + m_Socket.Send(Buffer, Ip); + } + g_Reflector.ReleasePeers(); + + } + break; + case XLX_PROTOCOL_REVISION_1: + case XLX_PROTOCOL_REVISION_2: + default: // acknowledge the request EncodeConnectAckPacket(&Buffer, Modules); m_Socket.Send(Buffer, Ip); - } - g_Reflector.ReleasePeers(); - } - else - { - // acknowledge the request - EncodeConnectAckPacket(&Buffer, Modules); - m_Socket.Send(Buffer, Ip); + break; } } else @@ -143,7 +150,7 @@ void CXlxProtocol::Task(void) m_Socket.Send(Buffer, Ip); } } - else if ( IsValidAckPacket(Buffer, &Callsign, Modules) ) + else if ( IsValidAckPacket(Buffer, &Callsign, Modules, &Version) ) { std::cout << "XLX ack packet for modules " << Modules << " from " << Callsign << " at " << Ip << std::endl; @@ -156,8 +163,8 @@ void CXlxProtocol::Task(void) { // create the new peer // this also create one client per module - CXlxPeer *peer = new CXlxPeer(Callsign, Ip, Modules); - + CXlxPeer *peer = new CXlxPeer(Callsign, Ip, Modules, Version); + // append the peer to reflector peer list // this also add all new clients to reflector client list peers->AddPeer(peer); @@ -253,6 +260,13 @@ void CXlxProtocol::HandleQueue(void) CBuffer buffer; if ( EncodeDvPacket(*packet, &buffer) ) { + // encode revision dependent version + CBuffer bufferLegacy = buffer; + if ( packet->IsDvFrame() && (bufferLegacy.size() == 45) ) + { + bufferLegacy.resize(27); + } + // and push it to all our clients linked to the module and who are not streaming in CClients *clients = g_Reflector.GetClients(); int index = -1; @@ -263,7 +277,25 @@ void CXlxProtocol::HandleQueue(void) if ( !client->IsAMaster() && (client->GetReflectorModule() == packet->GetModuleId()) ) { // no, send the packet - m_Socket.Send(buffer, client->GetIp()); + // this is protocol revision dependent + switch ( client->GetProtocolRevision() ) + { + case XLX_PROTOCOL_REVISION_0: + case XLX_PROTOCOL_REVISION_1: + m_Socket.Send(bufferLegacy, client->GetIp()); + break; + case XLX_PROTOCOL_REVISION_2: + default: + if ( g_Transcoder.IsConnected() ) + { + m_Socket.Send(buffer, client->GetIp()); + } + else + { + m_Socket.Send(bufferLegacy, client->GetIp()); + } + break; + } } } g_Reflector.ReleaseClients(); @@ -459,7 +491,7 @@ bool CXlxProtocol::IsValidKeepAlivePacket(const CBuffer &Buffer, CCallsign *call } -bool CXlxProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *callsign, char *modules, uint8 *major, uint8 *minor, uint8 *rev) +bool CXlxProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *callsign, char *modules, CVersion *version) { bool valid = false; if ((Buffer.size() == 39) && (Buffer.data()[0] == 'L') && (Buffer.data()[38] == 0)) @@ -467,9 +499,7 @@ bool CXlxProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *callsi callsign->SetCallsign((const uint8 *)&(Buffer.data()[1]), 8); ::strcpy(modules, (const char *)&(Buffer.data()[12])); valid = callsign->IsValid(); - *major = Buffer.data()[9]; - *minor = Buffer.data()[10]; - *rev = Buffer.data()[11]; + *version = CVersion(Buffer.data()[9], Buffer.data()[10], Buffer.data()[11]); for ( int i = 0; i < ::strlen(modules); i++ ) { valid &= IsLetter(modules[i]); @@ -489,7 +519,7 @@ bool CXlxProtocol::IsValidDisconnectPacket(const CBuffer &Buffer, CCallsign *cal return valid; } -bool CXlxProtocol::IsValidAckPacket(const CBuffer &Buffer, CCallsign *callsign, char *modules) +bool CXlxProtocol::IsValidAckPacket(const CBuffer &Buffer, CCallsign *callsign, char *modules, CVersion *version) { bool valid = false; if ((Buffer.size() == 39) && (Buffer.data()[0] == 'A') && (Buffer.data()[38] == 0)) @@ -497,6 +527,7 @@ bool CXlxProtocol::IsValidAckPacket(const CBuffer &Buffer, CCallsign *callsign, callsign->SetCallsign((const uint8 *)&(Buffer.data()[1]), 8); ::strcpy(modules, (const char *)&(Buffer.data()[12])); valid = callsign->IsValid(); + *version = CVersion(Buffer.data()[9], Buffer.data()[10], Buffer.data()[11]); for ( int i = 0; i < ::strlen(modules); i++ ) { valid &= IsLetter(modules[i]); @@ -516,6 +547,74 @@ bool CXlxProtocol::IsValidNackPacket(const CBuffer &Buffer, CCallsign *callsign) return valid; } +CDvFramePacket *CXlxProtocol::IsValidDvFramePacket(const CBuffer &Buffer) +{ + CDvFramePacket *dvframe = NULL; + + // base class first (protocol revision 1 and lower) + dvframe = CDextraProtocol::IsValidDvFramePacket(Buffer); + + // otherwise try protocol revision 2 + if ( (dvframe == NULL) && + (Buffer.size() == 45) && (Buffer.Compare((uint8 *)"DSVT", 4) == 0) && + (Buffer.data()[4] == 0x20) && (Buffer.data()[8] == 0x20) && + ((Buffer.data()[14] & 0x40) == 0) ) + { + // create packet + dvframe = new CDvFramePacket( + // sid + *((uint16 *)&(Buffer.data()[12])), + // dstar + Buffer.data()[14], &(Buffer.data()[15]), &(Buffer.data()[24]), + // dmr + Buffer.data()[27], Buffer.data()[28], &(Buffer.data()[29]), &(Buffer.data()[38])); + + // check validity of packet + if ( !dvframe->IsValid() ) + { + delete dvframe; + dvframe = NULL; + } + } + + // done + return dvframe; +} + +CDvLastFramePacket *CXlxProtocol::IsValidDvLastFramePacket(const CBuffer &Buffer) +{ + CDvLastFramePacket *dvframe = NULL; + + // base class first (protocol revision 1 and lower) + dvframe = CDextraProtocol::IsValidDvLastFramePacket(Buffer); + + // otherwise try protocol revision 2 + if ( (dvframe == NULL) && + (Buffer.size() == 45) && (Buffer.Compare((uint8 *)"DSVT", 4) == 0) && + (Buffer.data()[4] == 0x20) && (Buffer.data()[8] == 0x20) && + ((Buffer.data()[14] & 0x40) != 0) ) + { + // create packet + dvframe = new CDvLastFramePacket( + // sid + *((uint16 *)&(Buffer.data()[12])), + // dstar + Buffer.data()[14], &(Buffer.data()[15]), &(Buffer.data()[24]), + // dmr + Buffer.data()[27], Buffer.data()[28], &(Buffer.data()[29]), &(Buffer.data()[38])); + + // check validity of packet + if ( !dvframe->IsValid() ) + { + delete dvframe; + dvframe = NULL; + } + } + + // done + return dvframe; +} + //////////////////////////////////////////////////////////////////////////////////////// // packet encoding helpers @@ -584,3 +683,42 @@ void CXlxProtocol::EncodeConnectNackPacket(CBuffer *Buffer) Buffer->Append((uint8)0); } +bool CXlxProtocol::EncodeDvFramePacket(const CDvFramePacket &Packet, CBuffer *Buffer) const +{ + uint8 tag[] = { 'D','S','V','T',0x20,0x00,0x00,0x00,0x20,0x00,0x01,0x02 }; + + Buffer->Set(tag, sizeof(tag)); + Buffer->Append(Packet.GetStreamId()); + Buffer->Append((uint8)(Packet.GetDstarPacketId() % 21)); + Buffer->Append((uint8 *)Packet.GetAmbe(), AMBE_SIZE); + Buffer->Append((uint8 *)Packet.GetDvData(), DVDATA_SIZE); + + Buffer->Append((uint8)Packet.GetDmrPacketId()); + Buffer->Append((uint8)Packet.GetDmrPacketSubid()); + Buffer->Append((uint8 *)Packet.GetAmbePlus(), AMBEPLUS_SIZE); + Buffer->Append((uint8 *)Packet.GetDvSync(), DVSYNC_SIZE); + + return true; + +} + +bool CXlxProtocol::EncodeDvLastFramePacket(const CDvLastFramePacket &Packet, CBuffer *Buffer) const +{ + uint8 tag[] = { 'D','S','V','T',0x20,0x00,0x00,0x00,0x20,0x00,0x01,0x02 }; + uint8 dstarambe[] = { 0x55,0xC8,0x7A,0x00,0x00,0x00,0x00,0x00,0x00 }; + uint8 dstardvdata[] = { 0x25,0x1A,0xC6 }; + + Buffer->Set(tag, sizeof(tag)); + Buffer->Append(Packet.GetStreamId()); + Buffer->Append((uint8)((Packet.GetPacketId() % 21) | 0x40)); + Buffer->Append(dstarambe, sizeof(dstarambe)); + Buffer->Append(dstardvdata, sizeof(dstardvdata)); + + + Buffer->Append((uint8)Packet.GetDmrPacketId()); + Buffer->Append((uint8)Packet.GetDmrPacketSubid()); + Buffer->Append((uint8 *)Packet.GetAmbePlus(), AMBEPLUS_SIZE); + Buffer->Append((uint8 *)Packet.GetDvSync(), DVSYNC_SIZE); + + return true; +} diff --git a/src/cxlxprotocol.h b/src/cxlxprotocol.h index 795fa06..1d23c50 100644 --- a/src/cxlxprotocol.h +++ b/src/cxlxprotocol.h @@ -25,7 +25,7 @@ #ifndef cxlxprotocol_h #define cxlxprotocol_h - +#include "cversion.h" #include "ctimepoint.h" #include "cdextraprotocol.h" #include "cclients.h" @@ -65,18 +65,22 @@ protected: void OnDvLastFramePacketIn(CDvLastFramePacket *, const CIp * = NULL); // packet decoding helpers - bool IsValidKeepAlivePacket(const CBuffer &, CCallsign *); - bool IsValidConnectPacket(const CBuffer &, CCallsign *, char *, uint8 *, uint8 *, uint8 *); - bool IsValidDisconnectPacket(const CBuffer &, CCallsign *); - bool IsValidAckPacket(const CBuffer &, CCallsign *, char *); - bool IsValidNackPacket(const CBuffer &, CCallsign *); + bool IsValidKeepAlivePacket(const CBuffer &, CCallsign *); + bool IsValidConnectPacket(const CBuffer &, CCallsign *, char *, CVersion *); + bool IsValidDisconnectPacket(const CBuffer &, CCallsign *); + bool IsValidAckPacket(const CBuffer &, CCallsign *, char *, CVersion *); + bool IsValidNackPacket(const CBuffer &, CCallsign *); + CDvFramePacket *IsValidDvFramePacket(const CBuffer &); + CDvLastFramePacket *IsValidDvLastFramePacket(const CBuffer &); // packet encoding helpers - void EncodeKeepAlivePacket(CBuffer *); - void EncodeConnectPacket(CBuffer *, const char *); - void EncodeDisconnectPacket(CBuffer *); - void EncodeConnectAckPacket(CBuffer *, const char *); - void EncodeConnectNackPacket(CBuffer *); + void EncodeKeepAlivePacket(CBuffer *); + void EncodeConnectPacket(CBuffer *, const char *); + void EncodeDisconnectPacket(CBuffer *); + void EncodeConnectAckPacket(CBuffer *, const char *); + void EncodeConnectNackPacket(CBuffer *); + bool EncodeDvFramePacket(const CDvFramePacket &, CBuffer *) const; + bool EncodeDvLastFramePacket(const CDvLastFramePacket &, CBuffer *) const; protected: // time diff --git a/src/main.cpp b/src/main.cpp index 830f74e..154a53b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -94,6 +94,9 @@ int main(int argc, const char * argv[]) return 1; } + // splash + std::cout << "Starting xlxd " << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_REVISION << std::endl << std::endl; + // initialize reflector g_Reflector.SetCallsign(argv[1]); g_Reflector.SetListenIp(CIp(argv[2])); diff --git a/src/main.h b/src/main.h index 566d986..ac77c96 100644 --- a/src/main.h +++ b/src/main.h @@ -48,8 +48,8 @@ // version ----------------------------------------------------- #define VERSION_MAJOR 2 -#define VERSION_MINOR 0 -#define VERSION_REVISION 0 +#define VERSION_MINOR 2 +#define VERSION_REVISION 1 // global ------------------------------------------------------ @@ -127,8 +127,9 @@ // DMRid database ----------------------------------------------- -#define DMRIDDB_USE_RLX_SERVER 0 -#define DMRIDDB_PATH "/xlxd/dmrid.dat" +#define DMRIDDB_USE_RLX_SERVER 1 // 1 = use http, 0 = use local file +#define DMRIDDB_PATH "/xlxd/dmrid.dat" // local file path +#define DMRIDDB_REFRESH_RATE 180 // in minutes // xml & json reporting ----------------------------------------- @@ -180,8 +181,13 @@ extern CReflector g_Reflector; class CGateKeeper; extern CGateKeeper g_GateKeeper; -class CDmridDir; -extern CDmridDir g_DmridDir; +#if (DMRIDDB_USE_RLX_SERVER == 1) + class CDmridDirHttp; + extern CDmridDirHttp g_DmridDir; +#else + class CDmridDirFile; + extern CDmridDirFile g_DmridDir; +#endif class CTranscoder; extern CTranscoder g_Transcoder;