blob: 76dc526641b3ee968280b17833fbcfb288e61f11 [file] [log] [blame]
#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, 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()
{
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 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. 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;
}