#include "socket_inet.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>

#include "os/os.h"
#include "list/slist.h"

#include "wifi.h"

#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_WRN
#define SYS_LOG_DOMAIN "SOCKET"
#define CONS_ABORT()
#include "sys_log.h"

#define _THREAD_PRIOR 21

/* port ------------------------------------------------------------------------------------------------------------*/

typedef struct
{
    struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
    uint16_t size;
    uint8_t data[0];
} __udp_rx_fifo_t;

static struct
{
    bool wifi_open_flag;
    os_mutex_t mutex_hdl;
    slist_t udp_list; // 已启动的 udp 的链，节点 &__port_data_t::start_node
    slist_t tcp_list; // 已启动的 tcp 的链，节点 &__port_data_t::start_node
} *p_cm;

typedef struct
{
    sb_data_port_t port;
    slist_t *p_status_list;   // 指向 &__port_data_t::bind_list, &__port_data_t::idle_list, &__port_data_t::recv_list, &__port_data_t::close_list
    slist_node_t status_node; // 链表 __port_tcp_t::p_status_list
    int client_sock;
    os_pipe_t rx_pipe;
    os_sem_t rx_sem;
    socket_server_bind_t local; // 绑定时的设置信息
} __port_tcp_t;

typedef struct
{
    sb_data_port_t port;           // 数据接口框架
    uint16_t listen_port;          // 监听的端口
    int sock;                      // 监听套接字
    os_thread_t thread_hdl_listen; // 监听服务线程
    slist_node_t start_node;       // 用于判断在何时启动或关闭 wifi 服务，链表 &p_cm->udp_list, &p_cm->tcp_list
    volatile bool unbind_flag;     // 置位时表示在监听线程中回收资源

    union
    {
        struct
        {
            os_fifo_t rx_fifo;                 // udp 接收缓存
            os_sem_t rx_sem;                   // 接收缓存读取后唤醒接收线程
            volatile int32_t rx_cnt;           // rx_fifo 已缓存的报文数据的总长度
            socket_server_bind_t local;        // 绑定时的设置信息
            struct sockaddr_storage dest_addr; // Large enough for both IPv4 or IPv6
        } udp;

        struct
        {
            slist_t bind_list;    // tcp 已绑定链
            slist_t idle_list;    // tcp 已设置启动的但未连接的空闲链
            slist_t recv_list;    // tcp 已连接的链
            slist_t close_list;   // 正在执行关闭数据接口
            os_sem_t idle_sem;    // 当 idle_list 被更新时释放信号
            uint16_t backlog_cnt; // tcp 已设置启动的连接计数
            uint16_t tcp_backlog; // 为此套接字维护的最大连接个数
            connect_cb connect;   // 连接状态通知
        } tcp;
    };

    __port_tcp_t *tcp_port;

} __port_data_t;

static int _port_udp_start(sb_data_port_t *port);
static int _port_udp_stop(sb_data_port_t *port);
static int _port_udp_write(sb_data_port_t *port, const void *data, uint32_t size);
static int _port_udp_read(sb_data_port_t *port, void *data, uint32_t size);
static bool _port_udp_is_started(sb_data_port_t *port);
static uint32_t _port_udp_get_rx_length(sb_data_port_t *port);

static int _port_tcp_start(sb_data_port_t *port);
static int _port_tcp_stop(sb_data_port_t *port);
static int _port_tcp_write(sb_data_port_t *port, const void *data, uint32_t size);
static int _port_tcp_read(sb_data_port_t *port, void *data, uint32_t size);
static bool _port_tcp_is_started(sb_data_port_t *port);
static uint32_t _port_tcp_get_rx_length(sb_data_port_t *port);

static sb_data_port_vtable_t const s_port_vtable_udp = {
    .start = _port_udp_start,
    .stop = _port_udp_stop,
    .write = _port_udp_write,
    .read = _port_udp_read,
    .is_started = _port_udp_is_started,
    .get_rx_length = _port_udp_get_rx_length,
};

static sb_data_port_vtable_t const s_port_vtable_tcp = {
    .start = _port_tcp_start,
    .stop = _port_tcp_stop,
    .write = _port_tcp_write,
    .read = _port_tcp_read,
    .is_started = _port_tcp_is_started,
    .get_rx_length = _port_tcp_get_rx_length,
};

static void _wifi_open(void);
static void _wifi_close(void);
static int _socket_init_udp(__port_data_t *port_data);
static int _socket_init_tcp(__port_data_t *port_data);
static void _socket_close(__port_data_t *port_data);
static int _do_tcp_recv_start(__port_tcp_t *tcp_port);
static void _do_tcp_recv_stop(__port_tcp_t *tcp_port);
static sb_data_port_t *_find_hdl_by_port(uint16_t listen_port);
static sb_data_port_t *_create_port_data(const sb_data_port_vtable_t *vtable, uint16_t listen_port);
static void _thread_handler_udp_listen(void *arg);
static void _thread_handler_tcp_listen(void *arg);
static void _thread_handler_tcp_recv(void *arg);

static int _port_udp_start(sb_data_port_t *port)
{
    os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);
    int ret = -1;

    __port_data_t *port_data = port->data;

    do
    {
        if (slist_is_pending(&port_data->start_node))
        {
            SYS_LOG_WRN("udp data port already started");
            break;
        }

        if (_find_hdl_by_port(port_data->listen_port))
        {
            SYS_LOG_WRN("The local listening port (%u) is already occupied", port_data->listen_port);
            break;
        }

        /* 打开 wifi */
        _wifi_open();

        /* 创建监听服务线程 */
        if (os_thread_create(&port_data->thread_hdl_listen,
                             "udp-listen",
                             _thread_handler_udp_listen,
                             port_data,
                             0x1000,
                             _THREAD_PRIOR) != OS_OK)
        {
            SYS_LOG_WRN("_thread_handler_udp_listen() create fail");
            break;
        }

        /* 插入已启动的 udp 的链 */
        slist_insert_tail(&p_cm->udp_list, &port_data->start_node);
        SYS_LOG_INF("success. stype: udp");

        /* 操作成功 */
        ret = 0;

    } while (0);

    if (ret != 0)
    {
        /* 关闭 wifi */
        _wifi_close();
    }

    os_mutex_unlock(&p_cm->mutex_hdl);

    return ret;
}

