| 501 | } |
| 502 | |
| 503 | bool ICMP_Session::Ping::Send(IP_Address parAdapterIP, IP_Address parDestIP, int parTimeToLive, PayloadPtr* parPayload) |
| 504 | { |
| 505 | #ifdef _WIN32 |
| 506 | // Documentation is incorrect, IP_OPTION_INFORMATION is to be used regardless of platform |
| 507 | IP_OPTION_INFORMATION ipInfo{}; |
| 508 | ipInfo.Ttl = parTimeToLive; |
| 509 | DWORD ret; |
| 510 | if (parAdapterIP.integer != 0) |
| 511 | ret = IcmpSendEcho2Ex(icmpFile, icmpEvent, nullptr, nullptr, parAdapterIP.integer, parDestIP.integer, const_cast<u8*>(parPayload->data), parPayload->GetLength(), &ipInfo, icmpResponseBuffer.get(), icmpResponseBufferLen, |
| 512 | static_cast<DWORD>(std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count())); |
| 513 | else |
| 514 | ret = IcmpSendEcho2(icmpFile, icmpEvent, nullptr, nullptr, parDestIP.integer, const_cast<u8*>(parPayload->data), parPayload->GetLength(), &ipInfo, icmpResponseBuffer.get(), icmpResponseBufferLen, |
| 515 | static_cast<DWORD>(std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count())); |
| 516 | |
| 517 | // Documentation states that IcmpSendEcho2 returns ERROR_IO_PENDING |
| 518 | // However, it actually returns zero, with the error set to ERROR_IO_PENDING |
| 519 | if (ret == 0) |
| 520 | ret = GetLastError(); |
| 521 | |
| 522 | if (ret != ERROR_IO_PENDING) |
| 523 | { |
| 524 | Console.Error("DEV9: ICMP: Failed to send echo, %d", GetLastError()); |
| 525 | return false; |
| 526 | } |
| 527 | |
| 528 | return true; |
| 529 | #elif defined(__POSIX__) |
| 530 | switch (icmpConnectionKind) |
| 531 | { |
| 532 | case (PingType::ICMP): |
| 533 | case (PingType::RAW): |
| 534 | { |
| 535 | icmpDeathClockStart = std::chrono::steady_clock::now(); |
| 536 | |
| 537 | // Broadcast and multicast might need extra setsockopts calls |
| 538 | // I don't think any game will do a broadcast/multicast ping |
| 539 | |
| 540 | if (parAdapterIP.integer != 0) |
| 541 | { |
| 542 | sockaddr_in endpoint{}; |
| 543 | endpoint.sin_family = AF_INET; |
| 544 | endpoint.sin_addr = std::bit_cast<in_addr>(parAdapterIP); |
| 545 | |
| 546 | if (bind(icmpSocket, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint)) == -1) |
| 547 | { |
| 548 | Console.Error("DEV9: ICMP: Failed to bind socket. Error: %d", errno); |
| 549 | ::close(icmpSocket); |
| 550 | icmpSocket = -1; |
| 551 | return false; |
| 552 | } |
| 553 | } |
| 554 | |
| 555 | #if defined(ICMP_SOCKETS_LINUX) |
| 556 | const int value = 1; |
| 557 | if (setsockopt(icmpSocket, SOL_IP, IP_RECVERR, reinterpret_cast<const char*>(&value), sizeof(value))) |
| 558 | { |
| 559 | Console.Error("DEV9: ICMP: Failed to setsockopt IP_RECVERR. Error: %d", errno); |
| 560 | ::close(icmpSocket); |
nothing calls this directly
no test coverage detected