when a session is closed, use the packet manager to create a pseudo packet,
set the session to be closed as packet Exdata, and schedule it to the packet forwarding stage.
when the pseudo packet free, the session will be free.
370 lines
9.0 KiB
C
370 lines
9.0 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 "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)
|
||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||
|
||
#define likely(expr) __builtin_expect((expr), 1)
|
||
#define unlikely(expr) __builtin_expect((expr), 0)
|
||
|
||
/*
|
||
* 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
|