369 lines
8.9 KiB
C
369 lines
8.9 KiB
C
#pragma once
|
||
|
||
#ifdef __cplusplus
|
||
extern "C"
|
||
{
|
||
#endif
|
||
|
||
#include <time.h>
|
||
#include <errno.h>
|
||
#include <stdio.h>
|
||
#include <stdint.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
#include "stellar/utils.h"
|
||
|
||
#include "toml.h"
|
||
#include "log_internal.h"
|
||
|
||
#define RX_BURST_MAX 32
|
||
#define MAX_THREAD_NUM 256 // limit by snowflake
|
||
#define SYNC_STAT_INTERVAL_MS 1 // TODO
|
||
|
||
#define ATOMIC_INC(x) __atomic_fetch_add(x, 1, __ATOMIC_RELAXED)
|
||
#define ATOMIC_DEC(x) __atomic_fetch_sub(x, 1, __ATOMIC_RELAXED)
|
||
#define ATOMIC_READ(x) __atomic_load_n(x, __ATOMIC_RELAXED)
|
||
#define ATOMIC_ZERO(x) __atomic_fetch_and(x, 0, __ATOMIC_RELAXED)
|
||
#define ATOMIC_ADD(x, y) __atomic_fetch_add(x, y, __ATOMIC_RELAXED)
|
||
#define ATOMIC_SET(x, y) __atomic_store_n(x, y, __ATOMIC_RELAXED)
|
||
|
||
|
||
/*
|
||
* The maximum number of seconds that can be stored in the time_t value is 2147483647 –- a little over 68 years.
|
||
*
|
||
* struct timespec
|
||
* {
|
||
* time_t tv_sec; // seconds
|
||
* long tv_nsec; // nanoseconds
|
||
* };
|
||
*
|
||
* 1 s = 1000 ms
|
||
* 1 ms = 1000 us
|
||
* 1 us = 1000 ns
|
||
*/
|
||
|
||
#define TIMESPEC_TO_MSEC(ts) ((ts).tv_sec * 1000 + (ts).tv_nsec / 1000000)
|
||
|
||
static inline uint64_t clock_get_real_time_ms()
|
||
{
|
||
struct timespec now;
|
||
clock_gettime(CLOCK_REALTIME_COARSE, &now);
|
||
|
||
return TIMESPEC_TO_MSEC(now);
|
||
}
|
||
|
||
static inline void hexdump_to_fd(int fd, uint32_t idx, const char *data, uint16_t len)
|
||
{
|
||
uint16_t i = 0;
|
||
uint16_t used = 0;
|
||
uint16_t offset = 0;
|
||
|
||
#define LINE_LEN 80
|
||
char line[LINE_LEN]; /* space needed 8+16*3+3+16 == 75 */
|
||
while (offset < len)
|
||
{
|
||
used = snprintf(line, LINE_LEN, "%08X ", idx + offset);
|
||
|
||
// hexdump
|
||
for (i = 0; ((offset + i) < len) && (i < 16); i++)
|
||
{
|
||
if (i == 8)
|
||
{
|
||
used += snprintf(line + used, LINE_LEN - used, " ");
|
||
}
|
||
used += snprintf(line + used, LINE_LEN - used, " %02x", (data[offset + i] & 0xff));
|
||
}
|
||
|
||
// padding
|
||
for (; i <= 16; i++)
|
||
{
|
||
if (i == 8)
|
||
{
|
||
used += snprintf(line + used, LINE_LEN - used, " ");
|
||
}
|
||
used += snprintf(line + used, LINE_LEN - used, " ");
|
||
}
|
||
|
||
// ascii
|
||
for (i = 0; (offset < len) && (i < 16); i++, offset++)
|
||
{
|
||
unsigned char c = data[offset];
|
||
if ((c < ' ') || (c > '~'))
|
||
{
|
||
c = '.';
|
||
}
|
||
if (i == 8)
|
||
{
|
||
used += snprintf(line + used, LINE_LEN - used, " ");
|
||
}
|
||
used += snprintf(line + used, LINE_LEN - used, "%c", c);
|
||
}
|
||
dprintf(fd, "%s\n", line);
|
||
}
|
||
}
|
||
|
||
// key: "a.b.c"
|
||
static inline const char *get_toml_raw_by_hierarchical_key(toml_table_t *root, const char *key)
|
||
{
|
||
toml_table_t *table = root;
|
||
|
||
char *saveptr;
|
||
char *dup_key = strdup(key);
|
||
char *token = strtok_r(dup_key, ".", &saveptr);
|
||
|
||
while (token != NULL)
|
||
{
|
||
table = toml_table_in(table, token);
|
||
if (table == NULL)
|
||
{
|
||
free(dup_key);
|
||
return NULL;
|
||
}
|
||
|
||
if (strchr(saveptr, '.') == NULL)
|
||
{
|
||
const char *val = toml_raw_in(table, saveptr);
|
||
free(dup_key);
|
||
return val;
|
||
}
|
||
|
||
token = strtok_r(NULL, ".", &saveptr);
|
||
}
|
||
|
||
free(dup_key);
|
||
return toml_raw_in(root, key);
|
||
}
|
||
|
||
static inline toml_array_t *get_toml_array_by_hierarchical_key(toml_table_t *root, const char *key)
|
||
{
|
||
toml_table_t *table = root;
|
||
|
||
char *saveptr;
|
||
char *dup_key = strdup(key);
|
||
char *token = strtok_r(dup_key, ".", &saveptr);
|
||
|
||
while (token != NULL)
|
||
{
|
||
table = toml_table_in(table, token);
|
||
if (table == NULL)
|
||
{
|
||
free(dup_key);
|
||
return NULL;
|
||
}
|
||
|
||
if (strchr(saveptr, '.') == NULL)
|
||
{
|
||
toml_array_t *arr = toml_array_in(table, saveptr);
|
||
free(dup_key);
|
||
return arr;
|
||
}
|
||
|
||
token = strtok_r(NULL, ".", &saveptr);
|
||
}
|
||
|
||
free(dup_key);
|
||
return toml_array_in(root, key);
|
||
}
|
||
|
||
static inline int load_toml_integer_config(const char *toml_file, const char *key, uint64_t *val, uint64_t min, uint64_t max)
|
||
{
|
||
int ret = -1;
|
||
char errbuf[200];
|
||
const char *ptr = NULL;
|
||
FILE *fp = NULL;
|
||
toml_table_t *root = NULL;
|
||
|
||
fp = fopen(toml_file, "r");
|
||
if (fp == NULL)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s open failed, %s", toml_file, strerror(errno));
|
||
return -1;
|
||
}
|
||
|
||
root = toml_parse_file(fp, errbuf, sizeof(errbuf));
|
||
if (root == NULL)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s parse failed, %s", toml_file, errbuf);
|
||
goto error_out;
|
||
}
|
||
|
||
ptr = get_toml_raw_by_hierarchical_key(root, key);
|
||
if (ptr == NULL)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file missing %s", key);
|
||
goto error_out;
|
||
}
|
||
|
||
*val = atoll(ptr);
|
||
if ((*val) < min || (*val) > max)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "invalid %s: %lu, supported range: [%lu, %lu]", key, *val, min, max);
|
||
goto error_out;
|
||
}
|
||
|
||
ret = 0;
|
||
error_out:
|
||
if (root != NULL)
|
||
{
|
||
toml_free(root);
|
||
}
|
||
if (fp)
|
||
{
|
||
fclose(fp);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
static inline int load_toml_double_config(const char *toml_file, const char *key, double *val, double min, double max)
|
||
{
|
||
int ret = -1;
|
||
char errbuf[200];
|
||
const char *ptr = NULL;
|
||
FILE *fp = NULL;
|
||
toml_table_t *root = NULL;
|
||
|
||
fp = fopen(toml_file, "r");
|
||
if (fp == NULL)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s open failed, %s", toml_file, strerror(errno));
|
||
return -1;
|
||
}
|
||
|
||
root = toml_parse_file(fp, errbuf, sizeof(errbuf));
|
||
if (root == NULL)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s parse failed, %s", toml_file, errbuf);
|
||
goto error_out;
|
||
}
|
||
|
||
ptr = get_toml_raw_by_hierarchical_key(root, key);
|
||
if (ptr == NULL)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file missing %s", key);
|
||
goto error_out;
|
||
}
|
||
|
||
*val = atof(ptr);
|
||
if ((*val) < min || (*val) > max)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "invalid %s: %f, supported range: [%f, %f]", key, *val, min, max);
|
||
goto error_out;
|
||
}
|
||
|
||
ret = 0;
|
||
error_out:
|
||
if (root != NULL)
|
||
{
|
||
toml_free(root);
|
||
}
|
||
if (fp)
|
||
{
|
||
fclose(fp);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
static inline int load_toml_str_config(const char *toml_file, const char *key, char *val)
|
||
{
|
||
int ret = -1;
|
||
char errbuf[200];
|
||
const char *ptr = NULL;
|
||
FILE *fp = NULL;
|
||
toml_table_t *root = NULL;
|
||
|
||
fp = fopen(toml_file, "r");
|
||
if (fp == NULL)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s open failed, %s", toml_file, strerror(errno));
|
||
return -1;
|
||
}
|
||
|
||
root = toml_parse_file(fp, errbuf, sizeof(errbuf));
|
||
if (root == NULL)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s parse failed, %s", toml_file, errbuf);
|
||
goto error_out;
|
||
}
|
||
|
||
ptr = get_toml_raw_by_hierarchical_key(root, key);
|
||
if (ptr == NULL)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file missing %s", key);
|
||
goto error_out;
|
||
}
|
||
memcpy(val, ptr + 1, strlen(ptr) - 2);
|
||
ret = 0;
|
||
|
||
error_out:
|
||
if (root != NULL)
|
||
{
|
||
toml_free(root);
|
||
}
|
||
if (fp)
|
||
{
|
||
fclose(fp);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
static inline int load_toml_array_config(const char *toml_file, const char *key, uint64_t val[], uint64_t size)
|
||
{
|
||
int ret = 0;
|
||
char errbuf[200];
|
||
const char *ptr = NULL;
|
||
toml_array_t *arr = NULL;
|
||
FILE *fp = NULL;
|
||
toml_table_t *root = NULL;
|
||
uint64_t loop = 0;
|
||
|
||
fp = fopen(toml_file, "r");
|
||
if (fp == NULL)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s open failed, %s", toml_file, strerror(errno));
|
||
return -1;
|
||
}
|
||
|
||
root = toml_parse_file(fp, errbuf, sizeof(errbuf));
|
||
if (root == NULL)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s parse failed, %s", toml_file, errbuf);
|
||
goto error_out;
|
||
}
|
||
|
||
arr = get_toml_array_by_hierarchical_key(root, key);
|
||
if (arr == NULL)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file missing %s", key);
|
||
goto error_out;
|
||
}
|
||
|
||
loop = MIN((uint64_t)toml_array_nelem(arr), size);
|
||
for (uint64_t i = 0; i < loop; i++)
|
||
{
|
||
ptr = toml_raw_at(arr, i);
|
||
if (ptr == NULL)
|
||
{
|
||
STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file missing %s[%d]", key, i);
|
||
goto error_out;
|
||
}
|
||
val[i] = atoll(ptr);
|
||
}
|
||
|
||
ret = loop;
|
||
error_out:
|
||
if (root != NULL)
|
||
{
|
||
toml_free(root);
|
||
}
|
||
if (fp)
|
||
{
|
||
fclose(fp);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|