IcmpClientImpl.cpp 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #include "IcmpClientImpl.h"
  2. #include <chrono>
  3. namespace Network {
  4. IcmpClientImpl::IcmpClientImpl() :
  5. m_socket(m_ioContext, asio::ip::icmp::v4()),
  6. m_done(false)
  7. {
  8. StartReceive();
  9. m_thread = std::thread([&] { m_ioContext.run(); });
  10. #ifdef __linux__
  11. pthread_setname_np(m_thread.native_handle(), "IcmpClientImpl");
  12. #endif
  13. }
  14. IcmpClientImpl::~IcmpClientImpl()
  15. {
  16. m_ioContext.stop();
  17. m_thread.join();
  18. }
  19. bool IcmpClientImpl::Ping(const std::string& targetAddress)
  20. {
  21. m_done = false;
  22. SendEchoRequest(asio::ip::icmp::endpoint(asio::ip::address::from_string(targetAddress), 0), std::string());
  23. std::unique_lock<std::mutex> lock(m_mutex);
  24. if (m_condition.wait_for(lock, std::chrono::seconds(3), [&] { return m_done; }))
  25. return true;
  26. return false;
  27. }
  28. void IcmpClientImpl::SendEchoRequest(const asio::ip::icmp::endpoint& targetEndpoint, const std::string& data)
  29. {
  30. Internal::IcmpHeader echoRequest;
  31. echoRequest.type(Internal::IcmpHeader::echo_request);
  32. echoRequest.code(0);
  33. echoRequest.identifier(GetIdentifier());
  34. echoRequest.sequence_number(0);
  35. Internal::ComputeChecksum(echoRequest, data.begin(), data.end());
  36. asio::streambuf requestBuffer;
  37. std::ostream os(&requestBuffer);
  38. os << echoRequest << data;
  39. m_socket.send_to(requestBuffer.data(), targetEndpoint);
  40. }
  41. void IcmpClientImpl::StartReceive()
  42. {
  43. m_replyBuffer.consume(m_replyBuffer.size());
  44. m_socket.async_receive(m_replyBuffer.prepare(65536), std::bind(&IcmpClientImpl::HandleReceive, this, std::placeholders::_1, std::placeholders::_2));
  45. }
  46. void IcmpClientImpl::HandleReceive(const asio::error_code& error, std::size_t length)
  47. {
  48. m_replyBuffer.commit(length);
  49. std::istream is(&m_replyBuffer);
  50. Internal::Ipv4Header ipv4Header;
  51. Internal::IcmpHeader icmpHeader;
  52. is >> ipv4Header >> icmpHeader;
  53. if (is && icmpHeader.type() == Internal::IcmpHeader::echo_reply
  54. && icmpHeader.identifier() == GetIdentifier()
  55. && icmpHeader.sequence_number() == 0)
  56. {
  57. m_done = true;
  58. m_condition.notify_all();
  59. }
  60. StartReceive();
  61. }
  62. unsigned short IcmpClientImpl::GetIdentifier()
  63. {
  64. return static_cast<unsigned short>(::getpid());
  65. }
  66. } // namespace Network