#include #include #include #include #include #include #include #include #include "dataserver_rb.h" #include "dataserver_reader.h" #include "dataserver_inner.h" #include "dataserver_utils.h" #ifdef LOG_LOGCAT #define LOG_TAG "ccdataserver" #include #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 "}, {.cmd = "src_para_userdata_vid", .fn = cmd_src_para, .desc = "src_para_userdata_vid "}, {.cmd = "rb_en", .fn = cmd_rb_en, .desc = "rb_en "}, {.cmd = "src_set", .fn = cmd_src_set, .desc = "src_set :"}, {.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 [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; }