Add Udp::ReceiveMultiple method

This commit is contained in:
Jérôme Leclercq 2017-07-11 12:11:20 +02:00
parent 2ca844be63
commit b4732d8c17
6 changed files with 189 additions and 0 deletions

View File

@ -39,6 +39,7 @@ namespace Nz
std::size_t QueryMaxDatagramSize();
bool Receive(void* buffer, std::size_t size, IpAddress* from, std::size_t* received);
bool ReceiveMultiple(NetBuffer* buffers, std::size_t bufferCount, IpAddress* from, std::size_t* received);
bool ReceivePacket(NetPacket* packet, IpAddress* from);
bool Send(const IpAddress& to, const void* buffer, std::size_t size, std::size_t* sent);

View File

@ -549,6 +549,90 @@ namespace Nz
else // else we received something
senderIp = IpAddressImpl::FromSockAddr(reinterpret_cast<const sockaddr*>(&nameBuffer));
if (from)
*from = IpAddressImpl::FromSockAddr(reinterpret_cast<const sockaddr*>(&nameBuffer));
if (read)
*read = byteRead;
if (error)
*error = SocketError_NoError;
return true;
}
bool SocketImpl::ReceiveMultiple(SocketHandle handle, NetBuffer* buffers, std::size_t bufferCount, IpAddress* from, int* read, SocketError* error)
{
NazaraAssert(handle != InvalidHandle, "Invalid handle");
NazaraAssert(buffers && bufferCount > 0, "Invalid buffers");
StackAllocation memory = NazaraStackAllocation(bufferCount * sizeof(iovec));
struct iovec* sysBuffers = static_cast<struct iovec*>(memory.GetPtr());
for (std::size_t i = 0; i < bufferCount; ++i)
{
sysBuffers[i].iov_base = buffers[i].data;
sysBuffers[i].iov_len = buffers[i].dataLength;
}
struct msghdr msgHdr;
std::memset(&msgHdr, 0, sizeof(msgHdr));
msgHdr.msg_iov = sysBuffers;
msgHdr.msg_iovlen = static_cast<int>(bufferCount);
IpAddressImpl::SockAddrBuffer nameBuffer;
if (from)
{
msgHdr.msg_name = nameBuffer.data();
msgHdr.msg_namelen = static_cast<socklen_t>(nameBuffer.size());
}
int byteRead = recvmsg(handle, &msgHdr, MSG_NOSIGNAL);
if (byteRead == -1)
{
int errorCode = GetLastErrorCode();
if (errorCode == EAGAIN)
errorCode = EWOULDBLOCK;
switch (errorCode)
{
case EWOULDBLOCK:
{
// If we have no data and are not blocking, return true with 0 byte read
recvLength = 0;
senderIp = IpAddress::Invalid;
break;
}
default:
{
if (error)
*error = TranslateErrnoToResolveError(errorCode);
return false; //< Error
}
}
}
else if (byteRead == 0)
{
if (error)
*error = SocketError_ConnectionClosed;
return false; //< Connection closed
}
else // else we received something
senderIp = IpAddressImpl::FromSockAddr(reinterpret_cast<const sockaddr*>(nameBuffer.data()));
#ifdef HAS_MSGHDR_FLAGS
if (msgHdr.msg_flags & MSG_TRUNC)
{
if (error)
*error = SocketError_DatagramSize;
return false;
}
#endif
if (from)
*from = senderIp;

View File

@ -63,6 +63,7 @@ namespace Nz
static bool Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error);
static bool ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error);
static bool ReceiveMultiple(SocketHandle handle, NetBuffer* buffers, std::size_t bufferCount, IpAddress* from, int* read, SocketError* error);
static bool Send(SocketHandle handle, const void* buffer, int length, int* sent, SocketError* error);
static bool SendMultiple(SocketHandle handle, const NetBuffer* buffers, std::size_t bufferCount, const IpAddress& to, int* sent, SocketError* error);

