代码之家  ›  专栏  ›  技术社区  ›  Gene Vincent

某些FreeBSD系统上sendmsg()的参数错误无效

  •  -1
  • Gene Vincent  · 技术社区  · 8 年前

    我有代码从特定的源IP发送UDP数据包(见下文)。

    不幸的是,在客户端系统上,sendmsg()失败,出现“无效参数”错误,我无法找出原因。

    FreeBSD版本是相同的,所有系统上的测试都使用相同类型的IPv4地址作为源和目标。

    我做了一个ktrace,但只显示了使用的部分参数(6中的sockaddr\u),但这些看起来很好。Valgrind也没有抱怨(在我的系统上)。

    更新: 请关注我可以使用的工具或技术。您可以查看代码段,但如果没有周围的代码,它将无法编译。

    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;
    }
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   Gene Vincent    8 年前

    事实证明,当FreeBSD允许在UDP套接字上使用IP_sendscrcadr时,它非常挑剔。如果套接字绑定到INADDR\u,那么我的代码可以正常工作。如果套接字绑定到单个IP,则sendmsg()返回EINVAL(无效参数)。