/*** This file is part of snapcast Copyright (C) 2014-2017 Johannes Pohl This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ***/ #ifndef UTILS_H #define UTILS_H #include "common/strCompat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef FREEBSD #include #endif #include #ifdef MACOS #include #include #endif // trim from start static inline std::string <rim(std::string &s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(std::isspace)))); return s; } // trim from end static inline std::string &rtrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(std::isspace))).base(), s.end()); return s; } // trim from both ends static inline std::string &trim(std::string &s) { return ltrim(rtrim(s)); } // trim from start static inline std::string ltrim_copy(const std::string &s) { std::string str(s); return ltrim(str); } // trim from end static inline std::string rtrim_copy(const std::string &s) { std::string str(s); return rtrim(str); } // trim from both ends static inline std::string trim_copy(const std::string &s) { std::string str(s); return trim(str); } // decode %xx to char static std::string uriDecode(const std::string& src) { std::string ret; char ch; for (size_t i=0; i(ii); ret += ch; i += 2; } else { ret += src[i]; } } return (ret); } static std::vector &split(const std::string &s, char delim, std::vector &elems) { std::stringstream ss(s); std::string item; while (std::getline(ss, item, delim)) { elems.push_back(item); } return elems; } static std::vector split(const std::string &s, char delim) { std::vector elems; split(s, delim, elems); return elems; } static int mkdirRecursive(const char *path, mode_t mode) { std::vector pathes = split(path, '/'); std::stringstream ss; int res = 0; for (const auto& p: pathes) { if (p.empty()) continue; ss << "/" << p; int res = mkdir(ss.str().c_str(), mode); if ((res != 0) && (errno != EEXIST)) return res; } return res; } static std::string execGetOutput(const std::string& cmd) { std::shared_ptr pipe(popen((cmd + " 2> /dev/null").c_str(), "r"), pclose); if (!pipe) return ""; char buffer[1024]; std::string result = ""; while (!feof(pipe.get())) { if (fgets(buffer, 1024, pipe.get()) != NULL) result += buffer; } return trim(result); } #ifdef ANDROID static std::string getProp(const std::string& prop) { return execGetOutput("getprop " + prop); } #endif static std::string getOS() { std::string os; #ifdef ANDROID os = trim_copy("Android " + getProp("ro.build.version.release")); #else os = execGetOutput("lsb_release -d"); if (os.find(":") != std::string::npos) os = trim_copy(os.substr(os.find(":") + 1)); #endif if (os.empty()) { os = trim_copy(execGetOutput("cat /etc/os-release /etc/openwrt_release |grep -e PRETTY_NAME -e DISTRIB_DESCRIPTION")); if (os.find("=") != std::string::npos) { os = trim_copy(os.substr(os.find("=") + 1)); os.erase(std::remove(os.begin(), os.end(), '"'), os.end()); os.erase(std::remove(os.begin(), os.end(), '\''), os.end()); } } if (os.empty()) { utsname u; uname(&u); os = u.sysname; } return trim_copy(os); } static std::string getHostName() { #ifdef ANDROID std::string result = getProp("net.hostname"); if (!result.empty()) return result; #endif char hostname[1024]; hostname[1023] = '\0'; gethostname(hostname, 1023); return hostname; } static std::string getArch() { std::string arch; #ifdef ANDROID arch = getProp("ro.product.cpu.abi"); if (!arch.empty()) return arch; #endif arch = execGetOutput("arch"); if (arch.empty()) arch = execGetOutput("uname -i"); if (arch.empty() || (arch == "unknown")) arch = execGetOutput("uname -m"); return trim_copy(arch); } static long uptime() { #ifndef FREEBSD struct sysinfo info; sysinfo(&info); return info.uptime; #else std::string uptime = execGetOutput("sysctl kern.boottime"); if ((uptime.find(" sec = ") != std::string::npos) && (uptime.find(",") != std::string::npos)) { uptime = trim_copy(uptime.substr(uptime.find(" sec = ") + 7)); uptime.resize(uptime.find(",")); timeval now; gettimeofday(&now, NULL); try { return now.tv_sec - cpt::stoul(uptime); } catch (...) { } } return 0; #endif } /// http://stackoverflow.com/questions/2174768/generating-random-uuids-in-linux static std::string generateUUID() { static bool initialized(false); if (!initialized) { std::srand(std::time(0)); initialized = true; } std::stringstream ss; ss << std::setfill('0') << std::hex << std::setw(4) << (std::rand() % 0xffff) << std::setw(4) << (std::rand() % 0xffff) << "-" << std::setw(4) << (std::rand() % 0xffff) << "-" << std::setw(4) << (std::rand() % 0xffff) << "-" << std::setw(4) << (std::rand() % 0xffff) << "-" << std::setw(4) << (std::rand() % 0xffff) << std::setw(4) << (std::rand() % 0xffff) << std::setw(4) << (std::rand() % 0xffff); return ss.str(); } /// https://gist.github.com/OrangeTide/909204 static std::string getMacAddress(int sock) { struct ifreq ifr; struct ifconf ifc; char buf[16384]; int success = 0; if (sock < 0) return ""; ifc.ifc_len = sizeof(buf); ifc.ifc_buf = buf; if (ioctl(sock, SIOCGIFCONF, &ifc) != 0) return ""; struct ifreq* it = ifc.ifc_req; for (int i=0; iifr_addr.sa_len; #else size_t len = sizeof(*it); #endif strcpy(ifr.ifr_name, it->ifr_name); if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) { if (!(ifr.ifr_flags & IFF_LOOPBACK)) // don't count loopback { #ifdef MACOS /// Dirty Mac version struct ifaddrs *ifap, *ifaptr; unsigned char *ptr; if (getifaddrs(&ifap) == 0) { for (ifaptr = ifap; ifaptr != NULL; ifaptr = ifaptr->ifa_next) { // std::cout << ifaptr->ifa_name << ", " << ifreq->ifr_name << "\n"; if (strcmp(ifaptr->ifa_name, it->ifr_name) != 0) continue; if (ifaptr->ifa_addr->sa_family == AF_LINK) { ptr = (unsigned char *)LLADDR((struct sockaddr_dl *)ifaptr->ifa_addr); char mac[19]; sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)); if (strcmp(mac, "00:00:00:00:00:00") == 0) continue; freeifaddrs(ifap); return mac; } } freeifaddrs(ifap); } #endif #ifdef FREEBSD if (ioctl(sock, SIOCGIFMAC, &ifr) == 0) #else if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) #endif { success = 1; break; } else { std::stringstream ss; ss << "/sys/class/net/" << ifr.ifr_name << "/address"; std::ifstream infile(ss.str().c_str()); std::string line; if (infile.good() && std::getline(infile, line)) { trim(line); if ((line.size() == 17) && (line[2] == ':')) return line; } } } } else { /* handle error */ } it = (struct ifreq*)((char*)it + len); i += len; } if (!success) return ""; char mac[19]; #ifndef FREEBSD sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x", (unsigned char)ifr.ifr_hwaddr.sa_data[0], (unsigned char)ifr.ifr_hwaddr.sa_data[1], (unsigned char)ifr.ifr_hwaddr.sa_data[2], (unsigned char)ifr.ifr_hwaddr.sa_data[3], (unsigned char)ifr.ifr_hwaddr.sa_data[4], (unsigned char)ifr.ifr_hwaddr.sa_data[5]); #else sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x", (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[0], (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[1], (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[2], (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[3], (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[4], (unsigned char)ifr.ifr_ifru.ifru_addr.sa_data[5]); #endif return mac; } #endif