263 lines
7.4 KiB
C
Executable File
263 lines
7.4 KiB
C
Executable File
/*************************************************
|
|
File name : pal_tcpclient.h
|
|
Module :
|
|
Author : amir
|
|
Version : 0.1
|
|
Created on : 2022-02-07
|
|
Description :
|
|
Data structure and function definitions required by the socket interface
|
|
|
|
Modify History:
|
|
1. Date: Author: Modification:
|
|
*************************************************/
|
|
|
|
#include "hthread.h"
|
|
#include "mw_tcpclient.h"
|
|
#include "hlog.h"
|
|
#include "hbase.h"
|
|
#include "hsocket.h"
|
|
#include "hloop.h"
|
|
#include "hevent.h"
|
|
|
|
#define dump_addr(io){\
|
|
char localaddrstr[SOCKADDR_STRLEN] = {0};\
|
|
char peeraddrstr[SOCKADDR_STRLEN] = {0};\
|
|
SOCKADDR_STR(io->localaddr, localaddrstr);\
|
|
SOCKADDR_STR(io->peeraddr, peeraddrstr);\
|
|
hlogw("%s %s,%s\n", __func__, localaddrstr, peeraddrstr);}
|
|
|
|
|
|
static void on_close(hio_t* io) {
|
|
tcpclient *tclient = io->loop->userdata;
|
|
if (tclient->hio == io){
|
|
tclient->hio = NULL;
|
|
}
|
|
dump_addr(io);
|
|
}
|
|
|
|
static void on_recv(hio_t* io, void* buf, int readbytes) {
|
|
tcpclient *tclient = io->loop->userdata;
|
|
iobuffer_appendData(&tclient->read_iobuf, buf, readbytes);
|
|
tclient->handler.on_unpacket(tclient, &tclient->read_iobuf);
|
|
}
|
|
|
|
static void on_connect(hio_t* io) {
|
|
tcpclient *tclient = io->loop->userdata;
|
|
if (tclient->hio) { /*最快的已连接上了, 关闭后面的*/
|
|
hio_close(io);
|
|
return;
|
|
}
|
|
dump_addr(io);
|
|
tclient->hio = io;
|
|
hio_setcb_read(io, on_recv);
|
|
hio_read_start(io);
|
|
TLV tlv = {.T = CONN_CONNECTED};
|
|
tclient->handler.on_packet(tclient, &tlv);
|
|
}
|
|
|
|
void tcpclient_conn(tcpclient *tclient, const char *domain_or_ip, const int port) {
|
|
hio_t* io = hio_create_socket(tclient->loop, domain_or_ip, port, HIO_TYPE_TCP, HIO_CLIENT_SIDE);
|
|
if (io == NULL) {
|
|
perror("socket");
|
|
exit(1);
|
|
}
|
|
dump_addr(io);
|
|
tcp_nodelay(hio_fd(io), 1);
|
|
hio_setcb_connect(io, on_connect);
|
|
hio_setcb_close(io, on_close);
|
|
hio_connect(io);
|
|
TLV tlv = {.T = CONN_STARTED};
|
|
tclient->handler.on_packet(tclient, &tlv);
|
|
|
|
}
|
|
|
|
int32_t tcpclient_send(tcpclient *tclient, const char *data, const uint32_t sz){
|
|
char out_data[MAX_PATH];
|
|
uint32_t cnt = tclient->handler.on_pack(out_data, sizeof(out_data), data, sz);
|
|
if ( cnt > 0 ){
|
|
if (tclient->status != 'E'){
|
|
hlogd(">>> %s size:%u", __func__, cnt);
|
|
hio_write(tclient->hio, out_data, cnt);
|
|
return OK;
|
|
}
|
|
}
|
|
return NG;
|
|
}
|
|
|
|
static void *tcpclient_tast(void *param)
|
|
{
|
|
tcpclient *tclient = (tcpclient *)param;
|
|
hloge("%s tcpclient:%p loop:%p\n",__func__, param, tclient->loop);
|
|
tclient->status = 'R';
|
|
while(tclient->status != 'E'){
|
|
hloop_run(tclient->loop);
|
|
}
|
|
hlogw("%s exit:%p\n",__func__, param);
|
|
//tclient->handler.on_funcpacket(tclient, CONN_DESTROY);
|
|
tclient->th = 0;
|
|
return(NULL);
|
|
}
|
|
|
|
tcpclient *tcpclient_init(int stack_size, packet_handler handler){
|
|
tcpclient *tclient = (tcpclient*)calloc(1, sizeof(tcpclient));
|
|
tclient->loop = hloop_new(0);
|
|
tclient->loop->userdata = tclient;
|
|
tclient->status = 'I';//idle
|
|
tclient->stack_size = stack_size;
|
|
tclient->handler = handler;
|
|
iobuffer_init(&tclient->read_iobuf);
|
|
tclient->th = hthread_create(tcpclient_tast, (void*)tclient);
|
|
return tclient;
|
|
}
|
|
|
|
int32_t tcpclient_deinit(tcpclient *tclient){
|
|
if (tclient)
|
|
{
|
|
tclient->status = 'E';
|
|
hloop_wakeup(tclient->loop);
|
|
hlogw("%s hloop_free\n",__func__);
|
|
hloop_free(&tclient->loop);
|
|
free(tclient);
|
|
return OK;
|
|
}
|
|
return NG;
|
|
}
|
|
|
|
|
|
|
|
/**********************应用层demo***********************/
|
|
|
|
#define DEMO_UART_JSON (1) /* 1. 为了测试string在串口工具显示, 实际要发收TLV*/
|
|
|
|
/* 应用层四步
|
|
**
|
|
** 一, 声明枚举指令 和 回调函数
|
|
** 二, 填写 packet_cmd_s 的 s_cmd_list
|
|
** 三, 发数on_pack, 收数on_unpacket后回调
|
|
**/
|
|
|
|
/* 第一步 */
|
|
typedef enum {
|
|
EV_LOGIN = 1000,//=>Server
|
|
}EV_CMD;
|
|
|
|
typedef struct{
|
|
EV_CMD cmd;
|
|
uint32_t (*on_cmd)(tcpclient *client, TLV *tlv);
|
|
}packet_cmd_s;
|
|
|
|
static uint32_t on_login(tcpclient *client, TLV *tlv){
|
|
hloge("%s tlv->T:%u L:%u V:%s", __func__, tlv->T, tlv->L, tlv->V);
|
|
return OK;
|
|
}
|
|
|
|
/* 第二步 */
|
|
static packet_cmd_s s_cmd_list[]={
|
|
{EV_LOGIN, on_login},
|
|
};
|
|
|
|
static int32_t on_packet(tcpclient *client, void *data){
|
|
json_pkt packet = {0};
|
|
char buf[MAX_PATH] = {0};
|
|
TLV *recv_tlv = (TLV *)data;
|
|
switch(recv_tlv->T){
|
|
case CONN_STARTED:
|
|
break;
|
|
case CONN_CONNECTING:
|
|
break;
|
|
case CONN_CONNECTED:
|
|
json_pkt_add_int(&packet, "cmd", EV_LOGIN);
|
|
json_pkt_add_str(&packet, "udid", "my_uuid_is_123456789");
|
|
json_pkt_add_str(&packet, "wakeup_type", "pir");
|
|
break;
|
|
case CONN_SECOND_TICK:
|
|
break;
|
|
case CONN_CLOSED:
|
|
break;
|
|
case CONN_DESTROY:
|
|
break;
|
|
default:
|
|
for ( uint16_t i=0; i< sizeof(s_cmd_list)/sizeof(s_cmd_list[0]); i++ ){
|
|
if ( s_cmd_list[i].cmd == recv_tlv->T ){
|
|
s_cmd_list[i].on_cmd(client, recv_tlv);
|
|
return OK;
|
|
}
|
|
}
|
|
hloge("unknown cmd:%u", recv_tlv->T);
|
|
break;
|
|
}
|
|
|
|
if (packet.json){
|
|
char *str = json_pkt_toJson_string(&packet);
|
|
uint32_t len = 0;
|
|
if (str && ( len = strlen(str)) > 0 && len + sizeof(TLV) < sizeof(buf)){
|
|
TLV *send_tlv =(TLV*)buf;
|
|
send_tlv->T = packet.cmd;
|
|
send_tlv->L = len;
|
|
memcpy(send_tlv->V, str, len);
|
|
tcpclient_send(client, (const char *)send_tlv, sizeof(TLV) + send_tlv->L);
|
|
free(str);
|
|
}else {
|
|
hloge("error json:%p, len:%u", str, len);
|
|
}
|
|
json_pkt_reset(&packet);
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
/* 第三步 */
|
|
int32_t on_pack(char *out_data, const uint32_t max_sz, const char *in_data, const uint32_t sz){
|
|
/* 1. 比如可以在这里对data进行加密 */
|
|
/* 2. in_data 是TLV */
|
|
uint32_t cnt = 0;
|
|
if ( sz < max_sz ){
|
|
#if DEMO_UART_JSON
|
|
TLV *tlv =(TLV*)in_data;
|
|
memcpy(out_data, tlv->V, tlv->L);
|
|
cnt = tlv->L;
|
|
#else
|
|
memcpy(out_data, in_data, sz);
|
|
cnt = sz;
|
|
#endif
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
int32_t on_unpacket(tcpclient *client, iobuffer *iobuf){ /*TLV*/
|
|
json_pkt packet = {0};
|
|
#if DEMO_UART_JSON
|
|
if (json_pkt_parse(&packet, iobuf->iodata, "cmd") ){
|
|
char buf[MAX_PATH] = {0};
|
|
TLV *recv_tlv = (TLV *)buf;
|
|
recv_tlv->T = packet.cmd;
|
|
recv_tlv->L = iobuf->size;
|
|
memcpy(recv_tlv->V, iobuf->iodata, iobuf->size);
|
|
on_packet(client, recv_tlv);
|
|
iobuffer_eraseall(iobuf);
|
|
}
|
|
#else
|
|
TLV *tlv =(TLV*)iobuf->iodata;
|
|
if (json_pkt_parse(&packet, tlv->V, "cmd") ){
|
|
iobuffer_erase(iobuf, 0, sizeof(TLV)+tlv->L);
|
|
on_packet(client, &packet);
|
|
}
|
|
#endif
|
|
|
|
if (packet.json){
|
|
json_pkt_deinit(&packet);
|
|
}else{
|
|
hloge("<< unpack error \\n cannot be found: %s", iobuf->iodata);
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
void tcpclient_test(){
|
|
packet_handler handler = {on_packet, on_unpacket, on_pack};
|
|
tcpclient *client = tcpclient_init(1024, handler);
|
|
tcpclient_conn(client, "192.168.1.98", 60000);
|
|
//tcpclient_conn(client, "192.168.1.238", 80);
|
|
//tcpclient_conn(client, "www.baidu.com", 80);
|
|
hv_sleep(3);
|
|
}
|
|
|