GCC Code Coverage Report


Directory: ./
File: MDNSManager.h
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 1 1 100.0%
Functions: 1 1 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 #pragma once
2 /*
3 * This file is part of the Falcon Player (FPP) and is Copyright (C)
4 * 2013-2022 by the Falcon Player Developers.
5 *
6 * The Falcon Player (FPP) is free software, and is covered under
7 * multiple Open Source licenses. Please see the included 'LICENSES'
8 * file for descriptions of what files are covered by each license.
9 *
10 * This source file is covered under the LGPL v2.1 as described in the
11 * included LICENSE.LGPL file.
12 */
13
14 #include <functional>
15 #include <map>
16 #include <mutex>
17 #include <set>
18 #include <string>
19
20 class MDNSManager {
21 public:
22 static MDNSManager INSTANCE;
23
24 MDNSManager();
25 ~MDNSManager();
26
27 /**
28 * @param callbacks placeholder matching other managers, not currently used
29 */
30 void Initialize(std::map<int, std::function<bool(int)>>& callbacks);
31 void Cleanup();
32
33 /**
34 * Register a callback that will be invoked when a new MDNS-based host
35 * address is discovered. The argument is the IPv4 address of the host.
36 * Returns an ID that can be used to remove the callback later.
37 */
38 int registerCallback(std::function<void(const std::string&)>&& callback);
39 void removeCallback(int id);
40
41 // Helpers used by the active backend's C callbacks (public so static
42 // callbacks can reach them). isWled is true when the host was discovered
43 // via the _wled._tcp browser, in which case it is probed over HTTP rather
44 // than the FPP ping protocol.
45 void HandleResolveIP(const std::string& ip, bool isWled = false);
46 void SetServiceBrowser(void* sb);
47 void SetWLEDServiceBrowser(void* sb);
48 void RegisterService(void* client); // register local _fppd._udp service
49 void PickAlternativeServiceName(); // pick new name on collision
50 void WithdrawService(); // daemon re-establishing its host records
51 void ResetServiceName(); // back to the host name, retries cleared
52 void ScheduleServiceNameRetry(); // try the host name again after a collision
53 void RetryBaseServiceName();
54
55 // Client liveness, driven from the backend's client state callback. Only
56 // Avahi has a client that can go away; the Bonjour backend leaves these
57 // empty.
58 void NoteClientRunning(); // connected: clear the retry state and the warning
59 void NoteClientDown(); // disconnected: start/continue the reconnect retries
60
61 8 const std::string& ServiceName() const { return m_serviceName; }
62 void SetServiceName(const std::string& name) { m_serviceName = name; }
63
64 private:
65 // Defined by exactly one of MDNSBackendAvahi.cpp / MDNSBackendBonjour.cpp,
66 // or by the no-op pair in MDNSManager.cpp when the platform has neither.
67 void StartBackend();
68 void StopBackend();
69
70 // Set once the backend has started. It does NOT mean there is a live
71 // connection to a daemon - for Avahi that is m_client, which comes and goes.
72 bool m_running = false;
73
74 // Avahi's client never reconnects: once avahi-daemon goes away the client is
75 // dead for good and a new one has to be built. These drive that retry, and hold
76 // off the "is avahi-daemon running?" warning until the outage looks real rather
77 // than like the daemon restarting or the machine shutting down. Bonjour has
78 // no equivalent failure -- mDNSResponder is part of the OS -- so its backend
79 // leaves them alone.
80 int m_reconnectTimerFd = -1;
81 std::function<bool(int)> m_reconnectCallback;
82 long long m_clientDownSinceMS = 0; // 0 == client is up
83 int m_reconnectDelayMS = 0;
84 bool StartAvahiClient();
85 void ScheduleClientReconnect();
86 void ReconnectAvahiClient();
87
88 std::set<std::string> m_knownHosts;
89
90 std::recursive_mutex m_callbackLock;
91 std::map<int, std::function<void(const std::string&)>> m_callbacks;
92 int m_nextCallbackId = 1;
93
94 // Service name (may be modified on collision), and the host name it started
95 // as. A collision is not always another box with the same name -- avahi
96 // re-announcing after a host name change can hear an echo of our own old
97 // records -- so an alternative name is only kept after the base name has
98 // been retried and lost a few times.
99 std::string m_serviceName;
100 std::string m_baseServiceName;
101 void* m_nameRetryTimeout = nullptr; // Avahi only: AvahiTimeout* on m_pollAdapter
102 int m_nameRetryAttempts = 0;
103 void CancelServiceNameRetry();
104
105 // Backend-owned handles. Only the active backend file touches these, and
106 // what they point at is that backend's business: AvahiPoll*, AvahiClient*,
107 // AvahiServiceBrowser* and AvahiEntryGroup* for Avahi; DNSServiceRef for
108 // Bonjour. m_backendState is for whatever else a backend needs to keep --
109 // Bonjour hangs its list of in-flight resolves there.
110 void* m_pollAdapter = nullptr; // Avahi only: custom AvahiPoll adapter
111 void* m_client = nullptr; // connection to the mDNS daemon
112 void* m_serviceBrowser = nullptr; // browser for _fppd._udp
113 void* m_wledServiceBrowser = nullptr; // browser for _wled._tcp
114 void* m_entryGroup = nullptr; // the locally advertised services
115 void* m_backendState = nullptr; // backend's own bookkeeping
116 };
117