我有代码从特定的源IP发送UDP数据包(见下文)。 这对我迄今为止尝试的所有系统都很好用,包括FreeBSD。
不幸的是,在客户端系统上,sendmsg()因“无效参数”错误而失败,我无法弄清楚原因。
FreeBSD版本是相同的,所有系统的测试都使用相同类型的源地址和目的地的IPv4地址。
我做了一个ktrace,但只显示了部分使用的参数(sockaddr_in6),但这些似乎很好。 Valgrind也没有抱怨(在我的系统上)。
我如何找到这个?是否有工具显示sendmsg()调用的完整msghdr结构?
更新:请关注我可以使用的工具或技术。您可以查看代码段,但如果没有完整的代码,它将无法编译。
ssize_t UDPSendWithSourceIP(int fd, void * data, size_t len, const sockaddr_in6 & toAddress)
{
struct sockaddr_in6 dest = toAddress;
// set source address
PIPSocket::Address src = RasServer::Instance()->GetLocalAddress(toIP);
struct msghdr msgh = { };
struct cmsghdr *cmsg;
struct iovec iov = { };
char cbuf[256];
memset(&cbuf, 0, sizeof(cbuf));
// Set up iov and msgh structures
memset(&msgh, 0, sizeof(struct msghdr));
iov.iov_base = data;
iov.iov_len = len;
msgh.msg_iov = &iov;
msgh.msg_iovlen = 1;
msgh.msg_name = (struct sockaddr*)&dest;
// must pass short len when sending to IPv4 address on Solaris 11, OpenBSD and NetBSD
// sizeof(dest) is OK on Linux and FreeBSD
size_t addr_len = sizeof(sockaddr_in);
if (toIP.GetVersion() == 6)
addr_len = sizeof(sockaddr_in6);
msgh.msg_namelen = addr_len;
if ((((struct sockaddr*)&dest)->sa_family == AF_INET6)) {
struct in6_pktinfo *pkt;
msgh.msg_control = cbuf;
msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt));
cmsg = CMSG_FIRSTHDR(&msgh);
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
pkt = (struct in6_pktinfo *) CMSG_DATA(cmsg);
memset(pkt, 0, sizeof(*pkt));
pkt->ipi6_addr = src;
msgh.msg_controllen = cmsg->cmsg_len;
} else
{
#ifdef IP_SENDSRCADDR // FreeBSD
struct in_addr *in;
msgh.msg_control = cbuf;
msgh.msg_controllen = CMSG_SPACE(sizeof(*in));
cmsg = CMSG_FIRSTHDR(&msgh);
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_SENDSRCADDR;
cmsg->cmsg_len = CMSG_LEN(sizeof(*in));
in = (struct in_addr *) CMSG_DATA(cmsg);
*in = src;
#endif // IP_SENDSRCADDR
}
ssize_t bytesSent = sendmsg(fd, &msgh, 0);
if (bytesSent < 0) {
cerr << "RTP\tSend error " << strerror(errno) << endl;
}
return bytesSent;
}
答案 0 :(得分:0)
事实证明,当允许在UDP套接字上使用IP_SENDSRCADDR时,FreeBSD非常挑剔。如果套接字绑定到INADDR_ANY我的代码工作正常。如果套接字绑定到单个IP,则sendmsg()返回EINVAL(无效参数)。