Files
kunlun/common/socket/iot_socket_api.c
2024-09-28 14:24:04 +08:00

977 lines
26 KiB
C
Executable File

/****************************************************************************
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
be copied by any method or incorporated into another program without
the express written consent of Aerospace C.Power. This Information or any portion
thereof remains the property of Aerospace C.Power. The Information contained herein
is believed to be accurate and Aerospace C.Power assumes no responsibility or
liability for its use in any way and conveys no license or title under
any patent or copyright and makes no representation or warranty that this
Information is free from patent or copyright infringement.
****************************************************************************/
/* os_shim header files */
#include "os_types_api.h"
#include "os_event_api.h"
/* lwip header files */
#include "posix/sys/socket.h"
/* iot header files */
#include "iot_config.h"
#include "iot_task_api.h"
#include "iot_utils_api.h"
#include "iot_errno_api.h"
#include "iot_socket_api.h"
#include "iot_mem_pool_api.h"
#if IOT_LWIP_SUPPORT
#define IOT_SOCKET_MSG_POOL_SIZE 16
#define IOT_SOCKET_RECV_BUF_LEN 1024
#define IOT_SOCKET_SYNC_IP "127.0.0.1"
#define IOT_SOCKET_SYNC_UDP_PORT 44444
#define IOT_SOCKET_MAX_CNT 12
/* event for socket task to handle */
#define IOT_SOCKET_MSG_TYPE_CREATE_SOCK 1
#define IOT_SOCKET_MSG_TYPE_DELETE_SOCK 2
/* data send to sync_socket. */
const static uint8_t sync_data[] = {0xFA, 0xFB, 0xFC, 0xFD};
typedef struct _iot_socket_op_arg {
/* address to be bind with the new created socket.
* as address for ipv4 and ipv6 share the same buffer,
* we can always use ipv4 address to refer to this buffer.
*/
union {
struct sockaddr_in ipv4_addr;
#if LWIP_IPV6
struct sockaddr_in6 ipv6_addr;
#endif
} addr;
/* type of the socket to be create, see IOT_SOCKET_TYPE_XXX */
uint8_t sock_type;
/* callback function for the socket. */
iot_socket_cb_func_t func;
/* required headroom for received data of iot_socket_cb_func_t. */
uint8_t headroom;
/* socket to operate on. */
int32_t socket;
/* result of the operation. see ERR_XXX */
uint32_t result;
} iot_socket_op_arg_t;
/* socket task message */
typedef struct _iot_socket_msg {
/* iot task message */
iot_task_msg_t task_msg;
void *arg_ptr;
} iot_socket_msg_t;
typedef struct _iot_socket_entry {
/* socket handle. */
int32_t socket;
/* callback function for the socket, shall not be NULL for valid entry. */
iot_socket_cb_func_t func;
/* socket of the socket, see IOT_SOCKET_TYPE_XXX for detail. */
uint8_t sock_type;
/* domain of the socket, AF_NET for ipv4, AF_NET6 for ipv6. */
uint8_t domain;
/* required headroom for received data of iot_socket_cb_func_t. */
uint8_t headroom;
} iot_socket_entry_t;
typedef struct _iot_socket_global {
/* address for sync socket. */
struct sockaddr_in sync_addr;
/* pointer to socket task message queues */
iot_msg_queue_t msg_q;
/* socket task messages pool */
iot_mem_pool_t *msg_p;
/* socket and its callback method */
iot_socket_entry_t sock_entry[IOT_SOCKET_MAX_CNT];
/* socket used for sync */
int32_t sync_socket;
/* event for sync. only one task can create/delete socket at any time. */
os_event_h sock_evt;
/* event for sync. make async operation looks like sync operation. */
os_event_h sock_op_done;
/* socket task handle. */
iot_task_h task_h;
} iot_socket_global_t;
iot_socket_global_t *p_socket_glb = NULL;
static inline uint32_t iot_socket_is_ipv6_enabled()
{
uint32_t ipv6_enabled = 0;
#if LWIP_IPV6
ipv6_enabled = 1;
#endif
return ipv6_enabled;
}
static inline uint32_t iot_socket_is_valid_domain(int32_t domain)
{
if (domain == AF_INET) {
return 1;
}
if (domain == AF_INET6 && iot_socket_is_ipv6_enabled()) {
return 1;
}
return 0;
}
static inline uint32_t iot_socket_set_addr(struct sockaddr_in *addr,
uint8_t domain, const char* ip, uint16_t port)
{
struct sockaddr_in6 *addr_v6;
if (domain == AF_INET) {
if (ip == NULL) {
ip4_addr_set_any((ip4_addr_t*)&addr->sin_addr.s_addr);
} else {
addr->sin_addr.s_addr = inet_addr(ip);
if (IPADDR_NONE == addr->sin_addr.s_addr) {
/* invalid ip address. */
return ERR_INVAL;
}
}
addr->sin_family = AF_INET;
addr->sin_port = htons(port);
addr->sin_len = sizeof(struct sockaddr_in);
return ERR_OK;
} else if (domain == AF_INET6) {
#if LWIP_IPV6
addr_v6 = (struct sockaddr_in6 *)addr;
if (ip == NULL) {
ip6_addr_set_any((ip6_addr_t*)&addr_v6->sin6_addr);
} else {
if (!ip6addr_aton(ip, (ip6_addr_t*)&addr_v6->sin6_addr)) {
/* invalid ip address. */
return ERR_INVAL;
}
}
addr_v6->sin6_family = AF_INET6;
addr_v6->sin6_port = htons(port);
addr_v6->sin6_len = sizeof(struct sockaddr_in6);
return ERR_OK;
#else
(void)addr_v6;
(void)addr;
(void)domain;
(void)ip;
(void)port;
return ERR_NOSUPP;
#endif
} else {
return ERR_INVAL;
}
}
/*
* @brief: add a socket to local socket list
* @param socket: the socket to be added.
* @param sock_type: type of the socket. see IOT_SOCKET_TYPE_XXX.
* @param domain: domain of the socket, AF_NET or AF_INET6.
* @param func: callback function to be called when data/event
* arrival on this socket.
* @param pkt_headroom: required headroom for received data of
* iot_socket_cb_func_t.
* @return: ERR_OK for succeed case, other ERR_XXX for failed case.
*/
static uint32_t iot_socket_add_sock_entry(int32_t socket, uint8_t sock_type,
uint8_t domain, iot_socket_cb_func_t func, uint8_t pkt_headroom)
{
uint32_t i;
iot_socket_entry_t *free_entry = NULL;
if (func == NULL) {
return ERR_INVAL;
}
if (!iot_socket_is_valid_domain(domain)) {
return ERR_INVAL;
}
for (i = 0; i < IOT_SOCKET_MAX_CNT; ++i) {
if (free_entry == NULL && p_socket_glb->sock_entry[i].func == NULL) {
/* find a free entry. */
free_entry = &p_socket_glb->sock_entry[i];
}
/* if find the socket entry, update it's callback function. */
if (p_socket_glb->sock_entry[i].func &&
p_socket_glb->sock_entry[i].socket == socket) {
p_socket_glb->sock_entry[i].func = func;
p_socket_glb->sock_entry[i].sock_type = sock_type;
p_socket_glb->sock_entry[i].domain = domain;
p_socket_glb->sock_entry[i].headroom = pkt_headroom;
return ERR_OK;
}
}
if (free_entry) {
free_entry->func = func;
free_entry->socket = socket;
free_entry->sock_type = sock_type;
free_entry->domain = domain;
free_entry->headroom = pkt_headroom;
return ERR_OK;
}
/* failed, no free entry. */
return ERR_FAIL;
}
static iot_socket_entry_t* iot_socket_get_sock_entry(int32_t socket)
{
uint32_t i;
for (i = 0; i < IOT_SOCKET_MAX_CNT; ++i) {
/* if find the socket entry, update it's callback function */
if (p_socket_glb->sock_entry[i].func &&
p_socket_glb->sock_entry[i].socket == socket) {
return &p_socket_glb->sock_entry[i];
}
}
return NULL;
}
static void iot_socket_rm_all_sock_entry()
{
uint32_t i;
for (i = 0; i < IOT_SOCKET_MAX_CNT; ++i) {
/* if find the socket entry, update it's callback function */
if (p_socket_glb->sock_entry[i].func) {
p_socket_glb->sock_entry[i].func = NULL;
p_socket_glb->sock_entry[i].socket = 0;
}
}
}
static void iot_socket_rm_sock_entry(int32_t socket)
{
iot_socket_entry_t* sock_entry;
sock_entry = iot_socket_get_sock_entry(socket);
if (sock_entry) {
/* if find the socket entry, update it's callback function */
sock_entry->func = NULL;
sock_entry->socket = 0;
sock_entry->sock_type = 0;
sock_entry->domain = 0;
}
}
static iot_socket_cb_func_t iot_socket_get_cb(int32_t socket)
{
iot_socket_entry_t *sock_entry = iot_socket_get_sock_entry(socket);
if (sock_entry) {
return sock_entry->func;
}
return NULL;
}
static uint8_t iot_socket_get_msg_hdr_len(int32_t socket)
{
iot_socket_entry_t *sock_entry = iot_socket_get_sock_entry(socket);
if (sock_entry) {
return sock_entry->headroom;
}
return 0;
}
static void iot_socket_invoke_cb(int32_t socket, uint32_t cb_type,
iot_pkt_t *pkt)
{
iot_socket_cb_func_t cb = iot_socket_get_cb(socket);
if (cb) {
cb(cb_type, socket, pkt);
} else {
iot_pkt_free(pkt);
}
}
/*
* @brief: alloc a message from socket task's msg pool
* @return: socket message. NULL if failed to allocate a message.
*/
iot_socket_msg_t *iot_socket_task_alloc_msg()
{
iot_task_msg_t *msg;
msg = iot_mem_pool_alloc_with_reserve(p_socket_glb->msg_p, 0);
if (msg) {
iot_msg_entry_init(&msg->link);
}
return (iot_socket_msg_t*)msg;
}
/*
* @brief: free a msg to socket task's msg pool
* @param socket_msg: socket message to be freed.
*/
void iot_socket_task_free_msg(iot_socket_msg_t *socket_msg)
{
iot_task_msg_t *msg = (iot_task_msg_t *)&socket_msg->task_msg;
iot_mem_pool_free(p_socket_glb->msg_p, msg);
}
/*
* @brief: send data to sync socket to notify socket task
* that there is msg in queue and shall be processed.
*/
static void iot_socket_task_notify()
{
/* send a udp packet to signal socket. */
sendto(p_socket_glb->sync_socket, sync_data, sizeof(sync_data), 0,
(const struct sockaddr *)&p_socket_glb->sync_addr,
sizeof(p_socket_glb->sync_addr));
}
/*
* @brief: put a msg into msg queue and notify socket task.
* it returns when socket task finish operation.
* @param sock_msg: msg to be put into queue of socket task.
*/
static void iot_socket_task_put_msg_sync(iot_socket_msg_t *sock_msg)
{
iot_task_msg_t *msg = &sock_msg->task_msg;
os_wait_event(p_socket_glb->sock_evt, MAX_TIME);
iot_msg_queue_put(&p_socket_glb->msg_q, &msg->link);
iot_socket_task_notify();
/* wait until the operation finished.
* make async operation looks like sync operation.
*/
os_wait_event(p_socket_glb->sock_op_done, MAX_TIME);
os_set_event(p_socket_glb->sock_evt);
}
/*
* @brief: get a msg from msg pool of socket task.
* @return: msg from msg queue of socket task, NULL if failed..
*/
static iot_socket_msg_t* iot_socket_task_get_msg()
{
iot_task_msg_t *msg = NULL;
iot_msg_entry_t *entry = iot_msg_queue_get(&p_socket_glb->msg_q);
if (entry) {
msg = container_of(entry, iot_task_msg_t, link);
}
return (iot_socket_msg_t*)msg;
}
static void iot_socket_create_internal(iot_socket_msg_t *msg)
{
int32_t ret;
int32_t sock;
uint8_t domain;
uint32_t proto_type;
uint8_t socket_type;
iot_socket_op_arg_t *p_arg = (iot_socket_op_arg_t *)msg->arg_ptr;
if (p_arg == NULL) {
return;
}
socket_type = p_arg->sock_type;
if (socket_type == IOT_SOCKET_TYPE_UDP) {
proto_type = SOCK_DGRAM;
} else {
/* unsupported socket type. */
p_arg->socket = -1;
p_arg->result = ERR_INVAL;
return;
}
domain = p_arg->addr.ipv4_addr.sin_family;
sock = socket(domain, proto_type, 0);
ret = bind(sock, (struct sockaddr*)&p_arg->addr.ipv4_addr,
p_arg->addr.ipv4_addr.sin_len);
if (ret) {
/* failed to bind the socket */
closesocket(sock);
p_arg->socket = -1;
p_arg->result = ERR_FAIL;
return;
}
switch (proto_type) {
case SOCK_DGRAM:
{
p_arg->socket = sock;
p_arg->result = ERR_OK;
iot_socket_add_sock_entry(sock, socket_type, domain, p_arg->func,
p_arg->headroom);
break;
}
case SOCK_STREAM:
default:
p_arg->socket = -1;
p_arg->result = ERR_NOSUPP;
break;
}
}
static void iot_socket_delete_internal(iot_socket_msg_t *msg)
{
int32_t sock;
iot_socket_entry_t *sock_entry;
iot_socket_op_arg_t *p_arg = (iot_socket_op_arg_t *)msg->arg_ptr;
if (p_arg == NULL) {
return;
}
sock = p_arg->socket;
if (sock <= 0) {
/* socket 0 is for internal use. it cannot be deleted.
* socket less than 0 is invalid.
*/
return;
}
sock_entry = iot_socket_get_sock_entry(sock);
if (sock_entry == NULL) {
return;
}
switch (sock_entry->sock_type) {
case IOT_SOCKET_TYPE_UDP:
{
closesocket(sock);
iot_socket_rm_sock_entry(sock);
break;
}
default:
/* api shall reject unsupported operation.
* codes shall not reach here.
*/
IOT_ASSERT(0);
break;
}
}
/*
* @brief: message handler method. It always frees the msg.
* @param msg: message to be handled.
*/
static void iot_socket_msg_handler(iot_socket_msg_t *msg)
{
if (msg == NULL) {
return;
}
switch (msg->task_msg.type) {
case IOT_SOCKET_MSG_TYPE_CREATE_SOCK:
{
iot_socket_create_internal(msg);
os_set_event(p_socket_glb->sock_op_done);
break;
}
case IOT_SOCKET_MSG_TYPE_DELETE_SOCK:
{
iot_socket_delete_internal(msg);
os_set_event(p_socket_glb->sock_op_done);
break;
}
default:
break;
}
iot_socket_task_free_msg(msg);
}
/*
* @brief: get fd object from current socket list.
* @param set: output parameter for fd_set object
* @return: max socket handle in fd_set, -1 for failed case.
*/
static int32_t iot_socket_get_fd(fd_set *set)
{
uint32_t i;
int32_t max_fd = -1;
/* clear the fd_set object. */
os_mem_set(set, 0, sizeof(*set));
for (i = 0; i < IOT_SOCKET_MAX_CNT; ++i) {
if (p_socket_glb->sock_entry[i].func) {
if (p_socket_glb->sock_entry[i].socket > max_fd) {
max_fd = p_socket_glb->sock_entry[i].socket;
}
FD_SET(p_socket_glb->sock_entry[i].socket, set);
}
}
return max_fd;
}
/*
* @brief: task function for socket task.
* it use a socket as a event for synchronization.
* when recv data from sync socket, it takes a msg from task
* msg queue and handle it. when recv data from other socket,
* it call corresponding callback function.
* @arg: argument for the task func
*/
static void iot_socket_task_func(void* arg)
{
int32_t i;
int32_t result;
int32_t max_fd;
int32_t pending_data_len = 0;
uint8_t pkt_headroom = 0;
fd_set fd;
iot_pkt_t *pkt;
iot_printf("%s - %p\n", __FUNCTION__, arg);
while (1) {
max_fd = iot_socket_get_fd(&fd);
result = select(max_fd + 1, &fd, NULL, NULL, NULL);
if (result < 0) {
/* error happened */
continue;
}
for (i = 0; i <= max_fd; i++) {
if (!FD_ISSET(i, &fd)) {
continue;
}
if (ioctlsocket(i, FIONREAD, &pending_data_len)) {
/* for ioctlsocket to work on lwip, LWIP_FIONREAD_LINUXMODE
* shall be set to 1 to enable Linux style ioctl/FIONREAD.
* Linux style ioctl/FIONREAD return length next pending data.
* Windows style ioctl/FIONREAD return length of all pending
* data, which shall NOT be used here.
*/
IOT_ASSERT(0);
}
if (pending_data_len == 0) {
pending_data_len = 1;
}
pkt_headroom = iot_socket_get_msg_hdr_len(i);
pkt = iot_pkt_alloc(pending_data_len + pkt_headroom,
IOT_SOCKET_MID);
IOT_ASSERT(pkt);
iot_pkt_reserve(pkt, pkt_headroom);
result = recv(i, iot_pkt_data(pkt),
iot_pkt_tail_len(pkt) - pkt_headroom, 0);
iot_pkt_put(pkt, result);
iot_socket_invoke_cb(i, IOT_SOCKET_CB_DATA_RECV, pkt);
}
}
}
/*
* @brief: callback method for sync socket
* @param cb_type: type of event that trigger the callback
* @param socket: the socket on which event occur
* @param data_pkt: pkt contains data for the callback.
* this method shall free data_pkt.
*/
static void iot_sg_sync_socket_cb(uint32_t cb_type, int32_t socket,
iot_pkt_t* data_pkt)
{
uint8_t *ptr;
iot_socket_msg_t *msg;
if (cb_type != IOT_SOCKET_CB_DATA_RECV) {
return;
}
if (socket != p_socket_glb->sync_socket) {
return;
}
if (data_pkt == NULL) {
return;
}
ptr = iot_pkt_data(data_pkt);
if (iot_pkt_data_len(data_pkt) == sizeof(sync_data) &&
os_mem_cmp(ptr, sync_data, sizeof(sync_data)) == 0) {
/* receives data from sync socket and pattern matches. */
msg = iot_socket_task_get_msg();
iot_socket_msg_handler(msg);
}
iot_pkt_free(data_pkt);
}
uint32_t iot_socket_task_init()
{
int32_t ret;
uint8_t socket_created = 0;
uint8_t msg_q_created = 0;
if (p_socket_glb == NULL) {
p_socket_glb = os_mem_malloc(IOT_SOCKET_MID, sizeof(*p_socket_glb));
if (p_socket_glb == NULL) {
goto err_label;
}
}
if (p_socket_glb->task_h) {
/* don't create again. */
return ERR_OK;
}
/* event for synchronization, it's set by default. */
p_socket_glb->sock_evt = os_create_event(IOT_SMART_GRID_MID, 1);
if (p_socket_glb->sock_evt == 0) {
goto err_label;
}
p_socket_glb->sock_op_done = os_create_event(IOT_SMART_GRID_MID, 0);
if (p_socket_glb->sock_op_done == 0) {
goto err_label;
}
p_socket_glb->sync_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (p_socket_glb->sync_socket >= 0) {
socket_created = 1;
} else {
/* create socket failed. close the socket. */
goto err_label;
}
/* init local address for sync. */
iot_socket_set_addr(&p_socket_glb->sync_addr, AF_INET,
IOT_SOCKET_SYNC_IP, IOT_SOCKET_SYNC_UDP_PORT);
/* bind socket with local ipv4 address. */
ret = bind(p_socket_glb->sync_socket,
(const struct sockaddr*)&p_socket_glb->sync_addr,
sizeof(p_socket_glb->sync_addr));
iot_printf("bind socket, ret = %d\n", ret);
if (ret) {
/* bind failed. close the socket. */
goto err_label;
}
ret = iot_mem_pool_new(IOT_SOCKET_MID, IOT_SOCKET_MSG_POOL_SIZE,
sizeof(iot_socket_msg_t), &p_socket_glb->msg_p, 1);
if (ret != ERR_OK) {
goto err_label;
}
msg_q_created = 1;
ret = iot_msg_queue_init(&p_socket_glb->msg_q);
if (ret != ERR_OK) {
goto err_label;
}
iot_socket_add_sock_entry(p_socket_glb->sync_socket,
IOT_SOCKET_TYPE_UDP, AF_INET, iot_sg_sync_socket_cb, 0);
p_socket_glb->task_h = os_create_task(iot_socket_task_func,
p_socket_glb, IOT_SOCKET_TASK_PRIO);
if (p_socket_glb->task_h == 0) {
goto err_label;
}
iot_printf("%s: socket_task = 0x%08X\n",
__FUNCTION__, p_socket_glb->task_h);
return ERR_OK;
err_label:
if (p_socket_glb->sock_evt) {
os_delete_event(p_socket_glb->sock_evt);
p_socket_glb->sock_evt = 0;
}
if (p_socket_glb->sock_op_done) {
os_delete_event(p_socket_glb->sock_op_done);
p_socket_glb->sock_op_done = 0;
}
if (p_socket_glb->task_h) {
os_delete_task(p_socket_glb->task_h);
p_socket_glb->task_h = 0;
}
if (socket_created) {
closesocket(p_socket_glb->sync_socket);
}
if (p_socket_glb->msg_p) {
iot_mem_pool_destroy(p_socket_glb->msg_p);
}
if (msg_q_created) {
iot_msg_queue_deinit(&p_socket_glb->msg_q);
}
iot_socket_rm_all_sock_entry();
if (p_socket_glb) {
os_mem_free(p_socket_glb);
p_socket_glb = NULL;
}
/* failed to create socket task. */
return ERR_FAIL;
}
void iot_socket_task_deinit()
{
if (p_socket_glb == NULL) {
/* task was not initialized yet. */
return;
}
if (p_socket_glb->task_h) {
os_delete_task(p_socket_glb->task_h);
p_socket_glb->task_h = 0;
}
if (p_socket_glb->sock_evt) {
os_delete_event(p_socket_glb->sock_evt);
p_socket_glb->sock_evt = 0;
}
if (p_socket_glb->sock_op_done) {
os_delete_event(p_socket_glb->sock_op_done);
p_socket_glb->sock_op_done = 0;
}
closesocket(p_socket_glb->sync_socket);
p_socket_glb->sync_socket = 0;
iot_msg_queue_deinit(&p_socket_glb->msg_q);
if (p_socket_glb->msg_p) {
iot_mem_pool_destroy(p_socket_glb->msg_p);
p_socket_glb->msg_p = NULL;
}
iot_socket_rm_all_sock_entry();
os_mem_free(p_socket_glb);
p_socket_glb = NULL;
}
static inline uint32_t iot_socket_create_arg_validate(uint32_t socket_type,
uint32_t is_ipv6, iot_socket_cb_func_t recv_cb, int32_t *ret_sock)
{
int32_t result = ERR_OK;
uint32_t valid_sock_type;
if (recv_cb == NULL || ret_sock == NULL) {
/* invalid arguments. */
result = ERR_INVAL;
goto exit_label;
}
if (iot_socket_is_ipv6_enabled() == 0 && is_ipv6) {
/* ipv6 is not supported */
result = ERR_NOSUPP;
goto exit_label;
}
switch (socket_type) {
case IOT_SOCKET_TYPE_UDP:
{
valid_sock_type = 1;
break;
}
default:
valid_sock_type = 0;
break;
}
if (valid_sock_type == 0) {
result = ERR_INVAL;
goto exit_label;
}
exit_label:
return result;
}
uint32_t iot_socket_create(uint8_t socket_type, uint8_t is_ipv6,
const char *ip, uint16_t port, iot_socket_cb_func_t recv_cb,
uint8_t pkt_headroom, int32_t *ret_sock)
{
iot_socket_msg_t *msg;
int32_t result = ERR_OK;
uint8_t domain = AF_INET;
iot_socket_op_arg_t create_arg = {0};
if (p_socket_glb == NULL) {
iot_printf("%s - error. socket not start yet.\n", __FUNCTION__);
result = ERR_NOT_READY;
goto exit_label;
}
if (iot_socket_create_arg_validate(socket_type, is_ipv6,
recv_cb, ret_sock)) {
/* invalid arguments. */
result = ERR_INVAL;
goto exit_label;
}
msg = iot_socket_task_alloc_msg();
if (msg == NULL) {
result = ERR_NOMEM;
goto exit_label;
}
if (is_ipv6) {
domain = AF_INET6;
}
msg->task_msg.type = IOT_SOCKET_MSG_TYPE_CREATE_SOCK;
msg->task_msg.id = 0;
msg->arg_ptr = (void*)&create_arg;
create_arg.func = recv_cb;
create_arg.sock_type = socket_type;
create_arg.headroom = pkt_headroom;
if (ERR_OK != iot_socket_set_addr(&create_arg.addr.ipv4_addr,
domain, ip, port)) {
iot_socket_task_free_msg(msg);
result = ERR_INVAL;
goto exit_label;
}
iot_socket_task_put_msg_sync(msg);
*ret_sock = create_arg.socket;
result = create_arg.result;
if (*ret_sock < 0) {
result = ERR_FAIL;
}
exit_label:
iot_printf("%s - %d, reason = %lu\n", __FUNCTION__, *ret_sock, result);
return result;
}
void iot_socket_delete(int32_t socket)
{
int32_t result = ERR_OK;
iot_socket_op_arg_t delete_arg = {0};
iot_socket_msg_t *msg;
if (p_socket_glb == NULL) {
iot_printf("%s - error. socket not start yet.\n", __FUNCTION__);
result = ERR_NOT_READY;
goto exit_label;
}
if (socket <= 0) {
/* socket 0 is for internal use. it shall not be deleted.
* socket less than 0 is invalid.
*/
result = ERR_INVAL;
goto exit_label;
}
msg = iot_socket_task_alloc_msg();
if (msg == NULL) {
result = ERR_NOMEM;
goto exit_label;
}
msg->task_msg.type = IOT_SOCKET_MSG_TYPE_DELETE_SOCK;
msg->task_msg.id = 0;
msg->arg_ptr = (void*)&delete_arg;
delete_arg.socket = socket;
iot_socket_task_put_msg_sync(msg);
exit_label:
iot_printf("%s - result = %lu.\n", __FUNCTION__, result);
return;
}
uint32_t iot_socket_udp_send(int32_t socket, uint8_t *data,
uint32_t data_len, uint32_t is_ipv6, const char *ip, uint16_t port)
{
uint32_t result = ERR_OK;
struct sockaddr_storage sock_addr_obj = {0};
struct sockaddr_in *sock_addr = (struct sockaddr_in*)&sock_addr_obj;
int32_t send_ret;
uint8_t domain;
if (p_socket_glb == NULL) {
iot_printf("%s - error. socket not start yet.\n", __FUNCTION__);
result = ERR_NOT_READY;
goto exit_label;
}
if (data == NULL || data_len == 0) {
result = ERR_INVAL;
goto exit_label;
}
domain = AF_INET;
if (is_ipv6) {
domain = AF_INET6;
}
if (iot_socket_set_addr(sock_addr, domain, ip, port)) {
result = ERR_INVAL;
goto exit_label;
}
send_ret = sendto(socket, data, data_len, 0,
(const struct sockaddr*)sock_addr, sock_addr->sin_len);
iot_printf("%s: len = %d, send ret = %d\n",
__FUNCTION__, data_len, send_ret);
exit_label:
return result;
}
#else /* IOT_LWIP_SUPPORT */
uint32_t iot_socket_task_init()
{
return ERR_NOSUPP;
}
void iot_socket_task_deinit()
{
}
uint32_t iot_socket_create(uint8_t socket_type, uint8_t is_ipv6,
const char *ip, uint16_t port, iot_socket_cb_func_t recv_cb,
uint8_t pkt_headroom, int32_t *ret_sock)
{
(void)socket_type;
(void)is_ipv6;
(void)ip;
(void)port;
(void)recv_cb;
(void)pkt_headroom;
(void)ret_sock;
return ERR_NOSUPP;
}
void iot_socket_delete(int32_t socket)
{
(void)socket;
}
uint32_t iot_socket_udp_send(int32_t socket, uint8_t *data, uint32_t len,
uint32_t is_ipv6, const char *ip, uint16_t port)
{
(void)socket;
(void)data;
(void)len;
(void)is_ipv6;
(void)ip;
(void)port;
return ERR_NOSUPP;
}
#endif /* IOT_LWIP_SUPPORT */