[英]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.