View File

@ -118,6 +118,42 @@ namespace Nz
return true;
}
/*!
* \brief Receive multiple datagram from one peer
* \return true If data were sent
*
* \param to Destination IpAddress (must match socket protocol)
* \param buffers A pointer to an array of NetBuffer containing buffers and size data
* \param bufferCount Number of buffers available
* \param from IpAddress of the peer
* \param received Optional argument to get the number of bytes received
*/
bool UdpSocket::ReceiveMultiple(NetBuffer* buffers, std::size_t bufferCount, IpAddress* from, std::size_t* received)
{
NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created");
NazaraAssert(buffers && bufferCount > 0, "Invalid buffer");
int read;
if (!SocketImpl::ReceiveMultiple(m_handle, buffers, bufferCount, from, &read, &m_lastError))
{
switch (m_lastError)
{
case SocketError_ConnectionClosed:
m_lastError = SocketError_NoError;
read = 0;
break;
default:
return false;
}
}
if (received)
*received = read;
return true;
}
/*!
* \brief Receives the packet available
* \return true If packet received

View File

@ -586,6 +586,72 @@ namespace Nz
return true;
}
bool SocketImpl::ReceiveMultiple(SocketHandle handle, NetBuffer* buffers, std::size_t bufferCount, IpAddress* from, int* read, SocketError* error)
{
NazaraAssert(handle != InvalidHandle, "Invalid handle");
NazaraAssert(buffers && bufferCount > 0, "Invalid buffers");
IpAddressImpl::SockAddrBuffer nameBuffer;
int bufferLength = static_cast<int>(nameBuffer.size());
IpAddress senderIp;
StackAllocation memory = NazaraStackAllocation(bufferCount * sizeof(WSABUF));
WSABUF* winBuffers = static_cast<WSABUF*>(memory.GetPtr());
for (std::size_t i = 0; i < bufferCount; ++i)
{
winBuffers[i].buf = static_cast<CHAR*>(buffers[i].data);
winBuffers[i].len = static_cast<ULONG>(buffers[i].dataLength);
}
DWORD flags = 0;
DWORD byteRead;
if (WSARecvFrom(handle, winBuffers, static_cast<DWORD>(bufferCount), &byteRead, &flags, reinterpret_cast<sockaddr*>(nameBuffer.data()), &bufferLength, nullptr, nullptr) == SOCKET_ERROR)
{
int errorCode = WSAGetLastError();
switch (errorCode)
{
case WSAECONNRESET:
case WSAEWOULDBLOCK:
{
// If we have no data and are not blocking, return true with 0 byte read
byteRead = 0;
senderIp = IpAddress::Invalid;
break;
}
default:
{
if (error)
*error = TranslateWSAErrorToSocketError(errorCode);
return false; //< Error
}
}
}
else
senderIp = IpAddressImpl::FromSockAddr(reinterpret_cast<const sockaddr*>(&nameBuffer));
if (flags & MSG_PARTIAL)
{
if (error)
*error = SocketError_DatagramSize;
return false;
}
if (from)
*from = senderIp;
if (read)
*read = byteRead;
if (error)
*error = SocketError_NoError;
return true;
}
bool SocketImpl::Send(SocketHandle handle, const void* buffer, int length, int* sent, SocketError* error)
{
NazaraAssert(handle != InvalidHandle, "Invalid handle");

View File

@ -64,6 +64,7 @@ namespace Nz
static bool Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error);
static bool ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error);
static bool ReceiveMultiple(SocketHandle handle, NetBuffer* buffers, std::size_t bufferCount, IpAddress* from, int* read, SocketError* error);
static bool Send(SocketHandle handle, const void* buffer, int length, int* sent, SocketError* error);
static bool SendMultiple(SocketHandle handle, const NetBuffer* buffers, std::size_t bufferCount, const IpAddress& to, int* sent, SocketError* error);