UDP监听多IP的服务器 2018-11-12 09:48:51

#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <errno.h>

#undef DEBUG
#define DEBUG(fmt, args...) printf("[D] %03d: " fmt "\n", __LINE__, ##args)
#undef ERROR
#define ERROR(fmt, args...) printf("[E] %03d: " fmt "\n", __LINE__, ##args)
#undef ERRNO
#define ERRNO(fmt, args...) \
    ERROR("Failed(%d) to " fmt ", %s.", errno, ##args, strerror(errno))
#undef FATAL
#define FATAL(fmt, args...) {\
    printf("[F] %03d: " fmt "\n", __LINE__, ##args);\
    exit(__LINE__);\
}
#undef FATALNO
#define FATALNO(fmt, args...) \
    FATAL("Failed(%d) to " fmt ", %s.", errno, ##args, strerror(errno))


#define IP_STR_LEN 16
#define IPV4_BIN_TO_STR(bin)    ({struct in_addr ia={.s_addr=htonl(bin)};inet_ntoa(ia);})


#define u64 unsigned long long
#define u32 unsigned
#define u8 unsigned char
#define u16 unsigned short

#define SERVER_PORT 1
#define BUFFER_SIZE 1024

static int udp_send(u32 sip, u16 sport, struct sockaddr_in *daddr, u8 *data, u32 data_len)
{
    struct sockaddr_in saddr = {.sin_family = AF_INET};
    int sent = 0;
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        FATALNO("create socket");
    }

{
    int opt = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
}

    saddr.sin_addr.s_addr = htonl(sip);
    saddr.sin_port = htons(sport);
    if (bind(fd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
        FATALNO("bind socket");
    }

{
    char sips[IP_STR_LEN] = {0}, dips[IP_STR_LEN] = {0};
    u32 dip = ntohl(daddr->sin_addr.s_addr);
    strcpy(sips, IPV4_BIN_TO_STR(sip));
    strcpy(dips, IPV4_BIN_TO_STR(dip));
    DEBUG("%s:%u >> %s:%u", sips, sport, dips, ntohs(daddr->sin_port));
}

    sent = sendto(fd, data, data_len, 0, (struct sockaddr*)daddr, sizeof(*daddr));
    if (sent < 0) {
        FATALNO("sendto");
    }

    close(fd);
    return sent;
}

int main(int argc, char *argv[])
{
    int i;
    struct sockaddr_in saddr = {.sin_family = AF_INET};
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        FATALNO("create socket");
    }
{
    int opt = 1;
    setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt));
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    //setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
}

    saddr.sin_port = htons(SERVER_PORT);

    if (bind(fd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
        FATALNO("bind socket");
    }

    for (;;) {
        struct sockaddr_in caddr = {.sin_family = AF_INET};
        socklen_t alen = sizeof(caddr);
        u8 buf[BUFFER_SIZE] = {0};
        struct iovec iov[1] = {{.iov_base = buf, .iov_len = sizeof(buf)}};
        char cmbuf[100] = {0};
        struct msghdr mh = {
            .msg_name = &caddr,
            .msg_namelen = alen,
            .msg_control = cmbuf,
            .msg_controllen = sizeof(cmbuf),
            .msg_iov = iov,
            .msg_iovlen = 1
        };
        int received, found = 0;
        struct cmsghdr *cmsg;
        u32 dip = 0;

        //received = recvfrom(fd, buf, BUFFER_SIZE, 0, (struct sockaddr*)&caddr, &alen);
        received = recvmsg(fd, &mh, 0);
        if (received < 0) {
            FATALNO("recvmsg");
        }

        for (cmsg = CMSG_FIRSTHDR (&mh); cmsg; cmsg = CMSG_NXTHDR (&mh, cmsg)) {
            if (cmsg->cmsg_level == IPPROTO_IP || cmsg->cmsg_type == IP_PKTINFO) {
                struct in_pktinfo *pi = CMSG_DATA(cmsg);
                char sips[IP_STR_LEN] = {0}, dips[IP_STR_LEN] = {0};
                // at this point, caddr is the source sockaddr
                u32 sip = ntohl(caddr.sin_addr.s_addr);
                // pi->ipi_spec_dst is the destination in_addr
                dip = ntohl(pi->ipi_spec_dst.s_addr);

                strcpy(sips, IPV4_BIN_TO_STR(sip));
                strcpy(dips, IPV4_BIN_TO_STR(dip));
                DEBUG("%s:%u << %s:%u", dips, SERVER_PORT, sips, caddr.sin_port);
                found = 1;
                break;
            }
        }

        if (!found) {
            FATAL("Failed to get dst ip for %s:%u", IPV4_BIN_TO_STR(ntohl(caddr.sin_addr.s_addr)), caddr.sin_port);
        }

        udp_send(dip, SERVER_PORT, &caddr, buf, received);
    }

    return 0;
}

创建于 2018-08-31 15:47:25
最后更新于 2018-11-12 09:48:51
昵称 密钥