(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
This commit is contained in:
tron 2006-06-21 19:39:23 +00:00
parent c96daf6230
commit 47a1e50406
4 changed files with 70 additions and 69 deletions

118
network.c
View File

@ -289,7 +289,7 @@ char *GetNetworkErrorMsg(char *buf, NetworkErrorCode err)
// 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 @@ static void NetworkFindIPs(void)
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 @@ static void NetworkFindIPs(void)
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 @@ static void NetworkFindIPs(void)
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));
}
}

View File

@ -157,7 +157,7 @@ VARDEF uint32 _frame_counter_max; // To where we may go with our clients
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

View File

@ -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 @@ typedef struct ifreq IFREQ;
#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())

View File

@ -472,26 +472,18 @@ static void NetworkUDPBroadCast(SOCKET udp)
{
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);