GCC Code Coverage Report


Directory: ./
File: common.h
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 4 4 100.0%
Functions: 1 1 100.0%
Branches: 1 2 50.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 <stdint.h>
15 #include "fpp-json-fwd.h"
16
17 #include <functional>
18 #include <list>
19 #include <string>
20 #include <vector>
21
22 #include "common_mini.h"
23 #include "log.h"
24
25 /////////////////////////////////////////////////////////////////////////////
26 // printf macros for printing bitmaps
27 //
28 // Macros from https://stackoverflow.com/a/25108449
29
30 #define PRINTF_BINARY_PATTERN_INT8 "%c%c%c%c%c%c%c%c"
31 #define PRINTF_BYTE_TO_BINARY_INT8(i) \
32 (((i)&0x80ll) ? '1' : '0'), \
33 (((i)&0x40ll) ? '1' : '0'), \
34 (((i)&0x20ll) ? '1' : '0'), \
35 (((i)&0x10ll) ? '1' : '0'), \
36 (((i)&0x08ll) ? '1' : '0'), \
37 (((i)&0x04ll) ? '1' : '0'), \
38 (((i)&0x02ll) ? '1' : '0'), \
39 (((i)&0x01ll) ? '1' : '0')
40
41 #define PRINTF_BINARY_PATTERN_INT16 \
42 PRINTF_BINARY_PATTERN_INT8 PRINTF_BINARY_PATTERN_INT8
43 #define PRINTF_BYTE_TO_BINARY_INT16(i) \
44 PRINTF_BYTE_TO_BINARY_INT8((i) >> 8), PRINTF_BYTE_TO_BINARY_INT8(i)
45 #define PRINTF_BINARY_PATTERN_INT32 \
46 PRINTF_BINARY_PATTERN_INT16 PRINTF_BINARY_PATTERN_INT16
47 #define PRINTF_BYTE_TO_BINARY_INT32(i) \
48 PRINTF_BYTE_TO_BINARY_INT16((i) >> 16), PRINTF_BYTE_TO_BINARY_INT16(i)
49 #define PRINTF_BINARY_PATTERN_INT64 \
50 PRINTF_BINARY_PATTERN_INT32 PRINTF_BINARY_PATTERN_INT32
51 #define PRINTF_BYTE_TO_BINARY_INT64(i) \
52 PRINTF_BYTE_TO_BINARY_INT32((i) >> 32), PRINTF_BYTE_TO_BINARY_INT32(i)
53
54 /////////////////////////////////////////////////////////////////////////////
55 void HexDump(const char* title, const void* data, int len, FPPLoggerInstance& facility, int perLine = 16);
56 int CheckForHostSpecificFile(const std::string& hostname, std::string& filename);
57 int CheckForHostSpecificFile(const char* hostname, char* filename);
58 std::string ReplaceKeywords(std::string str, std::map<std::string, std::string>& keywords);
59 char* FindInterfaceForIP(char* ip);
60
61 void MergeJsonValues(Json::Value& a, Json::Value& b);
62 Json::Value LoadJsonFromFile(const std::string& filename);
63 Json::Value LoadJsonFromString(const std::string& str);
64 bool LoadJsonFromString(const std::string& str, Json::Value& root);
65 bool LoadJsonFromFile(const std::string& filename, Json::Value& root);
66 bool LoadJsonFromFile(const char* filename, Json::Value& root);
67
68 /*
69 * Load a config file and require its root to be the shape the caller expects.
70 *
71 * A file that parses cleanly but holds the wrong kind of value - an array where
72 * an object is expected, or the reverse - is a corrupt config, not usable data.
73 * Every jsoncpp accessor a caller reaches for next (operator[], isMember(),
74 * getMemberNames(), get()) throws Json::LogicError on that mismatch, and nothing
75 * in fppd catches it, so a single bad config file aborts the daemon. Checking
76 * here, where untrusted file data enters, keeps that throw unreachable.
77 *
78 * On any failure root is set to an empty value of the expected shape, so callers
79 * that ignore the return value iterate over nothing instead of aborting.
80 *
81 * These are separate overloads rather than a defaulted argument on the two
82 * versions above on purpose: adding a parameter would change those mangled names
83 * and break already-built plugins that link against them. The shape is an FPP
84 * enum rather than Json::ValueType so this header can keep using the Json::Value
85 * forward declaration instead of pulling jsoncpp into every includer.
86 */
87 enum class JsonRoot {
88 Object,
89 Array
90 };
91 bool LoadJsonFromFile(const std::string& filename, Json::Value& root, JsonRoot expected);
92 Json::Value LoadJsonFromFile(const std::string& filename, JsonRoot expected);
93 bool LoadJsonFromString(const std::string& str, Json::Value& root, JsonRoot expected);
94 Json::Value LoadJsonFromString(const std::string& str, JsonRoot expected);
95 std::string SaveJsonToString(const Json::Value& root, const std::string& indentation = "");
96 bool SaveJsonToString(const Json::Value& root, std::string& str, const std::string& indentation);
97 bool SaveJsonToFile(const Json::Value& root, const std::string& filename, const std::string& indentation = "\t");
98 bool SaveJsonToFile(const Json::Value& root, const char* filename, const char* indentation = "\t");
99
100 std::string getSimpleHTMLTTag(const std::string& html, const std::string& searchStr, const std::string& skipStr, const std::string& endStr);
101 std::string getSimpleXMLTag(const std::string& xml, const std::string& tag);
102
103 // URL Helpers
104 // Build an "http://host[path]" URL from a raw address. IPv6 literals are
105 // wrapped in brackets and any link-local zone id ("%iface") is percent-encoded
106 // so curl accepts them; IPv4 addresses and hostnames are passed through
107 // unchanged. This is what makes discovery work on IPv6-only networks.
108 std::string buildHttpURL(const std::string& address, const std::string& path = "");
109
110 // True for an IPv4 127/8 or IPv6 ::1 address. Discovery treats loopback as
111 // "this box finding itself" and never as a peer -- see MultiSync::UpdateSystem().
112 bool IsLoopbackAddress(const std::string& address);
113
114 // Resolve `host` to a single IPv4 address, stored in `addr` in network byte
115 // order. A dotted-quad is parsed directly; anything else goes to getaddrinfo()
116 // and is remembered -- successes and failures alike -- in a small process-wide
117 // cache with a short TTL.
118 //
119 // The negative caching is the point. An unresolvable name costs a flat ~4s
120 // through systemd-resolved, and a name only has to appear once in
121 // co-universes.json to be looked up from several places during startup; six
122 // such lookups for two dead output hostnames were 23s of a 26s fppd start.
123 // Callers must still hold onto the address they get -- this is a stampede
124 // guard, not a substitute for the resolver.
125 //
126 // TTLs are deliberately short in both directions: long enough to collapse a
127 // startup burst, short enough that a controller which comes up (or moves) is
128 // picked up on the next poll rather than at the next restart.
129 bool ResolveHostToIPv4(const std::string& host, uint32_t& addr);
130
131 // As above, returning the dotted-quad form, or "" if it could not be resolved.
132 std::string ResolveHostToIPv4(const std::string& host);
133
134 // Drop every cached entry. Call this when the network underneath the resolver
135 // changes (an interface gaining or losing an address), so a name that failed
136 // while the link was down is retried immediately instead of after the TTL.
137 void FlushHostResolveCache();
138
139 // Reduces a MAC in any of the usual spellings to 12 uppercase hex digits with
140 // no separators, or "" if it isn't one. Every path that derives an identity
141 // from a hardware address must go through this, so that the same device gets
142 // the same string whichever way it was found.
143 std::string NormalizeMacAddress(const std::string& mac);
144
145 // The MAC of an on-link IPv4 neighbour, as 12 uppercase hex digits with no
146 // separators, or "" if it isn't known. Read from the kernel's ARP table, so it
147 // only answers for hosts on a directly attached subnet -- a routed host simply
148 // has no entry, which is what we want (we must never hand back the gateway's
149 // MAC for a device behind it). Used to give controllers that report no UUID of
150 // their own a stable identity; see MultiSyncSystem::update().
151 std::string GetMacForAddress(const std::string& address);
152 // DEPRECATED. These drive a private curl easy handle to completion inline, so
153 // the calling thread is stopped for as long as the request takes -- up to the
154 // connect timeout plus `timeout` per call, and a caller that makes several in a
155 // row pays that for each one. New FPP code must use CurlManager instead: its
156 // add()/addGet()/addPost()/addPut() queue onto the shared multi handle and hand
157 // the answer to a callback run from the main loop, so nothing blocks.
158 //
159 // They are kept, and will stay kept, because external channel-output plugins
160 // link against them. They are also still the only correct choice for the FPP
161 // code that has no main loop to complete against: fppmm and fppoled are their
162 // own binaries, and CurlManager's synchronous doGet()/doPut() are not usable
163 // off the main-loop thread -- they spin on processCurls(), which drains and
164 // invokes *every* subsystem's pending callbacks on whatever thread calls it.
165 // Until CurlManager grows a thread-safe blocking call, "deprecated" here means
166 // "do not reach for this in new fppd code", not "unusable".
167 bool urlHelper(const std::string method, const std::string& url, const std::string& data, std::string& resp, const std::list<std::string>& headers, const unsigned int timeout = 30);
168 bool urlHelper(const std::string method, const std::string& url, const std::string& data, std::string& resp, const unsigned int timeout = 30);
169 bool urlHelper(const std::string method, const std::string& url, std::string& resp, const unsigned int timeout = 30);
170 bool urlGet(const std::string url, std::string& resp);
171 bool urlPost(const std::string url, const std::string data, std::string& resp);
172 bool urlPut(const std::string url, const std::string data, std::string& resp);
173 bool urlDelete(const std::string url, const std::string data, std::string& resp);
174 bool urlDelete(const std::string url, std::string& resp);
175
176 std::string base64Encode(uint8_t const* bytes_to_encode, unsigned int in_len);
177 std::vector<uint8_t> base64Decode(std::string const& encodedString);
178
179 void ShutdownFPPD(bool restart = false);
180 // Restart fppd and resume the currently-running playlist even when it was
181 // started manually rather than by the scheduler. For self-initiated recovery
182 // restarts (the wedged-decoder ladder in GStreamerOut) where coming back idle
183 // and leaving the show -- and every synced remote -- dead defeats the whole
184 // point of restarting (issue #2727).
185 void RestartFPPDResumingPlaylist();
186 bool RestartShouldResumePlaylist();
187 void RegisterShutdownHandler(const std::function<void(bool)> hook);
188
189 // Builds a -manual crash report; returns its name in crashes/, or "" and sets error
190 std::string BuildManualCrashReport(std::string& error);
191 void RegisterManualCrashReportHandler(const std::function<std::string(std::string&)> hook);
192
193 // Breadcrumb for the main-loop stall watchdog (issue #2727): the last call the
194 // fppd main loop entered. Pass a string literal (or any string with static
195 // storage) -- the watchdog thread reads the pointer while the main loop is
196 // wedged, so it must outlive the call that set it.
197 void SetMainLoopPhase(const char* phase);
198 const char* GetMainLoopPhase();
199
200 void GetCurrentFPPDStatus(Json::Value& result);
201
202 std::string getPlatform();
203
204 257554 inline std::string toStdStringAndFree(char* v) {
205
1/2
✓ Branch 0 taken 257554 times.
✗ Branch 1 not taken.
257554 std::string s = v;
206 257554 free(v);
207 257554 return s;
208 }
209
210 void SetThreadName(const std::string& name);
211 bool SetThreadRealtimePriority(int priority);
212
213 void TransposeBits32x32(uint32_t *dst, uint32_t *src);
214
215