diff options
Diffstat (limited to 'misc.cc')
-rw-r--r-- | misc.cc | 169 |
1 files changed, 118 insertions, 51 deletions
@@ -56,6 +56,7 @@ #include <boost/format.hpp> #include "iputils.hh" #include "dnsparser.hh" +#include "dns_random.hh" #include <pwd.h> #include <grp.h> #include <climits> @@ -432,41 +433,46 @@ int waitForMultiData(const set<int>& fds, const int seconds, const int useconds, } } set<int>::const_iterator it(pollinFDs.begin()); - advance(it, random() % pollinFDs.size()); + advance(it, dns_random(pollinFDs.size())); *fdOut = *it; return 1; } // returns -1 in case of error, 0 if no data is available, 1 if there is. In the first two cases, errno is set -int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int*fd) +int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fdPtr) { - int ret; - - struct pollfd pfds[2]; - memset(&pfds[0], 0, 2*sizeof(struct pollfd)); + std::array<pollfd,2> pfds{}; + memset(pfds.data(), 0, pfds.size() * sizeof(struct pollfd)); pfds[0].fd = fd1; pfds[1].fd = fd2; pfds[0].events= pfds[1].events = POLLIN; - int nsocks = 1 + (fd2 >= 0); // fd2 can optionally be -1 + int nsocks = 1 + static_cast<int>(fd2 >= 0); // fd2 can optionally be -1 - if(seconds >= 0) - ret = poll(pfds, nsocks, seconds * 1000 + useconds/1000); - else - ret = poll(pfds, nsocks, -1); - if(!ret || ret < 0) + int ret{}; + if (seconds >= 0) { + ret = poll(pfds.data(), nsocks, seconds * 1000 + useconds / 1000); + } + else { + ret = poll(pfds.data(), nsocks, -1); + } + if (ret <= 0) { return ret; + } - if((pfds[0].revents & POLLIN) && !(pfds[1].revents & POLLIN)) - *fd = pfds[0].fd; - else if((pfds[1].revents & POLLIN) && !(pfds[0].revents & POLLIN)) - *fd = pfds[1].fd; + if ((pfds[0].revents & POLLIN) != 0 && (pfds[1].revents & POLLIN) == 0) { + *fdPtr = pfds[0].fd; + } + else if ((pfds[1].revents & POLLIN) != 0 && (pfds[0].revents & POLLIN) == 0) { + *fdPtr = pfds[1].fd; + } else if(ret == 2) { - *fd = pfds[random()%2].fd; + *fdPtr = pfds.at(dns_random_uint32() % 2).fd; + } + else { + *fdPtr = -1; // should never happen } - else - *fd = -1; // should never happen return 1; } @@ -576,17 +582,25 @@ string bitFlip(const string &str) void cleanSlashes(string &str) { - string::const_iterator i; string out; - for(i=str.begin();i!=str.end();++i) { - if(*i=='/' && i!=str.begin() && *(i-1)=='/') - continue; - out.append(1,*i); + bool keepNextSlash = true; + for (const auto& value : str) { + if (value == '/') { + if (keepNextSlash) { + keepNextSlash = false; + } + else { + continue; + } + } + else { + keepNextSlash = true; + } + out.append(1, value); } - str=out; + str = std::move(out); } - bool IpToU32(const string &str, uint32_t *ip) { if(str.empty()) { @@ -847,11 +861,11 @@ bool stringfgets(FILE* fp, std::string& line) bool readFileIfThere(const char* fname, std::string* line) { line->clear(); - auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(fname, "r"), fclose); - if (!fp) { + auto filePtr = pdns::UniqueFilePtr(fopen(fname, "r")); + if (!filePtr) { return false; } - return stringfgets(fp.get(), *line); + return stringfgets(filePtr.get(), *line); } Regex::Regex(const string &expr) @@ -1014,7 +1028,7 @@ bool isNonBlocking(int sock) return flags & O_NONBLOCK; } -bool setReceiveSocketErrors(int sock, int af) +bool setReceiveSocketErrors([[maybe_unused]] int sock, [[maybe_unused]] int af) { #ifdef __linux__ int tmp = 1, ret; @@ -1159,7 +1173,7 @@ int getMACAddress(const ComboAddress& ca, char* dest, size_t destLen) return foundMAC ? 0 : ENOENT; } #else -int getMACAddress(const ComboAddress& ca, char* dest, size_t len) +int getMACAddress(const ComboAddress& /* ca */, char* /* dest */, size_t /* len */) { return ENOENT; } @@ -1175,7 +1189,7 @@ string getMACAddress(const ComboAddress& ca) return ret; } -uint64_t udpErrorStats(const std::string& str) +uint64_t udpErrorStats([[maybe_unused]] const std::string& str) { #ifdef __linux__ ifstream ifs("/proc/net/snmp"); @@ -1217,7 +1231,7 @@ uint64_t udpErrorStats(const std::string& str) return 0; } -uint64_t udp6ErrorStats(const std::string& str) +uint64_t udp6ErrorStats([[maybe_unused]] const std::string& str) { #ifdef __linux__ const std::map<std::string, std::string> keys = { @@ -1371,30 +1385,29 @@ DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum) uint64_t getOpenFileDescriptors(const std::string&) { #ifdef __linux__ - DIR* dirhdl=opendir(("/proc/"+std::to_string(getpid())+"/fd/").c_str()); - if(!dirhdl) - return 0; - - struct dirent *entry; - int ret=0; - while((entry = readdir(dirhdl))) { + uint64_t nbFileDescriptors = 0; + const auto dirName = "/proc/" + std::to_string(getpid()) + "/fd/"; + auto directoryError = pdns::visit_directory(dirName, [&nbFileDescriptors]([[maybe_unused]] ino_t inodeNumber, const std::string_view& name) { uint32_t num; try { - pdns::checked_stoi_into(num, entry->d_name); + pdns::checked_stoi_into(num, std::string(name)); + if (std::to_string(num) == name) { + nbFileDescriptors++; + } } catch (...) { - continue; // was not a number. + // was not a number. } - if(std::to_string(num) == entry->d_name) - ret++; + return true; + }); + if (directoryError) { + return 0U; } - closedir(dirhdl); - return ret; - + return nbFileDescriptors; #elif defined(__OpenBSD__) // FreeBSD also has this in libopenbsd, but I don't know if that's available always return getdtablecount(); #else - return 0; + return 0U; #endif } @@ -1545,7 +1558,7 @@ bool isSettingThreadCPUAffinitySupported() #endif } -int mapThreadToCPUList(pthread_t tid, const std::set<int>& cpus) +int mapThreadToCPUList([[maybe_unused]] pthread_t tid, [[maybe_unused]] const std::set<int>& cpus) { #ifdef HAVE_PTHREAD_SETAFFINITY_NP # ifdef __NetBSD__ @@ -1613,7 +1626,7 @@ std::vector<ComboAddress> getResolvers(const std::string& resolvConfPath) return results; } -size_t getPipeBufferSize(int fd) +size_t getPipeBufferSize([[maybe_unused]] int fd) { #ifdef F_GETPIPE_SZ int res = fcntl(fd, F_GETPIPE_SZ); @@ -1627,7 +1640,7 @@ size_t getPipeBufferSize(int fd) #endif /* F_GETPIPE_SZ */ } -bool setPipeBufferSize(int fd, size_t size) +bool setPipeBufferSize([[maybe_unused]] int fd, [[maybe_unused]] size_t size) { #ifdef F_SETPIPE_SZ if (size > static_cast<size_t>(std::numeric_limits<int>::max())) { @@ -1735,3 +1748,57 @@ bool constantTimeStringEquals(const std::string& a, const std::string& b) #endif /* !HAVE_SODIUM_MEMCMP */ #endif /* !HAVE_CRYPTO_MEMCMP */ } + +namespace pdns +{ +struct CloseDirDeleter +{ + void operator()(DIR* dir) const noexcept { + closedir(dir); + } +}; + +std::optional<std::string> visit_directory(const std::string& directory, const std::function<bool(ino_t inodeNumber, const std::string_view& name)>& visitor) +{ + auto dirHandle = std::unique_ptr<DIR, CloseDirDeleter>(opendir(directory.c_str())); + if (!dirHandle) { + auto err = errno; + return std::string("Error opening directory '" + directory + "': " + stringerror(err)); + } + + bool keepGoing = true; + struct dirent* ent = nullptr; + // NOLINTNEXTLINE(concurrency-mt-unsafe): readdir is thread-safe nowadays and readdir_r is deprecated + while (keepGoing && (ent = readdir(dirHandle.get())) != nullptr) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay: dirent API + auto name = std::string_view(ent->d_name, strlen(ent->d_name)); + keepGoing = visitor(ent->d_ino, name); + } + + return std::nullopt; +} + +UniqueFilePtr openFileForWriting(const std::string& filePath, mode_t permissions, bool mustNotExist, bool appendIfExists) +{ + int flags = O_WRONLY | O_CREAT; + if (mustNotExist) { + flags |= O_EXCL; + } + else if (appendIfExists) { + flags |= O_APPEND; + } + int fileDesc = open(filePath.c_str(), flags, permissions); + if (fileDesc == -1) { + return {}; + } + auto filePtr = pdns::UniqueFilePtr(fdopen(fileDesc, appendIfExists ? "a" : "w")); + if (!filePtr) { + auto error = errno; + close(fileDesc); + errno = error; + return {}; + } + return filePtr; +} + +} |