Difference between INADDR_ANY on Linux and Windows Socket Programming

My Winsock Delphi must listen on all network interfaces for UDP / IP multicast. He listened fine until I tried it on another PC with priority queues for network adapters.

Then I began to research the problem and found in some forums that INADDR_ANY (or 0.0.0.0 ) has different meanings on Windows and Linux:

Could you confirm or deny this?

How to listen really on all interfaces?

Here is a small snippet of my code:

 TMulticastListener = class(TThread) private mreq: ip_mreq; ............ end; constructor TMulticastListener.Create; var err: Integer; wData: WsaData; reuse: Integer; begin inherited Create(true); err := WSAStartup(MAKEWORD(2, 2), wData); if err = SOCKET_ERROR then begin // Tell the user that we could not find a usable Winsock DLL perror('WSAStartup'); Exit; end; // create what looks like an ordinary UDP socket fd := socket(AF_INET, SOCK_DGRAM, 0); if fd = INVALID_SOCKET then begin perror('socket'); Exit; end; reuse := 1; // allow multiple sockets to use the same PORT number if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, Pointer(@reuse), SizeOf(reuse)) < 0) then begin perror('Reusing ADDR failed'); Exit; end; // set up destination address FillChar(addr, sizeof(addr), 0); addr.sin_family := AF_INET; addr.sin_addr.s_addr := htonl(INADDR_ANY); // NB: differs from sender addr.sin_port := htons(HELLO_PORT); // bind to receive address if (bind(fd, addr, sizeof(addr)) < 0) then begin perror('bind'); Exit; end; // use setsockopt() to request that the kernel join a multicast group mreq.imr_multiaddr.s_addr := inet_addr(HELLO_GROUP); mreq.imr_interface.s_addr := htonl(INADDR_ANY); //inet_addr('0.0.0.0'); if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, @mreq, sizeof(mreq)) < 0) then begin perror('setsockopt'); Exit; end; end; 
+5
source share
2 answers

Windows and Linux actually behave the same with respect to using INADDR_ANY . The confusion here is that the two links you provide are used in different contexts.

When using the bind function to bind to an address / port, specifying INADDR_ANY means that the socket will be able to receive packets on this port from any interface. However, it does not configure anything regarding multicast.

In the context of calling IP_ADD_MEMBERSHIP on setsockopt setting the interface to INADDR_ANY will cause the system to join this multicast group over the default network interface.

The Linux link you provided is for bind , and the Windows link is for setsockopt and IP_ADD_MEMBERSHIP .

If you want to join the multicast group on all interfaces, you need to get a list of interfaces in the system and join each of them. On Windows, the GetAdaptersAddresses() function GetAdaptersAddresses() provide you with a list of interfaces. On Linux, use the getifaddrs() function.

Here is an example using the GetAdaptersAddresses() function in C:

 struct iflist { char name[50]; struct sockaddr_in sin; int isloopback; int ismulti; int ifidx; }; void getiflist(struct iflist *list, int *len) { IP_ADAPTER_ADDRESSES *head, *curr; IP_ADAPTER_UNICAST_ADDRESS *uni; char *buf; int buflen, err, i; buflen = 100000; buf = calloc(buflen, 1); head = (IP_ADAPTER_ADDRESSES *)buf; if ((err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, head, &buflen)) != ERROR_SUCCESS) { char errbuf[300]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, errbuf, sizeof(errbuf), NULL); printf("GetAdaptersAddresses failed: (%d) %s", err, errbuf); free(buf); return; } for (*len = 0, curr = head; curr; curr = curr->Next) { if (curr->IfType == IF_TYPE_TUNNEL) continue; for (uni = curr->FirstUnicastAddress; uni; uni = uni->Next) { if (curr->OperStatus == IfOperStatusUp) { memset(&list[*len], 0, sizeof(struct iflist)); strncpy(list[*len].name, (char *)curr->AdapterName, sizeof(list[i].name) - 1); memcpy(&list[*len].sin, uni->Address.lpSockaddr, uni->Address.iSockaddrLength); list[*len].isloopback = (curr->IfType == IF_TYPE_SOFTWARE_LOOPBACK); list[*len].ismulti = ((curr->Flags & IP_ADAPTER_NO_MULTICAST) == 0); if (uni->Address.lpSockaddr->sa_family == AF_INET6) { list[*len].ifidx = curr->Ipv6IfIndex; } else { list[*len].ifidx = curr->IfIndex; } (*len)++; } } } free(buf); } 
+3
source

your source does not completely notice the fact that the Internet protocol itself does not know anything about “ports” and “interfaces”, the aforementioned operator (“listen on all interfaces”) does not even make sense, it is completely composed , but packets for broadcast addresses are usually are routed to several interfaces, more on this below:

0.0.0.0 is a special reserved IPv4 address, called a "network identifier" - in fact, IPv4 addresses that end with 0 are usually reserved - it is usually not used except for broadcast and network . Operating systems typically reserve 0.0.0.0 for broadcasts over a single transport protocol.

Now: these broadcast addresses always receive broadcasts for one transport protocol via the default route , which can point to several (or all) network interfaces. What you probably read is something completely different: Multicast is another worm out of worms, it can send singular packets to several assigned receivers. Microsoft Windows has a default multicast route, and for Linux to work, you usually need to set up multicast (AFAIK) —but you don't want to.

Conclusion : for your purposes, 0.0.0.0 is identical in Windows and Linux - its broadcast address for the selected transport protocol, there is no difference

0
source

Source: https://habr.com/ru/post/1262922/


All Articles