Fix TCP/IP API

Change-Id: I302bf1ff97d2560e6f68402e0fae609e1435e257
diff --git a/mbtk/include/mbtk/mbtk_net_control.h b/mbtk/include/mbtk/mbtk_net_control.h
index bc886f8..2cfe788 100755
--- a/mbtk/include/mbtk/mbtk_net_control.h
+++ b/mbtk/include/mbtk/mbtk_net_control.h
@@ -30,6 +30,42 @@
     MBTK_NET_STATE_CONN_UNKNOWN
 } mbtk_net_state_t;
 
+typedef enum {
+    MBTK_NET_CHANGE_IF,         // Interface changed.
+    MBTK_NET_CHANGE_ADDR        // Address changed
+} mbtk_net_change_type_t;
+
+typedef enum {
+    MBTK_NET_IF_CHANGE_TYPE_ADD,       // Interface add.
+    MBTK_NET_IF_CHANGE_TYPE_DEL        // Interface delete.
+} mbtk_net_if_change_type_t;
+
+typedef enum {
+    MBTK_NET_IF_CHANGE_STATE_UP,       // Interface up.
+    MBTK_NET_IF_CHANGE_STATE_DOWN        // Interface down.
+} mbtk_net_if_change_state_t;
+
+typedef enum {
+    MBTK_NET_ADDR_CHANGE_TYPE_ADD,       // Address add.
+    MBTK_NET_ADDR_CHANGE_TYPE_DEL        // Address delete.
+} mbtk_net_addr_change_type_t;
+
+typedef struct {
+    int if_index;
+    char if_name[100];
+    mbtk_net_if_change_type_t type;
+    mbtk_net_if_change_state_t state;
+} mbtk_net_if_change_info_t;
+
+typedef struct {
+    int if_index;
+    char if_name[100];
+    mbtk_net_addr_change_type_t type;
+    char addr[100];
+} mbtk_net_addr_change_info_t;
+
+typedef void (*mbtk_net_state_callback_func)(mbtk_net_change_type_t type, const void *data);
+
 /*************************************************************
     Extern variables
 *************************************************************/
@@ -40,6 +76,7 @@
 *************************************************************/
 mbtk_net_state_t mbtk_net_state_get();
 int mbtk_net_enable(bool enable);
+int mbtk_net_monitor_reg(const char* if_name, mbtk_net_state_callback_func state_cb);
 
 #ifdef __cplusplus
 } // extern "C"
diff --git a/mbtk/include/mbtk/mbtk_sock2.h b/mbtk/include/mbtk/mbtk_sock2.h
index fbd8a0d..88121c1 100755
--- a/mbtk/include/mbtk/mbtk_sock2.h
+++ b/mbtk/include/mbtk/mbtk_sock2.h
@@ -11,6 +11,7 @@
 #define __MBTK_SOCK2_H__
 
 #include "mbtk_type.h"
+#include "mbtk_net_control.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -70,7 +71,7 @@
     MBTK_NET_MAX
 } mbtk_net_type;
 
-typedef void (*mbtk_net_cb_func)(mbtk_sock_handle handle, int state);
+typedef void (*mbtk_net_cb_func)(mbtk_sock_handle handle, int state, const char* addr, const char* if_name);
 typedef void (*mbtk_sock_cb_func)(mbtk_sock_handle handle, mbtk_sock_session sock_fd, int event);
 
 //Used to provide external and to transmit information
@@ -81,11 +82,14 @@
     bool ingnore_cert; //is ingnore certificate
     char address[256]; //server address
     int port; //server port
