| 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 |