25#ifndef JOIN_FABRIC_NAMESERVER_HPP
26#define JOIN_FABRIC_NAMESERVER_HPP
39 template <
typename Protocol>
43 using Socket =
typename Protocol::Socket;
53 ,
_buffer (
std::make_unique<char[]> (Protocol::maxMsgSize))
95 if (Socket::bind (endpoint) == -1)
108 virtual void close () noexcept
override
123 int reply (
const DnsPacket& query,
const std::vector<ResourceRecord>& answers = {},
124 const std::vector<ResourceRecord>& authorities = {},
125 const std::vector<ResourceRecord>& additionals = {}, uint16_t rcode = 0)
128 packet.id = query.
id;
129 packet.flags = (uint16_t (1) << 15) | (query.
flags & 0x7800) | (uint16_t (1) << 10) | (rcode & 0x000F);
130 packet.dest = query.
src;
131 packet.port = query.
port;
134 packet.answers = answers;
135 packet.authorities = authorities;
136 packet.additionals = additionals;
138 return send (packet);
155 int size = this->readFrom (
_buffer.get (), Protocol::maxMsgSize, &from);
158 std::stringstream data;
159 data.rdbuf ()->pubsetbuf (
_buffer.get (), size);
163 packet.
src = from.ip ();
164 packet.
dest = this->localEndpoint ().ip ();
165 packet.
port = from.port ();
167 if ((packet.
flags & 0x8000) == 0)
181 std::stringstream data;
190 std::string buffer = data.str ();
191 if (buffer.size () > Protocol::maxMsgSize)
199 if (this->writeTo (buffer.data (), buffer.size (), {packet.dest, packet.port}) == -1)
223 template <
typename Protocol>
307 IpAddress maddress = Protocol::multicastAddress (family);
310 if ((this->_state == Socket::State::Closed) && (this->open (endpoint.protocol ()) == -1))
315 if (this->setOption (Socket::ReusePort, 1) == -1)
323 if (Socket::bind (endpoint) == -1)
331 if (endpoint.protocol ().family () == AF_INET6)
334 ::memcpy (&mreq.ipv6mr_multiaddr, maddress.
addr (), maddress.
length ());
336 if (::setsockopt (this->handle (), IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
sizeof (mreq)) == -1)
339 lastError = std::error_code (errno, std::generic_category ());
344 if (::setsockopt (this->handle (), IPPROTO_IPV6, IPV6_MULTICAST_IF, &
_ifindex,
sizeof (
_ifindex)) == -1)
347 lastError = std::error_code (errno, std::generic_category ());
357 ::memcpy (&mreq.imr_multiaddr, maddress.
addr (), maddress.
length ());
358 mreq.imr_ifindex =
static_cast<int> (
_ifindex);
359 if (::setsockopt (this->handle (), IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof (mreq)) == -1)
361 lastError = std::error_code (errno, std::generic_category ());
365 if (::setsockopt (this->handle (), IPPROTO_IP, IP_MULTICAST_IF, &mreq,
sizeof (mreq)) == -1)
367 lastError = std::error_code (errno, std::generic_category ());
375 if (this->setOption (Socket::MulticastLoop, 0) == -1)
394 int probe (
const std::vector<ResourceRecord>& records)
396 if (records.empty ())
405 IpAddress mcast = Protocol::multicastAddress (this->family ());
407 packet.port = Protocol::defaultPort;
409 for (
auto const& record : records)
412 question.
host = record.host;
415 packet.questions.push_back (question);
417 packet.authorities.push_back (record);
420 return this->
send (packet);
428 int announce (
const std::vector<ResourceRecord>& records)
430 if (records.empty ())
438 packet.flags = (uint16_t (1) << 15) | (uint16_t (1) << 10);
439 IpAddress mcast = Protocol::multicastAddress (this->family ());
441 packet.port = Protocol::defaultPort;
443 for (
auto const& record : records)
445 packet.answers.push_back (record);
448 return this->
send (packet);
456 int goodbye (
const std::vector<ResourceRecord>& records)
458 if (records.empty ())
466 packet.flags = (uint16_t (1) << 15) | (uint16_t (1) << 10);
467 IpAddress mcast = Protocol::multicastAddress (this->family ());
469 packet.port = Protocol::defaultPort;
471 for (
auto const& record : records)
475 packet.answers.push_back (
goodbye);
478 return this->
send (packet);
486 int browse (
const std::string& serviceType)
488 if (serviceType.empty ())
497 IpAddress mcast = Protocol::multicastAddress (this->family ());
499 packet.port = Protocol::defaultPort;
502 question.
host = serviceType;
505 packet.questions.push_back (question);
507 return this->
send (packet);
518 std::chrono::milliseconds timeout = std::chrono::seconds (5))
527 packet.flags = 1 << 8;
530 question.
host = host;
533 packet.questions.push_back (question);
535 if (
query (packet, timeout) == -1)
542 for (
auto const& answer : packet.answers)
544 if (!answer.addr.isWildcard () && (answer.type == question.
type))
546 addresses.push_back (answer.addr);
560 std::chrono::milliseconds timeout = std::chrono::seconds (5))
564 for (
auto const& family : {AF_INET, AF_INET6})
567 addresses.insert (addresses.end (), tmp.begin (), tmp.end ());
581 std::chrono::milliseconds timeout = std::chrono::seconds (5))
614 std::chrono::milliseconds timeout = std::chrono::seconds (5))
623 packet.flags = 1 << 8;
629 packet.questions.push_back (question);
631 if (
query (packet, timeout) == -1)
638 for (
auto const& answer : packet.answers)
642 aliases.insert (answer.name);
679 int size = this->readFrom (this->
_buffer.get (), Protocol::maxMsgSize, &from);
682 std::stringstream data;
683 data.rdbuf ()->pubsetbuf (this->
_buffer.get (), size);
687 IpAddress mcast = Protocol::multicastAddress (this->family ());
688 packet.
src = from.ip ();
690 packet.
port = from.port ();
692 if ((packet.
flags & 0x8000) == 0)
694 bool unicast =
false;
697 if (q.dnsclass & 0x8000)
719 it->second->packet = packet;
721 it->second->cond.signal ();
735 static void defaultOnSuccess (
const DnsPacket& packet)
737 std::cout << std::endl;
738 std::cout <<
"PEER: " << packet.
dest <<
"#" << packet.
port << std::endl;
740 std::cout << std::endl;
741 std::cout <<
";; QUESTION SECTION: " << std::endl;
742 for (
auto const& question : packet.
questions)
744 std::cout << question.host;
747 std::cout << std::endl;
750 std::cout << std::endl;
751 std::cout <<
";; ANSWER SECTION: " << std::endl;
752 for (
auto const& answer : packet.
answers)
754 std::cout << answer.host;
757 std::cout <<
" " << answer.ttl;
760 std::cout <<
" " << answer.addr;
764 std::cout <<
" " << answer.name;
768 std::cout <<
" " << answer.addr;
770 std::cout << std::endl;
778 static void defaultOnFailure (
const DnsPacket& packet)
780 std::cout << std::endl;
781 std::cout <<
"PEER: " << packet.dest <<
"#" << packet.port << std::endl;
783 std::cout << std::endl;
784 std::cout <<
";; QUESTION SECTION: " << std::endl;
785 for (
auto const& question : packet.questions)
787 std::cout << question.host;
790 std::cout << std::endl;
793 std::cout << std::endl;
794 std::cout << lastError.message () << std::endl;
819 IpAddress mcast = Protocol::multicastAddress (this->family ());
821 packet.
port = Protocol::defaultPort;
823 std::stringstream data;
832 std::string buffer = data.str ();
833 if (buffer.size () > Protocol::maxMsgSize)
843 auto inserted =
_pending.emplace (packet.
id, std::make_unique<PendingRequest> ());
844 if (!inserted.second)
853 if (this->writeTo (buffer.data (), buffer.size (), {packet.dest, packet.port}) == -1)
862 if (!inserted.first->second->cond.timedWait (lock, timeout))
872 auto pendingReq = std::move (inserted.first->second);
878 lastError = pendingReq->ec;
884 packet = std::move (pendingReq->packet);
902 std::unordered_map<uint16_t, std::unique_ptr<PendingRequest>>
_pending;
basic DNS name server over datagram socket.
Definition nameserver.hpp:41
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:123
typename Protocol::Socket Socket
Definition nameserver.hpp:43
BasicDatagramNameServer(Reactor &reactor=ReactorThread::reactor())
construct the name server instance.
Definition nameserver.hpp:50
DnsMessage _message
DNS message codec.
Definition nameserver.hpp:211
virtual void close() noexcept override
close the socket and unregister from the reactor.
Definition nameserver.hpp:108
BasicDatagramNameServer(const BasicDatagramNameServer &other)=delete
copy constructor.
std::unique_ptr< char[]> _buffer
reception buffer.
Definition nameserver.hpp:217
virtual int bind(const Endpoint &endpoint) noexcept override
bind the socket to the given endpoint and register with the reactor.
Definition nameserver.hpp:93
Reactor & _reactor
event loop reactor.
Definition nameserver.hpp:214
virtual ~BasicDatagramNameServer() noexcept=default
destroy instance.
virtual void onQuery(const DnsPacket &packet)=0
method called when a DNS query is received.
virtual void onReadable(int fd) override
method called when data are ready to be read on handle.
Definition nameserver.hpp:152
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:179
static constexpr size_t _headerSize
DNS message header size.
Definition nameserver.hpp:208
typename Protocol::Endpoint Endpoint
Definition nameserver.hpp:44
mDNS peer.
Definition nameserver.hpp:225
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:517
int probe(const std::vector< ResourceRecord > &records)
probe the local network for the presence of a service.
Definition nameserver.hpp:394
typename BasicDatagramNameServer< Protocol >::Socket Socket
Definition nameserver.hpp:227
virtual ~BasicDatagramPeer() noexcept=default
destroy instance.
BasicDatagramPeer(unsigned int ifindex, Reactor &reactor=ReactorThread::reactor())
construct the mDNS peer instance.
Definition nameserver.hpp:244
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:597
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:486
typename BasicDatagramNameServer< Protocol >::Endpoint Endpoint
Definition nameserver.hpp:228
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:580
void onReadable(int fd) override final
method called when data are ready to be read on handle.
Definition nameserver.hpp:676
AliasList resolveAllName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host address.
Definition nameserver.hpp:613
int query(DnsPacket &packet, std::chrono::milliseconds timeout)
serialize and send a DNS query, waiting for a response.
Definition nameserver.hpp:817
std::unordered_map< uint16_t, std::unique_ptr< PendingRequest > > _pending
synchronous requests indexed by sequence number.
Definition nameserver.hpp:902
std::string resolveName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host address.
Definition nameserver.hpp:655
DnsNotify onFailure
callback called when a lookup sequence failed.
Definition nameserver.hpp:237
DnsNotify onSuccess
callback called when a lookup sequence succeed.
Definition nameserver.hpp:234
void notify(const DnsNotify &func, const DnsPacket &packet) const noexcept
safe way to notify DNS events.
Definition nameserver.hpp:803
int goodbye(const std::vector< ResourceRecord > &records)
send a goodbye message.
Definition nameserver.hpp:456
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:262
int announce(const std::vector< ResourceRecord > &records)
announce the presence of a service on the local network.
Definition nameserver.hpp:428
int bind(int family) noexcept
bind the socket to specified address family.
Definition nameserver.hpp:305
std::function< void(const DnsPacket &)> DnsNotify
DNS notification callback type.
Definition nameserver.hpp:231
Mutex _syncMutex
protection mutex.
Definition nameserver.hpp:905
unsigned int _ifindex
interface index.
Definition nameserver.hpp:891
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:559
condition variable class.
Definition condition.hpp:42
DNS message codec.
Definition dnsmessage.hpp:105
int serialize(const DnsPacket &packet, std::stringstream &data) const
serialize a DNS packet into a byte stream.
Definition dnsmessage.hpp:174
static std::string className(uint16_t recordClass)
get record class name.
Definition dnsmessage.hpp:360
@ A
Definition dnsmessage.hpp:112
@ PTR
Definition dnsmessage.hpp:116
@ ANY
Definition dnsmessage.hpp:121
@ AAAA
Definition dnsmessage.hpp:119
int deserialize(DnsPacket &packet, std::stringstream &data) const
deserialize a DNS packet from a byte stream.
Definition dnsmessage.hpp:235
static std::error_code decodeError(uint16_t error) noexcept
convert DNS error to system error code.
Definition dnsmessage.hpp:311
@ IN
Definition dnsmessage.hpp:129
static std::string typeName(uint16_t recordType)
get record type name.
Definition dnsmessage.hpp:336
Event handler interface class.
Definition reactor.hpp:46
IPv6, IPv4 address class.
Definition ipaddress.hpp:51
socklen_t length() const
get the size in byte of the internal address structure.
Definition ipaddress.cpp:1268
const void * addr() const
get the internal address structure.
Definition ipaddress.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:514
Reactor class.
Definition reactor.hpp:129
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:403
std::unordered_set< std::string > AliasList
list of aliases.
Definition dnsmessage.hpp:46
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:150
std::vector< IpAddress > IpAddressList
List of IP address.
Definition ipaddress.hpp:45
pending synchronous request.
Definition nameserver.hpp:895
std::error_code ec
Definition nameserver.hpp:898
DnsPacket packet
Definition nameserver.hpp:897
Condition cond
Definition nameserver.hpp:896
DNS packet.
Definition dnsmessage.hpp:89
uint16_t id
Definition dnsmessage.hpp:90
uint16_t flags
Definition dnsmessage.hpp:91
uint16_t port
Definition dnsmessage.hpp:94
std::vector< QuestionRecord > questions
Definition dnsmessage.hpp:95
IpAddress src
Definition dnsmessage.hpp:92
IpAddress dest
Definition dnsmessage.hpp:93
std::vector< ResourceRecord > answers
Definition dnsmessage.hpp:96
question record.
Definition dnsmessage.hpp:58
std::string host
Definition dnsmessage.hpp:59
uint16_t type
Definition dnsmessage.hpp:60
uint16_t dnsclass
Definition dnsmessage.hpp:61
resource record.
Definition dnsmessage.hpp:68
uint32_t ttl
Definition dnsmessage.hpp:69
IpAddress address
Definition tcpacceptor_test.cpp:35