简体   繁体   English

Linux C++ IPv6 UDP 多播发送失败并出现错误 EADDRNOTAVAIL (99) 无法分配请求的地址

[英]Linux C++ IPv6 UDP Multicast sendto fails with errno EADDRNOTAVAIL (99) Cannot assign requested address

I'm trying to send IPv6 UDP multicast messages.我正在尝试发送 IPv6 UDP 多播消息。

Part of test code below shows two parts, one for sending IPv6 multicast messages, the other for sending IPv4 multicast messages.下面的部分测试代码显示了两个部分,一个用于发送 IPv6 组播消息,另一个用于发送 IPv4 组播消息。

Code for IPv4 works fine. IPv4 的代码工作正常。

Code for IPv6 always fails in sendto, returning with EADDRNOTAVAIL (99) Cannot assign requested address.用于 IPv6 的代码在 sendto 中总是失败,返回 EADDRNOTAVAIL (99) 无法分配请求的地址。

... ...

  if (ipV6Select)
  {
    // Create IPv6 DGRAM Socket
    int sock = socket(AF_INET6, SOCK_DGRAM, 0);
    if (sock < 0)
      throw OIP::OipException(OIP_SOCK_ACTION_FAILED("Cannot set socket option IPV6 socket, socket function failed with retVal " <<
                                                      sock << " (errno=" << strerror(errno) << " (" << errno << ")."));

    // Register multicast interface.
    int ifIdx{static_cast<int>(if_nametoindex("svlan1_260"))};
    std::cout << "Temp:ifIdx=" << ifIdx << std::endl;
    std::lock_guard<std::mutex> lockGuard(setSockoptMutex);
    retVal = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifIdx, sizeof(ifIdx));
    if (retVal < 0)
       throw OIP::OipException(OIP_SOCK_ACTION_FAILED("Cannot set socket option IPV6_MULTICAST_IF, setsockopt function failed with retVal " <<
                                                      retVal << " (errno=" << strerror(errno) << " (" << errno << ")."));

    // Create IPv6 address.
    struct sockaddr_in6 sockAddrIpV6{};
    sockAddrIpV6.sin6_family = {AF_INET6};
    sockAddrIpV6.sin6_port = {htons(2020)};
    sockAddrIpV6.sin6_scope_id = {static_cast<uint32_t>(ifIdx)};
    inet_pton(AF_INET6, "FF02:0000:0000:0000:0000:0000:0000:00FE", &sockAddrIpV6.sin6_addr);

    std::cout << "IPV6 Send: family=" << sockAddrIpV6.sin6_family << ", sin6_port=" << sockAddrIpV6.sin6_port  << ", sin6_scope_id=" << sockAddrIpV6.sin6_scope_id
              << ", addr=FF02:0000:0000:0000:0000:0000:0000:00FE" << std::endl;


    // Send message to socket.
    retVal = sendto(sock,
                    sendMsgCharBufVect.data(),
                    sendMsgCharBufVect.size(),
                    0,
                    reinterpret_cast<struct sockaddr*>(&sockAddrIpV6),
                    sizeof(struct sockaddr_in6));
    if (retVal < 0)
      throw OIP::OipException(OIP_SOCK_ACTION_FAILED("IPV6 Socket send data (socket sendto function) failed with retVal " << retVal <<
                                                      " (errno=" << strerror(errno) << " (" << errno << "))."));
  }

  // Send IPV4 multicast message.
  else
  {
    // Create IPv4 DGRAM Socket
    std::string ipV4Str{"239.0.0.254"};
    int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock < 0)
      throw OIP::OipException(OIP_SOCK_ACTION_FAILED("Cannot set socket option IPV4 socket, socket function failed with retVal " <<
                                                      sock << " (errno=" << strerror(errno) << " (" << errno << ")."));

    // Register multicast interface.
    struct ip_mreqn mreqn{};
    inet_aton(ipV4Str.c_str(), &mreqn.imr_multiaddr);
    mreqn.imr_ifindex        = {static_cast<int>(if_nametoindex("svlan1_260"))};
    retVal = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn));
    if (retVal < 0)
       throw OIP::OipException(OIP_SOCK_ACTION_FAILED("Cannot set socket option IP_MULTICAST_IF, setsockopt function failed with retVal " <<
                                                      retVal << " (errno=" << strerror(errno) << " (" << errno << ")."));

    // Create IPv4 address.
     struct sockaddr_in sockAddrIpV4{};
     sockAddrIpV4.sin_family = {AF_INET};
     sockAddrIpV4.sin_port = {htons(2020)};
     inet_aton(ipV4Str.c_str(), &sockAddrIpV4.sin_addr);

     std::cout << "IPV4 Send: family=" << sockAddrIpV4.sin_family << ", sin_port=" << sockAddrIpV4.sin_port  << ", addr=" << std::hex << sockAddrIpV4.sin_addr.s_addr<< std::dec <<std::endl;

     // Send message to socket.
     retVal = sendto(sock,
                     sendMsgCharBufVect.data(),
                     sendMsgCharBufVect.size(),
                     0,
                     reinterpret_cast<struct sockaddr*>(&sockAddrIpV4),
                     sizeof(struct sockaddr_in));
     if (retVal < 0)
       throw OIP::OipException(OIP_SOCK_ACTION_FAILED("IPV4 Socket send data (socket sendto function) failed with retVal " << retVal <<
                                                      " (errno=" << strerror(errno) << " (" << errno << "))."));
  }