static int _port_udp_stop(sb_data_port_t *port)
{
    os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);

    __port_data_t *port_data = port->data;
    _socket_close(port_data);

    os_mutex_unlock(&p_cm->mutex_hdl);

    return 0;
}

static int _port_udp_write(sb_data_port_t *port, const void *data, uint32_t size)
{
    __port_data_t *port_data = port->data;
    int err = sendto(port_data->sock, data, size, 0, (struct sockaddr *)&port_data->udp.dest_addr, sizeof(port_data->udp.dest_addr));

    // char ip_str[INET6_ADDRSTRLEN]; // 兼容 IPv4 和 IPv6
    // uint16_t test = 0;
    // struct sockaddr_in *addr4 =(struct sockaddr_in *)&port_data->udp.dest_addr;
    // inet_ntop(AF_INET, &addr4->sin_addr, ip_str, sizeof(ip_str));
    // test = ntohs(addr4->sin_port);
    // SYS_LOG_WRN("IPv4: %s:%u\n", ip_str, test);

    if (err < 0)
    {
        SYS_LOG_WRN("Error occurred during sending: errno %d", errno);
        return err;
    }
    else
    {
        SYS_LOG_DBG("size: %d", size);
        return size;
    }
}

static int _port_udp_read(sb_data_port_t *port, void *data, uint32_t size)
{
    __port_data_t *port_data = port->data;
    if (os_fifo_q_is_valid(&port_data->udp.rx_fifo))
    {
        __udp_rx_fifo_t *fifo = os_fifo_take(&port_data->udp.rx_fifo, 0);
        if (fifo == NULL)
        {
            return 0;
        }
        else
        {
            if (size > fifo->size)
            {
                size = fifo->size;
            }
            if (data)
            {
                memcpy(data, fifo->data, size);
            }
            port_data->udp.dest_addr = fifo->source_addr;
            os_fifo_free(fifo);

            os_scheduler_suspend();
            port_data->udp.rx_cnt -= fifo->size;
            os_scheduler_resume();

            os_sem_release(&port_data->udp.rx_sem);
            return size;
        }
    }
    else
    {
        return -1;
    }
}

static bool _port_udp_is_started(sb_data_port_t *port)
{
    if (port == NULL)
    {
        return false;
    }

    __port_data_t *port_data = port->data;
    if (port_data == NULL)
    {
        return false;
    }

    return (bool)!!slist_is_pending(&port_data->start_node);
}

static uint32_t _port_udp_get_rx_length(sb_data_port_t *port)
{
    __port_data_t *port_data = port->data;
    if (os_fifo_q_is_valid(&port_data->udp.rx_fifo))
    {
        __udp_rx_fifo_t *fifo = os_fifo_peek_head(&port_data->udp.rx_fifo);
        if (fifo)
        {
            return fifo->size;
        }
    }
    return 0;
}

/**
 * @brief 打开一个 tcp 数据接口，如果
 *
 * @param port
 * @return int
 */
static int _port_tcp_start(sb_data_port_t *port)
{
    os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);
    int ret = -1;

    __port_data_t *port_data = port->data;
    __port_tcp_t *tcp_port = SLIST_CONTAINER_OF(port, __port_tcp_t, port);

    do
    {
        if (tcp_port->p_status_list != &port_data->tcp.bind_list)
        {
            SYS_LOG_WRN("tcp data port already started");
            break;
        }

        /* 打开 wifi */
        _wifi_open();

        if (_do_tcp_recv_start(tcp_port) != 0)
        {
            break;
        }

        /* 创建监听服务线程 */
        if (!os_thread_is_valid(&port_data->thread_hdl_listen))
        {
            if (_find_hdl_by_port(port_data->listen_port))
            {
                SYS_LOG_WRN("The local listening port (%u) is already occupied", port_data->listen_port);
                break;
            }

            /* 创建接收线程状态信号量 */
            if (os_sem_create(&port_data->tcp.idle_sem, 0, 1) != OS_OK) // 当 idle_list 被更新时释放信号
                break;

            if (os_thread_create(&port_data->thread_hdl_listen,
                                 "tcp-listen",
                                 _thread_handler_tcp_listen,
                                 port_data,
                                 2400,
                                 _THREAD_PRIOR) != OS_OK)
            {
                SYS_LOG_WRN("_thread_handler_tcp_listen() create fail");
                /* 删除接收线程状态信号量 */
                os_sem_delete(&port_data->tcp.idle_sem);
                break;
            }

            /* 插入已启动的 tcp 的链 */
            slist_insert_tail(&p_cm->tcp_list, &port_data->start_node);
            SYS_LOG_INF("success. stype: tcp");
        }

        /* 操作成功 */
        ret = 0;

    } while (0);

    if (ret != 0)
    {
        _do_tcp_recv_stop(tcp_port);

        /* 关闭 wifi */
        _wifi_close();
    }

    os_mutex_unlock(&p_cm->mutex_hdl);

    return ret;
}

static int _port_tcp_stop(sb_data_port_t *port)
{
    os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);

    __port_tcp_t *tcp_port = SLIST_CONTAINER_OF(port, __port_tcp_t, port);
    _do_tcp_recv_stop(tcp_port);

    os_mutex_unlock(&p_cm->mutex_hdl);

    return 0;
}

static int _port_tcp_write(sb_data_port_t *port, const void *data, uint32_t size)
{
    __port_data_t *port_data = port->data;
    __port_tcp_t *tcp_port = SLIST_CONTAINER_OF(port, __port_tcp_t, port);

    if (tcp_port->p_status_list != &port_data->tcp.recv_list)
    {
        return 0;
    }

    if (tcp_port->client_sock != -1)
    {
        int err = send(tcp_port->client_sock, data, size, 0);
        if (err < 0)
        {
            SYS_LOG_WRN("Error occurred during sending: errno %d", errno);
            return err;
        }
        else
        {
            SYS_LOG_DBG("size: %d", size);
            return size;
        }
    }
    return -1;
}

