DEV9: Eliminate c-style casts from ICMP_Session

This commit is contained in:
TheLastRar 2024-07-12 18:21:47 +01:00 committed by lightningterror
parent f326e8775f
commit 3c7cff99f4
2 changed files with 60 additions and 41 deletions

View File

@ -15,6 +15,7 @@
#endif #endif
#include <algorithm> #include <algorithm>
#include <bit>
#include <errno.h> #include <errno.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -99,7 +100,7 @@ namespace Sessions
//Documentation says + 8 to allow for an ICMP error message //Documentation says + 8 to allow for an ICMP error message
//In testing, ICMP_ECHO_REPLY structure itself was returned with data set to null //In testing, ICMP_ECHO_REPLY structure itself was returned with data set to null
icmpResponseBufferLen = sizeof(ICMP_ECHO_REPLY) + requestSize + 8; icmpResponseBufferLen = sizeof(ICMP_ECHO_REPLY) + requestSize + 8;
icmpResponseBuffer = std::make_unique<u8[]>(icmpResponseBufferLen); icmpResponseBuffer = std::make_unique<std::byte[]>(icmpResponseBufferLen);
#elif defined(__POSIX__) #elif defined(__POSIX__)
{ {
switch (icmpConnectionKind) switch (icmpConnectionKind)
@ -142,6 +143,7 @@ namespace Sessions
} }
DevCon.WriteLn("DEV9: ICMP: Failed To Open RAW Socket"); DevCon.WriteLn("DEV9: ICMP: Failed To Open RAW Socket");
[[fallthrough]]; [[fallthrough]];
#endif #endif
default: default:
@ -149,7 +151,7 @@ namespace Sessions
return; return;
} }
icmpResponseBuffer = std::make_unique<u8[]>(icmpResponseBufferLen); icmpResponseBuffer = std::make_unique<std::byte[]>(icmpResponseBufferLen);
#endif #endif
} }
@ -179,7 +181,9 @@ namespace Sessions
//Prep buffer for reasing //Prep buffer for reasing
[[maybe_unused]] int count = IcmpParseReplies(icmpResponseBuffer.get(), icmpResponseBufferLen); [[maybe_unused]] int count = IcmpParseReplies(icmpResponseBuffer.get(), icmpResponseBufferLen);
pxAssert(count == 1); pxAssert(count == 1);
ICMP_ECHO_REPLY* pingRet = (ICMP_ECHO_REPLY*)icmpResponseBuffer.get();
// Rely on implicit object creation
ICMP_ECHO_REPLY* pingRet = reinterpret_cast<ICMP_ECHO_REPLY*>(icmpResponseBuffer.get());
//Map status to ICMP type/code //Map status to ICMP type/code
switch (pingRet->Status) switch (pingRet->Status)
@ -255,7 +259,7 @@ namespace Sessions
} }
result.dataLength = pingRet->DataSize; result.dataLength = pingRet->DataSize;
result.data = (u8*)pingRet->Data; result.data = static_cast<u8*>(pingRet->Data);
result.address.integer = pingRet->Address; result.address.integer = pingRet->Address;
return &result; return &result;
@ -274,7 +278,7 @@ namespace Sessions
fd_set sReady; fd_set sReady;
fd_set sExcept; fd_set sExcept;
timeval nowait{0}; timeval nowait{};
FD_ZERO(&sReady); FD_ZERO(&sReady);
FD_ZERO(&sExcept); FD_ZERO(&sExcept);
FD_SET(icmpSocket, &sReady); FD_SET(icmpSocket, &sReady);
@ -294,7 +298,7 @@ namespace Sessions
int error = 0; int error = 0;
socklen_t len = sizeof(error); socklen_t len = sizeof(error);
if (getsockopt(icmpSocket, SOL_SOCKET, SO_ERROR, (char*)&error, &len) < 0) if (getsockopt(icmpSocket, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&error), &len) < 0)
Console.Error("DEV9: ICMP: Unknown ICMP Connection Error (getsockopt Error: %d)", errno); Console.Error("DEV9: ICMP: Unknown ICMP Connection Error (getsockopt Error: %d)", errno);
else else
Console.Error("DEV9: ICMP: Recv Error: %d", error); Console.Error("DEV9: ICMP: Recv Error: %d", error);
@ -315,7 +319,7 @@ namespace Sessions
} }
#endif #endif
sockaddr endpoint{0}; sockaddr_in endpoint{};
iovec iov; iovec iov;
iov.iov_base = icmpResponseBuffer.get(); iov.iov_base = icmpResponseBuffer.get();
@ -325,10 +329,10 @@ namespace Sessions
//Needs to hold cmsghdr + sock_extended_err + sockaddr_in //Needs to hold cmsghdr + sock_extended_err + sockaddr_in
//for ICMP error responses (total 44 bytes) //for ICMP error responses (total 44 bytes)
//Unknown for other types of error //Unknown for other types of error
u8 cbuff[64]; std::byte cbuff[64]{};
#endif #endif
msghdr msg{0}; msghdr msg{};
msg.msg_name = &endpoint; msg.msg_name = &endpoint;
msg.msg_namelen = sizeof(endpoint); msg.msg_namelen = sizeof(endpoint);
msg.msg_iov = &iov; msg.msg_iov = &iov;
@ -377,7 +381,7 @@ namespace Sessions
if (msg.msg_flags & MSG_CTRUNC) if (msg.msg_flags & MSG_CTRUNC)
Console.Error("DEV9: ICMP: RecvMsg Control Truncated"); Console.Error("DEV9: ICMP: RecvMsg Control Truncated");
sock_extended_err* ex_err = nullptr; sock_extended_err* exErrorPtr = nullptr;
cmsghdr* cmsg; cmsghdr* cmsg;
/* Receive auxiliary data in msgh */ /* Receive auxiliary data in msgh */
@ -385,28 +389,42 @@ namespace Sessions
{ {
if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
{ {
ex_err = (sock_extended_err*)CMSG_DATA(cmsg); exErrorPtr = reinterpret_cast<sock_extended_err*>(CMSG_DATA(cmsg));
continue; continue;
} }
pxAssert(false); pxAssert(false);
} }
if (ex_err != nullptr) if (exErrorPtr != nullptr)
{ {
if (ex_err->ee_origin == SO_EE_ORIGIN_ICMP) /*
{ * The pointer returned cannot be assumed to be suitably aligned for accessing arbitrary payload data types
result.type = ex_err->ee_type; * So we would need to memcpy sock_extended_err
result.code = ex_err->ee_code; */
sock_extended_err exError;
std::memcpy(&exError, exErrorPtr, sizeof(exError));
sockaddr_in* sockaddr = (sockaddr_in*)SO_EE_OFFENDER(ex_err); if (exError.ee_origin == SO_EE_ORIGIN_ICMP)
result.address = *(IP_Address*)&sockaddr->sin_addr; {
result.type = exError.ee_type;
result.code = exError.ee_code;
/*
* SO_EE_OFFENDER reads data relative to, but not necessarily included in struct sock_extended_err
* So we need to pass the original pointer provided to us from CMSG_DATA()
* However, the input pointer needs to be of type sock_extended_err*, hence the reinterpret_cast
* The pointer returned may not be suitably aligned (see CMSG_DATA), so we need to memcpy
*/
sockaddr_in errorEndpoint;
std::memcpy(&errorEndpoint, SO_EE_OFFENDER(exErrorPtr), sizeof(errorEndpoint));
result.address = std::bit_cast<IP_Address>(errorEndpoint.sin_addr);
return &result; return &result;
} }
else else
{ {
Console.Error("DEV9: ICMP: Recv Error %d", ex_err->ee_errno); Console.Error("DEV9: ICMP: Recv Error %d", exError.ee_errno);
result.type = -1; result.type = -1;
result.code = ex_err->ee_errno; result.code = exError.ee_errno;
return &result; return &result;
} }
} }
@ -424,7 +442,8 @@ namespace Sessions
else else
#endif #endif
{ {
ip* ipHeader = (ip*)icmpResponseBuffer.get(); // Rely on implicit object creation
ip* ipHeader = reinterpret_cast<ip*>(icmpResponseBuffer.get());
int headerLength = ipHeader->ip_hl << 2; int headerLength = ipHeader->ip_hl << 2;
pxAssert(headerLength == 20); pxAssert(headerLength == 20);
@ -439,14 +458,14 @@ namespace Sessions
#endif #endif
} }
ICMP_Packet icmp(&icmpResponseBuffer[offset], length); // Rely on implicit object creation for u8
ICMP_Packet icmp(reinterpret_cast<u8*>(&icmpResponseBuffer[offset]), length);
PayloadPtr* icmpPayload = static_cast<PayloadPtr*>(icmp.GetPayload()); PayloadPtr* icmpPayload = static_cast<PayloadPtr*>(icmp.GetPayload());
result.type = icmp.type; result.type = icmp.type;
result.code = icmp.code; result.code = icmp.code;
sockaddr_in* sockaddr = (sockaddr_in*)&endpoint; result.address = std::bit_cast<IP_Address>(endpoint.sin_addr);
result.address = *(IP_Address*)&sockaddr->sin_addr;
if (icmp.type == 0) if (icmp.type == 0)
{ {
@ -504,15 +523,15 @@ namespace Sessions
{ {
#ifdef _WIN32 #ifdef _WIN32
//Documentation is incorrect, IP_OPTION_INFORMATION is to be used regardless of platform //Documentation is incorrect, IP_OPTION_INFORMATION is to be used regardless of platform
IP_OPTION_INFORMATION ipInfo{0}; IP_OPTION_INFORMATION ipInfo{};
ipInfo.Ttl = parTimeToLive; ipInfo.Ttl = parTimeToLive;
DWORD ret; DWORD ret;
if (parAdapterIP.integer != 0) if (parAdapterIP.integer != 0)
ret = IcmpSendEcho2Ex(icmpFile, icmpEvent, nullptr, nullptr, parAdapterIP.integer, parDestIP.integer, parPayload->data, parPayload->GetLength(), &ipInfo, icmpResponseBuffer.get(), icmpResponseBufferLen, ret = IcmpSendEcho2Ex(icmpFile, icmpEvent, nullptr, nullptr, parAdapterIP.integer, parDestIP.integer, parPayload->data, parPayload->GetLength(), &ipInfo, icmpResponseBuffer.get(), icmpResponseBufferLen,
(DWORD)std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count()); static_cast<DWORD>(std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count()));
else else
ret = IcmpSendEcho2(icmpFile, icmpEvent, nullptr, nullptr, parDestIP.integer, parPayload->data, parPayload->GetLength(), &ipInfo, icmpResponseBuffer.get(), icmpResponseBufferLen, ret = IcmpSendEcho2(icmpFile, icmpEvent, nullptr, nullptr, parDestIP.integer, parPayload->data, parPayload->GetLength(), &ipInfo, icmpResponseBuffer.get(), icmpResponseBufferLen,
(DWORD)std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count()); static_cast<DWORD>(std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count()));
//Documentation states that IcmpSendEcho2 returns ERROR_IO_PENDING //Documentation states that IcmpSendEcho2 returns ERROR_IO_PENDING
//However, it actually returns zero, with the error set to ERROR_IO_PENDING //However, it actually returns zero, with the error set to ERROR_IO_PENDING
@ -539,11 +558,11 @@ namespace Sessions
if (parAdapterIP.integer != 0) if (parAdapterIP.integer != 0)
{ {
sockaddr_in endpoint{0}; sockaddr_in endpoint{};
endpoint.sin_family = AF_INET; endpoint.sin_family = AF_INET;
*(IP_Address*)&endpoint.sin_addr = parAdapterIP; endpoint.sin_addr = std::bit_cast<in_addr>(parAdapterIP);
if (bind(icmpSocket, (const sockaddr*)&endpoint, sizeof(endpoint)) == -1) if (bind(icmpSocket, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint)) == -1)
{ {
Console.Error("DEV9: ICMP: Failed to bind socket. Error: %d", errno); Console.Error("DEV9: ICMP: Failed to bind socket. Error: %d", errno);
::close(icmpSocket); ::close(icmpSocket);
@ -554,7 +573,7 @@ namespace Sessions
#if defined(ICMP_SOCKETS_LINUX) #if defined(ICMP_SOCKETS_LINUX)
int value = 1; int value = 1;
if (setsockopt(icmpSocket, SOL_IP, IP_RECVERR, (char*)&value, sizeof(value))) if (setsockopt(icmpSocket, SOL_IP, IP_RECVERR, reinterpret_cast<const char*>(&value), sizeof(value)))
{ {
Console.Error("DEV9: ICMP: Failed to setsockopt IP_RECVERR. Error: %d", errno); Console.Error("DEV9: ICMP: Failed to setsockopt IP_RECVERR. Error: %d", errno);
::close(icmpSocket); ::close(icmpSocket);
@ -564,7 +583,7 @@ namespace Sessions
#endif #endif
// TTL (Note multicast & regular ttl are separate) // TTL (Note multicast & regular ttl are separate)
if (setsockopt(icmpSocket, IPPROTO_IP, IP_TTL, (const char*)&parTimeToLive, sizeof(parTimeToLive)) == -1) if (setsockopt(icmpSocket, IPPROTO_IP, IP_TTL, reinterpret_cast<const char*>(&parTimeToLive), sizeof(parTimeToLive)) == -1)
{ {
Console.Error("DEV9: ICMP: Failed to set TTL. Error: %d", errno); Console.Error("DEV9: ICMP: Failed to set TTL. Error: %d", errno);
::close(icmpSocket); ::close(icmpSocket);
@ -576,9 +595,9 @@ namespace Sessions
if (icmpConnectionKind == PingType::ICMP) if (icmpConnectionKind == PingType::ICMP)
{ {
//We get assigned a port //We get assigned a port
sockaddr_in endpoint{0}; sockaddr_in endpoint{};
socklen_t endpointsize = sizeof(endpoint); socklen_t endpointsize = sizeof(endpoint);
if (getsockname(icmpSocket, (sockaddr*)&endpoint, &endpointsize) == -1) if (getsockname(icmpSocket, reinterpret_cast<sockaddr*>(&endpoint), &endpointsize) == -1)
{ {
Console.Error("DEV9: ICMP: Failed to get id. Error: %d", errno); Console.Error("DEV9: ICMP: Failed to get id. Error: %d", errno);
::close(icmpSocket); ::close(icmpSocket);
@ -592,7 +611,7 @@ namespace Sessions
#endif #endif
{ {
//Use time, in ms, as id //Use time, in ms, as id
icmpId = (u16)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); icmpId = static_cast<u16>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
} }
ICMP_Packet icmp(parPayload->Clone()); ICMP_Packet icmp(parPayload->Clone());
@ -609,11 +628,11 @@ namespace Sessions
int offset = 0; int offset = 0;
icmp.WriteBytes(buffer.get(), &offset); icmp.WriteBytes(buffer.get(), &offset);
sockaddr_in endpoint{0}; sockaddr_in endpoint{};
endpoint.sin_family = AF_INET; endpoint.sin_family = AF_INET;
*(IP_Address*)&endpoint.sin_addr.s_addr = parDestIP; endpoint.sin_addr = std::bit_cast<in_addr>(parDestIP);
const int ret = sendto(icmpSocket, buffer.get(), icmp.GetLength(), 0, (const sockaddr*)&endpoint, sizeof(endpoint)); const int ret = sendto(icmpSocket, buffer.get(), icmp.GetLength(), 0, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint));
if (ret == -1) if (ret == -1)
{ {
Console.Error("DEV9: ICMP: Send Error %d", errno); Console.Error("DEV9: ICMP: Send Error %d", errno);
@ -782,8 +801,8 @@ namespace Sessions
u16 ps2Port = 0; u16 ps2Port = 0;
switch (prot) switch (prot)
{ {
case (u8)IP_Type::TCP: case static_cast<u8>(IP_Type::TCP):
case (u8)IP_Type::UDP: case static_cast<u8>(IP_Type::UDP):
//Read ports directly from the payload //Read ports directly from the payload
//both UDP and TCP have the same locations for ports //both UDP and TCP have the same locations for ports
IP_PayloadPtr* payload = static_cast<IP_PayloadPtr*>(retPkt->GetPayload()); IP_PayloadPtr* payload = static_cast<IP_PayloadPtr*>(retPkt->GetPayload());

View File

@ -57,7 +57,7 @@ namespace Sessions
//Return buffers //Return buffers
PingResult result{}; PingResult result{};
int icmpResponseBufferLen{0}; int icmpResponseBufferLen{0};
std::unique_ptr<u8[]> icmpResponseBuffer; std::unique_ptr<std::byte[]> icmpResponseBuffer;
public: public:
Ping(int requestSize); Ping(int requestSize);