... ...

tcpdump IPv4 shows outgoing multicast message with requested address: tcpdump IPv4 显示带有请求地址的传出多播消息:

2020-04-02 23:30:19.384892 00:60:1d:7d:08:07 (oui Unknown) > 01:00:5e:00:00:fe (oui Unknown), ethertype 802.1Q (0x8100), length 90: vlan 260, p 0, ethertype IPv4, (tos 0x0, ttl 1, id 54916, offset 0, flags [none], proto UDP (17), length 72)
    100.5.81.1.38790 > 239.0.0.254.2020: UDP, length 44
        0x0000:  0100 5e00 00fe 0060 1d7d 0807 8100 0104
        0x0010:  0800 4500 0048 d684 0000 0111 3e1c 6405
        0x0020:  5101 ef00 00fe 9786 07e4 0034 a54a 4479

tcpdump for IPV6 only shows automatic generated IPV6 multicast messages: IPV6 的 tcpdump 仅显示自动生成的 IPV6 多播消息:

2020-04-02 22:48:19.569203 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 174: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 0000 0016 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 0074 0001 0000 0000 0000
        0x0020:  0000 0000 0000 0000 0000 ff02 0000 0000
2020-04-02 22:48:20.049156 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 174: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 0000 0016 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 0074 0001 0000 0000 0000
        0x0020:  0000 0000 0000 0000 0000 ff02 0000 0000
2020-04-02 22:48:20.329171 00:60:1d:7d:08:07 (oui Unknown) > 33:33:ff:7d:08:07 (oui Unknown), ethertype 802.1Q (0x8100), length 90: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 ff7d 0807 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 0020 3aff 0000 0000 0000
        0x0020:  0000 0000 0000 0000 0000 ff02 0000 0000
root@MEC2-81-1-STDBY:/lib# 2020-04-02 22:48:21.359289 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 134: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 0000 0016 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 004c 0001 fe80 0000 0000
        0x0020:  0000 0260 1dff fe7d 0807 ff02 0000 0000
2020-04-02 22:48:21.389154 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 94: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 0000 0016 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 0024 0001 fe80 0000 0000
        0x0020:  0000 0260 1dff fe7d 0807 ff02 0000 0000
2020-04-02 22:48:22.159152 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 134: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 0000 0016 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 004c 0001 fe80 0000 0000
        0x0020:  0000 0260 1dff fe7d 0807 ff02 0000 0000
2020-04-02 22:48:22.319152 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 94: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 0000 0016 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 0024 0001 fe80 0000 0000
        0x0020:  0000 0260 1dff fe7d 0807 ff02 0000 0000

