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 #973, #2632, #2834, #2838.

Co-authored-by: Jiangjie Gao <[email protected]>
  • Loading branch information
maxsharabayko and mGaosi committed Apr 16, 2024
1 parent 8c9527d commit 3101c85
Showing 1 changed file with 49 additions and 8 deletions.
57 changes: 49 additions & 8 deletions srtcore/channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -774,18 +774,59 @@ 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();
class WSAEventRef
{
public:
WSAEventRef()
: e(::WSACreateEvent())
{
}
~WSAEventRef()
{
::WSACloseEvent(e);
e = NULL;
}
void reset()
{
::WSAResetEvent(e);
}
WSAEVENT Handle()
{
return e;
}

private:
WSAEVENT e;
};
#ifndef __MINGW32__
thread_local WSAEventRef lEvent;
#else
WSAEventRef lEvent;
#endif
WSAOVERLAPPED overlapped;
SecureZeroMemory((PVOID)&overlapped, sizeof(WSAOVERLAPPED));
::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 && NET_ERROR == WSA_IO_PENDING)
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 dwFlags = 0;
const bool bCompleted = WSAGetOverlappedResult(m_iSocket, &overlapped, &size, TRUE, &dwFlags);
if (bCompleted)
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;
Expand Down

0 comments on commit 3101c85

Please sign in to comment.