From cc92f37a05d6450ad84029332660393ccf3deba1 Mon Sep 17 00:00:00 2001 From: SASANO Takayoshi Date: Wed, 9 Oct 2019 10:29:21 +0900 Subject: [PATCH] add IPv6 UDP transport support (downloading DMR-ID via http still IPv4) --- src/cdmrmmdvmprotocol.cpp | 5 +- src/cdmrplusprotocol.cpp | 21 ++--- src/cdmrplusprotocol.h | 9 +- src/cip.cpp | 98 +++++++++++++++------ src/cip.h | 15 ++-- src/creflector.h | 8 +- src/cudpsocket.cpp | 176 ++++++++++++++++++++++++-------------- src/cudpsocket.h | 9 +- src/main.cpp | 5 +- src/main.h | 1 + 10 files changed, 224 insertions(+), 123 deletions(-) diff --git a/src/cdmrmmdvmprotocol.cpp b/src/cdmrmmdvmprotocol.cpp index 2398fd1..3357580 100644 --- a/src/cdmrmmdvmprotocol.cpp +++ b/src/cdmrmmdvmprotocol.cpp @@ -70,9 +70,8 @@ bool CDmrmmdvmProtocol::Init(void) m_LastKeepaliveTime.Now(); // random number generator - time_t t; - ::srand((unsigned) time(&t)); - m_uiAuthSeed = (uint32)rand(); + std::random_device rd; + m_uiAuthSeed = rd(); // done return ok; diff --git a/src/cdmrplusprotocol.cpp b/src/cdmrplusprotocol.cpp index 1d1180f..273e8c0 100644 --- a/src/cdmrplusprotocol.cpp +++ b/src/cdmrplusprotocol.cpp @@ -63,8 +63,9 @@ bool CDmrplusProtocol::Init(void) m_LastKeepaliveTime.Now(); // random number generator - time_t t; - ::srand((unsigned) time(&t)); + std::random_device rd; + std::mt19937 mt(rd()); + m_Random = mt; // done return ok; @@ -88,7 +89,7 @@ void CDmrplusProtocol::Task(void) if ( m_Socket.Receive(&Buffer, &Ip, 20) != -1 ) { // crack the packet - if ( IsValidDvFramePacket(Ip, Buffer, Frames) ) + if ( IsValidDvFramePacket(Buffer, Frames) ) { //std::cout << "DMRplus DV frame" << std::endl; //Buffer.DebugDump(g_Reflector.m_DebugFile); @@ -108,7 +109,7 @@ void CDmrplusProtocol::Task(void) }*/ } } - else if ( IsValidDvHeaderPacket(Ip, Buffer, &Header) ) + else if ( IsValidDvHeaderPacket(Buffer, &Header) ) { //std::cout << "DMRplus DV header:" << std::endl; //std::cout << "DMRplus DV header:" << std::endl << *Header << std::endl; @@ -444,7 +445,7 @@ bool CDmrplusProtocol::IsValidDisconnectPacket(const CBuffer &Buffer, CCallsign return valid; } -bool CDmrplusProtocol::IsValidDvHeaderPacket(const CIp &Ip, const CBuffer &Buffer, CDvHeaderPacket **Header) +bool CDmrplusProtocol::IsValidDvHeaderPacket(const CBuffer &Buffer, CDvHeaderPacket **Header) { bool valid = false; *Header = NULL; @@ -470,7 +471,7 @@ bool CDmrplusProtocol::IsValidDvHeaderPacket(const CIp &Ip, const CBuffer &Buffe rpt1.SetModule(DMRPLUS_MODULE_ID); CCallsign rpt2 = m_ReflectorCallsign; rpt2.SetModule(DmrDstIdToModule(uiDstId)); - uint32 uiStreamId = IpToStreamId(Ip); + uint32 uiStreamId = CreateStreamId(); // and packet *Header = new CDvHeaderPacket(uiSrcId, CCallsign("CQCQCQ"), rpt1, rpt2, uiStreamId, 0, 0); @@ -486,7 +487,7 @@ bool CDmrplusProtocol::IsValidDvHeaderPacket(const CIp &Ip, const CBuffer &Buffe return valid; } -bool CDmrplusProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer, CDvFramePacket **frames) +bool CDmrplusProtocol::IsValidDvFramePacket(const CBuffer &Buffer, CDvFramePacket **frames) { bool valid = false; frames[0] = NULL; @@ -528,7 +529,7 @@ bool CDmrplusProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer dmrsync[6] = dmrframe[19] & 0xF0; // and create 3 dv frames - uint32 uiStreamId = IpToStreamId(Ip); + uint32 uiStreamId = CreateStreamId(); // frame1 memcpy(dmrambe, &dmr3ambe[0], 9); frames[0] = new CDvFramePacket(dmrambe, dmrsync, uiStreamId, uiVoiceSeq, 1); @@ -840,7 +841,7 @@ void CDmrplusProtocol::ReplaceEMBInBuffer(CBuffer *buffer, uint8 uiDmrPacketId) // uiStreamId helpers -uint32 CDmrplusProtocol::IpToStreamId(const CIp &ip) const +uint32 CDmrplusProtocol::CreateStreamId(void) const { - return ip.GetAddr() ^ (uint32)(MAKEDWORD(ip.GetPort(), ip.GetPort())); + return m_Random(); } diff --git a/src/cdmrplusprotocol.h b/src/cdmrplusprotocol.h index e9d4c1e..1f6ad1a 100644 --- a/src/cdmrplusprotocol.h +++ b/src/cdmrplusprotocol.h @@ -83,8 +83,8 @@ protected: // packet decoding helpers bool IsValidConnectPacket(const CBuffer &, CCallsign *, char *, const CIp &); bool IsValidDisconnectPacket(const CBuffer &, CCallsign *, char *); - bool IsValidDvHeaderPacket(const CIp &, const CBuffer &, CDvHeaderPacket **); - bool IsValidDvFramePacket(const CIp &, const CBuffer &, CDvFramePacket **); + bool IsValidDvHeaderPacket(const CBuffer &, CDvHeaderPacket **); + bool IsValidDvFramePacket(const CBuffer &, CDvFramePacket **); // packet encoding helpers void EncodeConnectAckPacket(CBuffer *); @@ -102,7 +102,7 @@ protected: uint32 ModuleToDmrDestId(char) const; // uiStreamId helpers - uint32 IpToStreamId(const CIp &) const; + uint32 CreateStreamId(void) const; // Buffer & LC helpers void AppendVoiceLCToBuffer(CBuffer *, uint32) const; @@ -116,6 +116,9 @@ protected: // for queue header caches std::array m_StreamsCache; + + // random number generator + mutable std::mt19937 m_Random; }; //////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/cip.cpp b/src/cip.cpp index 5cec9b5..8e58123 100644 --- a/src/cip.cpp +++ b/src/cip.cpp @@ -33,44 +33,63 @@ CIp::CIp() { - ::memset(&m_Addr, 0, sizeof(m_Addr)); - m_Addr.sin_family = AF_INET; + ::memset(&m_Addr, 0, m_AddrLen = sizeof(struct sockaddr_in)); + m_Addr.ss_family = AF_INET; } CIp::CIp(const char *sz) { - ::memset(&m_Addr, 0, sizeof(m_Addr)); - m_Addr.sin_family = AF_INET; - // try xxx.xxx.xxx.xxxx first - m_Addr.sin_addr.s_addr = inet_addr(sz); - if ( m_Addr.sin_addr.s_addr == INADDR_NONE ) + struct addrinfo hints, *res; + + ::memset(&m_Addr, 0, m_AddrLen = sizeof(struct sockaddr_in)); + m_Addr.ss_family = AF_INET; + + ::memset(&hints, 0, sizeof(hints)); + if ( getaddrinfo(sz, NULL, &hints, &res) == 0 ) { - // otherwise try to resolve via dns - hostent *record = gethostbyname(sz); - if( record != NULL ) - { - m_Addr.sin_addr.s_addr = ((in_addr * )record->h_addr)->s_addr; - } + ::memcpy(&m_Addr, res->ai_addr, m_AddrLen = res->ai_addrlen); + freeaddrinfo(res); } } -CIp::CIp(const struct sockaddr_in *sa) +CIp::CIp(const struct sockaddr_storage *ss, socklen_t len) { - ::memcpy(&m_Addr, sa, sizeof(m_Addr)); + len = ( len < sizeof(m_Addr) ) ? len : sizeof(m_Addr); + ::memcpy(&m_Addr, ss, m_AddrLen = len); } - CIp::CIp(const CIp &ip) { - ::memcpy(&m_Addr, &ip.m_Addr, sizeof(m_Addr)); + ::memcpy(&m_Addr, &ip.m_Addr, m_AddrLen = ip.m_AddrLen); +} + +CIp::CIp(const CIp &ip, uint16 port) +{ + ::memcpy(&m_Addr, &ip.m_Addr, m_AddrLen = ip.m_AddrLen); + + switch (m_Addr.ss_family) { + case AF_INET: + ((struct sockaddr_in *)&m_Addr)->sin_port = htons(port); + break; + case AF_INET6: + ((struct sockaddr_in6 *)&m_Addr)->sin6_port = htons(port); + break; + } } //////////////////////////////////////////////////////////////////////////////////////// -// set +// sockaddr -void CIp::SetSockAddr(struct sockaddr_in *sa) +void CIp::SetSockAddr(struct sockaddr_storage *ss, socklen_t len) { - ::memcpy(&m_Addr, sa, sizeof(m_Addr)); + len = ( len < sizeof(m_Addr) ) ? len : sizeof(m_Addr); + ::memcpy(&m_Addr, ss, m_AddrLen = len); +} + +struct sockaddr_storage *CIp::GetSockAddr(socklen_t &len) +{ + len = m_AddrLen; + return &m_Addr; } //////////////////////////////////////////////////////////////////////////////////////// @@ -78,14 +97,41 @@ void CIp::SetSockAddr(struct sockaddr_in *sa) bool CIp::operator ==(const CIp &ip) const { - return ( (ip.m_Addr.sin_family == m_Addr.sin_family) && - (ip.m_Addr.sin_addr.s_addr == m_Addr.sin_addr.s_addr) && - (ip.m_Addr.sin_port == m_Addr.sin_port)) ; + if (ip.m_Addr.ss_family != m_Addr.ss_family) + { + return false; + } + + switch (m_Addr.ss_family) { + case AF_INET: + struct sockaddr_in *pi4, *pm4; + pi4 = (struct sockaddr_in *)&ip.m_Addr; + pm4 = (struct sockaddr_in *)&m_Addr; + return ( (pi4->sin_addr.s_addr == pm4->sin_addr.s_addr) && + (pi4->sin_port == pm4->sin_port) ); + case AF_INET6: + struct sockaddr_in6 *pi6, *pm6; + pi6 = (struct sockaddr_in6 *)&ip.m_Addr; + pm6 = (struct sockaddr_in6 *)&m_Addr; + return ( IN6_ARE_ADDR_EQUAL(&pi6->sin6_addr, &pm6->sin6_addr) && + (pi6->sin6_port == pm6->sin6_port) ); + default: + return false; + }; } CIp::operator const char *() const { - return ::inet_ntoa(m_Addr.sin_addr); + switch(m_Addr.ss_family) { + case AF_INET: + return ::inet_ntop(m_Addr.ss_family, + &((struct sockaddr_in *)&m_Addr)->sin_addr.s_addr, + m_AddrStr, sizeof(m_AddrStr)); + case AF_INET6: + return ::inet_ntop(m_Addr.ss_family, + ((struct sockaddr_in6 *)&m_Addr)->sin6_addr.s6_addr, + m_AddrStr, sizeof(m_AddrStr)); + default: + return ::strncpy(m_AddrStr, "unknown", sizeof(m_AddrStr)); + } } - - diff --git a/src/cip.h b/src/cip.h index 6c43288..c5a2f9d 100644 --- a/src/cip.h +++ b/src/cip.h @@ -35,20 +35,17 @@ public: // constructors CIp(); //CIp(uint8, uint8, uint8, uint8); - CIp(const struct sockaddr_in *); + CIp(const struct sockaddr_storage *, socklen_t); CIp(const char *); CIp(const CIp &); + CIp(const CIp &, uint16); // destructor virtual ~CIp() {}; // sockaddr - void SetSockAddr(struct sockaddr_in *); - struct sockaddr_in *GetSockAddr(void) { return &m_Addr; } - - // convertor - uint32 GetAddr(void) const { return m_Addr.sin_addr.s_addr; } - uint16 GetPort(void) const { return m_Addr.sin_port; } + void SetSockAddr(struct sockaddr_storage *, socklen_t); + struct sockaddr_storage *GetSockAddr(socklen_t &); // operator bool operator ==(const CIp &) const; @@ -56,7 +53,9 @@ public: protected: // data - struct sockaddr_in m_Addr; + struct sockaddr_storage m_Addr; + socklen_t m_AddrLen; + mutable char m_AddrStr[INET6_ADDRSTRLEN]; }; //////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/creflector.h b/src/creflector.h index 1424453..e231b15 100644 --- a/src/creflector.h +++ b/src/creflector.h @@ -31,6 +31,7 @@ #include "cprotocols.h" #include "cpacketstream.h" #include "cnotificationqueue.h" +#include "cudpsocket.h" //////////////////////////////////////////////////////////////////////////////////////// @@ -57,9 +58,10 @@ public: // settings void SetCallsign(const CCallsign &callsign) { m_Callsign = callsign; } const CCallsign &GetCallsign(void) const { return m_Callsign; } - void SetListenIp(const CIp &ip) { m_Ip = ip; } + void SetListenIp(int i, const CIp &ip) { if (i < UDP_SOCKET_MAX) m_Ip[i] = ip; } void SetTranscoderIp(const CIp &ip) { m_AmbedIp = ip; } - const CIp &GetListenIp(void) const { return m_Ip; } + const CIp &GetListenIp(void) const { return m_Ip[0]; } + const CIp &GetListenIp(int i) const { return m_Ip[i]; } const CIp &GetTranscoderIp(void) const { return m_AmbedIp; } // operation @@ -119,7 +121,7 @@ protected: protected: // identity CCallsign m_Callsign; - CIp m_Ip; + CIp m_Ip[UDP_SOCKET_MAX]; CIp m_AmbedIp; // objects diff --git a/src/cudpsocket.cpp b/src/cudpsocket.cpp index 5caa074..f1513bf 100644 --- a/src/cudpsocket.cpp +++ b/src/cudpsocket.cpp @@ -33,7 +33,10 @@ CUdpSocket::CUdpSocket() { - m_Socket = -1; + for ( int i = 0; i < UDP_SOCKET_MAX; i++ ) + { + m_Socket[i] = -1; + } } //////////////////////////////////////////////////////////////////////////////////////// @@ -41,10 +44,7 @@ CUdpSocket::CUdpSocket() CUdpSocket::~CUdpSocket() { - if ( m_Socket != -1 ) - { - Close(); - } + Close(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -53,26 +53,29 @@ CUdpSocket::~CUdpSocket() bool CUdpSocket::Open(uint16 uiPort) { bool open = false; + struct sockaddr_storage *ss; + socklen_t ss_len; - // create socket - m_Socket = socket(PF_INET,SOCK_DGRAM,0); - if ( m_Socket != -1 ) - { - // initialize sockaddr struct - ::memset(&m_SocketAddr, 0, sizeof(struct sockaddr_in)); - m_SocketAddr.sin_family = AF_INET; - m_SocketAddr.sin_port = htons(uiPort); - m_SocketAddr.sin_addr.s_addr = inet_addr(g_Reflector.GetListenIp()); + for ( int i = 0; i < UDP_SOCKET_MAX; i++ ) { + m_Ip[i] = CIp(g_Reflector.GetListenIp(i), uiPort); + ss = m_Ip[i].GetSockAddr(ss_len); - if ( bind(m_Socket, (struct sockaddr *)&m_SocketAddr, sizeof(struct sockaddr_in)) == 0 ) - { - fcntl(m_Socket, F_SETFL, O_NONBLOCK); - open = true; - } - else + // create socket + // (avoid INADDR_ANY on secondary and later IP address) + m_Socket[i] = ( i != 0 && m_Ip[i] == CIp() ) ? + -1 : socket(ss->ss_family, SOCK_DGRAM, 0); + if ( m_Socket[i] != -1 ) { - close(m_Socket); - m_Socket = -1; + if ( bind(m_Socket[i], (struct sockaddr *)ss, ss_len) == 0 ) + { + fcntl(m_Socket[i], F_SETFL, O_NONBLOCK); + open |= true; + } + else + { + close(m_Socket[i]); + m_Socket[i] = -1; + } } } @@ -82,11 +85,33 @@ bool CUdpSocket::Open(uint16 uiPort) void CUdpSocket::Close(void) { - if ( m_Socket != -1 ) + for ( int i = 0; i < UDP_SOCKET_MAX; i++ ) + { + if ( m_Socket[i] != -1 ) + { + close(m_Socket[i]); + m_Socket[i] = -1; + } + } +} + +int CUdpSocket::GetSocket(const CIp &Ip) +{ + CIp temp(Ip); + socklen_t ss_len; + struct sockaddr_storage *ss = temp.GetSockAddr(ss_len); + sa_family_t ss_family = ss->ss_family; + + for ( int i = 0; i < UDP_SOCKET_MAX; i++ ) { - close(m_Socket); - m_Socket = -1; + ss = m_Ip[i].GetSockAddr(ss_len); + if ( ss_family == ss->ss_family ) + { + return m_Socket[i]; + } } + + return -1; } //////////////////////////////////////////////////////////////////////////////////////// @@ -94,41 +119,58 @@ void CUdpSocket::Close(void) int CUdpSocket::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 sockaddr_storage Sin; + struct pollfd pfd[UDP_SOCKET_MAX]; + socklen_t uiFromLen = sizeof(Sin); + int i, socks, index, iRecvLen = -1; // socket valid ? - if ( m_Socket != -1 ) + for ( i = 0, socks = 0; i < UDP_SOCKET_MAX; i++ ) + { + if ( m_Socket[i] != -1 ) + { + pfd[socks].fd = m_Socket[i]; + pfd[socks].events = POLLIN; + socks++; + } + } + + if ( socks != 0 ) { // 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); - - // allocate buffer - Buffer->resize(UDP_BUFFER_LENMAX); + poll(pfd, socks, timeout); - // read - iRecvLen = (int)recvfrom(m_Socket, - (void *)Buffer->data(), UDP_BUFFER_LENMAX, - 0, (struct sockaddr *)&Sin, &uiFromLen); - - // handle - if ( iRecvLen != -1 ) + for ( i = 0; i < socks; i++ ) { - // adjust buffer size - Buffer->resize(iRecvLen); + // round robin + index = (i + m_Counter) % socks; - // get IP - Ip->SetSockAddr(&Sin); + if ( pfd[index].revents & POLLIN ) + { + // allocate buffer + Buffer->resize(UDP_BUFFER_LENMAX); + + // read + iRecvLen = (int)recvfrom(pfd[index].fd, + (void *)Buffer->data(), UDP_BUFFER_LENMAX, + 0, (struct sockaddr *)&Sin, &uiFromLen); + + // handle + if ( iRecvLen != -1 ) + { + // adjust buffer size + Buffer->resize(iRecvLen); + + // get IP + Ip->SetSockAddr(&Sin, uiFromLen); + + m_Counter++; + break; + } + } } } - + // done return iRecvLen; } @@ -139,35 +181,39 @@ int CUdpSocket::Receive(CBuffer *Buffer, CIp *Ip, int timeout) int CUdpSocket::Send(const CBuffer &Buffer, const CIp &Ip) { CIp temp(Ip); - return (int)::sendto(m_Socket, + socklen_t ss_len; + struct sockaddr_storage *ss = temp.GetSockAddr(ss_len); + return (int)::sendto(GetSocket(Ip), (void *)Buffer.data(), Buffer.size(), - 0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in)); + 0, (struct sockaddr *)ss, ss_len); } int CUdpSocket::Send(const char *Buffer, const CIp &Ip) { CIp temp(Ip); - return (int)::sendto(m_Socket, + socklen_t ss_len; + struct sockaddr_storage *ss = temp.GetSockAddr(ss_len); + return (int)::sendto(GetSocket(Ip), (void *)Buffer, ::strlen(Buffer), - 0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in)); + 0, (struct sockaddr *)ss, ss_len); } int CUdpSocket::Send(const CBuffer &Buffer, const CIp &Ip, uint16 destport) { - CIp temp(Ip); - temp.GetSockAddr()->sin_port = htons(destport); - return (int)::sendto(m_Socket, + CIp temp(Ip, destport); + socklen_t ss_len; + struct sockaddr_storage *ss = temp.GetSockAddr(ss_len); + return (int)::sendto(GetSocket(Ip), (void *)Buffer.data(), Buffer.size(), - 0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in)); + 0, (struct sockaddr *)ss, ss_len); } int CUdpSocket::Send(const char *Buffer, const CIp &Ip, uint16 destport) { - CIp temp(Ip); - temp.GetSockAddr()->sin_port = htons(destport); - return (int)::sendto(m_Socket, + CIp temp(Ip, destport); + socklen_t ss_len; + struct sockaddr_storage *ss = temp.GetSockAddr(ss_len); + return (int)::sendto(GetSocket(Ip), (void *)Buffer, ::strlen(Buffer), - 0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in)); + 0, (struct sockaddr *)ss, ss_len); } - - diff --git a/src/cudpsocket.h b/src/cudpsocket.h index e91ed80..0256145 100644 --- a/src/cudpsocket.h +++ b/src/cudpsocket.h @@ -29,6 +29,7 @@ //#include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ // define #define UDP_BUFFER_LENMAX 1024 +#define UDP_SOCKET_MAX 2 //////////////////////////////////////////////////////////////////////////////////////// @@ -57,7 +59,7 @@ public: // open & close bool Open(uint16); void Close(void); - int GetSocket(void) { return m_Socket; } + int GetSocket(const CIp &); // read int Receive(CBuffer *, CIp *, int); @@ -70,8 +72,9 @@ public: protected: // data - int m_Socket; - struct sockaddr_in m_SocketAddr; + int m_Socket[UDP_SOCKET_MAX]; + CIp m_Ip[UDP_SOCKET_MAX]; + unsigned int m_Counter; }; //////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/main.cpp b/src/main.cpp index 154a53b..0d807d2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -87,7 +87,7 @@ int main(int argc, const char * argv[]) #endif // check arguments - if ( argc != 4 ) + if ( argc < 4 ) { std::cout << "Usage: xlxd callsign xlxdip ambedip" << std::endl; std::cout << "example: xlxd XLX999 192.168.178.212 127.0.0.1" << std::endl; @@ -99,8 +99,9 @@ int main(int argc, const char * argv[]) // initialize reflector g_Reflector.SetCallsign(argv[1]); - g_Reflector.SetListenIp(CIp(argv[2])); + g_Reflector.SetListenIp(0, CIp(argv[2])); g_Reflector.SetTranscoderIp(CIp(CIp(argv[3]))); + g_Reflector.SetListenIp(1, ( argc >= 5 ) ? CIp(argv[4]) : CIp()); // and let it run if ( !g_Reflector.Start() ) diff --git a/src/main.h b/src/main.h index b974ff3..11fafe0 100644 --- a/src/main.h +++ b/src/main.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include