/**
 * @file    comm_udp.cpp
 * @brief   通讯抽象层 — UDP 通讯
 * @details UDP 服务器/客户端：socket → bind → recvfrom/sendto
 */

#include "comm_internal.h"

#include <arpa/inet.h>
#include <netinet/in.h>

/**
 * @brief 处理 UDP 可读事件
 */
void handle_udp_read(stru_comm_instance *inst, int fd)
{
    unsigned char buf[COMM_RECV_BUF_SIZE];

    while (1)
    {
        struct sockaddr_in from_addr;
        socklen_t          from_len = sizeof(from_addr);

        ssize_t n = recvfrom(fd, buf, sizeof(buf), 0,
                             (struct sockaddr *)&from_addr, &from_len);

        if (n > 0)
        {
            if (inst->recv_cb)
            {
                inst->recv_cb(inst->id, fd, buf, (int)n);
            }
        }
        else
        {
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                break;
            }

            if (errno != EINTR)
            {
                if (inst->debug)
                {
                    LOG_E("comm[%d] fd=%d recvfrom error: %s",
                             inst->id, fd, strerror(errno));
                }
            }
            break;
        }
    }
}

/**
 * @brief UDP bind
 */
int udp_bind(stru_comm_instance *inst)
{
    int                fd;
    struct sockaddr_in addr;

    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd == -1)
    {
        return COMM_ERR_SOCKET;
    }

    set_nonblock(fd);

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port   = htons(inst->local_port);

    if (inst->local_ip[0] != '\0')
    {
        inet_pton(AF_INET, inst->local_ip, &addr.sin_addr);
    }
    else
    {
        addr.sin_addr.s_addr = INADDR_ANY;
    }

    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
    {
        close(fd);

        return COMM_ERR_BIND;
    }

    if (epoll_add_fd(fd, inst->id, 0) != 0)
    {
        close(fd);

        return COMM_ERR_INTERNAL;
    }

    inst->local_fd = fd;

    if (inst->debug)
    {
        LOG_I("comm[%d] UDP bound to %s:%d",
                 inst->id, inst->local_ip, inst->local_port);
    }

    return COMM_OK;
}

/**
 * @brief UDP 发送（sendto 到远端地址）
 */
int udp_sendto(stru_comm_instance *inst, int fd, const unsigned char *data, int len)
{
    struct sockaddr_in addr;

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port   = htons(inst->remote_port);
    inet_pton(AF_INET, inst->remote_ip, &addr.sin_addr);

    ssize_t sent = sendto(fd, data, len, 0, (struct sockaddr *)&addr, sizeof(addr));

    if (sent == -1)
    {
        if (inst->debug)
        {
            LOG_E("comm[%d] fd=%d sendto error: %s", inst->id, fd, strerror(errno));
        }

        return COMM_ERR_SEND;
    }

    return (int)sent;
}
