Files
Network/Network/Dns/MulticastDnsClientImpl.cpp
T

147 lines
3.3 KiB
C++

#include "MulticastDnsClientImpl.h"
#include "MalformedPacket.h"
#include "Packet.h"
#include <Logging.h>
namespace Network {
namespace Dns {
MulticastDnsClientImpl::MulticastDnsClientImpl(std::function<void(const std::vector<ResourceRecordImpl>&)> callback) :
m_timer(m_ioService),
m_responseBuffer(1024),
m_socket(m_ioService, asio::ip::udp::v4()),
m_multicastEndpoint(asio::ip::address::from_string("224.0.0.251"), 5353),
m_callback(callback)
{
m_socket.set_option(asio::socket_base::reuse_address(true));
m_socket.set_option(asio::ip::multicast::join_group(m_multicastEndpoint.address()));
m_socket.set_option(asio::ip::multicast::hops(255));
m_socket.bind(asio::ip::udp::endpoint(asio::ip::udp::v4(), 5353));
m_thread = std::thread([&] { m_ioService.run(); });
}
MulticastDnsClientImpl::~MulticastDnsClientImpl()
{
m_ioService.stop();
m_thread.join();
}
void MulticastDnsClientImpl::Query(const QueryImpl& query)
{
m_query = query;
m_iterations = 3;
SendQuery();
}
void MulticastDnsClientImpl::SetTimer(int milliseconds)
{
m_timer.cancel();
m_timer.expires_from_now(std::chrono::milliseconds(milliseconds));
}
void MulticastDnsClientImpl::SendQuery()
{
if (m_iterations == 0)
return;
m_iterations--;
Packet packet;
packet.AddQuery(m_query);
auto data = std::make_shared<Data>(packet.GetData());
m_socket.async_send_to(
asio::buffer(data->GetPtr(), data->GetLength()),
m_multicastEndpoint,
std::bind(&MulticastDnsClientImpl::HandleQuerySent, this,
std::placeholders::_1,
data
)
);
}
void MulticastDnsClientImpl::HandleQuerySent(const asio::error_code & error, std::shared_ptr<Data> data)
{
if (error == asio::error::operation_aborted)
{
SendQuery();
}
else if (error)
{
std::stringstream ss;
ss << "MulticastDnsClientImpl::HandleQuerySent: " << error.message();
Logging::Log(Logging::Severity::Error, ss.str());
}
else
{
SetTimer(1000);
m_timer.async_wait(std::bind(
&MulticastDnsClientImpl::HandleQueryTimeout, this,
std::placeholders::_1
));
ReceiveQuery();
}
}
void MulticastDnsClientImpl::ReceiveQuery()
{
m_socket.async_receive_from(
asio::buffer(m_responseBuffer),
m_receiveEndpoint,
std::bind(&MulticastDnsClientImpl::HandleQueryResponse, this,
std::placeholders::_1,
std::placeholders::_2
)
);
}
void MulticastDnsClientImpl::HandleQueryResponse(const asio::error_code & error, std::size_t size)
{
if (error == asio::error::operation_aborted)
{
SendQuery();
}
else if (error)
{
std::stringstream ss;
ss << "MulticastDnsClientImpl::HandleQueryResponse: " << error.message();
Logging::Log(Logging::Severity::Error, ss.str());
}
else
{
try
{
Packet packet(DataReader(m_responseBuffer.data(), size), 0);
if (packet.GetQuery())
m_callback(packet.GetAnswers());
}
catch(MalformedPacket& mp)
{
}
ReceiveQuery();
}
}
void MulticastDnsClientImpl::HandleQueryTimeout(const asio::error_code & error)
{
if (error == asio::error::operation_aborted)
{
}
else if (error)
{
std::stringstream ss;
ss << "MulticastDnsClientImpl::HandleQueryTimeout: " << error.message();
Logging::Log(Logging::Severity::Error, ss.str());
}
else
{
m_socket.cancel();
}
}
} // namespace Dns
} // namespace Network