static int _port_tcp_read(sb_data_port_t *port, void *data, uint32_t size)
{
    __port_tcp_t *tcp_port = SLIST_CONTAINER_OF(port, __port_tcp_t, port);
    if (os_pipe_is_valid(&tcp_port->rx_pipe))
    {
        int ret = os_pipe_fifo_read(&tcp_port->rx_pipe, data, size);
        if (ret > 0)
        {
            os_sem_release(&tcp_port->rx_sem);
        }
        return ret;
    }
    else
    {
        return -1;
    }
}

static bool _port_tcp_is_started(sb_data_port_t *port)
{
    if (port == NULL)
    {
        return false;
    }

    __port_data_t *port_data = port->data;
    if (port_data == NULL)
    {
        return false;
    }

    __port_tcp_t *tcp_port = SLIST_CONTAINER_OF(port, __port_tcp_t, port);
    if (tcp_port->p_status_list == &port_data->tcp.recv_list ||
        tcp_port->p_status_list == &port_data->tcp.idle_list)
    {
        return true;
    }
    else
    {
        return false;
    }
}

static uint32_t _port_tcp_get_rx_length(sb_data_port_t *port)
{
    __port_tcp_t *tcp_port = SLIST_CONTAINER_OF(port, __port_tcp_t, port);
    if (os_pipe_is_valid(&tcp_port->rx_pipe))
    {
        return os_pipe_get_valid_size(&tcp_port->rx_pipe);
    }
    else
    {
        return 0;
    }
}

/**
 * @brief 根据 p_cm->udp_list 和 p_cm->tcp_list 的情况确定打开 wifi
 *
 */
static void _wifi_open(void)
{
    if (p_cm->wifi_open_flag == false)
    {
        if (slist_peek_head(&p_cm->udp_list) == NULL && slist_peek_head(&p_cm->tcp_list) == NULL)
        {
            p_cm->wifi_open_flag = true;
            wifi_start();
        }
    }
}

/**
 * @brief 根据 p_cm->udp_list 和 p_cm->tcp_list 的情况确定打关闭 wifi
 *
 */
static void _wifi_close(void)
{
    if (p_cm->wifi_open_flag != false)
    {
        if (slist_peek_head(&p_cm->udp_list) == NULL && slist_peek_head(&p_cm->tcp_list) == NULL)
        {
            p_cm->wifi_open_flag = false;
            wifi_stop();
        }
    }
}

/**
 * @brief 初始化 socket 并绑定本地地址
 *
 * @param port
 * @return int
 */
static int _socket_init_udp(__port_data_t *port_data)
{
    SYS_ASSERT(port_data->sock == -1, "");

    struct sockaddr_storage dest_addr;
    memset(&dest_addr, 0, sizeof(dest_addr));
    struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;
    dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY);
    dest_addr_ip4->sin_family = AF_INET;
    dest_addr_ip4->sin_port = htons(port_data->listen_port);

    port_data->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (port_data->sock < 0)
    {
        SYS_LOG_ERR("Unable to create socket: errno %d", errno);
        port_data->sock = -1;
        return -1;
    }
    SYS_LOG_INF("Socket created. sock = %u", port_data->sock);

    int err = bind(port_data->sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
    if (err < 0)
    {
        SYS_LOG_ERR("Socket unable to bind: errno %d", errno);
        close(port_data->sock);
        port_data->sock = -1;
        return -1;
    }
    SYS_LOG_INF("Socket bound, port %d", port_data->listen_port);

    return 0;
}

/**
 * @brief 初始化 socket 并绑定本地地址
 *
 * @param port
 * @return int
 */
static int _socket_init_tcp(__port_data_t *port_data)
{
    SYS_ASSERT(port_data->sock == -1, "");

    struct sockaddr_storage dest_addr;
    memset(&dest_addr, 0, sizeof(dest_addr));
    struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;
    dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY);
    dest_addr_ip4->sin_family = AF_INET;
    dest_addr_ip4->sin_port = htons(port_data->listen_port);

    port_data->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    if (port_data->sock < 0)
    {
        SYS_LOG_ERR("Unable to create socket: errno %d", errno);
        port_data->sock = -1;
        return -1;
    }
    setsockopt(port_data->sock, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));

    SYS_LOG_INF("Socket created. sock = %u", port_data->sock);

    int err = bind(port_data->sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
    if (err != 0)
    {
        SYS_LOG_ERR("Socket unable to bind: errno %d", errno);
        close(port_data->sock);
        port_data->sock = -1;
        return -1;
    }
    SYS_LOG_INF("Socket bound, port %d", port_data->listen_port);

    err = listen(port_data->sock, port_data->tcp.tcp_backlog);
    if (err != 0)
    {
        SYS_LOG_ERR("Error occurred during listen: errno %d", errno);
        close(port_data->sock);
        port_data->sock = -1;
        return -1;
    }

    return 0;
}

/**
 * @brief 关闭 socket
 *
 * @param port_data
 */
static void _socket_close(__port_data_t *port_data)
{
    if (port_data->sock != -1)
    {
        SYS_LOG_INF("close socket %d", port_data->sock);
        close(port_data->sock);
        port_data->sock = -1;
    }
}

static int _do_tcp_recv_start(__port_tcp_t *tcp_port)
{
    __port_data_t *port_data = tcp_port->port.data;

    /* 创建接收线程缓存信号量 */
    if (os_sem_create(&tcp_port->rx_sem, 0, 1) != OS_OK)
        return -1;

    /* 创建接收线程内部缓存 */
    if (os_pipe_create(&tcp_port->rx_pipe, tcp_port->local.rx_buf_size) != OS_OK)
        return -1;
    os_pipe_regist(&tcp_port->rx_pipe, tcp_port->local.rx_resume_work, 0);

    /* 初始化连接套按字 */
    tcp_port->client_sock = -1;

    /* 插入到空闲链 */
    slist_remove(tcp_port->p_status_list, &tcp_port->status_node);
    slist_insert_tail(&port_data->tcp.idle_list, &tcp_port->status_node);
    tcp_port->p_status_list = &port_data->tcp.idle_list;

    if (os_sem_is_valid(&port_data->tcp.idle_sem))
        os_sem_release(&port_data->tcp.idle_sem); // 释放状态变更信号

    return 0;
}

