283 lines
8.1 KiB
C
283 lines
8.1 KiB
C
#include "lwip/sockets.h"
|
|
#include "os_mem_api.h"
|
|
#include "os_task_api.h"
|
|
#include "httpd_socket_client.h"
|
|
|
|
/** The receive buffer size */
|
|
#define HTTP_CLIENT_BUFF_SIZE 1024
|
|
|
|
/** client task prio */
|
|
#define HTTP_CLIENT_TASK_PRIO 6
|
|
|
|
typedef struct _http_client_t {
|
|
iot_eth_config_t eth_cfg;
|
|
int32_t client_conn_fd;
|
|
os_task_h client_task_handle;
|
|
client_conn_state state;
|
|
int8_t client_recv_buff[HTTP_CLIENT_BUFF_SIZE];
|
|
http_client_recv_fn client_recv_func;
|
|
} http_client_t;
|
|
|
|
#define HTTP_CLIENT_SOCKET_ALLOC() (http_client_t *)os_mem_malloc \
|
|
(0, sizeof(http_client_t))
|
|
|
|
static http_client_t *g_http_client = NULL;
|
|
|
|
static void httpd_socket_client_task();
|
|
|
|
/**
|
|
* Initialize the client
|
|
*
|
|
* @return the return value of httpd_client_init
|
|
*/
|
|
int8_t httpd_client_init(iot_eth_config_t *cfg)
|
|
{
|
|
iot_cus_printf("http_client_init\n");
|
|
|
|
g_http_client = HTTP_CLIENT_SOCKET_ALLOC();
|
|
IOT_ASSERT(g_http_client);
|
|
os_mem_set(g_http_client, 0, sizeof(http_client_t));
|
|
|
|
g_http_client->state = CLIENT_CONN_IDLE;
|
|
g_http_client->eth_cfg = *cfg;
|
|
|
|
g_http_client->client_task_handle =
|
|
os_create_task(httpd_socket_client_task, NULL, HTTP_CLIENT_TASK_PRIO);
|
|
if (g_http_client->client_task_handle == NULL) {
|
|
g_http_client->client_conn_fd = -1;
|
|
iot_cus_printf("[err]task create failed\n");
|
|
return -1;
|
|
}
|
|
iot_cus_printf("client_task_handle creat success\n");
|
|
return 0;
|
|
}
|
|
|
|
uint32_t httpd_client_get_state(void)
|
|
{
|
|
if (g_http_client == NULL) {
|
|
iot_cus_printf("[err]can not find the connection\n");
|
|
return 0;
|
|
}
|
|
iot_cus_printf("httpd_client_get_state =%d\n", g_http_client->state);
|
|
return (uint32_t)g_http_client->state;
|
|
}
|
|
|
|
static void httpd_client_enable_connect_state_rpt(void)
|
|
{
|
|
g_http_client->state |= SOCKET_CONN_RPT_STATUS;
|
|
}
|
|
|
|
void httpd_client_disable_connect_state_rpt(void)
|
|
{
|
|
g_http_client->state &= ~SOCKET_CONN_RPT_STATUS;
|
|
}
|
|
|
|
/**
|
|
* set server addr
|
|
*
|
|
* @param server_ip: the ip of the server
|
|
* @param server_port: the port of the server
|
|
* @return the server addr valid
|
|
*/
|
|
int8_t httpd_client_set_server_addr(uint32_t server_ip, const uint16_t server_port)
|
|
{
|
|
if (server_ip == 0 ||server_port == 0) {
|
|
return -1;
|
|
}
|
|
if (server_ip != g_http_client->eth_cfg.server_ip ||
|
|
server_port != g_http_client->eth_cfg.port) {
|
|
if (g_http_client->state != CLIENT_CONN_IDLE) {
|
|
httpd_client_close();
|
|
}
|
|
g_http_client->eth_cfg.server_ip = server_ip;
|
|
g_http_client->eth_cfg.port = server_port;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* connect to server
|
|
*
|
|
* @param server_ip: the ip of the server
|
|
* @param server_port: the port of the server 8081
|
|
* @return the return value of gs_client_connect
|
|
*/
|
|
static int32_t httpd_client_connect(uint32_t server_ip, const uint16_t server_port)
|
|
{
|
|
int32_t ret = 0;
|
|
struct sockaddr_in ser_addr;
|
|
|
|
iot_cus_printf("http_client_connect: start server_ip=%x "
|
|
"server_port=%d\n", server_ip, server_port);
|
|
if ((server_ip == 0) || (server_port == 0)) {
|
|
ret = -128;
|
|
goto out;
|
|
}
|
|
|
|
g_http_client->state = CLIENT_CONN_CONNING;
|
|
ser_addr.sin_family= AF_INET;
|
|
ser_addr.sin_port = htons(server_port);
|
|
ser_addr.sin_addr.s_addr = server_ip;
|
|
|
|
//creat socket
|
|
if ((g_http_client->client_conn_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
|
ret = -129;
|
|
goto out;
|
|
}
|
|
|
|
if (connect(g_http_client->client_conn_fd, (struct sockaddr*)&ser_addr,
|
|
sizeof(struct sockaddr_in)) != ERR_OK){
|
|
ret = -130;
|
|
goto out;
|
|
}
|
|
g_http_client->state = CLIENT_CONN_CONNECTED;
|
|
httpd_client_enable_connect_state_rpt();
|
|
|
|
iot_cus_printf("[http]connect fd=%d success\n", g_http_client->client_conn_fd);
|
|
|
|
out:
|
|
if (ret < 0) {
|
|
iot_cus_printf("[err]connect failed ret=%d client_conn_fd=%d\n",
|
|
ret, g_http_client->client_conn_fd);
|
|
g_http_client->state = CLIENT_CONN_IDLE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Used to specify the function that should be called when a
|
|
* connection receives data.
|
|
*
|
|
* @param recv callback function to call when data is received
|
|
*/
|
|
int8_t httpd_client_register_recv(http_client_recv_fn recv)
|
|
{
|
|
if (recv != NULL) {
|
|
g_http_client->client_recv_func = recv;
|
|
return ERR_OK;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/** send data to tcp ,it should be called by app
|
|
*
|
|
* @param ptr Data to send
|
|
* @param length Length of data to send
|
|
* @return the return the send_bytes that have sent.
|
|
*/
|
|
int32_t httpd_client_send(const void* ptr, uint16_t length)
|
|
{
|
|
int32_t ret;
|
|
|
|
if ((ptr == NULL) || (length == 0)) {
|
|
iot_cus_printf("[err]param error, ptr=%p, length=%d\n",ptr, length);
|
|
ret = -128;
|
|
goto out;
|
|
} else if (g_http_client->state == CLIENT_CONN_IDLE) {
|
|
iot_cus_printf("[err]not connect server\n");
|
|
ret = -129;
|
|
goto out;
|
|
} else {
|
|
ret = send(g_http_client->client_conn_fd, ptr, length, 0);
|
|
iot_cus_printf("already send %d bytes\n", ret);
|
|
}
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/* close the connecting */
|
|
int32_t httpd_client_close()
|
|
{
|
|
int32_t ret = -1;
|
|
|
|
if (g_http_client->client_conn_fd >= 0) {
|
|
ret = lwip_close(g_http_client->client_conn_fd);
|
|
}
|
|
|
|
iot_cus_printf("httpd_client_close fd=%d ret=%d\n",
|
|
g_http_client->client_conn_fd, ret);
|
|
g_http_client->client_conn_fd = -1;
|
|
g_http_client->state = CLIENT_CONN_IDLE;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* the task processes the connection */
|
|
static void httpd_socket_client_task(void)
|
|
{
|
|
fd_set ser_fdset;
|
|
int32_t max_fd = 1;
|
|
struct timeval gs_time;
|
|
int32_t ret = -1;
|
|
|
|
iot_cus_printf("enter socket_client_task!\n");
|
|
IOT_ASSERT(g_http_client);
|
|
|
|
while(1) {
|
|
gs_time.tv_sec = 130; /* need large than heartbeat */
|
|
gs_time.tv_usec = 0;
|
|
// check connect
|
|
if (g_http_client->state == CLIENT_CONN_IDLE) {
|
|
if (g_http_client->eth_cfg.server_ip == 0 ||
|
|
g_http_client->eth_cfg.port == 0) {
|
|
os_delay(1000);
|
|
continue;
|
|
}
|
|
ret = httpd_client_connect(g_http_client->eth_cfg.server_ip,
|
|
g_http_client->eth_cfg.port);
|
|
if (ret < 0) {
|
|
httpd_client_close();
|
|
}
|
|
}
|
|
|
|
if (g_http_client->state != CLIENT_CONN_CONNECTED) {
|
|
os_delay(1000);
|
|
continue;
|
|
}
|
|
|
|
os_mem_set((void *)&ser_fdset, 0, sizeof(fd_set));
|
|
|
|
//add client fd
|
|
FD_SET(g_http_client->client_conn_fd, &ser_fdset);
|
|
if (max_fd < g_http_client->client_conn_fd) {
|
|
max_fd = g_http_client->client_conn_fd;
|
|
}
|
|
|
|
ret = select(max_fd + 1, &ser_fdset, NULL, NULL, &gs_time);
|
|
if (ret < 0) {
|
|
iot_cus_printf("select failure\n");
|
|
continue;
|
|
} else if (ret == 0) {
|
|
iot_cus_printf("time out!\n");
|
|
httpd_client_close();
|
|
continue;
|
|
} else {
|
|
//deal with the message
|
|
if (FD_ISSET(g_http_client->client_conn_fd, &ser_fdset)) {
|
|
int32_t byte_num;
|
|
os_mem_set(g_http_client->client_recv_buff, 0,
|
|
HTTP_CLIENT_BUFF_SIZE);
|
|
byte_num = recv(g_http_client->client_conn_fd,
|
|
g_http_client->client_recv_buff, HTTP_CLIENT_BUFF_SIZE, 0);
|
|
if (byte_num > 0) {
|
|
iot_cus_printf("message form client:%s, len=%d\n",
|
|
g_http_client->client_recv_buff, byte_num);
|
|
if (g_http_client->client_recv_func != NULL) {
|
|
g_http_client->client_recv_func(
|
|
(int8_t *)&(g_http_client->client_recv_buff),
|
|
byte_num);
|
|
} else {
|
|
httpd_client_send(g_http_client->client_recv_buff,
|
|
byte_num);
|
|
iot_cus_printf("need to register the recv func\n");
|
|
}
|
|
} else {
|
|
httpd_client_close();
|
|
iot_cus_printf("recv nothing!!!\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|