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