static void _do_tcp_recv_stop(__port_tcp_t *tcp_port)
{
    __port_data_t *port_data = tcp_port->port.data;

    slist_remove(tcp_port->p_status_list, &tcp_port->status_node);
    if (tcp_port->p_status_list != &port_data->tcp.close_list)
    {
        slist_insert_tail(&port_data->tcp.bind_list, &tcp_port->status_node);
        tcp_port->p_status_list = &port_data->tcp.bind_list;
    }

    if (os_sem_is_valid(&port_data->tcp.idle_sem))
        os_sem_release(&port_data->tcp.idle_sem); // 释放状态变更信号

    /* 关闭连接套按字 */
    if (tcp_port->client_sock != -1)
    {
        SYS_LOG_WRN("shutdown client sock %d", tcp_port->client_sock);
        shutdown(tcp_port->client_sock, SHUT_RDWR);
    }
    else // 未在 _thread_handler_tcp_listen() 中建立接收连接，直接删除内部缓存
    {
        /* 删除接收线程内部缓存 */
        if (os_pipe_is_valid(&tcp_port->rx_pipe))
            os_pipe_delete(&tcp_port->rx_pipe);

        /* 删除接收线程缓存信号量 */
        if (os_sem_is_valid(&tcp_port->rx_sem))
            os_sem_delete(&tcp_port->rx_sem);
    }

    if (slist_peek_head(&port_data->tcp.recv_list) == NULL && slist_peek_head(&port_data->tcp.idle_list) == NULL) // 所有接口已关闭
    {
        /* 关闭 socket */
        _socket_close(port_data);
    }
}

/**
 * @brief 内部函数，查询本地商品对应的句柄
 *
 * @param listen_port
 * @retval sb_data_port_t 数据接口
 */
static sb_data_port_t *_find_hdl_by_port(uint16_t listen_port)
{
    sb_data_port_t *port = NULL;
    __port_data_t *port_data;

    SYS_ASSERT(p_cm, "");

    if (port == NULL)
    {
        SLIST_FOR_EACH_CONTAINER(&p_cm->udp_list, port_data, start_node)
        {
            if (port_data->listen_port == listen_port)
            {
                port = SLIST_CONTAINER_OF(port_data, sb_data_port_t, data);
                break;
            }
        }
    }

    if (port == NULL)
    {
        SLIST_FOR_EACH_CONTAINER(&p_cm->tcp_list, port_data, start_node)
        {
            if (port_data->listen_port == listen_port)
            {
                port = SLIST_CONTAINER_OF(port_data, sb_data_port_t, data);
                break;
            }
        }
    }

    return port;
}

/**
 * @brief 插入到绑定链中
 *
 * @param port_data
 * @return sb_data_port_t *
 */
static sb_data_port_t *_create_port_data(const sb_data_port_vtable_t *vtable, uint16_t listen_port)
{
    sb_data_port_t *port = NULL;

    os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);

    __port_data_t *port_data = os_malloc(sizeof(__port_data_t));
    if (port_data)
    {
        memset(port_data, 0, sizeof(__port_data_t));

        port_data->port.vtable = vtable;
        port_data->port.data = port_data;
        port_data->listen_port = listen_port;
        port_data->sock = -1;
        slist_init_node(&port_data->start_node);

        port = &port_data->port;
    }

    os_mutex_unlock(&p_cm->mutex_hdl);

    return port;
}

/**
 * @brief 内部线程， udp 的服务线程，将用于轮询接收到的数据
 *
 * @param arg __port_data_t *port_data
 */
