#include #include #include #include #include #include #include "dataserver_rb.h" #include "dataserver_reader.h" #include "dataserver_reader_inner.h" #include "dataserver_message.h" #include "dataserver_process.h" #include "dataserver_utils.h" #include "dataserver_inner.h" #include "list.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 /*ret: * -1: next * -3: error */ int ds_connection_manage_data_in(ds_connection_t *conn) { /*Assume the size is no more than these values*/ #define MAX_MESSAGE_SIZE 1024 #define MAX_RESP_SIZE 1024 uint8_t buf[MAX_MESSAGE_SIZE]; uint8_t b_resp[MAX_RESP_SIZE]; int ret = 0; int n; n = conn->read(conn, buf, sizeof(ds_msg_head_t)); if (n < 0) return -3; if (n == 0) return -1; if (n != sizeof(ds_msg_head_t)) { ds_err("invalid msg, ignore. n[%d]", n); return -1; } ds_msg_head_t *h = (ds_msg_head_t *)buf; char s[64]; d2s(s, sizeof(s), (uint8_t *)&h->magic, 4); ds_inf("sess[%p] fd[%d]: recv(%d) msg[m:%s t:%d, l:%d]", conn, conn->fd, n, s, h->type, h->size); n = conn->read(conn, h->body, h->size); if (n < 0) return -3; if (n != h->size) { ds_err("invalid msg, ignore"); return -1; } switch (h->type) { case DS_T_CNTL: ret = process_control_msg(conn, h->body, h->size, b_resp, sizeof(b_resp)); if (ret) { ds_msg_head_t h_resp = { .magic = DS_MAGIC, .type = DS_T_RESP, .size = ret, }; ret = conn->write(conn, &h_resp, sizeof(h_resp)); if (ret < 0) return -3; ret = conn->write(conn, b_resp, h_resp.size); if (ret < 0) return -3; } else { ds_err("[ERROR] failed to process control msg"); strcpy((char *)b_resp, "ko"); ds_msg_head_t h_resp = { .magic = DS_MAGIC, .type = DS_T_RESP, .size = 3, }; ret = conn->write(conn, &h_resp, sizeof(h_resp)); if (ret < 0) return -3; ret = conn->write(conn, b_resp, h_resp.size); if (ret < 0) return -3; } break; case DS_T_RESP: ret = process_response_msg(conn, h->body, h->size); break; case DS_T_EVNT: ret = process_event_msg(conn, h->body, h->size); break; case DS_T_DATA: ret = process_data_msg(conn, h->body, h->size); break; case 0x80:/*request disconnect*/ ds_inf("data in break due to exit requested"); return -3; default: ds_err("unknown msg type[%d]", h->type); break; } return 0; } /*ret: * -1: next * -3: error */ int ds_connection_manage_data_out(ds_connection_t *conn) { #define DS_CONN_BUF_MAX_SIZE (1024 * 5 + 128) int flag = ds_rb_get_flag_timeout(&conn->rb, 10/*timeout:10ms*/); if (flag & DS_RB_FLAG_EXIT) { ds_inf("data out break due to exit requested"); return 0; } if (!(flag & DS_RB_FLAG_READY)) return -1; if (!(flag & DS_RB_FLAG_OVERFLOW)) { size_t size = 0; if (flag & DS_RB_FLAG_BLOCK) {/*block mode*/ size_t bs = 0; int ret = ds_rb_dequeue_block(&conn->rb, &bs); if (ret == 0 && bs > 0) { ssize_t avai = ds_rb_avail(&conn->rb); if (avai < size) { ds_err("avai(%zd) < bs(%zu), something incorrect", avai, size); return -3; } size = bs; if (size > DS_CONN_BUF_MAX_SIZE) { ds_err("DS_CONN_BUF_MAX_SIZE(%d) is not suitable for block mode, meet(%zd)", DS_CONN_BUF_MAX_SIZE, size); return -3; } } } else {//stream mode size = ds_rb_avail(&conn->rb); if (size > DS_CONN_BUF_MAX_SIZE) size = DS_CONN_BUF_MAX_SIZE; } if (size) { if (!conn->buf) { conn->buf = (uint8_t *)malloc(DS_CONN_BUF_MAX_SIZE); if (!conn->buf) { ds_err("memory fail"); return -3; } } ds_rb_read(&conn->rb, conn->buf, size); ds_msg_head_t h_data = { .magic = DS_MAGIC, .type = DS_T_DATA, .size = size, }; int ret = conn->write(conn, &h_data, sizeof(h_data)); if (ret < 0) return -3; ret = conn->write(conn, conn->buf, size); if (ret < 0) return -3; conn->data_cnt_out += size; } } else { char s_overflow[] = "rb_overflow"; ds_msg_head_t h_evnt = { .magic = DS_MAGIC, .type = DS_T_EVNT, .size = sizeof(s_overflow), }; int ret = conn->write(conn, &h_evnt, sizeof(h_evnt)); if (ret < 0) return -3; ret = conn->write(conn, s_overflow, h_evnt.size); if (ret < 0) return -3; } return 0; } static void _ds_conn_lock(void *g, int lock) { ds_connection_t *conn = (ds_connection_t *)g; if (lock) pthread_mutex_lock(&conn->lock); else pthread_mutex_unlock(&conn->lock); } ds_connection_t* ds_connection_create(void) { ds_connection_t *conn = (ds_connection_t *)calloc(1, sizeof(ds_connection_t)); if (conn) { INIT_LIST_HEAD(&conn->controls); pthread_mutex_init(&conn->lock, NULL); ds_rb_init_lock(&conn->rb, _ds_conn_lock, conn); return conn; } return NULL; } int ds_connection_start(ds_server_t *server, ds_connection_t *conn, void *priv) { int ret = 0; conn->server = server; if (conn->init) ret = conn->init(conn, priv); if (ret != 0) return -1; if (conn->start) { conn->active = 1; conn->wr_active = 1; conn->rd_active = 1; ret = conn->start(conn); } if (ret == 0) { list_add_tail(&conn->head, &server->conns); } else { conn->active = 0; conn->wr_active = 0; conn->rd_active = 0; if (conn->deinit) conn->deinit(conn); free(conn); ds_err("connection fd[%d], failed to start session due to thread failure, err(%d)", server->fd, ret); } return 0; } int ds_connection_stop(ds_connection_t *conn) { int ret = 0; list_del(&conn->head); if (conn->stop) conn->stop(conn); if (conn->dbg_free) conn->dbg_free(conn); if (conn->deinit) conn->deinit(conn); free(conn); return ret; } /*cleanup in the end of conn session task*/ int ds_connection_cleanup(ds_connection_t *conn) { ds_inf("connection [%p] cleanup", conn); conn->active = 0; ds_reader_stop(conn->device, &ds_data_fn, conn); pthread_mutex_lock(&conn->lock); if (conn->buf) { free(conn->buf); conn->buf = 0; } pthread_mutex_unlock(&conn->lock); ds_rb_deinit(&conn->rb); return 0; } int ds_server_start(ds_server_t *server, void *arg1, void *arg2, void*(*task)(void*)) { int ret = 0; /*init the server inst*/ INIT_LIST_HEAD(&server->conns); if (server->init) ret = server->init(server, arg1, arg2); if (ret != 0) return -1; server->running = 1; ret = pthread_create(&server->thread, NULL, task, server); if (ret != 0) { server->running = 0; ds_err("failed to start server due to thread failure. err(%d)", ret); if (server->deinit) server->deinit(server); } return ret; } int ds_server_stop(ds_server_t *server) { server->running = 0; if (server->stop) server->stop(server); ds_inf("server stopping..."); pthread_join(server->thread, NULL); if (server->deinit) server->deinit(server); ds_inf("server stopped."); return 0; } int ds_server_cleanup_connections(ds_server_t *server, int force) { ds_connection_t *conn, *conn_tmp; list_for_each_entry_safe(conn, conn_tmp, &server->conns, head) { if (!force && conn->active) continue; ds_connection_stop(conn); } return 0; }