博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
查看返回接收到UDP数据包的宿地址结构--(适用于LINUX和BSD系统)
阅读量:4028 次
发布时间:2019-05-24

本文共 4180 字,大约阅读时间需要 13 分钟。

/*
* recvfromto Like recvfrom, but also stores the destination
* IP address. Useful on multihomed hosts.
*
* Should work on Linux and BSD.
*
* Copyright (C) 2002 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
/* Remove this when autoconf can detect this. */
#if defined(IP_PKTINFO) && !defined(HAVE_IP_PKTINFO)
#  define HAVE_IP_PKTINFO 1
#elif defined(IP_RECVDSTADDR) && !defined(HAVE_IP_RECVDSTADDR)
#  define HAVE_IP_RECVDSTADDR
#endif
int recvfromto(int s, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen,
struct sockaddr *to, socklen_t *tolen)
{
struct msghdr msgh;
struct cmsghdr *cmsg;
struct iovec iov;
char cbuf[1024];
int opt, err;
/*
* If from or to are set, they must be big enough
* to store a struct sockaddr_in.
*/
if ((from && (!fromlen || *fromlen < sizeof(struct sockaddr_in))) ||
    (to   && (!tolen   || *tolen   < sizeof(struct sockaddr_in)))) {
errno = EINVAL;
return -1;
}
if (tolen) *tolen = 0;
#ifdef HAVE_IP_PKTINFO
/*
* IP_PKTINFO doesn't provide sin_port so we have to
* retrieve it using getsockname().
*/
if (to) {
struct sockaddr_in si;
socklen_t l = sizeof(si);
((struct sockaddr_in *)to)->sin_family = AF_INET;
((struct sockaddr_in *)to)->sin_port = 0;
l = sizeof(si);
if (getsockname(s, (struct sockaddr *)&si, &l) == 0) {
((struct sockaddr_in *)to)->sin_port = si.sin_port;
((struct sockaddr_in *)to)->sin_addr = si.sin_addr;
}
*tolen = sizeof(struct sockaddr_in);
}
#endif
/* Set MSG_DONTWAIT if O_NONBLOCK was set. */
if (fcntl(s, F_GETFL) & O_NONBLOCK) flags |= MSG_DONTWAIT;
/* Set up iov and msgh structures. */
iov.iov_base = buf;
iov.iov_len  = len;
msgh.msg_control = cbuf;
msgh.msg_controllen = sizeof(cbuf);
msgh.msg_name = from;
msgh.msg_namelen = fromlen ? *fromlen : 0;
msgh.msg_iov  = &iov;
msgh.msg_iovlen = 1;
#ifdef HAVE_IP_PKTINFO
/* Set the IP_PKTINFO option (Linux). */
opt = 1;
setsockopt(s, SOL_IP, IP_PKTINFO, &opt, sizeof(opt));
#endif
#ifdef HAVE_IP_RECVDSTADDR
/* Set the IP_RECVDSTADDR option (BSD). */
opt = 1;
setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt));
#endif
/* Receive one packet. */
err = recvmsg(s, &msgh, flags);
if (fromlen) *fromlen = msgh.msg_namelen;
/* Process auxiliary received data in msgh */
for (cmsg = CMSG_FIRSTHDR(&msgh);
     cmsg != NULL && cmsg->cmsg_len >= sizeof(*cmsg);
     cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
#ifdef HAVE_IP_PKTINFO
if (cmsg->cmsg_level == SOL_IP
    && cmsg->cmsg_type == IP_PKTINFO) {
struct in_pktinfo *i =
(struct in_pktinfo *)CMSG_DATA(cmsg);
if (to) {
((struct sockaddr_in *)to)->sin_addr =
i->ipi_addr;
*tolen = sizeof(struct sockaddr_in);
}
break;
}
#endif
#ifdef HAVE_IP_RECVDSTADDR
if (cmsg->cmsg_level == IPPROTO_IP
    && cmsg->cmsg_type == IP_RECVDSTADDR) {
struct in_addr *i = (struct in_addr *)CMSG_DATA(cmsg);
if (to) {
((struct sockaddr_in *)to)->sin_addr = *i;
*tolen = sizeof(struct sockaddr_in);
}
}
#endif
}
return err;
}
#ifdef STANDALONE
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
/*
* Small test program to test recvfromto
*/
int main(int argc, char **argv)
{
struct sockaddr_in from, to, in;
char buf[1024];
int port = 20000;
int n, s, fl, tl;
if (argc > 1) port = atoi(argv[1]);
s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
in.sin_family = AF_INET;
in.sin_port = htons(port);
in.sin_addr.s_addr = INADDR_ANY;
bind(s, &in, sizeof(in));
while (1) {
fl = tl = sizeof(struct sockaddr_in);
memset(&from, 0, sizeof(from));
memset(&to, 0, sizeof(to));
if ((n = recvfromto(s, buf, sizeof(buf), 0,
    (struct sockaddr *)&from, &fl,
    (struct sockaddr *)&to, &tl)) < 0) {
perror("recvfromto");
break;
}
printf("Received a packet of %d bytes/n", n);
printf("  src ip:port %s:%d/n",
inet_ntoa(from.sin_addr), ntohs(from.sin_port));
printf("  dst ip:port %s:%d/n",
inet_ntoa(to.sin_addr), ntohs(to.sin_port));
}
return 0;
}
#endif /* STANDALONE */

转载地址:http://stpbi.baihongyu.com/

你可能感兴趣的文章
MyEclipse安装aptana插件的问题
查看>>
Android环境搭建_转载
查看>>
JS操作SELECT表单大全,赋默认值,取值,增,删等
查看>>
浅谈BigDecimal类在电子商务中至关重要的地位!
查看>>
输出的数字的格式DecimalFormat的方法用途
查看>>
程序员的激情其实是一种痛苦
查看>>
如何使用spring的作用域:
查看>>
Tomcat DBCP 连接池参数说明
查看>>
hibernate集合映射inverse和cascade详解
查看>>
Android自定义控件系列一:如何测量控件尺寸
查看>>
Android自定义控件系列二:如何自定义属性
查看>>
Android自定义控件系列三:如何画画
查看>>
Android自定义控件系列四:绘制实用型的柱形图和折线图
查看>>
ReactJs入门教程-精华版
查看>>
android 多线程断点续传下载 四 - 仿下载助手
查看>>
Android机型适配之痛[干货分享]
查看>>
Android 4.4后WebView的一些注意事项
查看>>
Mobiscroll的介绍【一款兼容PC和移动设备的滑动插件】
查看>>
Android surfaceview详解(一)
查看>>
关于Android的.so文件所需要知道的
查看>>