+    char local_address[256]; //Local address
+    int local_port; // Local port
     int ftp_ssl_support;
 } mbtk_sock_info;
 
 typedef struct
 {
+    char if_name[100];
     mbtk_net_type net_type;
     mbtk_net_cb_func net_cb;
     mbtk_sock_cb_func sock_cb;
@@ -147,6 +151,9 @@
 extern int mbtk_sock_read_async(mbtk_sock_handle handle,mbtk_sock_session session,
             void *buffer,
             unsigned int buf_len);
+extern int mbtk_sock_read_sync(mbtk_sock_handle handle,mbtk_sock_session session,
+            void *buffer,
+            unsigned int buf_len);
 extern int mbtk_sock_close(mbtk_sock_handle handle,mbtk_sock_session session,
             unsigned int timeout,
             int *mbtk_errno);
diff --git a/mbtk/include/mbtk/mbtk_tcpip.h b/mbtk/include/mbtk/mbtk_tcpip.h
index f462c46..a97dad1 100755
--- a/mbtk/include/mbtk/mbtk_tcpip.h
+++ b/mbtk/include/mbtk/mbtk_tcpip.h
@@ -13,32 +13,39 @@
 #ifndef _MBTK_TCPIP_H
 #define _MBTK_TCPIP_H
 #include "mbtk_type.h"
+#include "mbtk_sock2.h"
 
 #define MBTK_TCPIP_LINK_MAX 4
 
-typedef void (*mbtk_tcpip_read_callback_func)(int link_id, const char* data, int data_len);
-
 typedef enum {
     MBTK_TCPIP_ERR_SUCCESS,
+    MBTK_TCPIP_ERR_NET_UNAVAILABLE,     /* Network unavailable. */
+    MBTK_TCPIP_ERR_NET_HANDLE,     /* Network handle error. */
+    MBTK_TCPIP_ERR_ARG,     /* Parameter error. */
+    MBTK_TCPIP_ERR_LINK_UNAVAILABLE,     /* Link unavailable. */
+    MBTK_TCPIP_ERR_LINK_NOT_CONNECT,     /* Link not connect. */
+
+
+
 
     MBTK_TCPIP_ERR_UNKNOWN
 } mbtk_tcpip_err_enum;
 
 typedef enum {
-    MBTK_PROT_TYPE_TCP,
-    MBTK_PROT_TYPE_UDP
-} mbtk_tcpip_prot_type_enum;
-
-typedef enum {
     MBTK_TCPIP_TYPE_CLIENT,
     MBTK_TCPIP_TYPE_SERVER
 } mbtk_tcpip_type_enum;
 
+typedef void (*mbtk_tcpip_net_callback_func)(int state, const char* addr);
+typedef void (*mbtk_tcpip_sock_callback_func)(int link_id, int state);
+typedef void (*mbtk_tcpip_read_callback_func)(int link_id, const char* data, int data_len);
+
 typedef struct {
     int link_id;
     char ser_addr[256];
     int ser_port;
-    mbtk_tcpip_prot_type_enum prot_type;
+    mbtk_sock_type prot_type; // TCP/UDP
+    mbtk_tcpip_type_enum tcpip_type; // Only support client.
     int local_port;
     bool ack_support;
     bool ssl_support;
@@ -49,7 +56,7 @@
     mbtk_tcpip_read_callback_func read_cb;
 } mbtk_tcpip_info_t;
 
-mbtk_tcpip_err_enum mbtk_tcpip_net_open();
+mbtk_tcpip_err_enum mbtk_tcpip_net_open(mbtk_tcpip_net_callback_func net_cb, mbtk_tcpip_sock_callback_func sock_cb);
 mbtk_tcpip_err_enum mbtk_tcpip_net_close();
 mbtk_tcpip_err_enum mbtk_tcpip_sock_open(const mbtk_tcpip_info_t *tcpip_info);
 mbtk_tcpip_err_enum mbtk_tcpip_sock_close(int link_id);
@@ -58,7 +65,7 @@
 int mbtk_tcpip_read(int link_id, char* buff, int buff_size);
 
 /*
-* Get the data traffic of the specified link.
+* Get the data traffic of the specified link. Return -1 if fail.
 */
 int mbtk_tcpip_data_traffic_get(int link_id);
 
@@ -68,7 +75,7 @@
 mbtk_tcpip_err_enum mbtk_tcpip_data_traffic_reset(int link_id);
 
 /*
-* Return 0 if disconnected, other for connected.
+* Return 0 if disconnected, 1 for connected, other for fail.
 */
 int mbtk_tcpip_link_state_get(int link_id);
 
diff --git a/mbtk/mbtk_lib/Makefile b/mbtk/mbtk_lib/Makefile
index 0e51728..77502d5 100755
--- a/mbtk/mbtk_lib/Makefile
+++ b/mbtk/mbtk_lib/Makefile
@@ -19,10 +19,10 @@
 	-lswscale \
 	-lcutils \
 	-laudio-apu
-	
+
 CFLAGS += -shared -Wl,-shared,-Bsymbolic
 
-DEFINE +=
+DEFINE += -DMBTK_NET_MONITOR_SUPPORT
 
 MY_FILES_PATH:=$(LOCAL_PATH)/src
 #ifeq ($(CONFIG_MBTK_QL_SUPPORT),y)
diff --git a/mbtk/mbtk_lib/src/mbtk_http_base.c b/mbtk/mbtk_lib/src/mbtk_http_base.c
index 40a6742..657b838 100755
--- a/mbtk/mbtk_lib/src/mbtk_http_base.c
+++ b/mbtk/mbtk_lib/src/mbtk_http_base.c
@@ -6,12 +6,6 @@
 
 static void http_sock_cb_func(int handle, int fd, int event);
 
-static mbtk_init_info http_init_info =
-{
-    MBTK_NET_LINUX,
-    NULL,
-    http_sock_cb_func
-};
 static bool http_sock_inited = FALSE;
 static int http_handle = -1;
 static int http_fd = -1;
@@ -36,7 +30,11 @@
         return -1;
     }
 
