blob: fadb1a690ee448d1b750ee02673c910898138845 [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, 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;
}
void mbtk_tcpip_lib_info_print()
{
MBTK_SOURCE_INFO_PRINT("mbtk_tcpip_lib");
}