Код: Выделить всё
int UDP::recv(byte* data, const uint16_t dataLen, uint16_t srcPort, IPV4& srcIp)
{
const size_t totalHeadersLen = IP_HEADERS_SIZE + UDP_HEADERS_SIZE;
byte* recvBuffer = new byte[UINT16_MAX];
sockaddr_in srcAddr;
int srcAddrSize = sizeof(srcAddr);
while (true) // Keep receiving until reaching a valid packet
{
// Receive the packet
int packetSize = recvfrom(
_socket,
reinterpret_cast(recvBuffer),
UINT16_MAX,
0,
reinterpret_cast(&srcAddr),
&srcAddrSize);
// Check for errors
if (packetSize == SOCKET_ERROR || packetSize < totalHeadersLen)
{
delete[] recvBuffer;
throw std::runtime_error(std::to_string(WSAGetLastError()));
}
// Parse IP header (20 bytes for IPv4)
const byte* ipHeader = recvBuffer;
// Extract source IP
srcIp[0] = ipHeader[12];
srcIp[1] = ipHeader[13];
srcIp[2] = ipHeader[14];
srcIp[3] = ipHeader[15];
const byte* udpHeader = recvBuffer + IP_HEADERS_SIZE;
UDPHeaders headers;
headers.srcPort = ntohs(*reinterpret_cast(udpHeader));
headers.dstPort = ntohs(*reinterpret_cast(udpHeader + 2));
headers.length = ntohs(*reinterpret_cast(udpHeader + 4));
headers.checksum = ntohs(*reinterpret_cast(udpHeader + 6));
// Check if the destination port matches the local port
if (headers.dstPort != _localPort)
{
// Ignore this packet
continue;
}
// Set the source port
srcPort = headers.srcPort;
// Calculate the checksum and verify it matches
size_t receivedDataLen = headers.length - UDP_HEADERS_SIZE;
uint16_t checksum = calcChecksum(headers, srcIp, _localAddr, recvBuffer + totalHeadersLen, receivedDataLen);
if (checksum != headers.checksum)
{
// Ignore this packet
continue;
}
// Verify data length and buffer size
if (dataLen < receivedDataLen)
{
delete[] recvBuffer;
throw std::runtime_error("Data buffer is too small.");
}
// Copy the UDP payload to the provided buffer
std::memcpy(data, recvBuffer + totalHeadersLen, receivedDataLen);
break;
}
delete[] recvBuffer;
return 0;
}
Создание сокета осуществляется в другом построителе класса UDP.
Вот часть создания:
Код: Выделить всё
_socket = socket(AF_INET, SOCK_RAW, POROTO_ID);
if (_socket == INVALID_SOCKET)
{
WSACleanup();
throw std::runtime_error(std::to_string(WSAGetLastError()));
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = 0;
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(_socket, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
closesocket(_socket);
WSACleanup();
throw std::runtime_error(std::to_string(WSAGetLastError()));
}
Единственный способ решения этой проблемы, который я нашел, — это путем реализации сетевого уровня (IPV4), чего я предпочитаю не делать.
Подробнее здесь: https://stackoverflow.com/questions/792 ... in-windows