如何正确使用SO_RXQ_OVFL检测Linux套接字上的UDP溢出?

时间:2016-11-29 16:28:13

标签: c linux sockets

我想使用Linux套接字选项SO_RXQ_OVFL来检测UDP溢出。此选项使用辅助消息来报告丢弃的数据包的数量。来自男人:

SO_RXQ_OVFL (since Linux 2.6.33)
Indicates that an unsigned 32-bit value ancillary message (cmsg) should be     
attached to received skbs indicating the number of packets dropped by the   
socket between the last received packet and this received packet.

我的代码没有找到辅助消息。这是我的工作:

启动时,我创建套接字并指定SO_RXQ_OVFL套接字选项:

int dropmonitor_on = 1;
if ( setsockopt(udpSocket, SOL_SOCKET, SO_RXQ_OVFL, &dropmonitor_on, sizeof(dropmonitor_on) ) != 0 )
{
    perror("setsockopt SO_RXQ_OVFL not supported by your Linux Kernel");
}

然后我有一个调用recvmsg的receive函数并查找辅助消息:

struct sockaddr_in src_addr;  // The source address will be assigned to here

struct iovec iov[1];
iov[0].iov_base=ap_rxBuffer;
iov[0].iov_len=a_maxSizeBytes-1;

int cmsg_len = CMSG_SPACE(sizeof(uint32_t));
char cmsg[CMSG_SPACE(sizeof(uint32_t))];
memset(cmsg,0,cmsg_len);

struct msghdr message;
memset(&message,0,sizeof(struct msghdr));
message.msg_name=&src_addr;
message.msg_namelen=sizeof(struct sockaddr_in);
message.msg_iov=iov;
message.msg_iovlen=1;
message.msg_control=cmsg;
message.msg_controllen=cmsg_len;

int receivedBytes = 0;

if ( (receivedBytes = recvmsg( a_socket, &message, 0 )) == SOCKET_ERROR )
{
    closeSocket(a_socket);
    fatal("recvmsg() failed");
}
else 
{
    // Reception successful so interrogate ancillary message to get number of dropped packets

    int udp_packets_dropped = 0;

    struct cmsghdr* p_cmsg;
    p_cmsg = CMSG_FIRSTHDR(&message);
    for (p_cmsg = CMSG_FIRSTHDR(&message); p_cmsg != NULL; p_cmsg = CMSG_NXTHDR(&message, p_cmsg))
    {
        if ((p_cmsg->cmsg_level == SOL_SOCKET) && (p_cmsg->cmsg_type == SO_RXQ_OVFL))
        {
            int* p_udp_packets_dropped = (int *) CMSG_DATA(p_cmsg);
            udp_packets_dropped = *p_udp_packets_dropped;
            cout << "UDP pkts dropped: " << udp_packets_dropped << endl;
            break;
        }
    }
    if (p_cmsg == NULL)
    {
        fatal("Error: p_cmsg == NULL");
    }
}

当我运行代码时,它会因此致命错误而停止:

Error: p_cmsg == NULL

由上面的代码生成,表示没有找到辅助消息。奇怪的是,有时我会得到一个辅助信息,所以也许我已经留下了未初始化的东西。

我仔细检查了代码,但没有看错。我很感激你的帮助。

2 个答案:

答案 0 :(得分:2)

我也有这个问题。

经过一番挖掘后,我在内核源代码中找到了一些提示: msdn

static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk,
                   struct sk_buff *skb)
{
    if (sock_flag(sk, SOCK_RXQ_OVFL) && skb && SOCK_SKB_CB(skb)->dropcount)
        put_cmsg(msg, SOL_SOCKET, SO_RXQ_OVFL,
            sizeof(__u32), &SOCK_SKB_CB(skb)->dropcount);
}

查看&#34; if(...&amp;&amp; SOCK_SKB_CB(skb) - &gt; dropcount)&#34;,我认为如果dropcount为0,则cmsg应为空。你的代码应该是正确的。

答案 1 :(得分:0)

如果使用与recvmsg相同的struct cmsghdr发送sendmsg数据包,请注意,与IP_PKTINFO,IP_TOS或IP6_TOS的cmsghdr控制数据不同,cmsghdr中SO_RXQ_OVFL消息数据的存在将导致EINVAL错误你试着发送它。

如果你没有在recvmsg调用上设置任何其他选项,如IP_PKTINFO等,你可以简单地将msg_controllen设置为零,并将msg_control设置为NULL。如果您依赖IP_PKTINFO来获取绑定到INADDR_ANY的套接字以确保回复上的源IP地址与查询中的目标IP地址匹配,则需要查看msg_control字节数据并仅复制sendmsg支持的cmsg类型