static void _thread_handler_udp_listen(void *arg)
{
    __port_data_t *port_data = arg;
    uint8_t rx_buffer[1500];
    int err = -1;

    os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);

    do
    {
        /* 初始化 socket */
        if (_socket_init_udp(port_data) != 0)
        {
            break;
        }

        /* 创建信号量 */
        if (os_sem_create(&port_data->udp.rx_sem, 0, 1) != OS_OK)
        {
            break;
        }

        /* 创建内部缓存 */
        if (os_fifo_q_create(&port_data->udp.rx_fifo) != OS_OK)
        {
            break;
        }
        os_fifo_q_regist(&port_data->udp.rx_fifo, port_data->udp.local.rx_resume_work, 0);
        port_data->udp.rx_cnt = 0;

        err = 0;

    } while (0);

    os_mutex_unlock(&p_cm->mutex_hdl);

    if (err == 0)
    {
        SYS_LOG_INF("start");

        for (;;)
        {
            struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
            socklen_t socklen = sizeof(source_addr);
            SYS_LOG_DBG("Waiting for data");
            int len = recvfrom(port_data->sock, rx_buffer, sizeof(rx_buffer), 0, (struct sockaddr *)&source_addr, &socklen);

            // Error occurred during receiving
            if (len < 0)
            {
                if (errno != 128) // #define	EKEYREVOKED	128	/* Key has been revoked */
                {
                    SYS_LOG_ERR("abort receiving: errno %d", errno);
                }
                break;
            }
            else // Data received
            {
                /* 打印调试信息 */
                struct
                {
                    uint8_t ip_v4[4];
                    uint16_t port;
                } remote_info;
                struct sockaddr_in *source_addr_ipv4 = (struct sockaddr_in *)&source_addr;
                *(uint32_t *)remote_info.ip_v4 = *(uint32_t *)&source_addr_ipv4->sin_addr;
                remote_info.port = htons(source_addr_ipv4->sin_port);
                SYS_LOG_DBG("Received %d bytes from %u.%u.%u.%u:%u",
                            len,
                            remote_info.ip_v4[0],
                            remote_info.ip_v4[1],
                            remote_info.ip_v4[2],
                            remote_info.ip_v4[3],
                            remote_info.port);
                SYS_LOG_DUMP(rx_buffer, len, 0, 0);

                /* 等待接收缓存可用 */
                while (port_data->udp.rx_cnt >= port_data->udp.local.rx_buf_size)
                {
                    os_sem_take(&port_data->udp.rx_sem, OS_WAIT_FOREVER);
                }

                /* 保存接收数据 */
                __udp_rx_fifo_t *fifo = os_fifo_alloc(sizeof(__udp_rx_fifo_t) + len);
                if (fifo)
                {
                    os_scheduler_suspend();
                    port_data->udp.rx_cnt += len;
                    os_scheduler_resume();

                    fifo->source_addr = source_addr;
                    fifo->size = len;
                    memcpy(fifo->data, rx_buffer, len);
                    if (os_fifo_put(&port_data->udp.rx_fifo, fifo) != OS_OK)
                    {
                        os_fifo_free(fifo);
                    }

                    if (port_data->udp.local.rx_event)
                    {
                        port_data->udp.local.rx_event(&port_data->port);
                    }
                }
            }
        }
    }

    os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);

    SYS_LOG_INF("close");

    /* 从已启动的 udp 的链移除节点 */
    if (slist_is_pending(&port_data->start_node))
        slist_remove(&p_cm->udp_list, &port_data->start_node);

    /* 删除内部缓存 */
    if (os_fifo_q_is_valid(&port_data->udp.rx_fifo))
        os_fifo_q_delete(&port_data->udp.rx_fifo);

    /* 删除信号量 */
    if (os_sem_is_valid(&port_data->udp.rx_sem))
        os_sem_delete(&port_data->udp.rx_sem);

    /* 关闭 wifi */
    _wifi_close();

    if (port_data->unbind_flag)
    {
        SYS_LOG_INF("free binding memory");
        port_data->unbind_flag = false;
        os_free(port_data);
    }

    os_mutex_unlock(&p_cm->mutex_hdl);

    os_thread_delete(NULL);
}

/**
 * @brief 内部线程， tcp 的服务线程，将用于轮询接收到的数据
 *
 * @param arg __port_data_t *port_data
 */
static void _thread_handler_tcp_listen(void *arg)
{
    __port_data_t *port_data = arg;
    int err = -1;

    os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);

    do
    {
        /* 初始化 socket */
        if (_socket_init_tcp(port_data) != 0)
        {
            break;
        }

        err = 0;

    } while (0);

    os_mutex_unlock(&p_cm->mutex_hdl);

    if (err == 0)
    {
        SYS_LOG_INF("start");

        for (;;)
        {
            __port_tcp_t *tcp_port = NULL;

            /* 等待有空闲的线程 */
            for (;;)
            {
                os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);

                slist_node_t *status_node = slist_peek_head(&port_data->tcp.idle_list);
                if (status_node)
                {
                    tcp_port = SLIST_CONTAINER_OF(status_node, __port_tcp_t, status_node);
                    os_mutex_unlock(&p_cm->mutex_hdl);
                    break;
                }
                else
                {
                    if (slist_peek_head(&port_data->tcp.recv_list))
                    {
                        os_mutex_unlock(&p_cm->mutex_hdl);

                        os_sem_take(&port_data->tcp.idle_sem, OS_WAIT_FOREVER);
                    }
                    else // 所有接口已关闭
                    {
                        SYS_LOG_WRN("all tcp recv has been stoped");
                        os_mutex_unlock(&p_cm->mutex_hdl);
                        break;
                    }
                }
            }

            if (port_data->sock == -1)
            {
                SYS_LOG_WRN("socket has been closed");
                break;
            }

            struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
            socklen_t socklen = sizeof(source_addr);
            SYS_LOG_INF("Socket listening");
            int client_sock = accept(port_data->sock, (struct sockaddr *)&source_addr, &socklen);
            if (client_sock < 0)
            {
                if (errno != 128) // #define	EKEYREVOKED	128	/* Key has been revoked */
                {
                    SYS_LOG_ERR("abort listening: errno %d", errno);
                }
                break;
            }
            else
            {
                /* Set tcp keepalive option */
                setsockopt(client_sock, SOL_SOCKET, SO_KEEPALIVE, &(int){1}, sizeof(int));
                // setsockopt(client_sock, IPPROTO_TCP, TCP_KEEPIDLE, &(int){1}, sizeof(int));
                // setsockopt(client_sock, IPPROTO_TCP, TCP_KEEPINTVL, &(int){1}, sizeof(int));
                // setsockopt(client_sock, IPPROTO_TCP, TCP_KEEPCNT, &(int){1}, sizeof(int));

                /* 打印调试信息 */
                struct
                {
                    uint8_t ip_v4[4];
                    uint16_t port;
                } remote_info;
                struct sockaddr_in *source_addr_ipv4 = (struct sockaddr_in *)&source_addr;
                *(uint32_t *)remote_info.ip_v4 = *(uint32_t *)&source_addr_ipv4->sin_addr;
                remote_info.port = htons(source_addr_ipv4->sin_port);
                SYS_LOG_INF("Socket accepted client socket %d, ip address: %u.%u.%u.%u:%u",
                            client_sock,
                            remote_info.ip_v4[0],
                            remote_info.ip_v4[1],
                            remote_info.ip_v4[2],
                            remote_info.ip_v4[3],
                            remote_info.port);

                /* 等待有空闲的线程 */
                for (;;)
                {
                    os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);

                    slist_node_t *status_node = slist_peek_head(&port_data->tcp.idle_list);
                    if (status_node)
                    {
                        tcp_port = SLIST_CONTAINER_OF(status_node, __port_tcp_t, status_node);

                        /* 设置连接套接字 */
                        tcp_port->client_sock = client_sock;

                        /* 创建接收线程 */
                        if (os_thread_create(NULL,
                                             "tcp-recv",
                                             _thread_handler_tcp_recv,
                                             tcp_port,
                                             2400,
                                             _THREAD_PRIOR) == OS_OK)
                        {
                            /* 设为接收状态 */
                            slist_remove(tcp_port->p_status_list, &tcp_port->status_node);
                            slist_insert_tail(&port_data->tcp.recv_list, &tcp_port->status_node);
                            tcp_port->p_status_list = &port_data->tcp.recv_list;
                        }
                        else
                        {
                            SYS_LOG_WRN("_thread_handler_tcp_recv() create fail");

                            /* 重置连接套接字 */
                            tcp_port->client_sock = -1;
                        }

                        os_mutex_unlock(&p_cm->mutex_hdl);
                        break;
                    }
                    else
                    {
                        if (slist_peek_head(&port_data->tcp.recv_list))
                        {
                            os_mutex_unlock(&p_cm->mutex_hdl);

                            os_sem_take(&port_data->tcp.idle_sem, OS_WAIT_FOREVER);
                        }
                        else // 所有接口已关闭
                        {
                            SYS_LOG_WRN("all tcp recv has been stoped, force shutdown and close client sock %d", client_sock);
                            shutdown(client_sock, SHUT_RDWR);
                            close(client_sock);
                            os_mutex_unlock(&p_cm->mutex_hdl);
                            break;
                        }
                    }
                }
            }
        }
    }

    os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);

    SYS_LOG_INF("close");

    /* 从已启动的 tcp 的链移除节点 */
    if (slist_is_pending(&port_data->start_node))
        slist_remove(&p_cm->tcp_list, &port_data->start_node);

    /* 关闭 socket */
    _socket_close(port_data);

    /* 关闭 wifi */
    _wifi_close();

    /* 删除信号量 */
    if (os_sem_is_valid(&port_data->tcp.idle_sem))
        os_sem_delete(&port_data->tcp.idle_sem);

    if (port_data->unbind_flag)
    {
        SYS_LOG_INF("free binding memory");
        port_data->unbind_flag = false;
        os_free(port_data);
    }

    os_mutex_unlock(&p_cm->mutex_hdl);

    os_thread_delete(NULL);
}

