Skip to content

Commit

Permalink
[core] Fixed PKTINFO case that was failing for IPv4+IPv6 bound sockets (
Browse files Browse the repository at this point in the history
  • Loading branch information
ethouris authored Jan 26, 2023
1 parent a42a39f commit b8962b4
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 15 deletions.
46 changes: 39 additions & 7 deletions srtcore/channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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))
{
Expand All @@ -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)
Expand Down Expand Up @@ -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<int, const char* const> errmsgflg [] = {
make_pair<int>(MSG_OOB, "OOB"),
make_pair<int>(MSG_EOR, "EOR"),
make_pair<int>(MSG_TRUNC, "TRUNC"),
make_pair<int>(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;
}
Expand Down
19 changes: 11 additions & 8 deletions srtcore/channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit b8962b4

Please sign in to comment.