1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-16 00:00:02 +01:00
VILLASnode/common/lib/utils.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

379 lines
6.3 KiB
C++
Raw Normal View History

2018-08-21 00:25:44 +02:00
/** Utilities.
*
* @author Daniel Krebs <github@daniel-krebs.net>
* @author Steffen Vogel <post@steffenvogel.de>
2022-03-15 09:05:42 -04:00
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
2022-05-19 17:40:10 +02:00
* @license Apache License 2.0
2018-08-21 00:25:44 +02:00
*********************************************************************************/
#include <vector>
#include <string>
2018-08-27 11:09:25 +02:00
#include <iostream>
2018-08-21 00:25:44 +02:00
#include <cstdlib>
#include <cstdio>
#include <cstdint>
#include <cstdarg>
#include <cstring>
2018-08-27 11:09:25 +02:00
#include <unistd.h>
#include <cmath>
2019-04-07 15:12:32 +02:00
#include <pthread.h>
#include <cctype>
2019-04-07 15:12:32 +02:00
#include <fcntl.h>
2018-08-27 11:09:25 +02:00
2019-05-28 10:55:24 +02:00
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/evp.h>
#include <jansson.h>
#include <uuid/uuid.h>
2019-05-28 10:55:24 +02:00
2021-08-11 12:40:19 -04:00
#include <villas/config.hpp>
2018-08-21 00:25:44 +02:00
#include <villas/utils.hpp>
2019-04-23 12:57:51 +02:00
#include <villas/colors.hpp>
2020-01-27 12:17:57 +01:00
#include <villas/exceptions.hpp>
2018-11-01 14:31:41 +01:00
#include <villas/log.hpp>
2018-08-21 00:25:44 +02:00
2019-04-23 12:57:51 +02:00
static pthread_t main_thread;
2018-08-21 00:25:44 +02:00
namespace villas {
namespace utils {
2022-10-21 09:09:39 +00:00
std::vector<std::string> tokenize(std::string s, const std::string &delimiter)
2018-08-21 00:25:44 +02:00
{
std::vector<std::string> tokens;
size_t lastPos = 0;
size_t curentPos;
2019-05-28 10:55:24 +02:00
while ((curentPos = s.find(delimiter, lastPos)) != std::string::npos) {
2018-08-21 00:25:44 +02:00
const size_t tokenLength = curentPos - lastPos;
tokens.push_back(s.substr(lastPos, tokenLength));
// Advance in string
2018-08-21 00:25:44 +02:00
lastPos = curentPos + delimiter.length();
}
// Check if there's a last token behind the last delimiter.
2019-05-28 10:55:24 +02:00
if (lastPos != s.length()) {
2018-08-21 00:25:44 +02:00
const size_t lastTokenLength = s.length() - lastPos;
tokens.push_back(s.substr(lastPos, lastTokenLength));
}
return tokens;
}
2021-09-19 19:05:53 +02:00
ssize_t readRandom(char *buf, size_t len)
2018-08-27 11:09:25 +02:00
{
int fd;
2018-10-21 21:53:16 +01:00
ssize_t bytes = -1;
2018-08-27 11:09:25 +02:00
fd = open("/dev/urandom", O_RDONLY);
if (fd < 0)
return -1;
while (len) {
bytes = read(fd, buf, len);
if (bytes < 0)
break;
len -= bytes;
buf += bytes;
}
close(fd);
return bytes;
}
// Setup exit handler
2021-09-19 19:05:53 +02:00
int signalsInit(void (*cb)(int signal, siginfo_t *sinfo, void *ctx), std::list<int> cbSignals, std::list<int> ignoreSignals)
2018-08-27 11:09:25 +02:00
{
int ret;
2018-11-30 21:43:37 +01:00
Logger logger = logging.get("signals");
2018-11-01 14:31:41 +01:00
logger->info("Initialize subsystem");
2018-08-27 11:09:25 +02:00
struct sigaction sa_cb;
sa_cb.sa_flags = SA_SIGINFO | SA_NODEFER;
sa_cb.sa_sigaction = cb;
2018-08-27 11:09:25 +02:00
struct sigaction sa_ign;
sa_ign.sa_flags = 0;
sa_ign.sa_handler = SIG_IGN;
2018-08-27 11:09:25 +02:00
main_thread = pthread_self();
sigemptyset(&sa_cb.sa_mask);
sigemptyset(&sa_ign.sa_mask);
2018-08-27 11:09:25 +02:00
2022-01-11 09:14:41 -05:00
cbSignals.insert(cbSignals.begin(), { SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGALRM });
cbSignals.sort();
cbSignals.unique();
2018-08-27 11:09:25 +02:00
for (auto signal : cbSignals) {
ret = sigaction(signal, &sa_cb, nullptr);
if (ret)
return ret;
}
2018-08-27 11:09:25 +02:00
for (auto signal : ignoreSignals) {
ret = sigaction(signal, &sa_ign, nullptr);
if (ret)
return ret;
}
2018-08-27 11:09:25 +02:00
return 0;
}
char * decolor(char *str)
{
char *p, *q;
bool inseq = false;
for (p = q = str; *p; p++) {
switch (*p) {
case 0x1b:
if (*(++p) == '[') {
inseq = true;
continue;
}
break;
case 'm':
if (inseq) {
inseq = false;
continue;
}
break;
}
if (!inseq) {
*q = *p;
q++;
}
}
*q = '\0';
return str;
}
void killme(int sig)
{
// Send only to main thread in case the ID was initilized by signalsInit()
if (main_thread)
pthread_kill(main_thread, sig);
else
kill(0, sig);
}
2021-09-19 19:05:53 +02:00
double boxMuller(float m, float s)
2019-04-07 15:12:32 +02:00
{
double x1, x2, y1;
static double y2;
static int use_last = 0;
if (use_last) { // Use value from previous call
2019-04-07 15:12:32 +02:00
y1 = y2;
use_last = 0;
}
else {
double w;
do {
x1 = 2.0 * randf() - 1.0;
x2 = 2.0 * randf() - 1.0;
w = x1*x1 + x2*x2;
} while (w >= 1.0);
w = sqrt(-2.0 * log(w) / w);
y1 = x1 * w;
y2 = x2 * w;
use_last = 1;
}
return m + y1 * s;
}
double randf()
{
return (double) random() / RAND_MAX;
}
char * vstrcatf(char **dest, const char *fmt, va_list ap)
{
char *tmp;
int n = *dest ? strlen(*dest) : 0;
int i = vasprintf(&tmp, fmt, ap);
*dest = (char *)(realloc(*dest, n + i + 1));
2019-04-08 10:42:45 +02:00
if (*dest != nullptr)
2019-04-07 15:12:32 +02:00
strncpy(*dest+n, tmp, i + 1);
free(tmp);
return *dest;
}
2019-04-23 12:57:51 +02:00
char * strcatf(char **dest, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vstrcatf(dest, fmt, ap);
va_end(ap);
return *dest;
}
2019-04-07 15:12:32 +02:00
char * strf(const char *fmt, ...)
{
2019-04-08 10:42:45 +02:00
char *buf = nullptr;
2019-04-07 15:12:32 +02:00
va_list ap;
va_start(ap, fmt);
vstrcatf(&buf, fmt, ap);
va_end(ap);
return buf;
}
char * vstrf(const char *fmt, va_list va)
{
2019-04-08 10:42:45 +02:00
char *buf = nullptr;
2019-04-07 15:12:32 +02:00
vstrcatf(&buf, fmt, va);
return buf;
}
void * memdup(const void *src, size_t bytes)
{
2019-07-01 08:30:05 +02:00
void *dst = new char[bytes];
2020-01-27 12:17:57 +01:00
if (!dst)
throw MemoryAllocationError();
2019-04-07 15:12:32 +02:00
memcpy(dst, src, bytes);
return dst;
}
pid_t spawn(const char* name, char *const argv[])
{
pid_t pid;
pid = fork();
switch (pid) {
case -1: return -1;
case 0: return execvp(name, (char * const*) argv);
}
return pid;
}
size_t strlenp(const char *str)
{
size_t sz = 0;
for (const char *d = str; *d; d++) {
const unsigned char *c = (const unsigned char *) d;
if (isprint(*c))
sz++;
else if (c[0] == '\b')
sz--;
else if (c[0] == '\t')
sz += 4; // Tab width == 4
// CSI sequence
2019-04-07 15:12:32 +02:00
else if (c[0] == '\e' && c[1] == '[') {
c += 2;
while (*c && *c != 'm')
c++;
}
// UTF-8
2019-04-07 15:12:32 +02:00
else if (c[0] >= 0xc2 && c[0] <= 0xdf) {
sz++;
c += 1;
}
else if (c[0] >= 0xe0 && c[0] <= 0xef) {
sz++;
c += 2;
}
else if (c[0] >= 0xf0 && c[0] <= 0xf4) {
sz++;
c += 3;
}
d = (const char *) c;
}
return sz;
}
2019-04-23 12:57:51 +02:00
int log2i(long long x) {
if (x == 0)
return 1;
return sizeof(x) * 8 - __builtin_clzll(x) - 1;
}
2019-05-28 10:55:24 +02:00
int sha1sum(FILE *f, unsigned char *sha1)
{
2022-10-21 09:09:39 +00:00
int ret;
2019-05-28 10:55:24 +02:00
char buf[512];
ssize_t bytes;
long seek;
seek = ftell(f);
fseek(f, 0, SEEK_SET);
2022-10-21 09:09:39 +00:00
EVP_MD_CTX *c = EVP_MD_CTX_new();
ret = EVP_DigestInit(c, EVP_sha1());
if (!ret)
return -1;
2019-05-28 10:55:24 +02:00
bytes = fread(buf, 1, 512, f);
while (bytes > 0) {
2022-10-21 09:09:39 +00:00
EVP_DigestUpdate(c, buf, bytes);
2019-05-28 10:55:24 +02:00
bytes = fread(buf, 1, 512, f);
}
2022-10-21 09:09:39 +00:00
EVP_DigestFinal(c, sha1, nullptr);
2019-05-28 10:55:24 +02:00
fseek(f, seek, SEEK_SET);
2022-10-21 09:09:39 +00:00
EVP_MD_CTX_free(c);
2019-05-28 10:55:24 +02:00
return 0;
}
2021-09-19 19:05:53 +02:00
bool isDocker()
{
return access("/.dockerenv", F_OK) != -1;
}
2021-09-19 19:05:53 +02:00
bool isKubernetes()
{
return access("/var/run/secrets/kubernetes.io", F_OK) != -1 ||
getenv("KUBERNETES_SERVICE_HOST") != nullptr;
}
2021-09-19 19:05:53 +02:00
bool isContainer() {
return isDocker() || isKubernetes();
}
2021-09-20 18:48:23 +02:00
bool isPrivileged() {
// TODO: a cleaner way would be to use libcap here and check for the
// SYS_ADMIN capability.
auto *f = fopen(PROCFS_PATH "/sys/vm/nr_hugepages", "w");
if (!f)
return false;
fclose(f);
2021-11-25 07:17:58 -05:00
return true;
2021-09-20 18:48:23 +02:00
}
} // namespace utils
} // namespace villas