From b8962b4a66e63e07977f385d12a3969dd47d211a Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Thu, 26 Jan 2023 09:26:40 +0100 Subject: [PATCH] [core] Fixed PKTINFO case that was failing for IPv4+IPv6 bound sockets (#2630). --- srtcore/channel.cpp | 46 ++++++++++++++++++++++++++++++++++++++------- srtcore/channel.h | 19 +++++++++++-------- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/srtcore/channel.cpp b/srtcore/channel.cpp index 555f84ab1..700759d0b 100644 --- a/srtcore/channel.cpp +++ b/srtcore/channel.cpp @@ -145,10 +145,9 @@ srt::CChannel::CChannel() { #ifdef SRT_ENABLE_PKTINFO // Do the check for ancillary data buffer size, kinda assertion - static const size_t CMSG_MAX_SPACE = sizeof (CMSGNodeAlike); + static const size_t CMSG_MAX_SPACE = sizeof (CMSGNodeIPv4) + sizeof (CMSGNodeIPv6); - if (CMSG_MAX_SPACE < CMSG_SPACE(sizeof(in_pktinfo)) - || CMSG_MAX_SPACE < CMSG_SPACE(sizeof(in6_pktinfo))) + if (CMSG_MAX_SPACE < CMSG_SPACE(sizeof(in_pktinfo)) + CMSG_SPACE(sizeof(in6_pktinfo))) { LOGC(kmlog.Fatal, log << "Size of CMSG_MAX_SPACE=" << CMSG_MAX_SPACE << " too short for cmsg " @@ -504,8 +503,16 @@ void srt::CChannel::setUDPSockOpt() { HLOGP(kmlog.Debug, "Socket bound to ANY - setting PKTINFO for address retrieval"); const int on = 1, off SRT_ATR_UNUSED = 0; - ::setsockopt(m_iSocket, IPPROTO_IP, IP_PKTINFO, (char*)&on, sizeof(on)); - ::setsockopt(m_iSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); + + if (m_BindAddr.family() == AF_INET || m_mcfg.iIpV6Only == 0) + { + ::setsockopt(m_iSocket, IPPROTO_IP, IP_PKTINFO, (char*)&on, sizeof(on)); + } + + if (m_BindAddr.family() == AF_INET6) + { + ::setsockopt(m_iSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); + } // XXX Unknown why this has to be off. RETEST. //::setsockopt(m_iSocket, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)); @@ -733,7 +740,10 @@ int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet, const socka bool have_set_src = false; #ifdef SRT_ENABLE_PKTINFO - if (m_bBindMasked && !source_addr.isany()) + + // Note that even if PKTINFO is desired, the first caller's packet will be sent + // without ancillary info anyway because there's no "peer" yet to know where to send it. + if (m_bBindMasked && source_addr.family() != AF_UNSPEC && !source_addr.isany()) { if (!setSourceAddress(mh, source_addr)) { @@ -745,6 +755,7 @@ int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet, const socka have_set_src = true; } } + #endif if (!have_set_src) @@ -972,9 +983,30 @@ srt::EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet // packet was received, so the packet will be then retransmitted. if (msg_flags != 0) { +#if ENABLE_HEAVY_LOGGING + + std::ostringstream flg; + +#if !defined(_WIN32) + + static const pair errmsgflg [] = { + make_pair(MSG_OOB, "OOB"), + make_pair(MSG_EOR, "EOR"), + make_pair(MSG_TRUNC, "TRUNC"), + make_pair(MSG_CTRUNC, "CTRUNC") + }; + + for (size_t i = 0; i < Size(errmsgflg); ++i) + if ((msg_flags & errmsgflg[i].first) != 0) + flg << " " << errmsgflg[i].second; + + // This doesn't work the same way on Windows, so on Windows just skip it. +#endif + HLOGC(krlog.Debug, log << CONID() << "NET ERROR: packet size=" << recv_size << " msg_flags=0x" << hex << msg_flags - << ", possibly MSG_TRUNC)"); + << ", detected flags:" << flg.str()); +#endif status = RST_AGAIN; goto Return_error; } diff --git a/srtcore/channel.h b/srtcore/channel.h index ee6e01d4c..bcc92431b 100644 --- a/srtcore/channel.h +++ b/srtcore/channel.h @@ -177,21 +177,24 @@ class CChannel // This structure is exclusively used to determine the required size for // CMSG buffer so that it can be allocated in a solid block with CChannel. // NOT TO BE USED to access any data inside the CMSG message. - struct CMSGNodeAlike + struct CMSGNodeIPv4 { - union - { - in_pktinfo in4; - in6_pktinfo in6; - }; + in_pktinfo in4; + size_t extrafill; + cmsghdr hdr; + }; + + struct CMSGNodeIPv6 + { + in6_pktinfo in6; size_t extrafill; cmsghdr hdr; }; // This is 'mutable' because it's a utility buffer defined here // to avoid unnecessary re-allocations. - mutable char m_acCmsgRecvBuffer [sizeof (CMSGNodeAlike)]; // Reserved space for ancillary data with pktinfo - mutable char m_acCmsgSendBuffer [sizeof (CMSGNodeAlike)]; // Reserved space for ancillary data with pktinfo + mutable char m_acCmsgRecvBuffer [sizeof (CMSGNodeIPv4) + sizeof (CMSGNodeIPv6)]; // Reserved space for ancillary data with pktinfo + mutable char m_acCmsgSendBuffer [sizeof (CMSGNodeIPv4) + sizeof (CMSGNodeIPv6)]; // Reserved space for ancillary data with pktinfo // IMPORTANT!!! This function shall be called EXCLUSIVELY just after // calling ::recvmsg function. It uses a static buffer to supply data