#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