temp:1

Change-Id: I596535a352526ed1a7345e54996a7f34aeb8953a
diff --git a/mbtk/libmbtk_tcpip/Makefile b/mbtk/libmbtk_tcpip/Makefile
new file mode 100755
index 0000000..3396400
--- /dev/null
+++ b/mbtk/libmbtk_tcpip/Makefile
@@ -0,0 +1,39 @@
+ROOT = $(shell pwd)/../..
+include ../Make.defines
+
+LOCAL_PATH=$(BUILD_ROOT)/libmbtk_tcpip
+
+INC_DIR +=
+
+LIB_DIR +=
+
+LIBS += -llog -lmbtk_lib -lmbtk_net
+
+CFLAGS += -shared -Wl,-shared,-Bsymbolic
+
+MY_FILES_PATH:=$(LOCAL_PATH)
+MY_FILES_SUFFIX:=%.c %.cpp
+My_All_Files := $(foreach src_path,$(MY_FILES_PATH), $(shell find "$(src_path)" -type f))
+MY_SRC_LIST  := $(filter $(MY_FILES_SUFFIX),$(My_All_Files))
+MY_SRC_LIST  := $(MY_SRC_LIST:$(LOCAL_PATH)/%=%)
+LOCAL_SRC_FILES += $(MY_SRC_LIST)
+
+OBJS = $(patsubst %.c, %.o, $(patsubst %.cpp, %.o, $(LOCAL_SRC_FILES)))
+$(info OBJS = $(OBJS))
+
+dtarget := $(OUT_DIR)/lib/libmbtk_tcpip.so
+
+all: $(dtarget)
+
+$(dtarget):$(OBJS)
+	$(CC) $(CFLAGS) $(DEFINE) $(LIB_DIR) $(LIBS) $(OBJS) -o $@
+
+%.o:%.c
+	$(CC) $(CFLAGS) $(INC_DIR) $(DEFINE) -c $< -o $@
+
+%.o:%.cpp
+	$(CC) $(CFLAGS) $(INC_DIR) $(DEFINE) -c $< -o $@
+
+clean:
+	rm -f $(OBJS) $(dtarget)
+
diff --git a/mbtk/libmbtk_tcpip/mbtk_tcpip_at.c b/mbtk/libmbtk_tcpip/mbtk_tcpip_at.c
new file mode 100755
index 0000000..8490ede
--- /dev/null
+++ b/mbtk/libmbtk_tcpip/mbtk_tcpip_at.c
@@ -0,0 +1,660 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <netinet/tcp.h>
+
+#include "mbtk_log.h"
+#include "mbtk_tcpip.h"
+#include "mbtk_net_control.h"
+
+#define MBTK_TCPIP_CID_DEFAULT  0
+#define MBTK_TCPIP_READ_BUFF_SIZE 2048
+#define TCPIP_DEBUG 0
+
+typedef struct {
+    mbtk_sock_session sock_fd;
+    char ser_addr[256];
+    int ser_port;
+    char local_addr[256];
+    int local_port;
+    bool ack_support;
+    bool ssl_support;
+    bool ignore_cert;
+    uint32 heartbeat_time;
+    uint32 delay_time;
+
+    mbtk_tcpip_read_callback_func read_cb;
+
+    uint32 data_traffic_send;
+    uint32 data_traffic_recv;
+
+} mbtk_tcpip_cli_info_t;
+
+typedef struct {
+    mbtk_sock_session sock_fd;
+    char ser_addr[256];
+    int ser_port;
+
+    int cli_num;
+    mbtk_tcpip_cli_info_t *cli_list;
+} mbtk_tcpip_ser_info_t;
+
+typedef struct {
+    int link_id;
+    int link_cid;
+    bool link_connected;
+    mbtk_sock_type prot_type;    // TCP/UDP
+
+    mbtk_tcpip_type_enum type;
+    union
+    {
+        mbtk_tcpip_cli_info_t cli_info;
+        mbtk_tcpip_ser_info_t ser_info;
+    } tcpip_info;
+
+} mbtk_tcpip_link_t;
+
+static mbtk_tcpip_link_t tcpip_link[MBTK_TCPIP_LINK_MAX];
+static bool tcpip_inited = FALSE;
+static mbtk_sock_handle tcpip_handle;
+static mbtk_tcpip_net_callback_func tcpip_net_cb = NULL;
+static mbtk_tcpip_sock_callback_func tcpip_sock_cb = NULL;
+
+/*
+struct tcp_info
+{
+  u_int8_t	tcpi_state;
+  u_int8_t	tcpi_ca_state;
+  u_int8_t	tcpi_retransmits;
+  u_int8_t	tcpi_probes;
+  u_int8_t	tcpi_backoff;
+  u_int8_t	tcpi_options;
+  u_int8_t	tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
+
+  u_int32_t	tcpi_rto;
+  u_int32_t	tcpi_ato;
+  u_int32_t	tcpi_snd_mss;
+  u_int32_t	tcpi_rcv_mss;
+
+  u_int32_t	tcpi_unacked;
+  u_int32_t	tcpi_sacked;
+  u_int32_t	tcpi_lost;
+  u_int32_t	tcpi_retrans;
+  u_int32_t	tcpi_fackets;
+
+  u_int32_t	tcpi_last_data_sent;
+  u_int32_t	tcpi_last_ack_sent;
+  u_int32_t	tcpi_last_data_recv;
+  u_int32_t	tcpi_last_ack_recv;
+
+  u_int32_t	tcpi_pmtu;
+  u_int32_t	tcpi_rcv_ssthresh;
+  u_int32_t	tcpi_rtt;
+  u_int32_t	tcpi_rttvar;
+  u_int32_t	tcpi_snd_ssthresh;
+  u_int32_t	tcpi_snd_cwnd;
+  u_int32_t	tcpi_advmss;
+  u_int32_t	tcpi_reordering;
+
+  u_int32_t	tcpi_rcv_rtt;
+  u_int32_t	tcpi_rcv_space;
+
+  u_int32_t	tcpi_total_retrans;
+};
+
+*/
+void tcp_info_print(struct tcp_info *tcp)
+{
+    if(tcp) {
+        LOGD("tcpi_state = %d", tcp->tcpi_state);
+        LOGD("tcpi_ca_state = %d", tcp->tcpi_ca_state);
+        LOGD("tcpi_retransmits = %d", tcp->tcpi_retransmits);
+        LOGD("tcpi_probes = %d", tcp->tcpi_probes);
+        LOGD("tcpi_backoff = %d", tcp->tcpi_backoff);
+        LOGD("tcpi_options = %d", tcp->tcpi_options);
+        LOGD("tcpi_snd_wscale = %d", 0x0F & tcp->tcpi_snd_wscale);
+        LOGD("tcpi_rcv_wscale = %d", 0xF0 & tcp->tcpi_rcv_wscale);
+        LOGD("tcpi_rto = %d", tcp->tcpi_rto);
+        LOGD("tcpi_ato = %d", tcp->tcpi_ato);
+        LOGD("tcpi_snd_mss = %d", tcp->tcpi_snd_mss);
+        LOGD("tcpi_rcv_mss = %d", tcp->tcpi_rcv_mss);
+        LOGD("tcpi_unacked = %d", tcp->tcpi_unacked);
+        LOGD("tcpi_sacked = %d", tcp->tcpi_sacked);
+        LOGD("tcpi_lost = %d", tcp->tcpi_lost);
+        LOGD("tcpi_retrans = %d", tcp->tcpi_retrans);
+        LOGD("tcpi_fackets = %d", tcp->tcpi_fackets);
+        LOGD("tcpi_last_data_sent = %d", tcp->tcpi_last_data_sent);
+        LOGD("tcpi_last_ack_sent = %d", tcp->tcpi_last_ack_sent);
+        LOGD("tcpi_last_data_recv = %d", tcp->tcpi_last_data_recv);
+        LOGD("tcpi_last_ack_recv = %d", tcp->tcpi_last_ack_recv);
+        LOGD("tcpi_pmtu = %d", tcp->tcpi_pmtu);
+        LOGD("tcpi_rcv_ssthresh = %d", tcp->tcpi_rcv_ssthresh);
+        LOGD("tcpi_rtt = %d", tcp->tcpi_rtt);
+        LOGD("tcpi_rttvar = %d", tcp->tcpi_rttvar);
+        LOGD("tcpi_snd_ssthresh = %d", tcp->tcpi_snd_ssthresh);
+        LOGD("tcpi_snd_cwnd = %d", tcp->tcpi_snd_cwnd);
+        LOGD("tcpi_advmss = %d", tcp->tcpi_advmss);
+        LOGD("tcpi_reordering = %d", tcp->tcpi_reordering);
+        LOGD("tcpi_rcv_rtt = %d", tcp->tcpi_rcv_rtt);
+        LOGD("tcpi_rcv_space = %d", tcp->tcpi_rcv_space);
+        LOGD("tcpi_total_retrans = %d", tcp->tcpi_total_retrans);
+    }
+}
+
+static int tcpip_fd_2_link(int fd)
+{
+    int link_id = 0;
+    mbtk_tcpip_link_t *link = NULL;
+    for(; link_id < MBTK_TCPIP_LINK_MAX; link_id++) {
+        link = tcpip_link + link_id;
+        if(link->link_connected) {
+            if(link->type == MBTK_TCPIP_TYPE_CLIENT) {
+                if(link->tcpip_info.cli_info.sock_fd > 0 && link->tcpip_info.cli_info.sock_fd == fd) {
+                    break;
+                }
+            } else {
+                // Not support.
+
+            }
+        }
+    }
+
+    if(link_id == MBTK_TCPIP_LINK_MAX) {
+        return -1;
+    } else {
+        return link_id;
+    }
+}
+
+static void tcpip_sock_cb_func(int handle, mbtk_sock_cb_info_s *sock_info)
+{
+    if(tcpip_inited && tcpip_handle == handle/* && http_fd == fd*/) {
+        if(sock_info->event & (EPOLLIN | EPOLLOUT)) { // Cand read or write.
+            int sock_error = 0;
+            socklen_t socklen = sizeof(sock_error);
+            if(getsockopt(sock_info->sock_fd, SOL_SOCKET, SO_ERROR, &sock_error, (socklen_t*)&socklen) == 0) {
+                LOGV("Socket error:%d", sock_error);
+            }
+
+            if(sock_error) {
+                LOGW("errno = %d", errno);
+                if(sock_error == ECONNRESET|| errno == EAGAIN)
+                {
+                    //
+                }
+                else
+                {
+                    return;
+                }
+            }
+
+            if(sock_info->sock_type == MBTK_SOCK_TCP) {
+                struct tcp_info info;
+                int len = sizeof(info);
+                if(getsockopt(sock_info->sock_fd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t*)&len) == 0) {
+                    LOGV("State : %d", info.tcpi_state);
+#if TCPIP_DEBUG
+                    //tcp_info_print(&info);
+#endif
+                }
+
+                if(TCP_ESTABLISHED != info.tcpi_state) {
+                    LOGW("errno = %d", errno);
+                    int link_id = tcpip_fd_2_link(sock_info->sock_fd);
+                    if(link_id >= 0) {
+                        // Socket disconnected?
+                        mbtk_tcpip_sock_close(link_id);
+
+                        if(tcpip_sock_cb) {
+                            tcpip_sock_cb(link_id, 0);
+                        }
+                    }
+                    return;
+                }
+            }
+        }
+
+        if(sock_info->event & EPOLLIN) { // READ
+            LOGV("fd[%d] can read.", sock_info->sock_fd);
+            int link_id = tcpip_fd_2_link(sock_info->sock_fd);
+            if(link_id >= 0) {
+                if(tcpip_link[link_id].type == MBTK_TCPIP_TYPE_CLIENT) {
+                    if(tcpip_link[link_id].tcpip_info.cli_info.read_cb) {
+                        char buff[MBTK_TCPIP_READ_BUFF_SIZE];
+                        memset(buff, 0x0, MBTK_TCPIP_READ_BUFF_SIZE);
+                        int read_len = mbtk_sock_read_async(tcpip_handle, sock_info->sock_fd, buff, MBTK_TCPIP_READ_BUFF_SIZE);
+                        if(read_len > 0) {
+                            tcpip_link[link_id].tcpip_info.cli_info.data_traffic_recv += read_len;
+                            tcpip_link[link_id].tcpip_info.cli_info.read_cb(link_id, (const char*)buff, read_len);
+                        }
+#if 0
+                        else { // Socket error(Such as server disconnected.).
+                            LOGW("errno = %d", errno);
+                            // Socket disconnected?
+                            mbtk_tcpip_sock_close(link_id);
+
+                            if(tcpip_sock_cb) {
+                                tcpip_sock_cb(link_id, 0);
+                            }
+                        }
+#endif
+                        while(read_len > 0) {
+                            memset(buff, 0x0, MBTK_TCPIP_READ_BUFF_SIZE);
+                            read_len = mbtk_sock_read_async(tcpip_handle, sock_info->sock_fd, buff, MBTK_TCPIP_READ_BUFF_SIZE);
+                            // LOGD("read_len = %d", read_len);
+                            if(read_len > 0) {
+                                tcpip_link[link_id].tcpip_info.cli_info.data_traffic_recv += read_len;
+                                tcpip_link[link_id].tcpip_info.cli_info.read_cb(link_id, (const char*)buff, read_len);
+                            }
+                        }
+                    }
+                } else {
+                    // Not support.
+
+                }
+            }
+        } else if(sock_info->event & EPOLLRDHUP) { // Close
+            LOGD("fd[%d] Closed?", sock_info->sock_fd);
+        } else {
+            LOGW("Unknown event:%x",sock_info->event);
+        }
+    }
+}
+
+static void tcpip_net_cb_func(mbtk_sock_handle handle, mbtk_net_cb_info_s *info)
+{
+    if(tcpip_inited && tcpip_handle == handle) {
+        LOGD("Net state : %d, %s, %s", info->state, info->if_name, info->addr);
+        if(info->state == 0) {
+            mbtk_tcpip_net_close();
+        }
+
+        if(tcpip_net_cb) {
+            tcpip_net_cb(info->state, info->addr);
+        }
+    }
+}
+
+static bool tcpip_link_check(int link_id)
+{
+    if(tcpip_inited && link_id >= 0 && link_id < MBTK_TCPIP_LINK_MAX) {
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static bool tcpip_link_connected(int link_id)
+{
+    if(!tcpip_link_check(link_id)) {
+        return FALSE;
+    }
+
+    if(!tcpip_link[link_id].link_connected) {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static int tcpip_link_reset(mbtk_tcpip_link_t *link, int link_id)
+{
+    if(link) {
+        // Close socket if necessary.
+        if(link->link_connected) {
+            if(link->type == MBTK_TCPIP_TYPE_CLIENT) {
+                if(link->tcpip_info.cli_info.sock_fd > 0) {
+                    int err;
+                    if(mbtk_sock_close(tcpip_handle, link->tcpip_info.cli_info.sock_fd, 3000, &err) == 0
+                        && err == MBTK_SOCK_SUCCESS) {
+                        LOGD("Close socket[%d] success.", link->tcpip_info.cli_info.sock_fd);
+                    } else {
+                        LOGE("Close socket[%d] fail.", link->tcpip_info.cli_info.sock_fd);
+                        return -1;
+                    }
+                }
+            } else {
+                // Not support.
+
+                return -1;
+            }
+        }
+
+        memset(link, 0x0, sizeof(mbtk_tcpip_link_t));
+        link->link_id = link_id;
+        link->link_cid = MBTK_TCPIP_CID_DEFAULT;
+        return 0;
+    }
+
+    return -1;
+}
+
+mbtk_tcpip_err_enum mbtk_tcpip_net_open(mbtk_tcpip_net_callback_func net_cb, mbtk_tcpip_sock_callback_func sock_cb)
+{
+    if(tcpip_inited) {
+        LOGW("TCP/IP has inited.");
+        return MBTK_TCPIP_ERR_SUCCESS;
+    } else {
+        //mbtk_log_init("radio", "MBTK_TCPIP");
+        mbtk_net_state_t net_state = mbtk_net_state_get();
+        if(net_state == MBTK_NET_STATE_OFF) {
+            LOGE("Network unavailable.");
+            return MBTK_TCPIP_ERR_NET_UNAVAILABLE;
+        }
+
+        memset(&tcpip_link, 0x0, sizeof(mbtk_tcpip_link_t) * MBTK_TCPIP_LINK_MAX);
+        int i = 0;
+        for(; i < MBTK_TCPIP_LINK_MAX; i++) {
+            tcpip_link_reset(tcpip_link + i, i);
+        }
+
+        mbtk_init_info init_info;
+        init_info.net_type = MBTK_NET_LINUX;
+        init_info.net_cb = tcpip_net_cb_func;
+        init_info.sock_cb = tcpip_sock_cb_func;
+        sprintf(init_info.if_name, "ccinet%d", MBTK_TCPIP_CID_DEFAULT);
+        tcpip_handle = mbtk_sock_init(&init_info);
+        if(tcpip_handle < 0) {
+            LOGE("mbtk_sock_init() fail.");
+            return MBTK_TCPIP_ERR_NET_HANDLE;
+        }
+
+        tcpip_net_cb = net_cb;
+        tcpip_sock_cb = sock_cb;
+        tcpip_inited = TRUE;
+        return MBTK_TCPIP_ERR_SUCCESS;
+    }
+}
+
+mbtk_tcpip_err_enum mbtk_tcpip_net_close()
+{
+    if(tcpip_inited) {
+        int i = 0;
+        mbtk_tcpip_err_enum tcpip_err = MBTK_TCPIP_ERR_SUCCESS;
+
+        // Close all socket.
+        for(; i < MBTK_TCPIP_LINK_MAX; i++) {
+            if(tcpip_link_reset(tcpip_link + i, i)) {
+                tcpip_err = MBTK_TCPIP_ERR_UNKNOWN;
+            }
+        }
+
+        if(tcpip_err == MBTK_TCPIP_ERR_SUCCESS) {
+            tcpip_inited = FALSE;
+        }
+        return tcpip_err;
+    } else {
+        LOGW("TCP/IP not inited.");
+        return MBTK_TCPIP_ERR_SUCCESS;
+    }
+}
+
+mbtk_tcpip_err_enum mbtk_tcpip_sock_open(const mbtk_tcpip_info_t *tcpip_info)
+{
+    if(tcpip_info == NULL || strlen(tcpip_info->ser_addr) == 0 || tcpip_info->ser_port <= 0) {
+        LOGE("ARG error.");
+        return MBTK_TCPIP_ERR_ARG;
+    }
+
+    if(!tcpip_link_check(tcpip_info->link_id)) {
+        LOGE("Link[%d] error.", tcpip_info->link_id);
+        return MBTK_TCPIP_ERR_LINK_UNAVAILABLE;
+    }
+
+    if(tcpip_link_connected(tcpip_info->link_id)) {
+        LOGE("Link[%d] has connected.", tcpip_info->link_id);
+        return MBTK_TCPIP_ERR_LINK_UNAVAILABLE;
+    }
+
+    if(tcpip_info->tcpip_type == MBTK_TCPIP_TYPE_CLIENT) {
+        mbtk_tcpip_link_t *link = tcpip_link + tcpip_info->link_id;
+
+        int err;
+        mbtk_sock_info sock_info;
+        memset(&sock_info, 0x0, sizeof(mbtk_sock_info));
+        sock_info.type = tcpip_info->prot_type;
+        sock_info.is_support_ssl = tcpip_info->ssl_support;
+        sock_info.ingnore_cert = tcpip_info->ignore_cert;
+        memcpy(sock_info.address, tcpip_info->ser_addr, strlen(tcpip_info->ser_addr));
+        sock_info.port = tcpip_info->ser_port;
+        sock_info.local_port = tcpip_info->local_port;
+
+        link->tcpip_info.cli_info.sock_fd = mbtk_sock_open(tcpip_handle, &sock_info, 3000, &err);
+        if(link->tcpip_info.cli_info.sock_fd > 0) {
+            link->prot_type = tcpip_info->prot_type;
+            link->type = MBTK_TCPIP_TYPE_CLIENT;
+            memcpy(link->tcpip_info.cli_info.ser_addr, tcpip_info->ser_addr, strlen(tcpip_info->ser_addr));
+            link->tcpip_info.cli_info.ser_port = tcpip_info->ser_port;
+            link->tcpip_info.cli_info.local_port = tcpip_info->local_port;
+            link->tcpip_info.cli_info.ack_support = tcpip_info->ack_support;
+            link->tcpip_info.cli_info.ssl_support = tcpip_info->ssl_support;
+            link->tcpip_info.cli_info.ignore_cert = tcpip_info->ignore_cert;
+            link->tcpip_info.cli_info.heartbeat_time = tcpip_info->heartbeat_time;
+            link->tcpip_info.cli_info.delay_time = tcpip_info->delay_time;
+            link->tcpip_info.cli_info.read_cb = tcpip_info->read_cb;
+            link->link_connected = TRUE;
+            LOGD("Open socket[%d] success.");
+            return MBTK_TCPIP_ERR_SUCCESS;
+        } else {
+            LOGE("Open socket[%d] fail.");
+            return MBTK_TCPIP_ERR_UNKNOWN;
+        }
+    } else {
+        LOGE("Only support CLIENT now!");
+        return MBTK_TCPIP_ERR_UNKNOWN;
+    }
+}
+
+mbtk_tcpip_err_enum mbtk_tcpip_sock_close(int link_id)
+{
+    if(!tcpip_link_connected(link_id)) {
+        LOGE("Link[%d] not connected.", link_id);
+        return MBTK_TCPIP_ERR_LINK_NOT_CONNECT;
+    }
+
+    if(tcpip_link_reset(tcpip_link + link_id, link_id)) {
+        LOGE("Close link[%d] fail.", link_id);
+        return MBTK_TCPIP_ERR_UNKNOWN;
+    }
+
+    return MBTK_TCPIP_ERR_SUCCESS;
+}
+
+int mbtk_tcpip_send(int link_id, const char* data, int data_len, const char* ser_addr, int ser_port)
+{
+    if(!tcpip_link_connected(link_id)) {
+        LOGE("Link[%d] not connected.", link_id);
+        return -1;
+    }
+
+    if(tcpip_link[link_id].type == MBTK_TCPIP_TYPE_CLIENT) {
+        int err;
+        int len = mbtk_sock_write(tcpip_handle, tcpip_link[link_id].tcpip_info.cli_info.sock_fd,
+                    data, data_len, 3000, &err);
+        if(len > 0) {
+            tcpip_link[link_id].tcpip_info.cli_info.data_traffic_send += len;
+        }
+        return len;
+    } else {
+        // Not support.
+        return -1;
+    }
+
+    return 0;
+}
+
+int mbtk_tcpip_read(int link_id, char* buff, int buff_size)
+{
+    if(!tcpip_link_connected(link_id)) {
+        LOGE("Link[%d] not connected.", link_id);
+        return -1;
+    }
+
+    if(tcpip_link[link_id].type == MBTK_TCPIP_TYPE_CLIENT) {
+        if(tcpip_handle, tcpip_link[link_id].tcpip_info.cli_info.read_cb) {
+            LOGE("Set read_cb function,can not manual read.");
+            return -1;
+        }
+        int len = mbtk_sock_read_async(tcpip_handle, tcpip_link[link_id].tcpip_info.cli_info.sock_fd,
+                    buff, buff_size);
+        if(len > 0) {
+            tcpip_link[link_id].tcpip_info.cli_info.data_traffic_recv += len;
+        }
+        return len;
+    } else {
+        // Not support.
+        return -1;
+    }
+}
+
+/*
+* Get the data traffic of the specified link. Return -1 if fail.
+*/
+int mbtk_tcpip_data_traffic_get(int link_id)
+{
+    if(!tcpip_link_connected(link_id)) {
+        LOGE("Link[%d] not connected.", link_id);
+        return -1;
+    }
+
+    if(tcpip_link[link_id].type == MBTK_TCPIP_TYPE_CLIENT) {
+        return tcpip_link[link_id].tcpip_info.cli_info.data_traffic_recv
+                + tcpip_link[link_id].tcpip_info.cli_info.data_traffic_send;
+    } else {
+        // Not support.
+        return -1;
+    }
+}
+
+/*
+* Reset the data traffic of the specified link.
+*/
+mbtk_tcpip_err_enum mbtk_tcpip_data_traffic_reset(int link_id)
+{
+    if(!tcpip_link_connected(link_id)) {
+        LOGE("Link[%d] not connected.", link_id);
+        return MBTK_TCPIP_ERR_LINK_NOT_CONNECT;
+    }
+
+    if(tcpip_link[link_id].type == MBTK_TCPIP_TYPE_CLIENT) {
+        tcpip_link[link_id].tcpip_info.cli_info.data_traffic_recv = 0;
+        tcpip_link[link_id].tcpip_info.cli_info.data_traffic_send = 0;
+        return MBTK_TCPIP_ERR_SUCCESS;
+    } else {
+        // Not support.
+
+    }
+
+    return MBTK_TCPIP_ERR_UNKNOWN;
+}
+
+/*
+* Return 0 if disconnected, 1 for connected, other for fail.
+*/
+int mbtk_tcpip_link_state_get(int link_id)
+{
+    if(!tcpip_link_check(link_id)) {
+        LOGE("Link error.");
+        return -1;
+    }
+
+    return tcpip_link[link_id].link_connected ? 1 : 0;
+}
+
+/*
+* Get TCP state informations.
+*/
+int mbtk_tcpip_info_get(int link_id, mbtk_tcpip_tcp_state_info_s *state_info)
+{
+    if(!tcpip_link_check(link_id)) {
+        LOGE("Link error.");
+        return -1;
+    }
+
+    if(state_info == NULL) {
+        LOGE("ARG error.");
+        return -1;
+    }
+
+    memset(state_info, 0x0, sizeof(mbtk_tcpip_tcp_state_info_s));
+
+    struct tcp_info info;
+    memset(&info, 0x0, sizeof(struct tcp_info));
+    int len = sizeof(info);
+    if(tcpip_link[link_id].prot_type == MBTK_SOCK_TCP) {
+        if(getsockopt(tcpip_link[link_id].tcpip_info.cli_info.sock_fd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t*)&len)) {
+            LOGE("Get TCP_INFO fail:%d", errno);
+            return -1;
+        }
+
+#if TCPIP_DEBUG
+        tcp_info_print(&info);
+#endif
+        state_info->state = info.tcpi_state;
+    } else {
+        state_info->state = 0;
+    }
+
+#if TCPIP_DEBUG
+    int rcvbuf_size;
+    len = sizeof(rcvbuf_size);
+    if(getsockopt(tcpip_link[link_id].tcpip_info.cli_info.sock_fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf_size, (socklen_t*)&len)) {
+        LOGE("Get SO_RCVBUF fail:%d", errno);
+        return -1;
+    }
+    LOGD("SO_RCVBUF = %d", rcvbuf_size);
+
+    int sndbuf_size;
+    len = sizeof(sndbuf_size);
+    if(getsockopt(tcpip_link[link_id].tcpip_info.cli_info.sock_fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size, (socklen_t*)&len)) {
+        LOGE("Get SO_SNDBUF fail:%d", errno);
+        return -1;
+    }
+    LOGD("SO_SNDBUF = %d", sndbuf_size);
+
+    int rcvlowat_size;
+    len = sizeof(rcvlowat_size);
+    if(getsockopt(tcpip_link[link_id].tcpip_info.cli_info.sock_fd, SOL_SOCKET, SO_RCVLOWAT, &rcvlowat_size, (socklen_t*)&len)) {
+        LOGE("Get SO_RCVLOWAT fail:%d", errno);
+        return -1;
+    }
+    LOGD("SO_RCVLOWAT = %d", rcvlowat_size);
+
+    int sndlowat_size;
+    len = sizeof(sndlowat_size);
+    if(getsockopt(tcpip_link[link_id].tcpip_info.cli_info.sock_fd, SOL_SOCKET, SO_SNDLOWAT, &sndlowat_size, (socklen_t*)&len)) {
+        LOGE("Get SO_SNDLOWAT fail:%d", errno);
+        return -1;
+    }
+    LOGD("SO_SNDLOWAT = %d", sndlowat_size);
+#endif
+
+    state_info->link_id = link_id;
+    state_info->sock_fd = tcpip_link[link_id].tcpip_info.cli_info.sock_fd;
+    state_info->recv_data_len = mbtk_sock_tcp_recv_len_get(tcpip_handle, tcpip_link[link_id].tcpip_info.cli_info.sock_fd);
+
+    return 0;
+}
+
+/*
+* Set socket auto read callback function,NULL for close auto read.
+*/
+void mbtk_tcpip_set_read_cb(int link_id, mbtk_tcpip_read_callback_func read_cb)
+{
+    if(!tcpip_link_check(link_id)) {
+        LOGE("Link error.");
+        return;
+    }
+
+    tcpip_link[link_id].tcpip_info.cli_info.read_cb = read_cb;
+}
+