Files

501 lines
13 KiB
C
Raw Permalink Normal View History

2026-08-13 11:28:40 +08:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <dlfcn.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <inttypes.h>
#include "dataserver_rb.h"
#include "dataserver_reader.h"
#include "dataserver_inner.h"
#include "dataserver_utils.h"
#ifdef LOG_LOGCAT
#define LOG_TAG "ccdataserver"
#include <log/log.h>
#define ds_inf(_fmt_,...) ALOGI("%s:%d "_fmt_, __func__, __LINE__, ##__VA_ARGS__)
#define ds_err(_fmt_,...) ALOGE("%s:%d "_fmt_, __func__, __LINE__, ##__VA_ARGS__)
#else
#define ds_inf(_fmt_,...) printf("I %s:%d "_fmt_"\n", __func__, __LINE__, ##__VA_ARGS__)
#define ds_err(_fmt_,...) printf("E %s:%d "_fmt_"\n", __func__, __LINE__, ##__VA_ARGS__)
#endif
#define DEFAULT_RB_SIZE (1024 * 4)
/*datacallback from the device reader*/
static void ds_data_callback(uint8_t *data, size_t size, void *priv)
{
ds_connection_t *conn = (ds_connection_t *)priv;
if (!DS_RB_IS_READY(&conn->rb)) {
ds_inf("no explicit setting for ringbuffer,"
" use default size[%d], dev[%s], cli[%s]",
DEFAULT_RB_SIZE, conn->device, conn->client);
ds_rb_init(&conn->rb, DEFAULT_RB_SIZE);
}
if (!DS_RB_IS_READY(&conn->rb)) {
ds_err("data lost[%zd], ringbuffer not ready for connection dev[%s] cli[%s]",
size, conn->device, conn->client);
return;
}
if (ds_rb_free(&conn->rb) >= size) {
ds_rb_write(&conn->rb, data, size);
conn->data_cnt_in += size;
} else {
ds_rb_set_flag(&conn->rb, DS_RB_FLAG_OVERFLOW);
ds_err("data lost, ringbuffer overflow, free[%zd] data[%zd], dev[%s] cli[%s]",
ds_rb_free(&conn->rb), size, conn->device, conn->client);
}
}
static void ds_data_ready(int mode, size_t size, void *priv)
{
ds_connection_t *conn = (ds_connection_t *)priv;
if (!DS_RB_IS_READY(&conn->rb)) {
ds_inf("no explicit setting for ringbuffer,"
" use default size[%d], dev[%s], cli[%s]",
DEFAULT_RB_SIZE, conn->device, conn->client);
ds_rb_init(&conn->rb, DEFAULT_RB_SIZE);
}
if (!DS_RB_IS_READY(&conn->rb)) {
ds_err("block lost[%zd], ringbuffer not ready for connection dev[%s] cli[%s]",
size, conn->device, conn->client);
return;
}
if (ds_rb_get_flag(&conn->rb) & DS_RB_FLAG_OVERFLOW)
return;
if (mode)
ds_rb_queue_block(&conn->rb, size);
ds_rb_set_flag(&conn->rb, DS_RB_FLAG_READY | (mode? DS_RB_FLAG_BLOCK : 0));
}
ds_data_callback_fn_t ds_data_fn = {
.data_cb = ds_data_callback,
.ready_cb = ds_data_ready,
};
static int cmd_src_set(ds_connection_t *conn,
uint8_t *cmd, size_t cmd_size, uint8_t *resp, size_t resp_size)
{
(void)cmd_size;
(void)resp_size;
char dev_name[MAX_NAME_SIZE + 1] = {'\0'};
char cli_name[MAX_NAME_SIZE + 1] = {'\0'};
int off_dev = strlen("src_set ");
int c = ':';
char *pos_cli = strchr((char *)cmd + off_dev, c);
if (pos_cli) {
int off_cli = pos_cli - (char *)cmd;
strncpy(dev_name, (char *)cmd + off_dev, off_cli - off_dev);
dev_name[MAX_NAME_SIZE] = '\0';
pos_cli++;//jump over the ':'
int len_cli = strlen(pos_cli);
if (len_cli > MAX_NAME_SIZE)
len_cli = MAX_NAME_SIZE;
strncpy(cli_name, pos_cli, len_cli);
cli_name[MAX_NAME_SIZE] = '\0';
}
ds_inf("cmd[src_set]: dev[%s] client[%s]", dev_name, cli_name);
if (!pos_cli) {
ds_err("bad command");
goto ko;
}
strcpy(conn->device, dev_name);
strcpy(conn->client, cli_name);
int ret = ds_reader_start(dev_name, conn->settings, &ds_data_fn, conn);
if (ret < 0)
goto ko;
assert(resp_size >= 3);
strcpy((char *)resp, "ok");
return 3;
ko:
assert(resp_size >= 3);
strcpy((char *)resp, "ko");
return 3;
}
static int cmd_src_unset(ds_connection_t *conn,
uint8_t *cmd, size_t cmd_size, uint8_t *resp, size_t resp_size)
{
(void)cmd;
(void)cmd_size;
(void)resp_size;
ds_inf("cmd[src_unset]: dev[%s] client[%s]", conn->device, conn->client);
int ret = ds_reader_stop(conn->device, &ds_data_fn, conn);
if (ret < 0)
goto ko;
/*clear the settings*/
conn->settings[0] = '\0';
assert(resp_size >= 3);
strcpy((char *)resp, "ok");
return 3;
ko:
assert(resp_size >= 3);
strcpy((char *)resp, "ko");
return 3;
}
static int cmd_src_para(ds_connection_t *conn,
uint8_t *cmd, size_t cmd_size, uint8_t *resp, size_t resp_size)
{
(void)cmd;
(void)cmd_size;
(void)resp_size;
strncpy(conn->settings, (char *)cmd, MAX_SETTINGS_SIZE);
conn->settings[MAX_SETTINGS_SIZE] = '\0';
assert(resp_size >= 3);
strcpy((char *)resp, "ok");
return 3;
}
static int cmd_rb_en(ds_connection_t *conn,
uint8_t *cmd, size_t cmd_size, uint8_t *resp, size_t resp_size)
{
(void)cmd_size;
(void)resp_size;
int rb_size = -1;
if (sscanf((char *)cmd, "rb_en %i", &rb_size) == 1) {
if (rb_size >= 0) {
ds_rb_deinit(&conn->rb);
if (ds_rb_init(&conn->rb, rb_size) == 0) {
assert(resp_size >= 3);
strcpy((char *)resp, "ok");
return 3;
}
}
}
assert(resp_size >= 3);
strcpy((char *)resp, "ko");
return 3;
}
static void* dl_load(ds_connection_t *conn, const char *file)
{
/*load plugin from file*/
void *dl = dlopen(file, RTLD_LAZY);
if (!dl) {
ds_err("dlopen fail, err(%s)", dlerror());
return NULL;
}
int (*load)(ds_connection_t *) =
(int(*)(ds_connection_t *))dlsym(dl, "load");
if (load)
load(conn);
return dl;
}
static void dl_unload(ds_connection_t *conn)
{
if (conn->dbg_dl) {
int (*unload)(ds_connection_t *) =
(int(*)(ds_connection_t *))dlsym(conn->dbg_dl, "unload");
if (unload)
unload(conn);
dlclose(conn->dbg_dl);
conn->dbg_dl = NULL;
}
}
static void debug_unload(void *args)
{
ds_connection_t *conn = (ds_connection_t *)args;
if (conn->dbg) {
free(conn->dbg);
conn->dbg = NULL;
conn->dbg_total = conn->dbg_size = 0;
}
dl_unload(conn);
}
static int cmd_debug_load(ds_connection_t *conn,
uint8_t *cmd, size_t cmd_size, uint8_t *resp, size_t resp_size)
{
(void)cmd_size;
(void)resp_size;
char plugin[512] = {0};
int size = 0;
int ret = sscanf((char *)cmd, "debug_load %s %i", plugin, &size);
if (ret == 1 && ((conn->dbg_dl = dl_load(conn, plugin)))) {
assert(resp_size >= 3);
strcpy((char *)resp, "ok");
return 3;
} else if (ret == 2 && size > 0) {
/*load plugin from data*/
conn->dbg = (uint8_t *)malloc(size);
conn->dbg_free = debug_unload;
conn->dbg_total = size;
conn->dbg_size = 0;
assert(resp_size >= 3);
strcpy((char *)resp, "ok");
return 3;
}
assert(resp_size >= 3);
strcpy((char *)resp, "ko");
return 3;
}
static int cmd_debug_unload(ds_connection_t *conn,
uint8_t *cmd, size_t cmd_size, uint8_t *resp, size_t resp_size)
{
(void)cmd;
(void)cmd_size;
(void)resp_size;
debug_unload(conn);
{
assert(resp_size >= 3);
strcpy((char *)resp, "ok");
return 3;
}
}
static int cmd_stat(ds_connection_t *conn,
uint8_t *cmd, size_t cmd_size, uint8_t *resp, size_t resp_size)
{
(void)cmd;
(void)cmd_size;
int ret = 0;
int cnt = 0;
#define stat_printf(_fmt, ...) do {\
if ((resp_size - cnt) > 1) {\
ret = snprintf((char *)resp + cnt, resp_size - cnt, _fmt, ##__VA_ARGS__);\
if (ret <= 0) {\
return cnt + 1;\
} else {\
cnt += ret;\
}\
} else {\
ds_err("resp not enough");\
}\
} while (0)
stat_printf("ok");
cnt++;
stat_printf("conns:\n");
{
ds_server_t *server = (ds_server_t *)conn->server;
ds_connection_t *conn;
list_for_each_entry(conn, &server->conns, head) {
stat_printf("\t[%s]-[%s] fd[%d] active[%d] rb(avai/size)[%#zx/%#zx] flag[%#x] data(in/out)[%"PRIx64"/%"PRIx64"]\n",
conn->device, conn->client, conn->fd, conn->active,
ds_rb_avail(&conn->rb), conn->rb.size, ds_rb_get_flag(&conn->rb),
conn->data_cnt_in, conn->data_cnt_out);
}
}
return cnt + 1;
}
static int cmd_help(ds_connection_t *conn,
uint8_t *cmd, size_t cmd_size, uint8_t *resp, size_t resp_size);
static ds_control_t controls[] = {
{.cmd = "help", .fn = cmd_help, .desc = "help"},
{.cmd = "src_para_vbi_type", .fn = cmd_src_para, .desc = "src_para_vbi_type <type>"},
{.cmd = "src_para_userdata_vid", .fn = cmd_src_para, .desc = "src_para_userdata_vid <vid>"},
{.cmd = "rb_en", .fn = cmd_rb_en, .desc = "rb_en <size>"},
{.cmd = "src_set", .fn = cmd_src_set, .desc = "src_set <device>:<client>"},
{.cmd = "src_unset", .fn = cmd_src_unset, .desc = "src_unset"},
{.cmd = "stat", .fn = cmd_stat, .desc = "stat"},
{.cmd = "debug_load", .fn = cmd_debug_load, .desc = "debug_load <plugin> [size]"},
{.cmd = "debug_unload", .fn = cmd_debug_unload, .desc = "debug_unload"},
};
static int size_controls = sizeof(controls) / sizeof(controls[0]);
static int cmd_help(ds_connection_t *conn,
uint8_t *cmd, size_t cmd_size, uint8_t *resp, size_t resp_size)
{
(void)cmd;
(void)cmd_size;
int ret;
int cnt = 0;
strcpy((char *)resp, "ok");
cnt += 3;
/*check the internal controls*/
int i;
for (i = 0; i < size_controls; i++) {
if ((resp_size - cnt) > 1) {
ret = snprintf((char *)resp + cnt, resp_size - cnt, "%s\n", controls[i].desc);
cnt += ret;
}
}
/*check the private controls*/
ds_control_t *control;
list_for_each_entry(control, &conn->controls, head) {
if ((resp_size - cnt) > 1) {
ret = snprintf((char *)resp + cnt, resp_size - cnt, "%s\n", control->desc);
cnt += ret;
}
}
return cnt + 1;
}
/**
* @brief
* @return size of the resp data
*/
int process_control_msg(ds_connection_t *conn,
uint8_t *msg_body, size_t size_body, uint8_t *b_resp, size_t b_size)
{
char cmd[256];
d2s(cmd, sizeof(cmd), msg_body, size_body);
ds_inf("cmd[%s]", cmd);
/*check the internal controls*/
int i;
for (i = 0; i < size_controls; i++) {
if (strncmp((char *)msg_body, controls[i].cmd, strlen(controls[i].cmd)) == 0)
return controls[i].fn(conn, msg_body, size_body, b_resp, b_size);
}
/*check the private controls*/
ds_control_t *control;
list_for_each_entry(control, &conn->controls, head) {
if (strncmp((char *)msg_body, control->cmd, strlen(control->cmd)) == 0)
return control->fn(conn, msg_body, size_body, b_resp, b_size);
}
return 0;
}
int process_response_msg(ds_connection_t *conn, uint8_t *msg_body, size_t size_body)
{
(void)conn;
(void)msg_body;
(void)size_body;
return 0;
}
int process_event_msg(ds_connection_t *conn, uint8_t *msg_body, size_t size_body)
{
(void)conn;
(void)msg_body;
(void)size_body;
return 0;
}
int process_data_msg(ds_connection_t *conn, uint8_t *msg_body, size_t size_body)
{
if (conn->dbg) {
int left = conn->dbg_total - conn->dbg_size;
if (size_body > left) {
ds_err("dbg overflow");
free(conn->dbg);
conn->dbg = NULL;
conn->dbg_total = conn->dbg_size = 0;
return 0;
}
memcpy(conn->dbg + conn->dbg_size, msg_body, size_body);
conn->dbg_size += size_body;
left = conn->dbg_total - conn->dbg_size;
ds_inf("xxx left:%d, size:%zd", left, size_body);
if (!left) {
int ret = 0;
#ifdef SUPPORT_SHM
char path[256];
snprintf(path, sizeof(path), "da_%p", conn);
int shm_fd = shm_open(path, O_RDWR|O_CREAT, S_IRWXU);
if (shm_fd < 0) {
ds_err("shm open fail");
return -1;
}
ret = write(shm_fd, conn->dbg, conn->dbg_size);
if (ret == conn->dbg_size) {
char load_path[512];
snprintf(load_path, sizeof(load_path), "/proc/%d/fd/%d", getpid(), shm_fd);
conn->dbg_dl = dl_load(conn, load_path);
}
close(shm_fd);
shm_unlink(path);
#endif
free(conn->dbg);
conn->dbg = NULL;
conn->dbg_total = 0;
conn->dbg_size = 0;
return ret;
}
}
return 0;
}