-    http_handle = mbtk_sock_init(&http_init_info);
+    mbtk_init_info init_info;
+    memset(&init_info, 0x0, sizeof(mbtk_init_info));
+    init_info.net_type = MBTK_NET_LINUX;
+    init_info.sock_cb = http_sock_cb_func;
+    http_handle = mbtk_sock_init(&init_info);
     if(http_handle < 0) {
         LOGE("mbtk_sock_init() fail.");
         return -1;
@@ -174,7 +172,7 @@
         char read_buf[1];
         int read_len = 0;
         while(TRUE) {
-            if(mbtk_sock_read_async(http_handle, sock_fd, read_buf, 1) == 1) {
+            if(mbtk_sock_read_sync(http_handle, sock_fd, read_buf, 1) == 1) {
                 *buf_ptr++ = read_buf[0];
                 read_len++;
 
diff --git a/mbtk/mbtk_lib/src/mbtk_net_control.c b/mbtk/mbtk_lib/src/mbtk_net_control.c
index ff3af08..722efda 100755
--- a/mbtk/mbtk_lib/src/mbtk_net_control.c
+++ b/mbtk/mbtk_lib/src/mbtk_net_control.c
@@ -49,12 +49,14 @@
 *************************************************************/
 static char net_interface[20];
 static char net_ip[20];
+static bool net_if_inited = FALSE;
 static mbtk_net_state_t net_state = MBTK_NET_STATE_OFF;
 static bool net_control_thread_running = FALSE;
 
 #ifdef MBTK_NET_MONITOR_SUPPORT
 static pthread_t net_control_thread_id = -1;
 static int net_control_fd = -1;
+static char net_if_name[100] = {0};
 #endif
 
 /*************************************************************
@@ -65,7 +67,7 @@
 /*************************************************************
     Local Function Declaration
 *************************************************************/
-
+static mbtk_net_state_callback_func net_state_cb = NULL;
 
 /*************************************************************
     Local Function Definitions
@@ -164,8 +166,18 @@
     return 0;
 }
 
+static void parse_rtattr(struct rtattr **tb, int max, struct rtattr *attr, int len)
+{
+    for ( ; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
+        if (attr->rta_type <= max) {
+            tb[attr->rta_type] = attr;
+        }
+    }
+}
+
 static void net_control_if_change(struct nlmsghdr *nh)
 {
+    int msg_len;
     struct rtattr *tb[IFLA_MAX + 1];
     struct ifinfomsg *ifinfo;
     bzero(tb, sizeof(tb));
@@ -182,45 +194,94 @@
         return;
     }
 
-    LOGD("nlmsghdr:%d,%d,%d,%d,%d\n",nh->nlmsg_len,
-         nh->nlmsg_type,
-         nh->nlmsg_flags,
-         nh->nlmsg_seq,
-         nh->nlmsg_pid);
+    msg_len = nh->nlmsg_len - NLMSG_SPACE(sizeof(*ifinfo));
+    parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifinfo), msg_len); /* 8 */
 
-    LOGD("ifinfomsg:%d,%d,%d,%d,%d,%d\n",ifinfo->ifi_family,
-         ifinfo->__ifi_pad,
-         ifinfo->ifi_type,
-         ifinfo->ifi_index,
-         ifinfo->ifi_flags,
-         ifinfo->ifi_change);
+    LOGD("Interface changed:if_index=%d,if_name=%s,type=%s,state=%s",
+        ifinfo->ifi_index, (tb[IFLA_IFNAME] ? RTA_DATA(tb[IFLA_IFNAME]) : " "),
+        (nh->nlmsg_type == RTM_NEWLINK) ? "NEWLINK" : "DELLINK",
+        (ifinfo->ifi_flags & IFF_UP) ? "up" : "down");
 
-    if((ifinfo->ifi_flags & IFF_RUNNING)
-       && (ifinfo->ifi_flags & IFF_LOWER_UP))
-    {
-        LOGD("Wired inserted.");
-    }
-    else
-    {
-        LOGD("Wired not insert.");
+    if(net_state_cb) {
+        mbtk_net_if_change_info_t if_info;
+        memset(&if_info, 0x0, sizeof(mbtk_net_if_change_info_t));
+        if_info.if_index = ifinfo->ifi_index;
+        if(tb[IFLA_IFNAME]) {
+            memcpy(if_info.if_name, RTA_DATA(tb[IFLA_IFNAME]), strlen(RTA_DATA(tb[IFLA_IFNAME])));
+        }
+        if_info.type = (nh->nlmsg_type == RTM_NEWLINK) ? MBTK_NET_IF_CHANGE_TYPE_ADD : MBTK_NET_IF_CHANGE_TYPE_DEL;
+        if_info.state = (ifinfo->ifi_flags & IFF_UP) ? MBTK_NET_IF_CHANGE_STATE_UP : MBTK_NET_IF_CHANGE_STATE_DOWN;
+        if(str_empty(net_if_name)) { // No set if name, process all interface change.
+            net_state_cb(MBTK_NET_CHANGE_IF, &if_info);
+        } else {
+            // Only monitor specific interface.
+            if(strcmp(net_if_name, if_info.if_name) == 0) {
+                net_state_cb(MBTK_NET_CHANGE_IF, &if_info);
+            }
+        }
     }
 }
 
-static void net_control_addr_change(struct nlmsghdr *nh)
+static void net_control_addr_change(struct nlmsghdr *nlh)
 {
-    if(nh == NULL)
-    {
-        LOGE("mbtk_net_if_change() nh == NULL");
-        return;
-    }
+    int len;
+    struct rtattr *tb[IFA_MAX + 1];
+    struct ifaddrmsg *ifaddr;
 
-    if(nh->nlmsg_type==RTM_NEWADDR)
-    {
-        LOGD("New addr...");
-    }
-    else
-    {
-        LOGD("Del addr...");
+    bzero(tb, sizeof(tb));
+    ifaddr = NLMSG_DATA(nlh);
+    len =nlh->nlmsg_len - NLMSG_SPACE(sizeof(*ifaddr));
+    parse_rtattr(tb, IFA_MAX, IFA_RTA (ifaddr), len);
+
+    if (tb[IFA_ADDRESS] != NULL) {
+        char tmp[256] = {0};
+        inet_ntop(ifaddr->ifa_family, RTA_DATA(tb[IFA_ADDRESS]), tmp, sizeof(tmp));
+        LOGD("Address changed:index=%d,type=%s,if_name=%s,addr=%s", ifaddr->ifa_index,
+                (nlh->nlmsg_type == RTM_NEWADDR) ? "NEWADDR":"DELADDR",
+                tb[IFA_LABEL] ? RTA_DATA(tb[IFA_LABEL]) : "Unknown", tmp);
+
+        if(net_state_cb) {
+            mbtk_net_addr_change_info_t addr_info;
+            memset(&addr_info, 0x0, sizeof(mbtk_net_addr_change_info_t));
+            addr_info.if_index = ifaddr->ifa_index;
+            addr_info.type = (nlh->nlmsg_type == RTM_NEWADDR) ? MBTK_NET_ADDR_CHANGE_TYPE_ADD : MBTK_NET_ADDR_CHANGE_TYPE_DEL;
+            if(tb[IFA_LABEL] != NULL) {
+                memcpy(addr_info.if_name, RTA_DATA(tb[IFA_LABEL]), strlen(RTA_DATA(tb[IFA_LABEL])));
+            }
+            if (strlen(tmp) > 0) {
+                memcpy(addr_info.addr, tmp, strlen(tmp));
+            }
+            if(str_empty(net_if_name)) { // No set if name, process all address change.
+                net_state_cb(MBTK_NET_CHANGE_ADDR, &addr_info);
+            } else {
+                // Only monitor specific address.
+                if(strcmp(net_if_name, addr_info.if_name) == 0) {
+                    net_state_cb(MBTK_NET_CHANGE_ADDR, &addr_info);
+                }
+            }
+        }
+    } else {
+        LOGD("Address changed:type=%s,if_name=%s,addr=%s",
+            (nlh->nlmsg_type == RTM_NEWADDR) ? "NEWADDR":"DELADDR",
+            tb[IFA_LABEL] ? RTA_DATA(tb[IFA_LABEL]) : "Unknown", "Unknown");
+
+        if(net_state_cb) {
+            mbtk_net_addr_change_info_t addr_info;
+            memset(&addr_info, 0x0, sizeof(mbtk_net_addr_change_info_t));
+            addr_info.if_index = ifaddr->ifa_index;
+            addr_info.type = (nlh->nlmsg_type == RTM_NEWADDR) ? MBTK_NET_ADDR_CHANGE_TYPE_ADD : MBTK_NET_ADDR_CHANGE_TYPE_DEL;
+            if(tb[IFA_LABEL] != NULL) {
+                memcpy(addr_info.if_name, RTA_DATA(tb[IFA_LABEL]), strlen(RTA_DATA(tb[IFA_LABEL])));
+            }
+            if(str_empty(net_if_name)) { // No set if name, process all address change.
+                net_state_cb(MBTK_NET_CHANGE_ADDR, &addr_info);
+            } else {
+                // Only monitor specific address.
+                if(strcmp(net_if_name, addr_info.if_name) == 0) {
+                    net_state_cb(MBTK_NET_CHANGE_ADDR, &addr_info);
+                }
+            }
+        }
     }
 }
 
@@ -258,11 +319,11 @@
             {
                 read_r = read(net_control_fd, buff, NET_CONTROL_BUF_SIZE);
                 LOGI("Net change:read len:%d",read_r);
-
+#if 0
                 int i;
                 for(i = 0; i < 32 && i < read_r; i++)
                     LOGI("data:%x",buff[i]);
-
+#endif
                 for (nh = (struct nlmsghdr *) buff; NLMSG_OK(nh, read_r); nh = NLMSG_NEXT(nh, read_r))
                 {
                     LOGI("msg_type:%d",nh->nlmsg_type);
@@ -353,27 +414,18 @@
 
 static int net_control_init()
 {
-//    if(net_control_thread_running)
-//    {
-//        LOGD("Network control has inited.");
-//        return 0;
-//    }
+    if(net_if_inited)
+    {
+        LOGD("Network control has inited.");
+        return 0;
+    }
 
     memset(net_ip,0x0,20);
     memset(net_interface,0x0,20);
-    if( net_control_interface_init())
+    if(net_control_interface_init())
         return -1;
-    net_control_thread_running = TRUE;
 
-#ifdef MBTK_NET_MONITOR_SUPPORT
-    if(mbtk_task_start(&net_control_thread))
-    {
-        LOGE("Create thread fail.");
-        net_control_thread_id = -1;
-        net_control_thread_running = FALSE;
-        return -1;
-    }
-#endif
+    net_if_inited = TRUE;
     LOGI("net_control_init() success.");
     return 0;
 }
@@ -533,3 +585,31 @@
     return result;
 }
 
+int mbtk_net_monitor_reg(const char* if_name, mbtk_net_state_callback_func state_cb)
+{
+    if( net_control_init())
+        return -1;
+
+#ifdef MBTK_NET_MONITOR_SUPPORT
+    net_control_thread_running = TRUE;
+    if(mbtk_task_start(&net_control_thread))
+    {
+        LOGE("Create thread fail.");
+        net_control_thread_id = -1;
+        net_control_thread_running = FALSE;
+        return -1;
+    }
+#endif
+
+    net_state_cb = state_cb;
+    if(str_empty(if_name)) {
+        memset(net_if_name, 0x0, sizeof(net_if_name));
+    } else {
+        memset(net_if_name, 0x0, sizeof(net_if_name));
+        memcpy(net_if_name, if_name, strlen(if_name));
+    }
+
+    return 0;
+}
+
+
diff --git a/mbtk/mbtk_lib/src/mbtk_sock2.c b/mbtk/mbtk_lib/src/mbtk_sock2.c
index 461c68c..f9f6b6b 100755
--- a/mbtk/mbtk_lib/src/mbtk_sock2.c
+++ b/mbtk/mbtk_lib/src/mbtk_sock2.c
@@ -200,6 +200,24 @@
     return 0;
 }
 
+void net_state_callback_func(mbtk_net_change_type_t type, const void *data)
+{
+    if(type == MBTK_NET_CHANGE_ADDR && data != NULL) {
+        int handle = 0;
+        const mbtk_net_addr_change_info_t *addr_info = (const mbtk_net_addr_change_info_t *)data;
+        while(handle < MBTK_HANDLE_MAX_NUM) {
+            if(mbtk_sock[handle] != NULL) {
+                if(mbtk_sock[handle]->init_info.net_cb != NULL) {
+                    mbtk_sock[handle]->init_info.net_cb(handle, (addr_info->type == MBTK_NET_ADDR_CHANGE_TYPE_ADD) ? 1 : 0,
+                        addr_info->addr, addr_info->if_name);
+                }
+            }
+
+            handle++;
+        }
+    }
+}
+
 extern mbtk_sock_handle mbtk_sock_init(mbtk_init_info *info)
 {
     mbtk_sock_handle handle = 0;
@@ -221,6 +239,9 @@
         mbtk_sock[handle]->init_info.net_type = info->net_type;
         mbtk_sock[handle]->init_info.net_cb = info->net_cb;
         mbtk_sock[handle]->init_info.sock_cb = info->sock_cb;
+        if(!str_empty(info->if_name)) {
+            memcpy(mbtk_sock[handle]->init_info.if_name, info->if_name, strlen(info->if_name));
+        }
     } else {
         mbtk_sock[handle]->init_info.net_type = MBTK_NET_LINUX;
         mbtk_sock[handle]->init_info.net_cb = NULL;
@@ -235,6 +256,11 @@
         }
     }
 
+    if(mbtk_net_monitor_reg(str_empty(info->if_name) ? NULL : info->if_name, net_state_callback_func)) {
+        LOGE("mbtk_net_monitor_reg() fail.");
+        return -1;
+    }
+
     return handle;
 }
 
@@ -527,6 +553,34 @@
     // Connect
     LOGD("Start conn:%s:%d",info->address,info->port);
     if(strlen(info->address) > 0 && info->port > 0) {
+        if(strlen(info->local_address) > 0 || info->local_port > 0) {
+            // 指定本地IP和端口,不指定内核会自动指定(一般不指定)
+            struct sockaddr_in loc_addr;
+            memset(&loc_addr, 0, sizeof(struct sockaddr_in));
+            loc_addr.sin_family = AF_INET;
+
+            // 指定IP
+            if(strlen(info->local_address) > 0) {
+                if(inet_pton(AF_INET, info->local_address, &loc_addr.sin_addr) < 0) {
+                    LOGE("inet_pton() error:%d", errno);
+                    goto result_fail_with_close;
+                }
+            }
+
+            if(info->local_port > 0) {
+                loc_addr.sin_port = htons(info->local_port);
+            }
+            if(bind(mbtk_sock[handle]->inter_infos[index_free].fd, (struct sockaddr *)&loc_addr, sizeof(loc_addr)) < 0) {
+                LOGE("bind() error:%d", errno);
+                if(errno == EADDRINUSE) { // 地址已在使用
+                    LOGE("EADDRINUSE : Local port already occupied.");
+                }
+                goto result_fail_with_close;
+            } else {
+                LOGD("Bind ip/port success.");
+            }
+        }
+
         struct sockaddr_in servaddr;
         bzero(&servaddr, sizeof(servaddr));
         servaddr.sin_family = AF_INET;
@@ -633,7 +687,7 @@
                         60000,
                         &err_rw);
                 printf("\nmbtk_sock_read:\n%s\n",mbtk_ftp_ssl_read_buf_s);
-                
+
             mbtk_sock[handle]->infos[index_free].is_support_ssl=1;
         }else{
             mbtk_sock[handle]->infos[index_free].is_support_ssl=1;
@@ -662,7 +716,7 @@
     return -1;
 }
 extern int mbtk_ssl_init_func(mbtk_sock_handle handle ,bool ingnore_cert,mbtk_sock_session fd)
-{   
+{
     int i=0;
     int index_free=0;
 
@@ -677,7 +731,7 @@
     return mbtk_ssl_init(mbtk_sock[handle]->inter_infos[index_free].fd,ingnore_cert,&mbtk_sock[handle]->inter_infos[index_free]);
 }
 extern int mbtk_ssl_close_func(mbtk_sock_handle handle ,bool ingnore_cert,mbtk_sock_session fd)
-{   
+{
     int i=0;
     int index_free=0;
 
@@ -1050,7 +1104,7 @@
                         LOGE("read error.[%d]",errno);
                         if(count <= 0)
                             count = -1;
-                        else { 
+                        else {
                             *read_line_count = count;
                         }
                         break;
@@ -1182,6 +1236,85 @@
         return -1;
     }
 
+    int len = 0;
+    int read_count = 0;
+    if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_TCP) {
+        memset(buffer,0x0,buf_len);
+        while(read_count < buf_len) {
+            if(mbtk_sock[handle]->infos[index].is_support_ssl)
+                len = ssl_read(inter_info->ssl,(char*)buffer + read_count,buf_len - read_count);
+            else
+                len = read(inter_info->fd,(char*)buffer  + read_count,buf_len - read_count);
+
+            if(len > 0) {
+                read_count += len;
+            } else {
+                break;
+            }
+        }
+    } else if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_UDP) {
+        // Start recv data
+        struct sockaddr_in seraddr;
+        socklen_t seraddr_len;
+        memset(buffer,0x0,buf_len);
+        seraddr_len = sizeof(struct sockaddr_in);
+        memset(buffer,0x0,buf_len);
+
+        while(read_count < buf_len) {
+            len = recvfrom(inter_info->fd,buffer + read_count,buf_len - read_count,0,&seraddr,&seraddr_len);
+
+            if(len > 0) {
+                read_count += len;
+            } else {
+                break;
+            }
+        }
+    } else {
+        LOGE("Socket type error.");
+        return -1;
+    }
+
+    LOGV("Read data[%d/%d].",len,buf_len);
+
+    return read_count;
+}
+
+extern int mbtk_sock_read_sync(mbtk_sock_handle handle,mbtk_sock_session session,
+            void *buffer,
+            unsigned int buf_len)
+{
+    if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+        || session < 0 || mbtk_sock[handle] == NULL) {
+        LOGE("Socket not inited.");
+        return -1;
+    }
+
+    if(buffer == NULL) {
+        LOGE("mbtk_sock_write() args error.");
+        return -1;
+    }
+
+    mbtk_sock_inter_info_s *inter_info = NULL;
+    int index = 0;
+    while(index < MBTK_SOCK_MAX_NUM) {
+        if(session ==
+            mbtk_sock[handle]->inter_infos[index].fd) {
+            inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+            break;
+        }
+        index++;
+    }
+    if(!sock_info_check(handle,inter_info)) {
+        LOGE("sock_info_check() fail.");
+        return -1;
+    }
+
+    index = sock_info_find_by_fd(handle,inter_info->fd);
+    if(index < 0) {
+        LOGE("No such socket in session list.");
+        return -1;
+    }
+
     int len;
     if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_TCP) {
 TCP_READ_AGAIN:
@@ -1193,6 +1326,7 @@
         if(len < 0){
             if(errno == EWOULDBLOCK){
                 usleep(100000);
+                LOGW("Read retry...");
                 goto TCP_READ_AGAIN;
             } else {
                 LOGE("read error.[%d]",errno);
diff --git a/mbtk/mbtk_lib/src/mbtk_tcpip_at.c b/mbtk/mbtk_lib/src/mbtk_tcpip_at.c
index 8f90bed..76dc526 100755
--- a/mbtk/mbtk_lib/src/mbtk_tcpip_at.c
+++ b/mbtk/mbtk_lib/src/mbtk_tcpip_at.c
@@ -1,13 +1,27 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <errno.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 {
-    int fd;
+    mbtk_sock_session sock_fd;
     char ser_addr[256];
     int ser_port;
     char local_addr[256];
@@ -26,7 +40,7 @@
 } mbtk_tcpip_cli_info_t;
 
 typedef struct {
-    int fd;
+    mbtk_sock_session sock_fd;
     char ser_addr[256];
     int ser_port;
 
@@ -37,8 +51,8 @@
 typedef struct {
     int link_id;
     int link_cid;
-    bool link_active;
-    mbtk_tcpip_prot_type_enum prot_type;    // TCP/UDP
+    bool link_connected;
+    mbtk_sock_type prot_type;    // TCP/UDP
 
     mbtk_tcpip_type_enum type;
     union
@@ -50,44 +64,467 @@
 } 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;
 
-mbtk_tcpip_err_enum mbtk_tcpip_net_open()
+/*
+struct tcp_info
 {
-    return MBTK_TCPIP_ERR_SUCCESS;
+  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, int fd, int event)
+{
+    if(tcpip_inited && tcpip_handle == handle/* && http_fd == fd*/) {
+        if(event & (EPOLLIN | EPOLLOUT)) { // Cand read or write.
+            int sock_error = 0;
+            socklen_t socklen = sizeof(sock_error);
+            if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &sock_error, (socklen_t*)&socklen) == 0) {
+                LOGD("Socket error:%d", sock_error);
+            }
+
+            if(sock_error) {
+                LOGW("errno = %d", errno);
+                return;
+            }
+
+            struct tcp_info info;
+            int len = sizeof(info);
+            if(getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t*)&len) == 0) {
+                LOGD("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(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(event & EPOLLIN) { // READ
+            LOGD("fd[%d] can read.", fd);
+            int link_id = tcpip_fd_2_link(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, 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, 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(event & EPOLLRDHUP) { // Close
+            LOGD("fd[%d] Closed?", fd);
+        } else {
+            LOGW("Unknown event:%x",event);
+        }
+    }
+}
+
+static void tcpip_net_cb_func(mbtk_sock_handle handle, int state, const char* addr, const char* if_name)
+{
+    if(tcpip_inited && tcpip_handle == handle) {
+        LOGD("Net state : %d, %s, %s", state, if_name, addr);
+        if(state == 0) {
+            mbtk_tcpip_net_close();
+        }
+
+        if(tcpip_net_cb) {
+            tcpip_net_cb(state, 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()
 {
-    return MBTK_TCPIP_ERR_SUCCESS;
+    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)
 {
-    return MBTK_TCPIP_ERR_SUCCESS;
+    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)
 {
-    return 0;
+    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 err;
+        int len = mbtk_sock_read(tcpip_handle, tcpip_link[link_id].tcpip_info.cli_info.sock_fd,
+                    buff, buff_size, 3000, &err);
+        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.
+* Get the data traffic of the specified link. Return -1 if fail.
 */
 int mbtk_tcpip_data_traffic_get(int link_id)
 {
-    return 0;
+    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;
+    }
 }
 
 /*
@@ -95,14 +532,33 @@
 */
 mbtk_tcpip_err_enum mbtk_tcpip_data_traffic_reset(int link_id)
 {
-    return MBTK_TCPIP_ERR_SUCCESS;
+    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, other for connected.
+* Return 0 if disconnected, 1 for connected, other for fail.
 */
 int mbtk_tcpip_link_state_get(int link_id)
 {
-    return 0;
+    if(!tcpip_link_check(link_id)) {
+        LOGE("Link error.");
+        return -1;
+    }
+
+    return tcpip_link[link_id].link_connected ? 1 : 0;
 }
 
diff --git a/mbtk/test/mbtk_tcpip_test.c b/mbtk/test/mbtk_tcpip_test.c
new file mode 100755
index 0000000..5bd39f1
--- /dev/null
+++ b/mbtk/test/mbtk_tcpip_test.c
@@ -0,0 +1,313 @@
+#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 "mbtk_tcpip.h"
+#include "mbtk_log.h"
+
+/*
+    int link_id;
+    char ser_addr[256];
+    int ser_port;
+    mbtk_sock_type prot_type; // TCP/UDP
+    mbtk_tcpip_type_enum tcpip_type; // Only support client.
+    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;
+
+*/
+static void help()
+{
+    printf("\n************************************************************************\n");
+    printf("net_open: Open network.\n");
+    printf("net_close: Close network.\n");
+    printf("link_open <link_id> <ser_addr> <ser_port> <loc_port> <TCP/UDP> <CLI/SER> <ack> <ssl> <ignore_cert> <heartbeat_time> <delay_time> <read_cb>: Open link.\n");
+    printf("link_close <link_id>: Close link.\n");
+    printf("send <link_id> <data>:Send data.\n");
+    printf("recv <link_id>:Recv data.\n");
+    printf("traffic_reset <link_id>:Traffic reset.\n");
+    printf("traffic_get <link_id>:Traffic get.\n");
+    printf("state_get <link_id>:Link state get.\n");
+    printf("\n************************************************************************\n");
+}
+
+static void sig_process(int sig)
+{
+    LOGI("I got signal %d\n", sig);
+    switch(sig)
+    {
+        case SIGINT: // Ctrl + C
+        {
+            LOGI("Exit by SIGINT.\n");
+            mbtk_tcpip_err_enum err = mbtk_tcpip_net_close();
+            if(err == MBTK_TCPIP_ERR_SUCCESS) {
+                printf("Net close success.\n");
+            } else {
+                printf("Net close fail:%d\n", err);
+            }
+            exit(0);
+        }
+        case SIGQUIT: // Ctrl + \ (类似 SIGINT ,但要产生core文件)
+        {
+            LOGI("Exit by SIGQUIT.\n");
+            mbtk_tcpip_err_enum err = mbtk_tcpip_net_close();
+            if(err == MBTK_TCPIP_ERR_SUCCESS) {
+                printf("Net close success.\n");
+            } else {
+                printf("Net close fail:%d\n", err);
+            }
+            exit(0);
+        }
+        case SIGTERM:// 默认kill   (同 SIGKILL ,但 SIGKILL 不可捕获)
+        {
+            LOGI("Exit by SIGTERM.\n");
+            mbtk_tcpip_err_enum err = mbtk_tcpip_net_close();
+            if(err == MBTK_TCPIP_ERR_SUCCESS) {
+                printf("Net close success.\n");
+            } else {
+                printf("Net close fail:%d\n", err);
+            }
+            exit(0);
+        }
+        case SIGTSTP:// Ctrl + Z (同 SIGSTOP ,但 SIGSTOP 不可捕获)
+        {
+            LOGI("Exit by SIGTSTP.\n");
+            exit(0);
+        }
+        case SIGSEGV: // 如空指针
+        {
+            LOGI("Exit by SIGSEGV.\n");
+            exit(0);
+        }
+        default:
+        {
+            LOGI("Unknown sig:%d\n",sig);
+            break;
+        }
+    }
+}
+
+void tcpip_read_cb(int link_id, const char* data, int data_len)
+{
+    printf("\nRECV(%d-%d):%s\n", link_id, data_len, data);
+}
+
+void tcpip_net_callback_func(int state, const char* addr)
+{
+    if(state) {
+        printf("Net conncect, IP : %s\n", addr);
+    } else {
+        printf("Net disconnect.\n");
+    }
+}
+
+void tcpip_sock_callback_func(int link_id, int state)
+{
+    if(state == 0) {
+        printf("Link[%d] disconnected.\n", link_id);
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    signal(SIGINT, sig_process);
+    signal(SIGQUIT, sig_process);
+    signal(SIGTERM, sig_process);
+    //signal(SIGTSTP, sig_process);
+    //signal(SIGSEGV, sig_process);
+
+    mbtk_log_init("radio","MBTK_TCPIP");
+
+    printf(">>>>>>>>>>>>>>>>>>>>>>>>Enter cmd:\n");
+    char cmd[100];
+    while(1)
+    {
+        memset(cmd, 0, 100);
+        mbtk_tcpip_err_enum err;
+        if(fgets(cmd, 100, stdin))
+        {
+            char *ptr = cmd + strlen(cmd) - 1;
+            while(ptr >= cmd && (*ptr == '\r' || *ptr == '\n'))
+            {
+                *ptr-- = '\0';
+            }
+            // net_open
+            if(!strncasecmp(cmd, "net_open", 8)){
+                err = mbtk_tcpip_net_open(tcpip_net_callback_func, tcpip_sock_callback_func);
+                if(err == MBTK_TCPIP_ERR_SUCCESS) {
+                    printf("Net open success.\n");
+                } else {
+                    printf("Net open fail:%d\n", err);
+                }
+            } else if(!strncasecmp(cmd, "net_close", 9)){ // net_close
+                err = mbtk_tcpip_net_close();
+                if(err == MBTK_TCPIP_ERR_SUCCESS) {
+                    printf("Net close success.\n");
+                } else {
+                    printf("Net close fail:%d\n", err);
+                }
+            }
+            // link_open <link_id> <ser_addr> <ser_port> <loc_port> <TCP/UDP> <CLI/SER> <ack> <ssl> <ignore_cert> <heartbeat_time> <delay_time> <read_cb>
+            else if(!strncasecmp(cmd, "link_open", 9)){
+                mbtk_tcpip_info_t info;
+                char prot_type[10] = {0};
+                char type[10] = {0};
+                int read_cb_set;
+                memset(&info, 0x0, sizeof(mbtk_tcpip_info_t));
+                int count = sscanf(cmd, "link_open %d %s %d %d %s %s %d %d %d %d %d %d", &(info.link_id),
+                                info.ser_addr, &(info.ser_port), &(info.local_port), prot_type, type,
+                                &(info.ack_support), &(info.ssl_support), &(info.ignore_cert), &(info.heartbeat_time),
+                                &(info.delay_time), &read_cb_set);
+                if(count == 12) {
+                    if(!strncasecmp(prot_type, "UDP", 3)) {
+                        info.prot_type = MBTK_SOCK_UDP;
+                    } else {
+                        info.prot_type = MBTK_SOCK_TCP;
+                    }
+
+                    if(!strncasecmp(type, "SER", 3)) {
+                        info.tcpip_type = MBTK_TCPIP_TYPE_SERVER;
+                    } else {
+                        info.tcpip_type = MBTK_TCPIP_TYPE_CLIENT;
+                    }
+
+                    if(read_cb_set) {
+                        info.read_cb = tcpip_read_cb;
+                    } else {
+                        info.read_cb = NULL;
+                    }
+
+                    err = mbtk_tcpip_sock_open((const mbtk_tcpip_info_t*)(&info));
+                    if(err == MBTK_TCPIP_ERR_SUCCESS) {
+                        printf("Link open success.\n");
+                    } else {
+                        printf("Link open fail:%d\n", err);
+                    }
+                } else {
+                    printf("ARG error.\n");
+                }
+            } else if(!strncasecmp(cmd, "link_close", 10)){ // link_close <link_id>
+                int link_id;
+                int count = sscanf(cmd, "link_close %d", &link_id);
+                if(count == 1) {
+                    err = mbtk_tcpip_sock_close(link_id);
+                    if(err == MBTK_TCPIP_ERR_SUCCESS) {
+                        printf("Link close success.\n");
+                    } else {
+                        printf("Link close fail:%d\n", err);
+                    }
+                } else {
+                    printf("ARG error.\n");
+                }
+            } else if(!strncasecmp(cmd, "send", 4)){ // send <link_id> <data>
+                int link_id;
+                char data[100] = {0};
+                int count = sscanf(cmd, "send %d %s", &link_id, data);
+                if(count == 2) {
+                    int len = mbtk_tcpip_send(link_id, data, strlen(data), NULL, 0);
+                    if(len == strlen(data)) {
+                        printf("Send success:%d.\n", len);
+                    } else {
+                        printf("Send fail:%d/%d\n", len, strlen(data));
+                    }
+                } else {
+                    printf("ARG error.\n");
+                }
+            } else if(!strncasecmp(cmd, "recv", 4)){ // recv <link_id>
+                int link_id;
+                int count = sscanf(cmd, "recv %d", &link_id);
+                if(count == 1) {
+                    char buff[2048] = {0};
+                    int len = mbtk_tcpip_read(link_id, buff, 2048);
+                    if(len > 0) {
+                        printf("RECV[%d]:%s\n", len, buff);
+                    } else {
+                        printf("RECV fail:%d\n", len);
+                    }
+                } else {
+                    printf("ARG error.\n");
+                }
+            } else if(!strncasecmp(cmd, "traffic_reset", 13)){ // traffic_reset <link_id>
+                int link_id;
+                int count = sscanf(cmd, "traffic_reset %d", &link_id);
+                if(count == 1) {
+                    err = mbtk_tcpip_data_traffic_reset(link_id);
+                    if(err == MBTK_TCPIP_ERR_SUCCESS) {
+                        printf("Traffic reset success.\n");
+                    } else {
+                        printf("Traffic reset fail:%d\n", err);
+                    }
+                } else {
+                    printf("ARG error.\n");
+                }
+            } else if(!strncasecmp(cmd, "traffic_get", 11)){ // traffic_get <link_id>
+                int link_id;
+                int count = sscanf(cmd, "traffic_get %d", &link_id);
+                if(count == 1) {
+                    int traffic = mbtk_tcpip_data_traffic_get(link_id);
+                    if(traffic >= 0) {
+                        printf("Traffic : %d\n", traffic);
+                    } else {
+                        printf("Get raffic fail:%d\n", traffic);
+                    }
+                } else {
+                    printf("ARG error.\n");
+                }
+            } else if(!strncasecmp(cmd, "state_get", 9)){ // state_get <link_id>
+                int link_id;
+                int count = sscanf(cmd, "state_get %d", &link_id);
+                if(count == 1) {
+                    int state = mbtk_tcpip_link_state_get(link_id);
+                    if(state == 1) {
+                        printf("Link %d connected.\n", link_id);
+                    } else if(state == 0) {
+                        printf("Link %d disconnected.\n", link_id);
+                    } else {
+                        printf("Get link state fail:%d\n", state);
+                    }
+                } else {
+                    printf("ARG error.\n");
+                }
+            }
+            else if(!strcasecmp(cmd, "h") || !strcasecmp(cmd, "help")) {
+                help();
+            } else if(!strcasecmp(cmd, "q")) {
+                err = mbtk_tcpip_net_close();
+                if(err == MBTK_TCPIP_ERR_SUCCESS) {
+                    printf("Net close success.\n");
+                } else {
+                    printf("Net close fail:%d\n", err);
+                }
+                break;
+            } else {
+                printf("\n");
+            }
+        }
+    }
+
+    LOGD("Client exec complete.");
+#if 1
+    while(1)
+    {
+        sleep(1000 * 365 * 24 * 60 * 60);
+    }
+#else
+    sleep(1);
+#endif
+    return 0;
+}
+