/**
 * @brief 内部函数，由 _thread_handler_tcp_listen() 在获得一个连接时创建
 *
 * @param arg __port_tcp_t *tcp_port = arg
 */
static void _thread_handler_tcp_recv(void *arg)
{
    __port_tcp_t *tcp_port = arg;
    __port_data_t *port_data = tcp_port->port.data;
    int err = 0;

    SYS_LOG_INF("start receiving client socket %d", tcp_port->client_sock);

    if (err == 0)
    {
        if (port_data->tcp.connect)
        {
            port_data->tcp.connect(true, &tcp_port->port);
        }

        for (;;)
        {
            void *empty_base;
            size_t empty_size;
            do
            {
                os_pipe_peek_empty(&tcp_port->rx_pipe, &empty_base, &empty_size);
                if (empty_size == 0)
                {
                    os_sem_take(&tcp_port->rx_sem, OS_WAIT_FOREVER);
                }
            } while (empty_size == 0);

            int len = recv(tcp_port->client_sock, empty_base, empty_size, 0);
            if (len > 0)
            {
                os_pipe_fifo_fill(&tcp_port->rx_pipe, NULL, len);

                if (tcp_port->local.rx_event)
                {
                    tcp_port->local.rx_event(&tcp_port->port);
                }
            }
            else if (len == 0)
            {
                SYS_LOG_INF("Connection closed");
                break;
            }
            else
            {
                if (errno != 128) // #define	EKEYREVOKED	128	/* Key has been revoked */
                {
                    SYS_LOG_ERR("abort receiving: errno %d", errno);
                }
                break;
            }
        }

        if (port_data->tcp.connect)
        {
            port_data->tcp.connect(false, &tcp_port->port);
        }
    }

    os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);

    /* 关闭连接套接字 */
    if (tcp_port->client_sock != -1)
    {
        close(tcp_port->client_sock);
        tcp_port->client_sock = -1;
    }

    /* 设置状态 */
    do
    {
        slist_remove(tcp_port->p_status_list, &tcp_port->status_node);
        if (tcp_port->p_status_list == &port_data->tcp.recv_list) // 连接被无端正常关闭
        {
            slist_insert_tail(&port_data->tcp.idle_list, &tcp_port->status_node);
            tcp_port->p_status_list = &port_data->tcp.idle_list;
            break;
        }
        else if (tcp_port->p_status_list == &port_data->tcp.bind_list) // 已设置停止
        {
            slist_insert_tail(&port_data->tcp.bind_list, &tcp_port->status_node);
            tcp_port->p_status_list = &port_data->tcp.bind_list;
        }
        else if (tcp_port->p_status_list == &port_data->tcp.close_list) // 已设置关闭
        {
            /* 执行 socket_inet_server_bind_tcp() 的反过程 */
            os_free(tcp_port);
            port_data->tcp.backlog_cnt--;
        }

        /* 删除接收线程内部缓存 */
        if (os_pipe_is_valid(&tcp_port->rx_pipe))
            os_pipe_delete(&tcp_port->rx_pipe);

        /* 删除接收线程缓存信号量 */
        if (os_sem_is_valid(&tcp_port->rx_sem))
            os_sem_delete(&tcp_port->rx_sem);

    } while (0);

    if (slist_peek_head(&port_data->tcp.recv_list) == NULL && slist_peek_head(&port_data->tcp.idle_list) == NULL) // 所有接口已关闭
    {
        /* 关闭 socket */
        _socket_close(port_data);
    }

    if (os_sem_is_valid(&port_data->tcp.idle_sem))
        os_sem_release(&port_data->tcp.idle_sem); // 释放状态变更信号

    os_mutex_unlock(&p_cm->mutex_hdl);

    os_thread_delete(NULL);
}

/* export ----------------------------------------------------------------------------------------------------------*/

/**
 * @brief 由 socket_inet.c 调用
 */
