(svn r5330) -Backport: r5292, r5293, r5295, r5297 0.4
authortron
Wed, 21 Jun 2006 19:39:23 +0000
branch0.4
changeset 10042 9a5166f890ee
parent 10041 9db77ebd952b
child 10043 131a51cb2eab
(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
network.c
network.h
network_core.h
network_udp.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));
 	}
 }
 
--- 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
--- 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())
--- 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);