可以使用recvmsg()获取每个传入数据包的IP_TOS字段,也可以只显示为特定套接字设置的IP_TOS值。如果没有,是否有人知道获得每个传入数据包的IP_TOS值的解决方案。我正在使用UDP应用程序,因此无法像应用程序一样查看应用程序层的IP_TOS字段。谢谢。
添加我到目前为止编写的代码,这有助于:
struct msghdr msg;
struct iovec iov[1];
memset(&msg, '\0', sizeof(msg));
msg.msg_iov = iov;
msg.msg_iovlen = 1;
iov[0].iov_base = (char *) &pkt;
iov[0].iov_len = sizeof(pkt);
struct cmsghdr cmsgcmsg[1];
msg.msg_control = cmsgcmsg;
msg.msg_controllen = sizeof(struct cmsghdr);
nRet = recvmsg(udpSocket, &msg, 0);
if (nRet > 0) {
struct cmsghdr *cmsg;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) {
if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_TOS) &&
(cmsg->cmsg_len) ){
int tos = *(uint8_t *)CMSG_DATA(cmsg);
int isecn = ((tos & INET_ECN_MASK) == INET_ECN_CE);
printf("the tos = %i , is ecn = %d \n", tos, isecn);
}
}
答案 0 :(得分:9)
我终于设法解决了这个问题,并在这里添加代码供其他人使用。我希望这对别人有帮助。这个是IP_TTL:
将UDPSocket设置为接收IP_TTL值:
int ttl = 60;
if(setsockopt(udpSocket, IPPROTO_IP, IP_RECVTTL, &ttl,sizeof(ttl))<0)
{
printf("cannot set recvttl\n");
}
else
{
printf("socket set to recvttl\n");
}
以下列方式从每个数据包中检索IP_TTL值(以下程序可以通过iov [0]检索数据消息,下面给出了代码片段):
struct msghdr msg;
struct iovec iov[1];
memset(&msg, '\0', sizeof(msg));
msg.msg_iov = iov;
msg.msg_iovlen = 1;
iov[0].iov_base = (char *) &pkt;
iov[0].iov_len = sizeof(pkt);
int *ttlptr=NULL;
int received_ttl = 0;
int cmsg_size = sizeof(struct cmsghdr)+sizeof(received_ttl); // NOTE: Size of header + size of data
char buf[CMSG_SPACE(sizeof(received_ttl))];
msg.msg_control = buf; // Assign buffer space for control header + header data/value
msg.msg_controllen = sizeof(buf); //just initializing it
nRet = recvmsg(udpSocket, &msg, 0);
if (nRet > 0) {
struct cmsghdr *cmsg;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) {
if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_TTL) &&
(cmsg->cmsg_len) ){
ttlptr = (int *) CMSG_DATA(cmsg);
received_ttl = *ttlptr;
printf("received_ttl = %i and %d \n", ttlptr, received_ttl);
break;
}
}
}
可以通过以下方式发送和获取数据消息:
发件人方:
struct DATA_to_SEND pkt;
struct msghdr msg;
struct iovec iov[1];
memset(&msg, '\0', sizeof(msg));
msg.msg_iov = iov;
msg.msg_iovlen = 1;
iov[0].iov_base = (char *) &pkt;
iov[0].iov_len = sizeof(pkt);
nRet = sendmsg(udpSocket, &msg,0);
接收方(假设DATA_To_SEND有一个名为“seq”的参数):
struct DATA_to_SEND pkt;
seqNum = ((struct DATA_to_SEND *) iov[0].iov_base)->seq;
以下是IP_TOS。 将套接字设置为接收IP_TOS:
unsigned char set = 0x03;
if(setsockopt(udpSocket, IPPROTO_IP, IP_RECVTOS, &set,sizeof(set))<0)
{
printf("cannot set recvtos\n");
}
else
{
printf("socket set to recvtos\n");
并通过以下方式从每个数据包标头中检索IP_TOS值:
struct PC_Pkt pkt;
int *ecnptr;
unsigned char received_ecn;
struct msghdr msg;
struct iovec iov[1];
memset(&msg, '\0', sizeof(msg));
msg.msg_iov = iov;
msg.msg_iovlen = 1;
iov[0].iov_base = (char *) &pkt;
iov[0].iov_len = sizeof(pkt);
int cmsg_size = sizeof(struct cmsghdr)+sizeof(received_ecn);
char buf[CMSG_SPACE(sizeof(received_ecn))];
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
nRet = recvmsg(udpSocket, &msg, 0);
if (nRet > 0) {
struct cmsghdr *cmsg;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
if ((cmsg->cmsg_level == IPPROTO_IP) &&
(cmsg->cmsg_type == IP_TOS) && (cmsg->cmsg_len) ){
ecnptr = (int *) CMSG_DATA(cmsg);
received_ecn = *ecnptr;
int isecn = ((received_ecn & INET_ECN_MASK) == INET_ECN_CE);
printf("received_ecn = %i and %d, is ECN CE marked = %d \n", ecnptr, received_ecn, isecn);
break;
}
}
}
答案 1 :(得分:1)
我创建了一个简单的示例,使用和setsockopt()
发送支持ECN的数据包,并使用recvmsg()
以及getsockopt()
从收到的数据包中获取ECN位。您可以在以下网址找到它:
https://gist.github.com/jirihnidek/95c369996a81be1b854e
使用getsockopt()
可能无法在Linux之外的其他平台上运行,但您可以将其与recv()
和recvfrom()
函数一起使用。
BTW:INET_ECN_MASK
,INET_ECN_CE
等未在in.h
中定义。因此,您需要包含Linux内核头文件(IMHO overhoot),或者您可以(重新)定义自己的常量:
#define INET_ECN_NOT_ECT 0x00 /* ECN was not enabled */
#define INET_ECN_ECT_1 0x01 /* ECN capable packet */
#define INET_ECN_ECT_0 0x02 /* ECN capable packet */
#define INET_ECN_CE 0x03 /* ECN congestion */
#define INET_ECN_MASK 0x03 /* Mask of ECN bits */
答案 2 :(得分:0)
您通常通过getsockopt()/ setsockopt()访问ToS字段,但它似乎是very implementation dependent。 您可能希望在Linux / net / ipv4 / ip_sockglue.c的Linux内核树中查看内核源代码中的do_ip_setsockopt()
导航源的最好朋友是there。