typename PortState::Enum GetPortState(const Ports::value_type port) { boost::recursive_mutex::scoped_lock lock(m_PortsMutex); PortState::Enum& state = m_EnabledPorts[port]; if (state == PortState::Unknown) { state = PortState::Pending; const std::size_t service = GetNextService(); const SocketPtr socket(new TCPSocket(GetService(service))); const TimerPtr timer(new Timer(GetService(service))); socket->async_connect( Tcp::endpoint(Address(INVALID_IP), port), boost::bind( &PingerImpl::GetPortStateCallback, this, ba::placeholders::error, port, socket, timer ) ); timer->expires_from_now(boost::posix_time::seconds(1)); timer->async_wait(boost::bind(&PingerImpl::CancelConnect, this, socket)); } return state; } void GetPortStateCallback(const boost::system::error_code& e, const Ports::value_type port, const SocketPtr, const TimerPtr) { boost::recursive_mutex::scoped_lock lock(m_PortsMutex); m_EnabledPorts[port] = e ? PortState::Enabled : PortState::Disabled; } void CancelConnect(const SocketPtr socket) { boost::system::error_code e; socket->close(e); }
virtual void StartTCPPing(std::size_t timeout) override { boost::mutex::scoped_lock lock(m_DataMutex); if (PingerLogic::IsCompleted() || m_Ports2Ping.empty()) return; Ports::const_iterator it = m_Ports2Ping.begin(); const Ports::const_iterator itEnd = m_Ports2Ping.end(); for (; it != itEnd; ) { const PortState::Enum state = m_Owner.GetPortState(*it); // — if (state == PortState::Disabled) { it = m_Ports2Ping.erase(it); continue; } else if (state == PortState::Pending) // , { ++it; continue; } if (m_Owner.CanAddSocket()) // , { PingPort(*it); it = m_Ports2Ping.erase(it); if (m_Ports2Ping.empty()) break; } else { break; } } if (!m_Ports2Ping.empty()) { // , m_RestartPingTimer.expires_from_now(boost::posix_time::milliseconds(DELAY_IF_MAX_SOCKETS_REACHED)); m_RestartPingTimer.async_wait(boost::bind( &Ping::StartTCPPing, shared_from_this(), timeout )); } // m_StartTime = boost::posix_time::microsec_clock().local_time(); m_PingTimer.expires_from_now(boost::posix_time::seconds(timeout)); m_PingTimer.async_wait(boost::bind(&Ping::OnTimeout, shared_from_this(), ba::placeholders::error, timeout)); }
void PingPort(const Ports::value_type port) { const Tcp::endpoint ep(m_Address, port); const SocketPtr socket(new TCPSocket(m_Owner.GetService(m_ServiceIndex))); m_Sockets.push_back(socket); m_Owner.OnSocketCreated(); // socket->async_connect(ep, boost::bind( &Ping::TCPConnectCallback, shared_from_this(), boost::asio::placeholders::error, socket )); }
void TCPConnectCallback(const boost::system::error_code& e, const SocketPtr socket) { m_Owner.OnSocketClosed(); // if (!e) TCPPingSucceeded(socket); else TCPPingFailed(socket); }
void TCPPingSucceeded(const SocketPtr socket) { const boost::posix_time::time_duration td(boost::posix_time::microsec_clock::local_time() - m_StartTime); boost::system::error_code error; socket->shutdown(TCPSocket::shutdown_both, error); // pinged successfully, close all opened sockets boost::mutex::scoped_lock lock(m_DataMutex); CloseSockets(); PingerLogic::OnTcpSucceeded(static_cast<std::size_t>(td.total_milliseconds())); } void TCPPingFailed(const SocketPtr socket) { // ping on this port fails, close this socket boost::system::error_code error; socket->close(error); boost::mutex::scoped_lock lock(m_DataMutex); const std::vector<SocketPtr>::const_iterator it = std::remove( m_Sockets.begin(), m_Sockets.end(), socket ); m_Sockets.erase(it, m_Sockets.end()); if (m_Sockets.empty()) m_PingTimer.cancel(); // all ports failed, cancel timer }
virtual void StartResolveIpByName(const std::string& name) override { const typename Resolver::query query(Tcp::v4(), name, ""); m_Resolver.async_resolve(query, boost::bind( &Ping::ResolveIpCallback, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::iterator )); } virtual void StartResolveNameByIp(unsigned long ip) override { const Tcp::endpoint ep(Address(ip), 0); m_Resolver.async_resolve(ep, boost::bind( &Ping::ResolveFQDNCallback, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::iterator )); }
class Ping : public boost::enable_shared_from_this<Ping>, public PingerLogic
//! Init ports virtual void InitPorts(const std::string& ports) = 0; //! Resolve ip virtual bool ResolveIP(const std::string& name) = 0; //! Start resolve callback virtual void StartResolveNameByIp(unsigned long ip) = 0; //! Start resolve callback virtual void StartResolveIpByName(const std::string& name) = 0; //! Start TCP ping callback virtual void StartTCPPing(std::size_t timeout) = 0; //! Start ICMP ping virtual void StartICMPPing(std::size_t timeout) = 0; //! Start get NetBios name virtual void StartGetNetBiosName(const std::string& name) = 0; //! Cancel all pending operations virtual void Cancel() = 0;
//! On ping start void OnStart() { InitPorts(m_Request.m_Ports); const bool ipResolved = ResolveIP(m_Request.m_HostName); if (!ipResolved) StartResolveIpByName(m_Request.m_HostName); } //! On ip resolved void OnIpResolved(const unsigned long ip) { boost::recursive_mutex::scoped_lock lock(m_Mutex); m_Result.m_ResolvedIP = ip; if (m_Request.m_Flags & SCANMGR_PING_RESOLVE_HOSTNAME) { m_HasPendingResolve = true; StartResolveNameByIp(ip); } if (m_Request.m_Flags & SCANMGR_PING_ICMP) { // if tcp ping needed it will be invoked after icmp completes StartICMPPing(m_Request.m_TimeoutSec); return; } if (m_Request.m_Flags & SCANMGR_PING_TCP) { // in case of tcp ping only StartTCPPing(m_Request.m_TimeoutSec); } }
Source: https://habr.com/ru/post/156795/
All Articles