Skip to content

Commit

Permalink
[core] Fixed thread safety using WSAOVERLAPPED in WSASendTo.
Browse files Browse the repository at this point in the history
The lpOverlapped parameter must be valid for the duration of the overlapped operation.
If multiple I/O operations are simultaneously outstanding, each must reference a separate WSAOVERLAPPED structure.
Resolves Haivision#973, Haivision#2632, Haivision#2834, Haivision#2838.

Co-authored-by: Jiangjie Gao <[email protected]>
  • Loading branch information
maxsharabayko and mGaosi committed Apr 16, 2024
2 parents f7735e3 + dd49c5b commit c0fdadd
Showing 1 changed file with 54 additions and 11 deletions.
65 changes: 54 additions & 11 deletions srtcore/channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -774,20 +774,63 @@ int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet, const socka

const int res = (int)::sendmsg(m_iSocket, &mh, 0);
#else
DWORD size = (DWORD)(CPacket::HDR_SIZE + packet.getLength());
int addrsize = addr.size();
WSAOVERLAPPED overlapped;
SecureZeroMemory((PVOID)&overlapped, sizeof(WSAOVERLAPPED));
int res = ::WSASendTo(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, 0, addr.get(), addrsize, &overlapped, NULL);
class WSAEventRef
{
public:
WSAEventRef()
: e(::WSACreateEvent())
{
}
~WSAEventRef()
{
::WSACloseEvent(e);
e = NULL;
}
void reset()
{
::WSAResetEvent(e);
}
WSAEVENT Handle()
{
return e;
}

if (res == SOCKET_ERROR && NET_ERROR == WSA_IO_PENDING)
private:
WSAEVENT e;
};
#ifndef __MINGW32__
thread_local WSAEventRef lEvent;
#else
WSAEventRef lEvent;
#endif
WSAOVERLAPPED overlapped;
::SecureZeroMemory(&overlapped, sizeof(overlapped));
overlapped.hEvent = lEvent.Handle();

DWORD size = (DWORD)(packet.m_PacketVector[0].size() + packet.m_PacketVector[1].size());
int addrsize = addr.size();
int res = ::WSASendTo(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, 0, addr.get(), addrsize, &overlapped, NULL);
if (res == SOCKET_ERROR)
{
DWORD dwFlags = 0;
const bool bCompleted = WSAGetOverlappedResult(m_iSocket, &overlapped, &size, true, &dwFlags);
WSACloseEvent(overlapped.hEvent);
res = bCompleted ? 0 : -1;
if (NET_ERROR == WSA_IO_PENDING)
{
DWORD flags = 0;
const bool completed = ::WSAGetOverlappedResult(m_iSocket, &overlapped, &size, TRUE, &flags);
if (completed)
{
res = 0;
}
else
{
LOGC(kslog.Warn, log << "CChannel::sendto call on ::WSAGetOverlappedResult failed with error: " << NET_ERROR);
}
lEvent.reset();
}
else
{
LOGC(kmlog.Error, log << CONID() << "WSASendTo failed with error: " << NET_ERROR);
}
}

res = (0 == res) ? size : -1;
#endif

Expand Down

0 comments on commit c0fdadd

Please sign in to comment.