IP_RECVDSTADDR undefined
刺猬@http://blog.csdn.net/littlehedgehog
今天写一个unp上面的例子程序,被IP_RECVDSTADDR undefined难倒了,gcc老是报错说该宏未定义,最后还是在老外的一个“开源苹果”网站查到原来linux修改了相关的函数定义,包括cmsghdr及setsockopt都采用了linux系统自己的定义。顺便说一下,这个貌似并不是linux故意另辟蹊径,在solari和bsd上面也是各不相同的。这里把代码贴出来,方便后面的同学。
ssize_t recvmsg_flags(int sockfd, void *buff, size_t nbytes, int *pflags, struct sockaddr *praddr, socklen_t *psocklen, struct in_addr *plocaladdr)
{
ssize_t ret;
struct msghdr msg;
struct cmsghdr *cmsgptr;
struct iovec iov[1];
union{
struct cmsghdr cmsg;
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
}cmsg_un;
msg.msg_name = praddr;
msg.msg_namelen = *psocklen;
iov[0].iov_base = buff;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsg_un.control;
msg.msg_controllen = sizeof(cmsg_un.control);
msg.msg_flags = 0; /*这个flags设置问题*/
if ((ret = recvmsg(sockfd, &msg, 0)) < 0)
{
perror("recvmsg");
return ret;
}
*psocklen = msg.msg_namelen;
*pflags = msg.msg_flags;
if ((msg.msg_controllen < sizeof(struct cmsghdr)) || (msg.msg_flags & MSG_CTRUNC) || !plocaladdr)
{
return ret;
}
for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
{
#if defined(IP_RECVDSTADDR)
if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVDSTADDR)
{
memcpy(plocaladdr, CMSG_DATA(cmsgptr), sizeof(struct in_addr));
}
#elif defined(IP_PKTINFO)
if (cmsgptr->cmsg_level == SOL_IP && cmsgptr->cmsg_type == IP_PKTINFO)
{
struct in_pktinfo *in = (struct in_pktinfo *)CMSG_DATA(cmsgptr);
memcpy(plocaladdr, &(in->ipi_addr), sizeof(struct in_addr));
}
#endif
}
return ret;
}
void echo(int sockfd, const struct sockaddr *pservaddr, socklen_t len, struct FILE *fp)
{
int ret;
int flags = 0;
const int on = 1;
struct in_addr localaddr;
char sendline[MAXLINE], recvline[MAXLINE];
#if defined(IP_RECVDSTADDR)
if (setsockopt(sockfd, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(int)) < 0)
{
perror("setsockopt");
return;
}
#elif defined(IP_PKTINFO)
if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(int)) < 0)
{
perror("setsockopt");
return;
}
#endif
memset(&localaddr, 0x00, sizeof(struct in_addr));
while (fgets(sendline, MAXLINE, fp) != NULL)
{
if (sendto(sockfd, sendline, strlen(sendline), 0x00, pservaddr, len) < 0)
{
perror("sendto");
return;
}
if ((ret = recvmsg_flags(sockfd, recvline, MAXLINE, &flags, pservaddr, &len, &localaddr)) < 0)
{
return;
}
printf("recvmsg %d-byte datagram through %s/n", ret, inet_ntoa(localaddr));
}
}
int main(int argc, char *argv[])
{
int connfd;
struct sockaddr_in servaddr;
if ((connfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(-1);
}
memset(&servaddr, 0x00, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(1988);
servaddr.sin_addr.s_addr = inet_addr("192.168.149.95");
echo(connfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in), stdin);
close(connfd);
return 0;
}