25#ifndef JOIN_FABRIC_NAMESERVER_HPP
26#define JOIN_FABRIC_NAMESERVER_HPP
41 template <
typename Protocol>
45 using Socket =
typename Protocol::Socket;
54 ,
_buffer (
std::make_unique<char[]> (Protocol::maxMsgSize))
96 if (
_socket.bind (endpoint) == -1)
124 int reply (
const DnsPacket& query,
const std::vector<ResourceRecord>& answers = {},
125 const std::vector<ResourceRecord>& authorities = {},
126 const std::vector<ResourceRecord>& additionals = {}, uint16_t rcode = 0)
129 packet.id = query.
id;
130 packet.flags = (uint16_t (1) << 15) | (query.
flags & 0x7800) | (uint16_t (1) << 10) | (rcode & 0x000F);
131 packet.dest = query.
src;
132 packet.port = query.
port;
135 packet.answers = answers;
136 packet.authorities = authorities;
137 packet.additionals = additionals;
139 return send (packet);
156 ssize_t size =
_socket.readFrom (
_buffer.get (), Protocol::maxMsgSize, &from);
159 std::stringstream data;
160 data.rdbuf ()->pubsetbuf (
_buffer.get (), size);
164 packet.
src = from.ip ();
166 packet.
port = from.port ();
168 if ((packet.
flags & 0x8000) == 0)
182 std::stringstream data;
191 std::string buffer = data.str ();
192 if (buffer.size () > Protocol::maxMsgSize)
200 if (
_socket.writeTo (buffer.data (), buffer.size (), {packet.dest, packet.port}) == -1)
227 template <
typename Protocol>
311 IpAddress maddress = Protocol::multicastAddress (family);
314 if ((this->
_socket.opened () ==
false) && (this->_socket.open (endpoint.protocol ()) == -1))
319 if (this->
_socket.setOption (Socket::ReusePort, 1) == -1)
327 if (this->
_socket.bind (endpoint) == -1)
335 if (endpoint.protocol ().family () == AF_INET6)
338 ::memcpy (&mreq.ipv6mr_multiaddr, maddress.
addr (), maddress.
length ());
340 if (::setsockopt (this->
_socket.handle (), IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof (mreq)) ==
344 lastError = std::error_code (errno, std::generic_category ());
349 if (::setsockopt (this->
_socket.handle (), IPPROTO_IPV6, IPV6_MULTICAST_IF, &
_ifindex,
353 lastError = std::error_code (errno, std::generic_category ());
363 ::memcpy (&mreq.imr_multiaddr, maddress.
addr (), maddress.
length ());
364 mreq.imr_ifindex =
static_cast<int> (
_ifindex);
365 if (::setsockopt (this->
_socket.handle (), IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof (mreq)) == -1)
367 lastError = std::error_code (errno, std::generic_category ());
371 if (::setsockopt (this->
_socket.handle (), IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof (mreq)) == -1)
373 lastError = std::error_code (errno, std::generic_category ());
381 if (this->
_socket.setOption (Socket::MulticastLoop, 0) == -1)
400 int probe (
const std::vector<ResourceRecord>& records)
402 if (records.empty ())
413 packet.port = Protocol::defaultPort;
415 for (
auto const& record : records)
418 question.
host = record.host;
421 packet.questions.push_back (question);
423 packet.authorities.push_back (record);
426 return this->
send (packet);
434 int announce (
const std::vector<ResourceRecord>& records)
436 if (records.empty ())
444 packet.flags = (uint16_t (1) << 15) | (uint16_t (1) << 10);
447 packet.port = Protocol::defaultPort;
449 for (
auto const& record : records)
451 packet.answers.push_back (record);
454 return this->
send (packet);
462 int goodbye (
const std::vector<ResourceRecord>& records)
464 if (records.empty ())
472 packet.flags = (uint16_t (1) << 15) | (uint16_t (1) << 10);
475 packet.port = Protocol::defaultPort;
477 for (
auto const& record : records)
481 packet.answers.push_back (
goodbye);
484 return this->
send (packet);
492 int browse (
const std::string& serviceType)
494 if (serviceType.empty ())
505 packet.port = Protocol::defaultPort;
508 question.
host = serviceType;
511 packet.questions.push_back (question);
513 return this->
send (packet);
524 std::chrono::milliseconds timeout = std::chrono::seconds (5))
533 packet.flags = 1 << 8;
536 question.
host = host;
539 packet.questions.push_back (question);
541 if (
query (packet, timeout) == -1)
548 for (
auto const& answer : packet.answers)
550 if (!answer.addr.isWildcard () && (answer.type == question.
type))
552 addresses.push_back (answer.addr);
566 std::chrono::milliseconds timeout = std::chrono::seconds (5))
570 for (
auto const& family : {AF_INET, AF_INET6})
573 addresses.insert (addresses.end (), tmp.begin (), tmp.end ());
587 std::chrono::milliseconds timeout = std::chrono::seconds (5))
620 std::chrono::milliseconds timeout = std::chrono::seconds (5))
629 packet.flags = 1 << 8;
635 packet.questions.push_back (question);
637 if (
query (packet, timeout) == -1)
644 for (
auto const& answer : packet.answers)
648 aliases.insert (answer.name);
685 ssize_t size = this->
_socket.readFrom (this->
_buffer.get (), Protocol::maxMsgSize, &from);
688 std::stringstream data;
689 data.rdbuf ()->pubsetbuf (this->
_buffer.get (), size);
694 packet.
src = from.ip ();
696 packet.
port = from.port ();
698 if ((packet.
flags & 0x8000) == 0)
700 bool unicast =
false;
703 if (q.dnsclass & 0x8000)
725 it->second->packet = packet;
727 it->second->cond.signal ();
741 static void defaultOnSuccess (
const DnsPacket& packet)
743 std::cout << std::endl;
744 std::cout <<
"PEER: " << packet.
dest <<
"#" << packet.
port << std::endl;
746 std::cout << std::endl;
747 std::cout <<
";; QUESTION SECTION: " << std::endl;
748 for (
auto const& question : packet.
questions)
750 std::cout << question.host;
753 std::cout << std::endl;
756 std::cout << std::endl;
757 std::cout <<
";; ANSWER SECTION: " << std::endl;
758 for (
auto const& answer : packet.
answers)
760 std::cout << answer.host;
763 std::cout <<
" " << answer.ttl;
766 std::cout <<
" " << answer.addr;
770 std::cout <<
" " << answer.name;
774 std::cout <<
" " << answer.addr;
776 std::cout << std::endl;
784 static void defaultOnFailure (
const DnsPacket& packet)
786 std::cout << std::endl;
787 std::cout <<
"PEER: " << packet.dest <<
"#" << packet.port << std::endl;
789 std::cout << std::endl;
790 std::cout <<
";; QUESTION SECTION: " << std::endl;
791 for (
auto const& question : packet.questions)
793 std::cout << question.host;
796 std::cout << std::endl;
799 std::cout << std::endl;
800 std::cout << lastError.message () << std::endl;
827 packet.
port = Protocol::defaultPort;
829 std::stringstream data;
838 std::string buffer = data.str ();
839 if (buffer.size () > Protocol::maxMsgSize)
849 auto inserted =
_pending.emplace (packet.
id, std::make_unique<PendingRequest> ());
850 if (!inserted.second)
859 if (this->
_socket.writeTo (buffer.data (), buffer.size (), {packet.dest, packet.port}) == -1)
868 if (!inserted.first->second->cond.timedWait (lock, timeout))
878 auto pendingReq = std::move (inserted.first->second);
884 lastError = pendingReq->ec;
890 packet = std::move (pendingReq->packet);
908 std::unordered_map<uint16_t, std::unique_ptr<PendingRequest>>
_pending;
basic DNS name server over datagram socket.
Definition nameserver.hpp:43
int reply(const DnsPacket &query, const std::vector< ResourceRecord > &answers={}, const std::vector< ResourceRecord > &authorities={}, const std::vector< ResourceRecord > &additionals={}, uint16_t rcode=0)
reply to a DNS query.
Definition nameserver.hpp:124
virtual void close() noexcept
close the socket and unregister from the reactor.
Definition nameserver.hpp:109
typename Protocol::Socket Socket
Definition nameserver.hpp:45
BasicDatagramNameServer(Reactor &reactor=ReactorThread::reactor())
construct the name server instance.
Definition nameserver.hpp:52
DnsMessage _message
DNS message codec.
Definition nameserver.hpp:212
virtual int bind(const Endpoint &endpoint) noexcept
bind the socket to the given endpoint and register with the reactor.
Definition nameserver.hpp:94
BasicDatagramNameServer(const BasicDatagramNameServer &other)=delete
copy constructor.
std::unique_ptr< char[]> _buffer
reception buffer.
Definition nameserver.hpp:221
Reactor & _reactor
event loop reactor.
Definition nameserver.hpp:218
virtual ~BasicDatagramNameServer() noexcept=default
destroy instance.
virtual void onQuery(const DnsPacket &packet)=0
method called when a DNS query is received.
Socket _socket
underlying socket.
Definition nameserver.hpp:215
virtual void onReadable(int fd) override
method called when data are ready to be read on handle.
Definition nameserver.hpp:153
BasicDatagramNameServer & operator=(const BasicDatagramNameServer &other)=delete
copy assignment operator.
BasicDatagramNameServer(BasicDatagramNameServer &&other)=delete
move constructor.
int send(DnsPacket &packet)
serialize and send a DNS packet.
Definition nameserver.hpp:180
static constexpr size_t _headerSize
DNS message header size.
Definition nameserver.hpp:209
typename Protocol::Endpoint Endpoint
Definition nameserver.hpp:46
mDNS peer.
Definition nameserver.hpp:229
IpAddressList resolveAllAddress(const std::string &host, int family, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name and return all IP addresses found.
Definition nameserver.hpp:523
int probe(const std::vector< ResourceRecord > &records)
probe the local network for the presence of a service.
Definition nameserver.hpp:400
typename BasicDatagramNameServer< Protocol >::Socket Socket
Definition nameserver.hpp:231
virtual ~BasicDatagramPeer() noexcept=default
destroy instance.
BasicDatagramPeer(unsigned int ifindex, Reactor &reactor=ReactorThread::reactor())
construct the mDNS peer instance.
Definition nameserver.hpp:248
BasicDatagramPeer(BasicDatagramPeer &&other)=delete
move constructor.
IpAddress resolveAddress(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name.
Definition nameserver.hpp:603
BasicDatagramPeer(const BasicDatagramPeer &other)=delete
copy constructor.
virtual void onAnnouncement(const DnsPacket &packet)=0
method called when a DNS query is received.
int browse(const std::string &serviceType)
browse for services on the local network.
Definition nameserver.hpp:492
typename BasicDatagramNameServer< Protocol >::Endpoint Endpoint
Definition nameserver.hpp:232
IpAddress resolveAddress(const std::string &host, int family, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name using address family.
Definition nameserver.hpp:586
void onReadable(int fd) override final
method called when data are ready to be read on handle.
Definition nameserver.hpp:682
AliasList resolveAllName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host address.
Definition nameserver.hpp:619
int query(DnsPacket &packet, std::chrono::milliseconds timeout)
serialize and send a DNS query, waiting for a response.
Definition nameserver.hpp:823
std::unordered_map< uint16_t, std::unique_ptr< PendingRequest > > _pending
synchronous requests indexed by sequence number.
Definition nameserver.hpp:908
std::string resolveName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host address.
Definition nameserver.hpp:661
DnsNotify onFailure
callback called when a lookup sequence failed.
Definition nameserver.hpp:241
DnsNotify onSuccess
callback called when a lookup sequence succeed.
Definition nameserver.hpp:238
void notify(const DnsNotify &func, const DnsPacket &packet) const noexcept
safe way to notify DNS events.
Definition nameserver.hpp:809
int goodbye(const std::vector< ResourceRecord > &records)
send a goodbye message.
Definition nameserver.hpp:462
BasicDatagramPeer & operator=(const BasicDatagramPeer &other)=delete
copy assignment operator.
BasicDatagramPeer(const std::string &interface, Reactor &reactor=ReactorThread::reactor())
construct the mDNS peer instance.
Definition nameserver.hpp:266
int announce(const std::vector< ResourceRecord > &records)
announce the presence of a service on the local network.
Definition nameserver.hpp:434
int bind(int family) noexcept
bind the socket to specified address family.
Definition nameserver.hpp:309
std::function< void(const DnsPacket &)> DnsNotify
DNS notification callback type.
Definition nameserver.hpp:235
Mutex _syncMutex
protection mutex.
Definition nameserver.hpp:911
unsigned int _ifindex
interface index.
Definition nameserver.hpp:897
IpAddressList resolveAllAddress(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name and return all IP addresses found.
Definition nameserver.hpp:565
condition variable class.
Definition condition.hpp:42
DNS message codec.
Definition dns_message.hpp:105
int serialize(const DnsPacket &packet, std::stringstream &data) const
serialize a DNS packet into a byte stream.
Definition dns_message.hpp:174
static std::string className(uint16_t recordClass)
get record class name.
Definition dns_message.hpp:360
@ A
Definition dns_message.hpp:112
@ PTR
Definition dns_message.hpp:116
@ ANY
Definition dns_message.hpp:121
@ AAAA
Definition dns_message.hpp:119
int deserialize(DnsPacket &packet, std::stringstream &data) const
deserialize a DNS packet from a byte stream.
Definition dns_message.hpp:235
static std::error_code decodeError(uint16_t error) noexcept
convert DNS error to system error code.
Definition dns_message.hpp:311
@ IN
Definition dns_message.hpp:129
static std::string typeName(uint16_t recordType)
get record type name.
Definition dns_message.hpp:336
Event handler interface class.
Definition reactor.hpp:48
IPv6, IPv4 address class.
Definition ip_address.hpp:51
socklen_t length() const
get the size in byte of the internal address structure.
Definition ip_address.cpp:1268
const void * addr() const
get the internal address structure.
Definition ip_address.cpp:1259
class used to protect shared data from being simultaneously accessed by multiple threads.
Definition mutex.hpp:37
static Reactor & reactor()
get the global Reactor instance.
Definition reactor.cpp:584
Reactor class.
Definition reactor.hpp:156
int delHandler(int fd, bool sync=true) noexcept
delete handler from reactor.
Definition reactor.cpp:155
int addHandler(int fd, EventHandler *handler, bool wantRead=true, bool wantWrite=false, bool sync=true) noexcept
add handler to reactor.
Definition reactor.cpp:100
class owning a mutex for the duration of a scoped block.
Definition mutex.hpp:246
Definition acceptor.hpp:32
std::enable_if_t< std::numeric_limits< Type >::is_integer, Type > randomize()
create a random number.
Definition utils.hpp:434
std::unordered_set< std::string > AliasList
list of aliases.
Definition dns_message.hpp:46
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
std::vector< IpAddress > IpAddressList
List of IP address.
Definition ip_address.hpp:45
pending synchronous request.
Definition nameserver.hpp:901
std::error_code ec
Definition nameserver.hpp:904
DnsPacket packet
Definition nameserver.hpp:903
Condition cond
Definition nameserver.hpp:902
DNS packet.
Definition dns_message.hpp:89
uint16_t id
Definition dns_message.hpp:90
uint16_t flags
Definition dns_message.hpp:91
uint16_t port
Definition dns_message.hpp:94
std::vector< QuestionRecord > questions
Definition dns_message.hpp:95
IpAddress src
Definition dns_message.hpp:92
IpAddress dest
Definition dns_message.hpp:93
std::vector< ResourceRecord > answers
Definition dns_message.hpp:96
question record.
Definition dns_message.hpp:58
std::string host
Definition dns_message.hpp:59
uint16_t type
Definition dns_message.hpp:60
uint16_t dnsclass
Definition dns_message.hpp:61
resource record.
Definition dns_message.hpp:68
uint32_t ttl
Definition dns_message.hpp:69
IpAddress address
Definition tcp_acceptor_test.cpp:35