#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define CFG_PORT 5000
#define CFG_SO_MAX_SEND_BUFFER 1024
char payload[CFG_SO_MAX_SEND_BUFFER];
int test_cmsgsize(int, struct in_addr *, struct in_addr *,
unsigned int, unsigned int);
int
main(int argc, char *argv[])
{
int so, bytes;
struct in_addr src, dst;
if (argc != 3)
errx(2, "usage: %s <source_address> <destination_address>",
argv[0]);
if (inet_pton(AF_INET, argv[1], &src) != 1)
err(1, "unable to parse source address");
if (inet_pton(AF_INET, argv[2], &dst) != 1)
err(1, "unable to parse destination address");
so = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
if (so < 0)
err(1, "1: socket");
bytes = test_cmsgsize(so, &src, &dst, CFG_SO_MAX_SEND_BUFFER,
CFG_SO_MAX_SEND_BUFFER);
if (bytes >= 0)
errx(1, "1: %d bytes sent", bytes);
if (errno != EMSGSIZE)
err(-1, "1: incorrect errno");
close(so);
so = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (so < 0)
err(1, "2: socket");
bytes = test_cmsgsize(so, &src, &dst, CFG_SO_MAX_SEND_BUFFER,
CFG_SO_MAX_SEND_BUFFER);
if (bytes >= 0)
errx(1, "2: %d bytes sent", bytes);
if (errno != EMSGSIZE)
err(-1, "2: incorrect errno");
close(so);
so = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
if (so < 0)
err(1, "3: socket 3");
bytes = test_cmsgsize(so, &src, &dst, CFG_SO_MAX_SEND_BUFFER,
CFG_SO_MAX_SEND_BUFFER/2);
if (bytes < 0)
err(1, "3: got errno");
close(so);
so = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (so < 0)
err(1, "4: socket");
bytes = test_cmsgsize(so, &src, &dst, CFG_SO_MAX_SEND_BUFFER,
CFG_SO_MAX_SEND_BUFFER/2);
if (bytes < 0)
err(4, "3: got errno");
close(so);
return 0;
}
int
test_cmsgsize(int so, struct in_addr *src, struct in_addr *dst,
unsigned int sndbuf_size, unsigned int payload_size)
{
char cmsgbuf[CMSG_SPACE(sizeof(struct in_addr))];
struct sockaddr_in to;
struct in_addr *source_address;
struct msghdr msg;
struct cmsghdr *cmsg;
struct iovec iov;
if (setsockopt(so, SOL_SOCKET, SO_SNDBUF, &sndbuf_size,
sizeof(sndbuf_size)) < 0)
err(1, "setsockopt send buffer");
memset(&to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_addr = *dst;
to.sin_port = htons(CFG_PORT);
memset(&msg, 0, sizeof(msg));
msg.msg_name = &to;
msg.msg_namelen = sizeof(to);
iov.iov_base = payload;
iov.iov_len = payload_size;
msg.msg_iovlen = 1;
msg.msg_iov = &iov;
memset(cmsgbuf, 0, sizeof(cmsgbuf));
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_SENDSRCADDR;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
source_address = (struct in_addr *)(CMSG_DATA(cmsg));
memcpy(source_address, src, sizeof(struct in_addr));
return sendmsg(so, &msg, 0);
}