diff --git a/src/cg3protocol.cpp b/src/cg3protocol.cpp
index ed4de34..053da9d 100644
--- a/src/cg3protocol.cpp
+++ b/src/cg3protocol.cpp
@@ -69,7 +69,7 @@ bool CG3Protocol::Init(void)
std::cout << "Error opening socket on port UDP" << G3_CONFIG_PORT << " on ip " << g_Reflector.GetListenIp() << std::endl;
}
- ok &= ((m_IcmpRawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) >= 0);
+ ok &= m_IcmpRawSocket.Open(IPPROTO_ICMP);
if ( !ok )
{
std::cout << "Error opening raw socket for ICMP" << std::endl;
@@ -136,14 +136,10 @@ void CG3Protocol::ConfigThread(CG3Protocol *This)
void CG3Protocol::IcmpThread(CG3Protocol *This)
{
- fcntl(This->m_IcmpRawSocket, F_SETFL, O_NONBLOCK);
-
while ( !This->m_bStopThread )
{
This->IcmpTask();
}
-
- close(This->m_IcmpRawSocket);
}
@@ -354,49 +350,27 @@ void CG3Protocol::ConfigTask(void)
void CG3Protocol::IcmpTask(void)
{
- unsigned char buffer[256];
+ CBuffer Buffer;
+ CIp Ip;
+ int iIcmpType;
- struct sockaddr_in sa;
- unsigned int sasize = sizeof(sa);
-
- fd_set FdSet;
- struct timeval tv;
-
- if (m_IcmpRawSocket != -1)
+ if ((iIcmpType = m_IcmpRawSocket.IcmpReceive(&Buffer, &Ip, 20)) != -1)
{
- FD_ZERO(&FdSet);
- FD_SET(m_IcmpRawSocket, &FdSet);
- tv.tv_sec = 0;
- tv.tv_usec = 100000;
- select(m_IcmpRawSocket + 1, &FdSet, 0, 0, &tv);
-
- int len = recvfrom(m_IcmpRawSocket, buffer, 255, 0, (struct sockaddr *)&sa, &sasize);
-
- if (len > 28)
+ if (iIcmpType == ICMP_DEST_UNREACH)
{
- struct ip *iph = (struct ip *)buffer;
- int iphdrlen = iph->ip_hl * 4;
- struct icmp *icmph = (struct icmp *)(buffer + iphdrlen);
-
- if (icmph->icmp_type == ICMP_DEST_UNREACH)
- {
- struct ip *remote_iph = (struct ip *)(buffer + iphdrlen + 8);
-
CClients *clients = g_Reflector.GetClients();
int index = -1;
CClient *client = NULL;
while ( (client = clients->FindNextClient(PROTOCOL_G3, &index)) != NULL )
{
- CIp Ip = client->GetIp();
- if (Ip.GetAddr() == remote_iph->ip_dst.s_addr)
+ CIp ClientIp = client->GetIp();
+ if (ClientIp.GetAddr() == Ip.GetAddr())
{
clients->RemoveClient(client);
}
}
g_Reflector.ReleaseClients();
-
- }
}
}
}
@@ -431,7 +405,8 @@ void CG3Protocol::Task(void)
{
BaseIp = &ClIp;
client->Alive();
- // supress host checks
+ // supress host checks - no ping needed to trigger potential ICMPs
+ // the regular data flow will do it
m_LastKeepaliveTime.Now();
break;
}
@@ -466,7 +441,7 @@ void CG3Protocol::Task(void)
else if ( (LastFrame = IsValidDvLastFramePacket(Buffer)) != NULL )
{
//std::cout << "Terminal DV last frame" << std::endl;
-
+
// handle it
OnDvLastFramePacketIn(LastFrame, BaseIp);
}
@@ -484,20 +459,20 @@ void CG3Protocol::Task(void)
// handle end of streaming timeout
CheckStreamsTimeout();
-
+
// handle queue from reflector
HandleQueue();
-
- // keep alive
+
+ // keep alive during idle if needed
if ( m_LastKeepaliveTime.DurationSinceNow() > G3_KEEPALIVE_PERIOD )
{
// handle keep alives
HandleKeepalives();
-
+
// update time
m_LastKeepaliveTime.Now();
- // reload option if needed
+ // reload option if needed - called once every G3_KEEPALIVE_PERIOD
NeedReload();
}
}
@@ -807,22 +782,22 @@ void CG3Protocol::NeedReload(void)
if (m_LastModTime != fileStat.st_mtime)
{
ReadOptions();
- }
- }
- // iterate on clients
- CClients *clients = g_Reflector.GetClients();
- int index = -1;
- CClient *client = NULL;
- while ( (client = clients->FindNextClient(PROTOCOL_G3, &index)) != NULL )
- {
- char module = client->GetReflectorModule();
- if (!strchr(m_Modules.c_str(), module) && !strchr(m_Modules.c_str(), '*'))
- {
- clients->RemoveClient(client);
+ // we have new options - iterate on clients for potential removal
+ CClients *clients = g_Reflector.GetClients();
+ int index = -1;
+ CClient *client = NULL;
+ while ( (client = clients->FindNextClient(PROTOCOL_G3, &index)) != NULL )
+ {
+ char module = client->GetReflectorModule();
+ if (!strchr(m_Modules.c_str(), module) && !strchr(m_Modules.c_str(), '*'))
+ {
+ clients->RemoveClient(client);
+ }
+ }
+ g_Reflector.ReleaseClients();
}
}
- g_Reflector.ReleaseClients();
}
void CG3Protocol::ReadOptions(void)
diff --git a/src/cg3protocol.h b/src/cg3protocol.h
index 7c0da03..5ffdb79 100644
--- a/src/cg3protocol.h
+++ b/src/cg3protocol.h
@@ -31,6 +31,8 @@
#include "cdvheaderpacket.h"
#include "cdvframepacket.h"
#include "cdvlastframepacket.h"
+#include "crawsocket.h"
+#include "cudpmsgsocket.h"
////////////////////////////////////////////////////////////////////////////////////////
@@ -44,9 +46,11 @@
// 2 - Destination request on port UDP 12345
// - Calls to specific callsigns will be accepted for a default module
// - Repeater calls will be accepted for local modules
-// - All other calls are rehected
+// - All other calls are rejected
//
-// 3 - Actual D-star flow like in Dextra to/from port 40000 (2 distint sockets)
+// 3 - Actual D-star flow like in Dextra to/from port 40000
+// 2 distinct sockets where used in the initial protocol
+// later firmwares implement a single bidirectional socket
//
// Alive monitoring is done via a "PING" to remote port 40000. We will get an
// ICMP unreachable on terminal mode close or on station shut down if routing is done
@@ -122,8 +126,8 @@ protected:
// sockets
CUdpSocket m_DvOutSocket;
CUdpSocket m_PresenceSocket;
- CUdpSocket m_ConfigSocket;
- int m_IcmpRawSocket;
+ CUdpMsgSocket m_ConfigSocket;
+ CRawSocket m_IcmpRawSocket;
// optional params
uint32 m_GwAddress;
diff --git a/src/crawsocket.cpp b/src/crawsocket.cpp
new file mode 100644
index 0000000..a30908d
--- /dev/null
+++ b/src/crawsocket.cpp
@@ -0,0 +1,156 @@
+//
+// crawsocket.cpp
+// xlxd
+//
+// Created by Marius Petrescu (YO2LOJ) on 22/02/2020.
+// Copyright © 2020 Marius Petrescu (YO2LOJ). 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 "crawsocket.h"
+
+
+////////////////////////////////////////////////////////////////////////////////////////
+// constructor
+
+CRawSocket::CRawSocket()
+{
+ m_Socket = -1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// destructor
+
+CRawSocket::~CRawSocket()
+{
+ if ( m_Socket != -1 )
+ {
+ Close();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// open & close
+
+bool CRawSocket::Open(uint16 uiProto)
+{
+ bool open = false;
+ int on = 1;
+
+ // create socket
+ m_Socket = socket(AF_INET,SOCK_RAW,uiProto);
+ if ( m_Socket != -1 )
+ {
+ fcntl(m_Socket, F_SETFL, O_NONBLOCK);
+ open = true;
+ m_Proto = uiProto;
+ }
+
+ // done
+ return open;
+}
+
+void CRawSocket::Close(void)
+{
+ if ( m_Socket != -1 )
+ {
+ close(m_Socket);
+ m_Socket = -1;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// read
+
+int CRawSocket::Receive(CBuffer *Buffer, CIp *Ip, int timeout)
+{
+ struct sockaddr_in Sin;
+ fd_set FdSet;
+ unsigned int uiFromLen = sizeof(struct sockaddr_in);
+ int iRecvLen = -1;
+ struct timeval tv;
+
+ // socket valid ?
+ if ( m_Socket != -1 )
+ {
+ // allocate buffer
+ Buffer->resize(UDP_BUFFER_LENMAX);
+
+ // control socket
+ FD_ZERO(&FdSet);
+ FD_SET(m_Socket, &FdSet);
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ select(m_Socket + 1, &FdSet, 0, 0, &tv);
+
+ // read
+ iRecvLen = (int)recvfrom(m_Socket,
+ (void *)Buffer->data(), RAW_BUFFER_LENMAX,
+ 0, (struct sockaddr *)&Sin, &uiFromLen);
+
+ // handle
+ if ( iRecvLen != -1 )
+ {
+ // adjust buffer size
+ Buffer->resize(iRecvLen);
+
+ // get IP
+ Ip->SetSockAddr(&Sin);
+ }
+ }
+
+ // done
+ return iRecvLen;
+}
+
+// protocol specific
+
+// ICMP
+
+int CRawSocket::IcmpReceive(CBuffer *Buffer, CIp *Ip, int timeout)
+{
+ int iIcmpType = -1;
+ int iRecv;
+
+ if (m_Proto == IPPROTO_ICMP)
+ {
+ iRecv = Receive(Buffer, Ip, timeout);
+
+ if (iRecv >= (int)(sizeof(struct ip) + sizeof(struct icmp)))
+ {
+ struct ip *iph = (struct ip *)Buffer->data();
+ int iphdrlen = iph->ip_hl * 4;
+ struct icmp *icmph = (struct icmp *)((unsigned char *)iph + iphdrlen);
+ struct ip *remote_iph = (struct ip *)((unsigned char *)icmph + 8);
+
+ iIcmpType = icmph->icmp_type;
+
+ struct sockaddr_in Sin;
+ bzero(&Sin, sizeof(Sin));
+ Sin.sin_family = AF_INET;
+ Sin.sin_addr.s_addr = remote_iph->ip_dst.s_addr;
+
+ Ip->SetSockAddr(&Sin);
+
+ }
+ }
+ return iIcmpType;
+}
diff --git a/src/crawsocket.h b/src/crawsocket.h
new file mode 100644
index 0000000..1de0f8a
--- /dev/null
+++ b/src/crawsocket.h
@@ -0,0 +1,99 @@
+//
+// crawsocket.h
+// xlxd
+//
+// Created by Marius Petrescu (YO2LOJ) on 22/02/2020.
+// Copyright © 2020 Marius Petrescu (YO2LOJ). 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 .
+// ----------------------------------------------------------------------------
+
+// Description:
+// Raw socket access class with protocol specific
+
+
+#ifndef crawsocket_h
+#define crawsocket_h
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include "cip.h"
+#include "cbuffer.h"
+
+////////////////////////////////////////////////////////////////////////////////////////
+// define
+
+#define RAW_BUFFER_LENMAX 65536
+
+
+////////////////////////////////////////////////////////////////////////////////////////
+// class
+
+class CRawSocket
+{
+public:
+ // constructor
+ CRawSocket();
+
+ // destructor
+ ~CRawSocket();
+
+ // open & close
+ bool Open(uint16);
+ void Close(void);
+ int GetSocket(void) { return m_Socket; }
+
+ // read
+
+ // if ETH_P_ALL is used, the received data buffer will hold
+ // the ethernet header (struct ethhdr) followed by the IP header (struct iphdr),
+ // the protocol header (e.g tcp, udp, icmp) and the data.
+ // For specific protocols, the data content may vary depending on the protocol
+ // Returns the number of received bytes in buffer
+
+ int Receive(CBuffer *, CIp *, int);
+
+ // ICMP receive helper
+ // parameters:
+ // buffer - packet receive buffer (starting with ip header)
+ // ip - remote address (filled in on receive)
+ // timeout - receive timeout in msec
+ // return value:
+ // ICMP type, -1 if nothing was received
+
+ int IcmpReceive(CBuffer *, CIp *, int);
+
+ // write
+ // no write support - complexity makes it out of scope for now
+ // to be added if needed
+
+protected:
+ // data
+ int m_Socket;
+ int m_Proto;
+ struct sockaddr_in m_SocketAddr;
+};
+
+////////////////////////////////////////////////////////////////////////////////////////
+#endif /* crawsocket_h */
diff --git a/src/cudpmsgsocket.cpp b/src/cudpmsgsocket.cpp
new file mode 100644
index 0000000..daadd17
--- /dev/null
+++ b/src/cudpmsgsocket.cpp
@@ -0,0 +1,102 @@
+//
+// cudpmsgsocket.cpp
+// xlxd
+//
+// Created by Marius Petrescu (YO2LOJ) on 22/02/2020.
+// Copyright © 2020 Marius Petrescu (YO2LOJ). 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 "cudpmsgsocket.h"
+
+////////////////////////////////////////////////////////////////////////////////////////
+// read
+
+int CUdpMsgSocket::Receive(CBuffer *Buffer, CIp *Ip, int timeout)
+{
+ struct sockaddr_in Sin;
+ fd_set FdSet;
+ unsigned int uiFromLen = sizeof(struct sockaddr_in);
+ int iRecvLen = -1;
+ struct timeval tv;
+
+ struct msghdr Msg;
+ struct iovec Iov[1];
+
+ union {
+ struct cmsghdr cm;
+ unsigned char pktinfo_sizer[sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)];
+ } Control;
+
+ // socket valid ?
+ if ( m_Socket != -1 )
+ {
+ // allocate buffer
+ Buffer->resize(UDP_MSG_BUFFER_LENMAX);
+
+ //prepare msghdr
+ bzero(&Msg, sizeof(Msg));
+ Iov[0].iov_base = Buffer->data();
+ Iov[0].iov_len = UDP_MSG_BUFFER_LENMAX;
+
+ bzero(&Sin, sizeof(Sin));
+ Msg.msg_name = &Sin;
+ Msg.msg_namelen = sizeof(Sin);
+ Msg.msg_iov = Iov;
+ Msg.msg_iovlen = 1;
+ Msg.msg_control = &Control;
+ Msg.msg_controllen = sizeof(Control);
+
+ // control socket
+ FD_ZERO(&FdSet);
+ FD_SET(m_Socket, &FdSet);
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ select(m_Socket + 1, &FdSet, 0, 0, &tv);
+
+ // read
+ iRecvLen = (int)recvmsg(m_Socket, &Msg, 0);
+
+ // handle
+ if ( iRecvLen != -1 )
+ {
+ // adjust buffer size
+ Buffer->resize(iRecvLen);
+
+ // get IP
+ Ip->SetSockAddr(&Sin);
+
+ // get local IP
+ struct cmsghdr *Cmsg;
+ for (Cmsg = CMSG_FIRSTHDR(&Msg); Cmsg != NULL; Cmsg = CMSG_NXTHDR(&Msg, Cmsg))
+ {
+ if (Cmsg->cmsg_level == IPPROTO_IP && Cmsg->cmsg_type == IP_PKTINFO)
+ {
+ struct in_pktinfo *PktInfo = (struct in_pktinfo *)CMSG_DATA(Cmsg);
+ m_LocalAddr.s_addr = PktInfo->ipi_spec_dst.s_addr;
+ }
+ }
+ }
+ }
+
+ // done
+ return iRecvLen;
+}
+
diff --git a/src/cudpmsgsocket.h b/src/cudpmsgsocket.h
new file mode 100644
index 0000000..657ed21
--- /dev/null
+++ b/src/cudpmsgsocket.h
@@ -0,0 +1,53 @@
+//
+// cudpmsgsocket.h
+// xlxd
+//
+// Created by Marius Petrescu (YO2LOJ) on 22/02/2020.
+// Copyright © 2020 Marius Petrescu (YO2LOJ). 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 .
+// ----------------------------------------------------------------------------
+
+// Description:
+// Extension of the CUdpSocket class to allow retrieving
+// the local target IP for a G3 Terminal mode config request
+
+#ifndef cudpmsgsocket_h
+#define cudpmsgsocket_h
+
+#include "cudpsocket.h"
+
+#define UDP_MSG_BUFFER_LENMAX 1024
+
+////////////////////////////////////////////////////////////////////////////////////////
+// class
+
+class CUdpMsgSocket : public CUdpSocket
+{
+public:
+ // read
+ int Receive(CBuffer *, CIp *, int);
+
+ struct in_addr *GetLocalAddr(void) { return &m_LocalAddr; }
+
+protected:
+ // data
+ struct in_addr m_LocalAddr;
+};
+
+////////////////////////////////////////////////////////////////////////////////////////
+#endif /* cudpmsgsocket_h */