void socket_inet_server_init(void)
{
    if (p_cm)
    {
        SYS_LOG_WRN("repeated init");
        return;
    }
    p_cm = os_malloc(sizeof(*p_cm));
    if (p_cm == NULL)
    {
        SYS_LOG_WRN("Insufficient memory");
        return;
    }
    memset(p_cm, 0, sizeof(*p_cm));

    os_mutex_create(&p_cm->mutex_hdl);
    slist_init_list(&p_cm->udp_list);
    slist_init_list(&p_cm->tcp_list);
}
/**
 * @brief 设置 udp 的广播地址  以及端口
 *
 * @param port 接口
 */
void set_udp_broadcast_add(sb_data_port_t* port)
{
    __port_data_t *port_data = port->data;
    
    struct sockaddr_in *dest_addr_ipv4 = (struct sockaddr_in *)&port_data->udp.dest_addr;
    dest_addr_ipv4->sin_family = AF_INET;            // IPv4 协议族
    dest_addr_ipv4->sin_port = htons(port_data->listen_port); // 端口
    dest_addr_ipv4->sin_addr.s_addr = inet_addr("255.255.255.255"); // 例如广播地址
}

/**
 * @brief 创建一个 udp 本地服务监听端口，同时为已启动监听的端口绑定一个数据接口。
 * 可监听的本地端口数量不限，但不能与任何已监听的本地端口重复。
 * 每个本地端口对应一个线程 _thread_handler_udp_listen() ，每当收到的客户端的报文时，远端信息和报文数据都在这个线程中记录并缓存到内部已绑定的的 fifo 中，
 * 注意：使用 sb_data_port_read() 读取报文数据时，不管指定的缓存是否能全部读取完成，这个报文数据都会被释放。
 *
 * @param listen_port 本地监听端口
 * @param bind_param
 * @return sb_data_port_t*
 */
sb_data_port_t *socket_inet_server_bind_udp(uint16_t listen_port, const socket_server_bind_t *bind_param)
{
    SYS_ASSERT(p_cm, "Initialization not performed using socket_inet_init()");

    sb_data_port_t *port = _create_port_data(&s_port_vtable_udp, listen_port);
    if (port)
    {
        __port_data_t *port_data = port->data;
        port_data->udp.local = *bind_param; // 绑定时的设置信息

        SYS_LOG_INF("bind udp: %p", port);
    }
    set_udp_broadcast_add(port);
    return port;
}

/**
 * @brief 关闭由 socket_inet_server_bind_udp() 创建监听的端口。
 *
 * @param port
 */
void socket_inet_server_unbind_udp(sb_data_port_t *port)
{
    if (port)
    {
        __port_data_t *port_data = SLIST_CONTAINER_OF(port, __port_data_t, port);
        port_data->unbind_flag = true;

        if (port->vtable->is_started(port))
        {
            SYS_LOG_WRN("Data interface started, forcing close udp %p", port);

            port->vtable->stop(port);
        }

        os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);

        if (!os_thread_is_valid(&port_data->thread_hdl_listen))
        {
            if (port_data->unbind_flag)
            {
                port_data->unbind_flag = false;
                os_free(port_data);
            }
        }

        os_mutex_unlock(&p_cm->mutex_hdl);
    }
}

/**
 * @brief 获取上次通过 sb_data_port_read() 读取到的远端的地址信息
 *
 * @param port              通过 socket_inet_server_unbind_udp() 绑定的数据接口
 * @param s_addr[out]       输出远端 IP
 * @param sin_port[out]     输出远端端口
 * @retval 0 成功
 * @retval -1 接口未启动
 */
int socket_inet_server_udp_read_addr(sb_data_port_t *port, in_addr_t *s_addr, in_port_t *sin_port)
{
    if (_port_udp_is_started(port))
    {
        __port_data_t *port_data = port->data;
        struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&port_data->udp.dest_addr;
        if (s_addr)
            *s_addr = dest_addr_ip4->sin_addr.s_addr;
        if (sin_port)
            *sin_port = dest_addr_ip4->sin_port;
        return 0;
    }
    else
    {
        return -1;
    }
}

/**
 * @brief 发送广播包
 *
 * @param port              通过 socket_inet_server_unbind_udp() 绑定的数据接口
 * @param ip_v4             远端 IP 地址
 * @param broadcast_port    远端端口
 * @param data              数据
 * @param size              数据长度（字节）
 * @retval >= 0 发送长度
 * @retval < 0 数据接口未启动或错误
 */
int socket_inet_server_udp_broadcast(sb_data_port_t *port, uint8_t ip_v4[4], uint16_t broadcast_port, const void *data, uint32_t size)
{
    if (_port_udp_is_started(port))
    {
        if (size == 0)
        {
            return 0;
        }

        struct sockaddr_storage dest_addr; // Large enough for both IPv4 or IPv6
        socklen_t socklen = sizeof(dest_addr);
        struct sockaddr_in *dest_addr_ipv4 = (struct sockaddr_in *)&dest_addr;
        dest_addr_ipv4->sin_family = AF_INET;
        dest_addr_ipv4->sin_port = htons(broadcast_port);
        dest_addr_ipv4->sin_len = sizeof(struct sockaddr_in);
        *(uint32_t *)&dest_addr_ipv4->sin_addr.s_addr = *(uint32_t *)ip_v4;

        __port_data_t *port_data = port->data;
        int err = sendto(port_data->sock, data, size, 0, (struct sockaddr *)&dest_addr, socklen);
        if (err < 0)
        {
            return -1;
        }
        else
        {
            SYS_LOG_DBG("size: %d", size);
            return size;
        }
    }
    else
    {
        return -1;
    }
}

