PImpl
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "Makefiles"]
|
||||||
|
path = Makefiles
|
||||||
|
url = https://gogs.dierkse.nl/JDierkse/Makefiles.git
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../Logging
|
||||||
Submodule
+1
Submodule Makefiles added at d82c8a2047
@@ -0,0 +1,12 @@
|
|||||||
|
#include "BroadcastClientImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
BroadcastClientImpl::BroadcastClientImpl(const std::string& listenAddress, int broadcastPort, std::function<void(const std::string&)> callback) :
|
||||||
|
UdpClientImpl(listenAddress, "255.255.255.255", broadcastPort, callback)
|
||||||
|
{
|
||||||
|
Receive();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef NETWORK_BROADCASTCLIENTIMPL_H
|
||||||
|
#define NETWORK_BROADCASTCLIENTIMPL_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include "UdpClientImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
class BroadcastClientImpl : public UdpClientImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BroadcastClientImpl(const std::string& listenAddress, int broadcastPort, std::function<void(const std::string&)> callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_BROADCASTCLIENTIMPL_H
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#include "BroadcastServerImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
BroadcastServerImpl::BroadcastServerImpl(const std::string& listenAddress, int broadcastPort, std::function<void(const std::string&)> callback) :
|
||||||
|
UdpClientImpl(listenAddress, "255.255.255.255", broadcastPort, callback)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef NETWORK_BROADCASTSERVER_IMPL_H
|
||||||
|
#define NETWORK_BROADCASTSERVER_IMPL_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include "UdpClientImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
class BroadcastServerImpl : public UdpClientImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BroadcastServerImpl(const std::string& listenAddress, int broadcastPort, std::function<void(const std::string&)> callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_BROADCASTSERVERIMPL_H
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
#include <chrono>
|
||||||
|
#include "IcmpClientImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
IcmpClientImpl::IcmpClientImpl() :
|
||||||
|
m_socket(m_ioContext, asio::ip::icmp::v4()),
|
||||||
|
m_done(false)
|
||||||
|
{
|
||||||
|
StartReceive();
|
||||||
|
m_thread = std::thread([&] { m_ioContext.run(); });
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
pthread_setname_np(m_thread.native_handle(), "IcmpClientImpl");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
IcmpClientImpl::~IcmpClientImpl()
|
||||||
|
{
|
||||||
|
m_ioContext.stop();
|
||||||
|
m_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IcmpClientImpl::Ping(const std::string& targetAddress)
|
||||||
|
{
|
||||||
|
m_done = false;
|
||||||
|
|
||||||
|
SendEchoRequest(asio::ip::icmp::endpoint(asio::ip::address::from_string(targetAddress), 0), std::string());
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
if (m_condition.wait_for(lock, std::chrono::seconds(3), [&] { return m_done; }))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IcmpClientImpl::SendEchoRequest(const asio::ip::icmp::endpoint& targetEndpoint, const std::string& data)
|
||||||
|
{
|
||||||
|
Internal::IcmpHeader echoRequest;
|
||||||
|
echoRequest.type(Internal::IcmpHeader::echo_request);
|
||||||
|
echoRequest.code(0);
|
||||||
|
echoRequest.identifier(GetIdentifier());
|
||||||
|
echoRequest.sequence_number(0);
|
||||||
|
Internal::ComputeChecksum(echoRequest, data.begin(), data.end());
|
||||||
|
|
||||||
|
asio::streambuf requestBuffer;
|
||||||
|
std::ostream os(&requestBuffer);
|
||||||
|
os << echoRequest << data;
|
||||||
|
|
||||||
|
m_socket.send_to(requestBuffer.data(), targetEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IcmpClientImpl::StartReceive()
|
||||||
|
{
|
||||||
|
m_replyBuffer.consume(m_replyBuffer.size());
|
||||||
|
m_socket.async_receive(m_replyBuffer.prepare(65536), std::bind(&IcmpClientImpl::HandleReceive, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void IcmpClientImpl::HandleReceive(const asio::error_code& error, std::size_t length)
|
||||||
|
{
|
||||||
|
m_replyBuffer.commit(length);
|
||||||
|
|
||||||
|
std::istream is(&m_replyBuffer);
|
||||||
|
Internal::Ipv4Header ipv4Header;
|
||||||
|
Internal::IcmpHeader icmpHeader;
|
||||||
|
is >> ipv4Header >> icmpHeader;
|
||||||
|
|
||||||
|
if (is && icmpHeader.type() == Internal::IcmpHeader::echo_reply
|
||||||
|
&& icmpHeader.identifier() == GetIdentifier()
|
||||||
|
&& icmpHeader.sequence_number() == 0)
|
||||||
|
{
|
||||||
|
m_done = true;
|
||||||
|
m_condition.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
StartReceive();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short IcmpClientImpl::GetIdentifier()
|
||||||
|
{
|
||||||
|
return static_cast<unsigned short>(::getpid());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef NETWORK_ICMPCLIENTIMPL_H
|
||||||
|
#define NETWORK_ICMPCLIENTIMPL_H
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
#include "asio.h"
|
||||||
|
#include "Ipv4Header.h"
|
||||||
|
#include "IcmpHeader.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
class IcmpClientImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IcmpClientImpl();
|
||||||
|
~IcmpClientImpl();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool Ping(const std::string& targetAddress);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SendEchoRequest(const asio::ip::icmp::endpoint& targetEndpoint, const std::string& data);
|
||||||
|
void StartReceive();
|
||||||
|
void HandleReceive(const asio::error_code& error, std::size_t length);
|
||||||
|
unsigned short GetIdentifier();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::thread m_thread;
|
||||||
|
std::mutex m_mutex;
|
||||||
|
std::condition_variable m_condition;
|
||||||
|
|
||||||
|
asio::io_context m_ioContext;
|
||||||
|
asio::ip::icmp::socket m_socket;
|
||||||
|
asio::streambuf m_replyBuffer;
|
||||||
|
|
||||||
|
bool m_done;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_ICMPCLIENTIMPL_H
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
#ifndef ICMPHEADER_H
|
||||||
|
#define ICMPHEADER_H
|
||||||
|
|
||||||
|
#include <istream>
|
||||||
|
#include "asio.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class IcmpHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
echo_reply = 0,
|
||||||
|
destination_unreachable = 3,
|
||||||
|
source_quench = 4,
|
||||||
|
redirect = 5,
|
||||||
|
echo_request = 8,
|
||||||
|
time_exceeded = 11,
|
||||||
|
parameter_problem = 12,
|
||||||
|
timestamp_request = 13,
|
||||||
|
timestamp_reply = 14,
|
||||||
|
info_request = 15,
|
||||||
|
info_reply = 16,
|
||||||
|
address_request = 17,
|
||||||
|
address_reply = 18
|
||||||
|
};
|
||||||
|
|
||||||
|
IcmpHeader() { std::fill(rep_, rep_ + sizeof(rep_), 0); }
|
||||||
|
|
||||||
|
unsigned char type() const { return rep_[0]; }
|
||||||
|
unsigned char code() const { return rep_[1]; }
|
||||||
|
unsigned short checksum() const { return decode(2, 3); }
|
||||||
|
unsigned short identifier() const { return decode(4, 5); }
|
||||||
|
unsigned short sequence_number() const { return decode(6, 7); }
|
||||||
|
|
||||||
|
void type(unsigned char n) { rep_[0] = n; }
|
||||||
|
void code(unsigned char n) { rep_[1] = n; }
|
||||||
|
void checksum(unsigned short n) { encode(2, 3, n); }
|
||||||
|
void identifier(unsigned short n) { encode(4, 5, n); }
|
||||||
|
void sequence_number(unsigned short n) { encode(6, 7, n); }
|
||||||
|
|
||||||
|
friend std::istream& operator>>(std::istream& is, IcmpHeader& header)
|
||||||
|
{ return is.read(reinterpret_cast<char*>(header.rep_), 8); }
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const IcmpHeader& header)
|
||||||
|
{ return os.write(reinterpret_cast<const char*>(header.rep_), 8); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned short decode(int a, int b) const
|
||||||
|
{ return (rep_[a] << 8) + rep_[b]; }
|
||||||
|
|
||||||
|
void encode(int a, int b, unsigned short n)
|
||||||
|
{
|
||||||
|
rep_[a] = static_cast<unsigned char>(n >> 8);
|
||||||
|
rep_[b] = static_cast<unsigned char>(n & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char rep_[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
void ComputeChecksum(IcmpHeader& header,
|
||||||
|
Iterator body_begin, Iterator body_end)
|
||||||
|
{
|
||||||
|
unsigned int sum = (header.type() << 8) + header.code()
|
||||||
|
+ header.identifier() + header.sequence_number();
|
||||||
|
|
||||||
|
Iterator body_iter = body_begin;
|
||||||
|
while (body_iter != body_end)
|
||||||
|
{
|
||||||
|
sum += (static_cast<unsigned char>(*body_iter++) << 8);
|
||||||
|
if (body_iter != body_end)
|
||||||
|
sum += static_cast<unsigned char>(*body_iter++);
|
||||||
|
}
|
||||||
|
|
||||||
|
sum = (sum >> 16) + (sum & 0xFFFF);
|
||||||
|
sum += (sum >> 16);
|
||||||
|
header.checksum(static_cast<unsigned short>(~sum));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // ICMPHEADER_H
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef IPV4HEADER_H
|
||||||
|
#define IPV4HEADER_H
|
||||||
|
|
||||||
|
#include <istream>
|
||||||
|
#include "asio.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class Ipv4Header
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Ipv4Header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }
|
||||||
|
|
||||||
|
unsigned char version() const { return (rep_[0] >> 4) & 0xF; }
|
||||||
|
unsigned short header_length() const { return (rep_[0] & 0xF) * 4; }
|
||||||
|
unsigned char type_of_service() const { return rep_[1]; }
|
||||||
|
unsigned short total_length() const { return decode(2, 3); }
|
||||||
|
unsigned short identification() const { return decode(4, 5); }
|
||||||
|
bool dont_fragment() const { return (rep_[6] & 0x40) != 0; }
|
||||||
|
bool more_fragments() const { return (rep_[6] & 0x20) != 0; }
|
||||||
|
unsigned short fragment_offset() const { return decode(6, 7) & 0x1FFF; }
|
||||||
|
unsigned int time_to_live() const { return rep_[8]; }
|
||||||
|
unsigned char protocol() const { return rep_[9]; }
|
||||||
|
unsigned short header_checksum() const { return decode(10, 11); }
|
||||||
|
|
||||||
|
asio::ip::address_v4 source_address() const
|
||||||
|
{
|
||||||
|
asio::ip::address_v4::bytes_type bytes = { { rep_[12], rep_[13], rep_[14], rep_[15] } };
|
||||||
|
return asio::ip::address_v4(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
asio::ip::address_v4 destination_address() const
|
||||||
|
{
|
||||||
|
asio::ip::address_v4::bytes_type bytes = { { rep_[16], rep_[17], rep_[18], rep_[19] } };
|
||||||
|
return asio::ip::address_v4(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend std::istream& operator>>(std::istream& is, Ipv4Header& header)
|
||||||
|
{
|
||||||
|
is.read(reinterpret_cast<char*>(header.rep_), 20);
|
||||||
|
if (header.version() != 4)
|
||||||
|
is.setstate(std::ios::failbit);
|
||||||
|
std::streamsize options_length = header.header_length() - 20;
|
||||||
|
if (options_length < 0 || options_length > 40)
|
||||||
|
is.setstate(std::ios::failbit);
|
||||||
|
else
|
||||||
|
is.read(reinterpret_cast<char*>(header.rep_) + 20, options_length);
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned short decode(int a, int b) const
|
||||||
|
{ return (rep_[a] << 8) + rep_[b]; }
|
||||||
|
|
||||||
|
unsigned char rep_[60];
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // IPV4HEADER_H
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#include "MulticastClientImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
MulticastClientImpl::MulticastClientImpl(const std::string& listenAddress, const std::string& multicastAddress, int multicastPort, std::function<void(const std::string&)> callback) :
|
||||||
|
UdpClientImpl(listenAddress, multicastAddress, multicastPort, callback)
|
||||||
|
{
|
||||||
|
EnableMulticast();
|
||||||
|
Receive();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef NETWORK_MULTICASTCLIENTIMPL_H
|
||||||
|
#define NETWORK_MULTICASTCLIENTIMPL_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include "UdpClientImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
class MulticastClientImpl : public UdpClientImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MulticastClientImpl(const std::string& listenAddress, const std::string& multicastAddress, int multicastPort, std::function<void(const std::string&)> callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_MULTICASTCLIENTIMPL_H
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
#include "Logging.h"
|
||||||
|
#include "UdpClientImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
UdpClientImpl::UdpClientImpl(const std::string& listenAddress, const std::string& targetAddress, int targetPort, std::function<void(const std::string&)> callback) :
|
||||||
|
m_bufferLength(1024),
|
||||||
|
m_deadline(m_ioServiceAnswer),
|
||||||
|
m_listenAddress(asio::ip::address::from_string(listenAddress)),
|
||||||
|
m_targetAddress(asio::ip::address::from_string(targetAddress)),
|
||||||
|
m_targetPort(targetPort),
|
||||||
|
m_receiveSocket(m_ioService),
|
||||||
|
m_answerSocket(m_ioServiceAnswer),
|
||||||
|
m_targetEndpoint(m_targetAddress, m_targetPort),
|
||||||
|
m_callback(callback)
|
||||||
|
{
|
||||||
|
m_thread = std::thread([&] { m_ioService.run(); });
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
pthread_setname_np(m_thread.native_handle(), "UdpClientImpl");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_socketReceiveData.reserve(m_bufferLength);
|
||||||
|
m_socketAnswerData.reserve(m_bufferLength);
|
||||||
|
|
||||||
|
asio::ip::udp::endpoint listenEndpoint(m_targetAddress, m_targetPort);
|
||||||
|
|
||||||
|
m_receiveSocket.open(listenEndpoint.protocol());
|
||||||
|
m_receiveSocket.set_option(asio::ip::udp::socket::reuse_address(true));
|
||||||
|
m_receiveSocket.bind(listenEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
UdpClientImpl::~UdpClientImpl()
|
||||||
|
{
|
||||||
|
m_ioService.stop();
|
||||||
|
m_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdpClientImpl::Receive()
|
||||||
|
{
|
||||||
|
ReceiveSocket();
|
||||||
|
|
||||||
|
m_deadline.expires_at(asio::system_timer::time_point(std::chrono::system_clock::duration::max()));
|
||||||
|
CheckDeadline();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string UdpClientImpl::Send(const std::string& data, int sourcePort)
|
||||||
|
{
|
||||||
|
asio::ip::udp::socket sendSocket(m_ioService);
|
||||||
|
sendSocket.open(asio::ip::udp::v4());
|
||||||
|
|
||||||
|
sendSocket.set_option(asio::ip::udp::socket::reuse_address(true));
|
||||||
|
|
||||||
|
if (sourcePort != 0)
|
||||||
|
{
|
||||||
|
asio::ip::udp::endpoint sendEndpoint(m_listenAddress, sourcePort);
|
||||||
|
sendSocket.bind(sendEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sendSocket.connect(m_targetEndpoint);
|
||||||
|
|
||||||
|
asio::ip::udp::endpoint listenEndpoint(m_listenAddress, sendSocket.local_endpoint().port());
|
||||||
|
m_answerSocket.open(listenEndpoint.protocol());
|
||||||
|
m_answerSocket.set_option(asio::ip::udp::socket::reuse_address(true));
|
||||||
|
m_answerSocket.bind(listenEndpoint);
|
||||||
|
|
||||||
|
sendSocket.send(asio::buffer(data));
|
||||||
|
|
||||||
|
asio::error_code error = asio::error::would_block;
|
||||||
|
std::size_t length = 0;
|
||||||
|
|
||||||
|
m_deadline.expires_from_now(std::chrono::seconds(1));
|
||||||
|
m_answerSocket.async_receive(asio::buffer(m_socketAnswerData.data(), m_bufferLength), std::bind(&UdpClientImpl::HandleAnswer, this, std::placeholders::_1, std::placeholders::_2, &error, &length));
|
||||||
|
|
||||||
|
do m_ioServiceAnswer.run_one();
|
||||||
|
while (error == asio::error::would_block);
|
||||||
|
|
||||||
|
std::string answer;
|
||||||
|
if (error != asio::error::operation_aborted)
|
||||||
|
answer = std::string(m_socketAnswerData.begin(), m_socketAnswerData.begin() + length);
|
||||||
|
else
|
||||||
|
answer = "Error";
|
||||||
|
|
||||||
|
m_answerSocket.close();
|
||||||
|
return answer;
|
||||||
|
}
|
||||||
|
catch (const asio::system_error& ex)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "UdpClientImpl::Send() - Error: " << ex.what() << std::endl;
|
||||||
|
Logging::Log(Logging::Severity::Error, ss.str());
|
||||||
|
return "Error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdpClientImpl::Broadcast(const std::string& data, int sourcePort)
|
||||||
|
{
|
||||||
|
asio::ip::udp::socket sendSocket(m_ioService);
|
||||||
|
sendSocket.open(asio::ip::udp::v4());
|
||||||
|
|
||||||
|
sendSocket.set_option(asio::ip::udp::socket::reuse_address(true));
|
||||||
|
sendSocket.set_option(asio::socket_base::broadcast(true));
|
||||||
|
|
||||||
|
if (sourcePort != 0)
|
||||||
|
{
|
||||||
|
asio::ip::udp::endpoint sendEndpoint(m_listenAddress, sourcePort);
|
||||||
|
sendSocket.bind(sendEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
asio::ip::udp::endpoint targetEndpoint(asio::ip::address_v4::broadcast(), m_targetPort);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sendSocket.connect(targetEndpoint);
|
||||||
|
|
||||||
|
sendSocket.send(asio::buffer(data));
|
||||||
|
}
|
||||||
|
catch (const asio::system_error& ex)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "UdpClientImpl::Broadcast() - Error: " << ex.what() << std::endl;
|
||||||
|
Logging::Log(Logging::Severity::Error, ss.str());
|
||||||
|
}
|
||||||
|
sendSocket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdpClientImpl::EnableMulticast()
|
||||||
|
{
|
||||||
|
m_receiveSocket.set_option(asio::ip::multicast::join_group(m_targetAddress.to_v4(), m_listenAddress.to_v4()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdpClientImpl::CheckDeadline()
|
||||||
|
{
|
||||||
|
if (m_deadline.expires_at() <= std::chrono::system_clock::now())
|
||||||
|
{
|
||||||
|
m_answerSocket.cancel();
|
||||||
|
m_deadline.expires_at(asio::system_timer::time_point(std::chrono::system_clock::duration::max()));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_deadline.async_wait(std::bind(&UdpClientImpl::CheckDeadline, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdpClientImpl::HandleAnswer(const asio::error_code& error, std::size_t length, asio::error_code* out_error, std::size_t* out_length) const
|
||||||
|
{
|
||||||
|
*out_error = error;
|
||||||
|
*out_length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdpClientImpl::ReceiveSocket()
|
||||||
|
{
|
||||||
|
m_receiveSocket.async_receive_from(asio::buffer(m_socketReceiveData.data(), m_bufferLength), m_sourceEndpoint, std::bind(&UdpClientImpl::HandleReceiveSocket, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdpClientImpl::HandleReceiveSocket(const asio::error_code& error, size_t bytes)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_callback)
|
||||||
|
{
|
||||||
|
std::vector<char>::iterator begin = m_socketReceiveData.begin();
|
||||||
|
m_callback(std::string(begin, begin + bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
ReceiveSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#ifndef NETWORK_UDPCLIENTIMPL_H
|
||||||
|
#define NETWORK_UDPCLIENTIMPL_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
#include "asio.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
class UdpClientImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UdpClientImpl(const std::string& listenAddress, const std::string& targetAddress, int targetPort, std::function<void(const std::string&)> callback);
|
||||||
|
~UdpClientImpl();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Receive();
|
||||||
|
|
||||||
|
std::string Send(const std::string& data, int sourcePort = 0);
|
||||||
|
void Broadcast(const std::string& data, int sourcePort = 0);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void EnableMulticast();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void CheckDeadline();
|
||||||
|
void HandleAnswer(const asio::error_code& error, size_t bytes, asio::error_code* out_error, std::size_t* out_length) const;
|
||||||
|
void ReceiveSocket();
|
||||||
|
void HandleReceiveSocket(const asio::error_code& error, size_t bytes);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::thread m_thread;
|
||||||
|
std::string m_url;
|
||||||
|
int m_bufferLength;
|
||||||
|
asio::io_service m_ioService;
|
||||||
|
asio::io_service m_ioServiceAnswer;
|
||||||
|
asio::system_timer m_deadline;
|
||||||
|
asio::ip::address m_listenAddress;
|
||||||
|
asio::ip::address m_targetAddress;
|
||||||
|
int m_targetPort;
|
||||||
|
asio::ip::udp::socket m_receiveSocket;
|
||||||
|
asio::ip::udp::socket m_answerSocket;
|
||||||
|
asio::ip::udp::endpoint m_targetEndpoint;
|
||||||
|
asio::ip::udp::endpoint m_sourceEndpoint;
|
||||||
|
std::vector<char> m_socketReceiveData;
|
||||||
|
std::vector<char> m_socketAnswerData;
|
||||||
|
|
||||||
|
std::function<void(const std::string&)> m_callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_UDPCLIENTIMPL_H
|
||||||
Reference in New Issue
Block a user