libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
mdnsmanager.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_MDNS
13#include <cstdint>
14#include <promeki/namespace.h>
15#include <promeki/atomic.h>
16#include <promeki/buffer.h>
17#include <promeki/error.h>
18#include <promeki/function.h>
19#include <promeki/ipv4address.h>
20#include <promeki/ipv6address.h>
21#include <promeki/list.h>
22#include <promeki/map.h>
23#include <promeki/mdnsrecord.h>
25#include <promeki/mutex.h>
28#include <promeki/string.h>
29#include <promeki/thread.h>
30#include <promeki/timestamp.h>
31#include <promeki/udpsocket.h>
32#include <promeki/uniqueptr.h>
33
34PROMEKI_NAMESPACE_BEGIN
35
36class MdnsBrowser;
37class MdnsPublisher;
38class MdnsTypeBrowser;
39class NetworkInterfaceMonitor;
40
99class MdnsManager : public Thread {
100 PROMEKI_OBJECT(MdnsManager, Thread)
101 public:
103 static constexpr uint16_t DefaultPort = 5353;
104
106 static constexpr size_t DefaultMaxPacketSize = 9000;
107
119 static constexpr unsigned int DefaultTickIntervalMs = 1000;
120
122 static Ipv4Address ipv4Group() { return Ipv4Address(224, 0, 0, 251); }
123
125 static Ipv6Address ipv6Group();
126
134 enum class IpFamily : uint8_t {
135 IPv4Only = 1,
136 IPv6Only = 2,
137 Both = 3,
138 };
139
141 void setIpFamily(IpFamily family);
142
144 IpFamily ipFamily() const { return _ipFamily; }
145
164 using PacketHook = Function<void(NetworkInterface iface,
165 SocketAddress sender,
166 Buffer data)>;
167
169 explicit MdnsManager(ObjectBase *parent = nullptr);
170
172 ~MdnsManager() override;
173
183 void setPort(uint16_t port);
184
186 uint16_t port() const { return _port; }
187
201 void setAutoTrackInterfaces(bool enable);
202
204 bool autoTrackInterfaces() const { return _autoTrackInterfaces; }
205
217 void setIncludeLoopback(bool include);
218
220 bool includeLoopback() const { return _includeLoopback; }
221
229 void setMaxPacketSize(size_t bytes);
230
232 size_t maxPacketSize() const { return _maxPacketSize; }
233
243 void setTickInterval(unsigned int ms);
244
246 unsigned int tickInterval() const { return _tickIntervalMs; }
247
287 Error sendQuery(const String &name, uint16_t recordType,
288 uint16_t transactionId = 0,
289 bool unicastResponse = false);
290
300 Error sendMetaQuery();
301
303 static String metaBrowseFqdn() {
304 return String("_services._dns-sd._udp.local.");
305 }
306
328 Error sendQueryWithKnownAnswers(const String &name, uint16_t recordType,
329 const List<MdnsRecord> &knownAnswers,
330 uint16_t transactionId = 0);
331
347 static Buffer buildQuery(const String &name, uint16_t recordType,
348 uint16_t transactionId = 0,
349 bool unicastResponse = false);
350
358 static Buffer buildQueryWithKnownAnswers(const String &name, uint16_t recordType,
359 const List<MdnsRecord> &knownAnswers,
360 uint16_t transactionId = 0,
361 bool unicastResponse = false);
362
372 void registerBrowser(MdnsBrowser *browser);
373
383 void registerPublisher(MdnsPublisher *publisher);
384
393 void unregisterPublisher(MdnsPublisher *publisher);
394
403 void registerTypeBrowser(MdnsTypeBrowser *typeBrowser);
404
411 void unregisterTypeBrowser(MdnsTypeBrowser *typeBrowser);
412
426 Error writeMulticast(const Buffer &packet, bool ipv6);
427
444 void unregisterBrowser(MdnsBrowser *browser);
445
456 void setPacketHook(PacketHook hook);
457
478 int registerPacketObserver(PacketHook observer);
479
489 void unregisterPacketObserver(int handle);
490
504 Error start();
505
521 Error start(const NetworkInterface::List &ifaces);
522
531 void stop();
532
534 bool isActive() const { return _active.value(); }
535
537 NetworkInterface::List joinedInterfaces() const;
538
545 uint64_t datagramCount() const { return _datagramCount.value(); }
546
548 uint64_t byteCount() const { return _byteCount.value(); }
549
559 UdpSocket *socket() const { return _socket.get(); }
560
568 UdpSocket *socketV6() const { return _socketV6.get(); }
569
571 PROMEKI_SIGNAL(interfaceAdded, NetworkInterface);
573 PROMEKI_SIGNAL(interfaceRemoved, NetworkInterface);
575 PROMEKI_SIGNAL(receiveError, Error);
576
577 protected:
579 void run() override;
580
581 private:
582 Error openAndJoin(const NetworkInterface::List &ifaces);
583 Error openSocket(bool ipv6);
584 Error joinGroups(const NetworkInterface::List &ifaces, int *joined);
585 Error joinGroupsOnInterface(const NetworkInterface &iface, int *joined);
586 void closeAndLeave();
587 NetworkInterface::List selectAllMulticastInterfaces() const;
588 bool acceptInterface(const NetworkInterface &iface) const;
589 NetworkInterface interfaceFromIfIndex(unsigned int ifindex) const;
590
591 // Sends @p pkt out @p dest on every joined interface
592 // via @p sock with @c IP_MULTICAST_IF / @c IPV6_MULTICAST_IF
593 // steering. Returns the number of successful sends.
594 int sendOnSocketPerInterface(UdpSocket *sock, const Buffer &pkt,
595 const SocketAddress &dest);
596
597 // EventLoop IO-source callback: drains @p sock until
598 // EAGAIN, then fans every received datagram out to
599 // browsers / publishers / type browsers under the
600 // standard mutex discipline. On @c IoError emits
601 // @ref receiveErrorSignal before attempting the drain
602 // (POLLERR / POLLHUP can co-occur with queued data).
603 void handleSocketEvents(UdpSocket *sock, uint32_t events);
604
605 // EventLoop timer callback: drives onManagerTick on
606 // every registered browser / publisher / type browser.
607 // Fires unconditionally — no wall-clock comparison
608 // because the EventLoop timer cadence already
609 // matches @ref tickInterval.
610 void runTick();
611
612 // Monitor wiring. @ref attachInterfaceMonitor is
613 // called from @ref start; @ref detachInterfaceMonitor
614 // from @ref stop. Slots are dispatched on the
615 // manager's affinity thread (the @ref ObjectBase
616 // construction thread); their bodies mutate the
617 // joined set under @ref _interfacesMtx and call into
618 // the @ref MulticastManager to issue per-interface
619 // joins / leaves on the wildcard socket.
620 void attachInterfaceMonitor();
621 void detachInterfaceMonitor();
622 void onInterfaceAppeared(const NetworkInterface &iface);
623 void onInterfaceDisappeared(const NetworkInterface &iface);
624
625 UdpSocket::UPtr _socket;
626 UdpSocket::UPtr _socketV6;
627 MulticastManager _multicastManager;
628 NetworkInterface::List _joinedInterfaces;
629 // Cached ifindex → NetworkInterface for fast receive-
630 // side attribution. Rebuilt on each interface join /
631 // leave so the receive thread can look up by the
632 // @c IP_PKTINFO / @c IPV6_PKTINFO cmsg without
633 // walking @ref _joinedInterfaces. Guarded by
634 // @ref _interfacesMtx.
635 Map<unsigned int, NetworkInterface> _byIfIndex;
636 mutable Mutex _interfacesMtx;
637 PacketHook _packetHook;
638 struct PacketObserver {
639 int handle = -1;
640 PacketHook hook;
641 };
642 List<PacketObserver> _packetObservers;
643 mutable Mutex _packetObserversMtx;
644 Atomic<int> _nextObserverHandle;
645 List<MdnsBrowser *> _browsers;
646 mutable Mutex _browsersMtx;
647 List<MdnsPublisher *> _publishers;
648 mutable Mutex _publishersMtx;
649 List<MdnsTypeBrowser *> _typeBrowsers;
650 mutable Mutex _typeBrowsersMtx;
651 UniquePtr<NetworkInterfaceMonitor> _ifMonitor;
652
653 uint16_t _port = DefaultPort;
654 bool _includeLoopback = true;
655 bool _autoTrackInterfaces = true;
656 IpFamily _ipFamily = IpFamily::Both;
657 size_t _maxPacketSize = DefaultMaxPacketSize;
658 unsigned int _tickIntervalMs = DefaultTickIntervalMs;
659
660 Atomic<bool> _active;
661 Atomic<uint64_t> _datagramCount;
662 Atomic<uint64_t> _byteCount;
663};
664
665PROMEKI_NAMESPACE_END
666
667#endif // PROMEKI_ENABLE_MDNS