Network interface: The used network interface is a VLAN interface svlan1_260 with VLAN ID 260, created on physical network interface eth2.网络接口:使用的网络接口是 VLAN ID 为 260 的 VLAN 接口 svlan1_260,在物理网络接口 eth2 上创建。

eth2      Link encap:Ethernet  HWaddr 00:00:00:00:81:01  
          UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1513  Metric:1
          RX packets:3684437 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3410666 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:572562185 (546.0 MiB)  TX bytes:109620349 (104.5 MiB)
          Interrupt:32
svlan1_260 Link encap:Ethernet  HWaddr 00:60:1d:7d:08:07  
          inet addr:100.5.81.1  Bcast:100.5.255.255  Mask:255.255.0.0
          inet6 addr: fe80::260:1dff:fe7d:807/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:709 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:85982 (83.9 KiB)

Questions:问题:

Is there any idea, what is going wrong for IPv6?有什么想法,IPv6出了什么问题?

May be wrong address, although I tried several?可能是地址不对,虽然我试了几个?

Any missing socket configuration?任何缺少的套接字配置?

Any system settings, not correctly set?任何系统设置,没有正确设置?

thanks谢谢

Found reason of the problem after much debugging.经过多次调试,找到了问题的原因。

The T-bit flag (Dynamically assigned multicast address), mentioned in comments above for sure should be correctly set.上面评论中提到的 T 位标志(动态分配的多播地址)肯定应该正确设置。 But sending also works, if T-bit is set to 0 (Well-known multicast address).但是,如果 T 位设置为 0(众所周知的多播地址),发送也可以。

There's following reason for the failing sendto call. sendto 调用失败的原因如下。 Short time before creating the socket and sending the message, on the respective network interface the MAC address has been changed via ioctl SIOCSIFHWADDR.在创建套接字和发送消息之前很短的时间,在相应的网络接口上,MAC 地址已通过 ioctl SIOCsIFHWADDR 更改。 In order to get the local IPv6 address automatically updated with the new MAC address the network interface was set down and up again via ioctl SIOCSIFFLAGS.为了使用新的 MAC 地址自动更新本地 IPv6 地址,网络接口通过 ioctl SIOCSIFFLAGS 重新设置和重新设置。

When socket was created and message sent, link up had not been finished.创建套接字并发送消息时,链接尚未完成。 Therefore the sendto failed.因此 sendto 失败。 The IPv6 messages in the tcpdump above belong to the network interface start up.上面 tcpdump 中的 IPv6 消息属于网络接口启动。

When waiting some seconds after network interface up, everything works fine.在网络接口启动后等待几秒钟,一切正常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 Linux 上的 C/C++ 中使用 ipv6 udp 套接字进行多播? - How to multicast with ipv6 udp socket in C/C++ on linux? IPV6绑定失败错误:无法分配请求的地址 - IPV6 Binding Failure Error: Cannot assign requested address Linux上的IPv6原始udp套接字sendto()“无效参数”错误 - sendto() “invalid argument” error with IPv6 raw udp socket on linux 通过sendto()进行的UDP广播在OS / X上返回“无法分配请求的地址”,但不返回Linux - UDP broadcast via sendto() returns “Can't assign requested address” on OS/X but not Linux 由于sin6_port的值,sendto在Linux的UDP原始套接字ipv6上返回带有无效参数的返回值? - sendto returns with Invalid Argument on UDP Raw Socket ipv6 in Linux due to sin6_port value? Python 3-无法接收IPv6数据包(UDP-Linux) - Python 3 - Cannot receive IPv6 packets (UDP - linux) TCP sendto(C ++)在Linux上失败,但在OSX上失败。 Errno:EINVAL 22无效参数 - TCP sendto (C++) fails on Linux but not OSX. Errno: EINVAL 22 Invalid argument connect:无法在linux中分配请求的地址 - connect: Cannot assign requested address in linux Linux UDP本地发送到“错误地址”错误 - Linux UDP sendto “Bad address” error in local 接收未分配地址以与Linux / C / IPv4接口的最广泛的UDP - Receive UDP broadast with no address assigned to interface with Linux/C/IPv4
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM