# HG changeset patch # User tron # Date 1150918763 0 # Node ID 9a5166f890ee0201d68e436c1b687b0afc48453d # Parent 9db77ebd952b704af7ad850b327157c579cc77e0 (svn r5330) -Backport: r5292, r5293, r5295, r5297 -Fix: When using SIOCGIFCONF to detect network interfaces accomodate for the fact that struct sockaddr doesn't have fixed size in all implementations -Fix: Not all network interfaces are capable of broadcasting. Don't record those which aren't -Fix: Not all networks are /24. Generate proper broadcast addresses for non-/24 nets diff -r 9db77ebd952b -r 9a5166f890ee network.c --- a/network.c Wed Jun 21 19:35:50 2006 +0000 +++ b/network.c Wed Jun 21 19:39:23 2006 +0000 @@ -289,7 +289,7 @@ // Find all IP-aliases for this host static void NetworkFindIPs(void) { - int i, last; + int i; #if defined(BEOS_NET_SERVER) /* doesn't have neither getifaddrs or net/if.h */ /* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */ @@ -311,7 +311,7 @@ i = 0; // If something fails, make sure the list is empty - _network_ip_list[0] = 0; + _broadcast_list[0] = 0; if (sock < 0) { DEBUG(net, 0)("Error creating socket!"); @@ -330,15 +330,22 @@ uint32 n, fields, read; uint8 i1, i2, i3, i4, j1, j2, j3, j4; struct in_addr inaddr; + uint32 ip; + uint32 netmask; + fields = sscanf(*output, "%u: %hhu.%hhu.%hhu.%hhu, netmask %hhu.%hhu.%hhu.%hhu%n", &n, &i1,&i2,&i3,&i4, &j1,&j2,&j3,&j4, &read); read += 1; if (fields != 9) { break; } - inaddr.s_addr = htonl((uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4); - if (inaddr.s_addr != 0) { - _network_ip_list[i] = inaddr.s_addr; + + ip = (uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4; + netmask = (uint32)j1 << 24 | (uint32)j2 << 16 | (uint32)j3 << 8 | (uint32)j4; + + if (ip != INADDR_LOOPBACK && ip != INADDR_ANY) { + inaddr.s_addr = htonl(ip | ~netmask); + _broadcast_list[i] = inaddr.s_addr; i++; } if (read < 0) { @@ -355,94 +362,99 @@ struct ifaddrs *ifap, *ifa; // If something fails, make sure the list is empty - _network_ip_list[0] = 0; + _broadcast_list[0] = 0; if (getifaddrs(&ifap) != 0) return; i = 0; for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { - if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET) - continue; - _network_ip_list[i] = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; + if (!(ifa->ifa_flags & IFF_BROADCAST)) continue; + if (ifa->ifa_broadaddr == NULL) continue; + if (ifa->ifa_broadaddr->sa_family != AF_INET) continue; + _broadcast_list[i] = ((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr; i++; } freeifaddrs(ifap); #else /* not HAVE_GETIFADDRS */ - - unsigned long len = 0; SOCKET sock; - IFREQ ifo[MAX_INTERFACES]; - -#ifndef WIN32 - struct ifconf if_conf; +#ifdef WIN32 + DWORD len = 0; + INTERFACE_INFO ifo[MAX_INTERFACES]; + uint j; +#else + char buf[4 * 1024]; // Arbitrary buffer size + struct ifconf ifconf; + const char* buf_end; + const char* p; #endif // If something fails, make sure the list is empty - _network_ip_list[0] = 0; + _broadcast_list[0] = 0; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) return; #ifdef WIN32 - // On windows it is easy memset(&ifo[0], 0, sizeof(ifo)); if ((WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0, &ifo[0], sizeof(ifo), &len, NULL, NULL)) != 0) { closesocket(sock); return; } + + i = 0; + for (j = 0; j < len / sizeof(*ifo); j++) { + if (ifo[j].iiFlags & IFF_LOOPBACK) continue; + if (!(ifo[j].iiFlags & IFF_BROADCAST)) continue; + /* iiBroadcast is unusable, because it always seems to be set to + * 255.255.255.255. + */ + _broadcast_list[i++] = + ifo[j].iiAddress.AddressIn.sin_addr.s_addr | + ~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr; + } #else - // On linux a bit harder - if_conf.ifc_len = (sizeof (struct ifreq)) * MAX_INTERFACES; - if_conf.ifc_buf = (char *)&ifo[0]; - if ((ioctl(sock, SIOCGIFCONF, &if_conf)) == -1) { + ifconf.ifc_len = sizeof(buf); + ifconf.ifc_buf = buf; + if (ioctl(sock, SIOCGIFCONF, &ifconf) == -1) { closesocket(sock); return; } - len = if_conf.ifc_len; -#endif /* WIN32 */ - // Now walk through all IPs and list them - for (i = 0; i < (int)(len / sizeof(IFREQ)); i++) { - // Request IP for this interface -#ifdef WIN32 - _network_ip_list[i] = *(&ifo[i].iiAddress.AddressIn.sin_addr.s_addr); -#else - if ((ioctl(sock, SIOCGIFADDR, &ifo[i])) != 0) { - closesocket(sock); - return; + i = 0; + buf_end = buf + ifconf.ifc_len; + for (p = buf; p < buf_end;) { + const struct ifreq* req = (const struct ifreq*)p; + + if (req->ifr_addr.sa_family == AF_INET) { + struct ifreq r; + + strncpy(r.ifr_name, req->ifr_name, lengthof(r.ifr_name)); + if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 && + r.ifr_flags & IFF_BROADCAST && + ioctl(sock, SIOCGIFBRDADDR, &r) != -1) { + _broadcast_list[i++] = + ((struct sockaddr_in*)&r.ifr_broadaddr)->sin_addr.s_addr; + } } - _network_ip_list[i] = ((struct sockaddr_in *)&ifo[i].ifr_addr)->sin_addr.s_addr; + p += sizeof(struct ifreq); +#ifdef AF_LINK + p += req->ifr_addr.sa_len - sizeof(struct sockaddr); #endif } +#endif closesocket(sock); - #endif /* not HAVE_GETIFADDRS */ - _network_ip_list[i] = 0; - last = i - 1; + _broadcast_list[i] = 0; - DEBUG(net, 3)("Detected IPs:"); + DEBUG(net, 3)("Detected broadcast addresses:"); // Now display to the debug all the detected ips - i = 0; - while (_network_ip_list[i] != 0) { - // Also check for non-used ips (127.0.0.1) - if (_network_ip_list[i] == inet_addr("127.0.0.1")) { - // If there is an ip after thisone, put him in here - if (last > i) - _network_ip_list[i] = _network_ip_list[last]; - // Clear the last ip - _network_ip_list[last] = 0; - // And we have 1 ip less - last--; - continue; - } - - DEBUG(net, 3)(" %d) %s", i, inet_ntoa(*(struct in_addr *)&_network_ip_list[i]));//inet_ntoa(inaddr)); - i++; + for (i = 0; _broadcast_list[i] != 0; i++) { + DEBUG(net, 3)(" %d) %s", i, inet_ntoa(*(struct in_addr *)&_broadcast_list[i]));//inet_ntoa(inaddr)); } } diff -r 9db77ebd952b -r 9a5166f890ee network.h --- a/network.h Wed Jun 21 19:35:50 2006 +0000 +++ b/network.h Wed Jun 21 19:39:23 2006 +0000 @@ -157,7 +157,7 @@ VARDEF uint32 _last_sync_frame; // Used in the server to store the last time a sync packet was sent to clients. // networking settings -VARDEF uint32 _network_ip_list[MAX_INTERFACES + 1]; // Network IPs +VARDEF uint32 _broadcast_list[MAX_INTERFACES + 1]; VARDEF uint _network_server_port; /* We use bind_ip and bind_ip_host, where bind_ip_host is the readable form of diff -r 9db77ebd952b -r 9a5166f890ee network_core.h --- a/network_core.h Wed Jun 21 19:35:50 2006 +0000 +++ b/network_core.h Wed Jun 21 19:39:23 2006 +0000 @@ -32,14 +32,12 @@ #define EWOULDBLOCK WSAEWOULDBLOCK // Windows has some different names for some types.. typedef unsigned long in_addr_t; -typedef INTERFACE_INFO IFREQ; #endif // WIN32 // UNIX stuff #if defined(UNIX) # define SOCKET int # define INVALID_SOCKET -1 -typedef struct ifreq IFREQ; # if !defined(__MORPHOS__) && !defined(__AMIGA__) # define ioctlsocket ioctl # if !defined(BEOS_NET_SERVER) @@ -100,7 +98,6 @@ #if defined(__OS2__) # define SOCKET int # define INVALID_SOCKET -1 -typedef struct ifreq IFREQ; # define ioctlsocket ioctl # define closesocket close # define GET_LAST_ERROR() (sock_errno()) diff -r 9db77ebd952b -r 9a5166f890ee network_udp.c --- a/network_udp.c Wed Jun 21 19:35:50 2006 +0000 +++ b/network_udp.c Wed Jun 21 19:39:23 2006 +0000 @@ -472,26 +472,18 @@ { int i; struct sockaddr_in out_addr; - byte *bcptr; - uint32 bcaddr; Packet *p; // Init the packet p = NetworkSend_Init(PACKET_UDP_CLIENT_FIND_SERVER); - // Go through all the ips on this pc i = 0; - while (_network_ip_list[i] != 0) { - bcaddr = _network_ip_list[i]; - bcptr = (byte *)&bcaddr; - // Make the address a broadcast address - bcptr[3] = 255; - - DEBUG(net, 6)("[NET][UDP] Broadcasting to %s", inet_ntoa(*(struct in_addr *)&bcaddr)); - + while (_broadcast_list[i] != 0) { out_addr.sin_family = AF_INET; out_addr.sin_port = htons(_network_server_port); - out_addr.sin_addr.s_addr = bcaddr; + out_addr.sin_addr.s_addr = _broadcast_list[i]; + + DEBUG(net, 6)("[NET][UDP] Broadcasting to %s", inet_ntoa(out_addr.sin_addr)); NetworkSendUDP_Packet(udp, p, &out_addr);