/**
 * @brief 创建一个 tcp 本地服务监听端口。
 * 每个已监听的本地端口仅允许使用 socket_inet_server_bind_tcp() 绑定一个接收接口，数量由 tcp_backlog 确定。
 * 可监听的本地端口数量不限，但不能与任何已监听的本地端口重复。
 * 每个本地端口对应一个线程 _thread_handler_tcp_listen() ，每当收到客户端的连接请求时，内部将根据 socket_inet_server_bind_tcp() 的次数，自动创建一个用于接收数据的线程 _thread_handler_tcp_recv().
 * 当客户端断开连接时 _thread_handler_tcp_recv() 自动关闭。
 *
 * @param listen_port   本地监听端口
 * @param tcp_backlog   允许这个端口的最大连个接数
 * @param connect       当监听到连接被变更时执行的回调函数，可设为 NULL 。其中参数 is_connect 为真值时表示已连接，为假值时表示连接已断开
 *
 * @return socket_listen_tcp_t *
 */
socket_listen_tcp_t socket_inet_server_listen_tcp(uint16_t listen_port, uint8_t tcp_backlog, const connect_cb connect)
{
    SYS_ASSERT(p_cm, "Initialization not performed using socket_inet_init()");

    if (tcp_backlog == 0)
    {
        SYS_LOG_WRN("fail. tcp_backlog = 0");
        return NULL;
    }
    sb_data_port_t *port = _create_port_data(&s_port_vtable_tcp, listen_port);
    if (port != NULL)
    {
        __port_data_t *port_data = port->data;
        slist_init_list(&port_data->tcp.bind_list);  // tcp 已绑定链
        slist_init_list(&port_data->tcp.idle_list);  // tcp 已设置启动的但未连接的空闲链
        slist_init_list(&port_data->tcp.recv_list);  // tcp 已设连接的链
        slist_init_list(&port_data->tcp.close_list); // 正在执行关闭数据接口
        port_data->tcp.tcp_backlog = tcp_backlog;    // 为此套接字维护的最大连接个数
        port_data->tcp.connect = connect;            // 连接状态通知
    }
    return (socket_listen_tcp_t)port;
}

/**
 * @brief 为已启动监听的端口绑定一个数据接口。可绑定的数量由 socket_inet_server_listen_tcp() 确定
 *
 * @param listen_tcp 由 socket_inet_server_listen_tcp() 创建的监听端口
 * @param bind_param
 * @return sb_data_port_t*
 */
sb_data_port_t *socket_inet_server_bind_tcp(socket_listen_tcp_t listen_tcp, const socket_server_bind_t *bind_param)
{
    SYS_ASSERT(listen_tcp, "Not initialized using socket socket_inet_server_listen_tcp()");

    os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);

    sb_data_port_t *port = listen_tcp;
    __port_data_t *port_data = port->data;
    __port_tcp_t *tcp_port = NULL;
    if (port_data->tcp.backlog_cnt < port_data->tcp.tcp_backlog)
    {
        port_data->tcp.backlog_cnt++;

        tcp_port = os_malloc(sizeof(__port_tcp_t));
        if (tcp_port)
        {
            memset(tcp_port, 0, sizeof(*tcp_port));

            slist_init_node(&tcp_port->status_node);
            tcp_port->port.vtable = port->vtable;
            tcp_port->port.data = port_data;
            tcp_port->client_sock = -1;
            tcp_port->local = *bind_param; // 绑定时的设置信息

            slist_insert_tail(&port_data->tcp.bind_list, &tcp_port->status_node);
            tcp_port->p_status_list = &port_data->tcp.bind_list;

            SYS_LOG_INF("bind tcp %u: %p", port_data->tcp.backlog_cnt, tcp_port);
        }
    }
    else
    {
        SYS_LOG_ERR("Exceeding the set quantity: tcp_backlog = %u", port_data->tcp.tcp_backlog);
    }

    os_mutex_unlock(&p_cm->mutex_hdl);

    return (sb_data_port_t *)tcp_port;
}

/**
 * @brief 关闭由 socket_inet_server_listen_tcp() 创建监听的端口。
 *
 * @param listen_tcp
 */
void socket_inet_server_unbind_tcp(socket_listen_tcp_t listen_tcp)
{
    sb_data_port_t *port = listen_tcp;
    if (port)
    {
        __port_data_t *port_data = port->data;
        port_data->unbind_flag = true;

        os_mutex_lock(&p_cm->mutex_hdl, OS_WAIT_FOREVER);

        for (;;)
        {
            slist_node_t *status_node = slist_take_head(&port_data->tcp.bind_list);
            if (status_node)
            {
                __port_tcp_t *tcp_port = SLIST_CONTAINER_OF(status_node, __port_tcp_t, status_node);
                SYS_LOG_INF("closing stoped tcp port %p", tcp_port);
                _do_tcp_recv_stop(tcp_port);
                os_free(tcp_port);
            }
            else
            {
                break;
            }
        }

        for (;;)
        {
            slist_node_t *status_node = slist_take_head(&port_data->tcp.idle_list);
            if (status_node)
            {
                __port_tcp_t *tcp_port = SLIST_CONTAINER_OF(status_node, __port_tcp_t, status_node);
                SYS_LOG_INF("closing idle tcp port %p", tcp_port);
                _do_tcp_recv_stop(tcp_port);
                os_free(tcp_port);
            }
            else
            {
                break;
            }
        }

        for (;;)
        {
            slist_node_t *status_node = slist_take_head(&port_data->tcp.recv_list);
            if (status_node)
            {
                __port_tcp_t *tcp_port = SLIST_CONTAINER_OF(status_node, __port_tcp_t, status_node);
                SYS_LOG_WRN("Data interface started, forcing close tcp %p", tcp_port);
                slist_insert_tail(&port_data->tcp.close_list, &tcp_port->status_node);
                tcp_port->p_status_list = &port_data->tcp.close_list;
                _do_tcp_recv_stop(tcp_port);
            }
            else
            {
                break;
            }
        }

        /* 关闭 socket */
        _socket_close(port_data);

        if (!os_thread_is_valid(&port_data->thread_hdl_listen))
        {
            if (port_data->unbind_flag)
            {
                port_data->unbind_flag = false;
                os_free(port_data);
            }
        }

        os_mutex_unlock(&p_cm->mutex_hdl);
    }
}
