501 lines
13 KiB
C
501 lines
13 KiB
C
|
|
#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;
|
|
}
|
|
|
|
|