489 lines
10 KiB
C++
489 lines
10 KiB
C++
|
/*
|
||
|
** Command & Conquer Renegade(tm)
|
||
|
** Copyright 2025 Electronic Arts Inc.
|
||
|
**
|
||
|
** This program is free software: you can redistribute it and/or modify
|
||
|
** it under the terms of the GNU General Public License as published by
|
||
|
** the Free Software Foundation, either version 3 of the License, or
|
||
|
** (at your option) any later version.
|
||
|
**
|
||
|
** This program is distributed in the hope that it will be useful,
|
||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
** GNU General Public License for more details.
|
||
|
**
|
||
|
** You should have received a copy of the GNU General Public License
|
||
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
//
|
||
|
// Filename: nicenum.cpp
|
||
|
// Author: Tom Spencer-Smith
|
||
|
// Date: Dec 1999
|
||
|
// Description:
|
||
|
//
|
||
|
|
||
|
#include "nicenum.h"
|
||
|
|
||
|
#include <winsock.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#include "wwdebug.h"
|
||
|
#include "netutil.h"
|
||
|
#include "useroptions.h"
|
||
|
#include "GameSpy_QnR.h"
|
||
|
|
||
|
//
|
||
|
// Class statics
|
||
|
//
|
||
|
ULONG cNicEnum::NicList[];
|
||
|
USHORT cNicEnum::NumNics = 0;
|
||
|
ULONG cNicEnum::GSNicList[];
|
||
|
USHORT cNicEnum::NumGSNics = 0;
|
||
|
|
||
|
//----------------------------------------------------------------------------------
|
||
|
void
|
||
|
cNicEnum::Init
|
||
|
(
|
||
|
void
|
||
|
)
|
||
|
{
|
||
|
WWDEBUG_SAY(("cNicEnum::Init\n"));
|
||
|
|
||
|
WSADATA wsa_data;
|
||
|
int startup_rc = ::WSAStartup(MAKEWORD(1, 1), &wsa_data);
|
||
|
if (startup_rc != 0)
|
||
|
{
|
||
|
WWDEBUG_SAY((" WSAStartup failed!\n"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Retrieve list of nic's
|
||
|
//
|
||
|
ULONG local_addresses[MAX_NICS];
|
||
|
ULONG num_addresses = Enumerate_Nics(local_addresses, MAX_NICS);
|
||
|
WWASSERT(num_addresses <= MAX_NICS);
|
||
|
|
||
|
WWDEBUG_SAY((" Found %d NIC(s)\n", num_addresses));
|
||
|
|
||
|
USHORT index = 0;
|
||
|
USHORT class_1 = 0;
|
||
|
USHORT class_2 = 0;
|
||
|
|
||
|
//
|
||
|
// First, extract the non-internet addressable nicks, ordered on general usage.
|
||
|
//
|
||
|
ULONG lan_addresses[MAX_NICS];
|
||
|
ULONG num_lan_addresses = 0;
|
||
|
|
||
|
//
|
||
|
// First, scan for 10.*.*.* addresses
|
||
|
//
|
||
|
for (index = 0; index < num_addresses; index++)
|
||
|
{
|
||
|
class_1 = (::ntohl(local_addresses[index]) & 0xff000000) >> 24;
|
||
|
|
||
|
if (class_1 == 10)
|
||
|
{
|
||
|
lan_addresses[num_lan_addresses++] = local_addresses[index];
|
||
|
local_addresses[index] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Next, scan for 192.168.*.* addresses
|
||
|
//
|
||
|
for (index = 0; index < num_addresses; index++)
|
||
|
{
|
||
|
class_1 = (::ntohl(local_addresses[index]) & 0xff000000) >> 24;
|
||
|
class_2 = (::ntohl(local_addresses[index]) & 0x00ff0000) >> 16;
|
||
|
|
||
|
if (class_1 == 192 && class_2 == 168)
|
||
|
{
|
||
|
lan_addresses[num_lan_addresses++] = local_addresses[index];
|
||
|
local_addresses[index] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Next, scan for 172.16-31.*.* addresses
|
||
|
//
|
||
|
for (index = 0; index < num_addresses; index++)
|
||
|
{
|
||
|
class_1 = (::ntohl(local_addresses[index]) & 0xff000000) >> 24;
|
||
|
class_2 = (::ntohl(local_addresses[index]) & 0x00ff0000) >> 16;
|
||
|
|
||
|
if (class_1 == 172 && class_2 >= 16 && class_2 <= 31)
|
||
|
{
|
||
|
lan_addresses[num_lan_addresses++] = local_addresses[index];
|
||
|
local_addresses[index] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Finally, scan for 169.254.*.* addresses (IP autoconfiguration)
|
||
|
//
|
||
|
for (index = 0; index < num_addresses; index++)
|
||
|
{
|
||
|
class_1 = (::ntohl(local_addresses[index]) & 0xff000000) >> 24;
|
||
|
class_2 = (::ntohl(local_addresses[index]) & 0x00ff0000) >> 16;
|
||
|
|
||
|
if (class_1 == 169 && class_2 == 254)
|
||
|
{
|
||
|
lan_addresses[num_lan_addresses++] = local_addresses[index];
|
||
|
local_addresses[index] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
WWDEBUG_SAY((" Of which %d are non-internet addressable.\n", num_lan_addresses));
|
||
|
|
||
|
//
|
||
|
// Next, copy the Internet addressable addresses. Weed out localhost and multicast
|
||
|
// addresses.
|
||
|
//
|
||
|
|
||
|
ULONG internet_addresses[MAX_NICS];
|
||
|
ULONG num_internet_addresses = 0;
|
||
|
|
||
|
for (index = 0; index < num_addresses; index++)
|
||
|
{
|
||
|
if (local_addresses[index] != 0)
|
||
|
{
|
||
|
class_1 = (::ntohl(local_addresses[index]) & 0xff000000) >> 24;
|
||
|
|
||
|
if (class_1 != 127 && class_1 != 224)
|
||
|
{
|
||
|
internet_addresses[num_internet_addresses++] = local_addresses[index];
|
||
|
local_addresses[index] = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now build the LAN and GameSpy NIC lists. They contain the same entries.
|
||
|
// The only difference is that the LAN list puts the non-internet addressable
|
||
|
// NIC's first, the GameSpy list puts them last.
|
||
|
//
|
||
|
NumNics = 0;
|
||
|
NumGSNics = 0;
|
||
|
|
||
|
for (index = 0; index < num_lan_addresses; index++)
|
||
|
{
|
||
|
NicList[NumNics++] = lan_addresses[index];
|
||
|
}
|
||
|
|
||
|
for (index = 0; index < num_internet_addresses; index++)
|
||
|
{
|
||
|
NicList[NumNics++] = internet_addresses[index];
|
||
|
}
|
||
|
|
||
|
for (index = 0; index < num_internet_addresses; index++)
|
||
|
{
|
||
|
GSNicList[NumGSNics++] = internet_addresses[index];
|
||
|
}
|
||
|
|
||
|
for (index = 0; index < num_lan_addresses; index++)
|
||
|
{
|
||
|
GSNicList[NumGSNics++] = lan_addresses[index];
|
||
|
}
|
||
|
|
||
|
WWASSERT(NumNics == NumGSNics);
|
||
|
|
||
|
//
|
||
|
// Initialize or update PreferredLanNic if required.
|
||
|
//
|
||
|
bool is_nic_valid = false;
|
||
|
for (index = 0; index < NumNics; index++)
|
||
|
{
|
||
|
if ((ULONG) cUserOptions::PreferredLanNic.Get() == NicList[index])
|
||
|
{
|
||
|
is_nic_valid = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!is_nic_valid)
|
||
|
{
|
||
|
if (NumNics > 0)
|
||
|
{
|
||
|
cUserOptions::PreferredLanNic.Set(NicList[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cUserOptions::PreferredLanNic.Set(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize or update PreferredGameSpyNic if required.
|
||
|
//
|
||
|
is_nic_valid = false;
|
||
|
for (index = 0; index < NumGSNics; index++)
|
||
|
{
|
||
|
if ((ULONG) cUserOptions::PreferredGameSpyNic.Get() == GSNicList[index])
|
||
|
{
|
||
|
is_nic_valid = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!is_nic_valid)
|
||
|
{
|
||
|
if (NumGSNics > 0)
|
||
|
{
|
||
|
cUserOptions::PreferredGameSpyNic.Set(GSNicList[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cUserOptions::PreferredGameSpyNic.Set(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
WWDEBUG_SAY((" PreferredLanNic is %u (%s)\n",
|
||
|
(ULONG) cUserOptions::PreferredLanNic.Get(),
|
||
|
cNetUtil::Address_To_String(cUserOptions::PreferredLanNic.Get())));
|
||
|
|
||
|
WWDEBUG_SAY((" PreferredGameSpyNic is %u (%s)\n",
|
||
|
(ULONG) cUserOptions::PreferredGameSpyNic.Get(),
|
||
|
cNetUtil::Address_To_String(cUserOptions::PreferredGameSpyNic.Get())));
|
||
|
|
||
|
int cleanup_rc = ::WSACleanup();
|
||
|
WWASSERT(cleanup_rc != SOCKET_ERROR);
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
ULONG
|
||
|
cNicEnum::Enumerate_Nics
|
||
|
(
|
||
|
ULONG * addresses,
|
||
|
ULONG max_nics
|
||
|
)
|
||
|
{
|
||
|
WWASSERT(addresses != NULL);
|
||
|
WWASSERT(max_nics > 0);
|
||
|
|
||
|
WWDEBUG_SAY(("cNicEnum::Enumerate_Nics\n"));
|
||
|
|
||
|
//
|
||
|
// Get the local hostname
|
||
|
//
|
||
|
char local_host_name[300];
|
||
|
int gethostname_rc = ::gethostname(local_host_name, sizeof(local_host_name));
|
||
|
WWASSERT(gethostname_rc != SOCKET_ERROR);
|
||
|
|
||
|
//
|
||
|
// Resolve hostname for local adapter addresses.
|
||
|
// This does a DNS lookup (name resolution)
|
||
|
//
|
||
|
LPHOSTENT p_hostent = ::gethostbyname(local_host_name);
|
||
|
if (p_hostent == NULL)
|
||
|
{
|
||
|
DIE;
|
||
|
}
|
||
|
|
||
|
ULONG num_addresses = 0;
|
||
|
while (num_addresses < max_nics && p_hostent->h_addr_list[num_addresses] != NULL)
|
||
|
{
|
||
|
IN_ADDR in_addr;
|
||
|
::memcpy(&in_addr, p_hostent->h_addr_list[num_addresses], sizeof(in_addr));
|
||
|
addresses[num_addresses] = in_addr.s_addr;
|
||
|
WWDEBUG_SAY((" NIC: %s\n", cNetUtil::Address_To_String(addresses[num_addresses])));
|
||
|
num_addresses++;
|
||
|
}
|
||
|
|
||
|
return num_addresses;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
void
|
||
|
cNicEnum::Init
|
||
|
(
|
||
|
void
|
||
|
)
|
||
|
{
|
||
|
WWDEBUG_SAY(("cNicEnum::Init\n"));
|
||
|
|
||
|
WSADATA wsa_data;
|
||
|
int startup_rc = ::WSAStartup(MAKEWORD(1, 1), &wsa_data);
|
||
|
if (startup_rc != 0)
|
||
|
{
|
||
|
WWDEBUG_SAY((" WSAStartup failed!\n"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Retrieve list of nic's
|
||
|
//
|
||
|
ULONG local_addresses[MAX_NICS];
|
||
|
ULONG num_addresses = Enumerate_Nics(local_addresses, MAX_NICS);
|
||
|
WWASSERT(num_addresses <= MAX_NICS);
|
||
|
|
||
|
WWDEBUG_SAY((" Found %d NIC(s)\n", num_addresses));
|
||
|
|
||
|
//
|
||
|
// We are going to discard anything that is internet addressable.
|
||
|
// The non-internet-addressable NIC's are:
|
||
|
// 10.*.*.*
|
||
|
// 192.168.*.*
|
||
|
// 172.16-31.*.*
|
||
|
// We will order these as above to promote the more common choice.
|
||
|
//
|
||
|
|
||
|
USHORT index = 0;
|
||
|
USHORT class_1 = 0;
|
||
|
USHORT class_2 = 0;
|
||
|
NumNics = 0;
|
||
|
NumGSNics = 0;
|
||
|
|
||
|
//
|
||
|
// Create a seperate list of GameSpy compatible NIC's that includes
|
||
|
// local and internet addressable
|
||
|
//
|
||
|
// Don't add the following interfaces to the list.
|
||
|
// 127.* (localhost)
|
||
|
// 224.* (multicast)
|
||
|
//
|
||
|
for (index = 0; index < num_addresses; index++)
|
||
|
{
|
||
|
class_1 = (::ntohl(local_addresses[index]) & 0xff000000) >> 24;
|
||
|
|
||
|
if (class_1 != 127 && class_1 != 224)
|
||
|
{
|
||
|
GSNicList[NumGSNics++] = local_addresses[index];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// First, scan for 10.*.*.* addresses
|
||
|
//
|
||
|
for (index = 0; index < num_addresses; index++)
|
||
|
{
|
||
|
class_1 = (::ntohl(local_addresses[index]) & 0xff000000) >> 24;
|
||
|
|
||
|
if (class_1 == 10)
|
||
|
{
|
||
|
NicList[NumNics++] = local_addresses[index];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Next, scan for 192.168.*.* addresses
|
||
|
//
|
||
|
for (index = 0; index < num_addresses; index++)
|
||
|
{
|
||
|
class_1 = (::ntohl(local_addresses[index]) & 0xff000000) >> 24;
|
||
|
class_2 = (::ntohl(local_addresses[index]) & 0x00ff0000) >> 16;
|
||
|
|
||
|
if (class_1 == 192 && class_2 == 168)
|
||
|
{
|
||
|
NicList[NumNics++] = local_addresses[index];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Finally, scan for 172.16-31.*.* addresses
|
||
|
//
|
||
|
for (index = 0; index < num_addresses; index++)
|
||
|
{
|
||
|
class_1 = (::ntohl(local_addresses[index]) & 0xff000000) >> 24;
|
||
|
class_2 = (::ntohl(local_addresses[index]) & 0x00ff0000) >> 16;
|
||
|
|
||
|
if (class_1 == 172 && class_2 >= 16 && class_2 <= 31)
|
||
|
{
|
||
|
NicList[NumNics++] = local_addresses[index];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
WWDEBUG_SAY((" Of which %d are non-internet addressable.\n", NumNics));
|
||
|
|
||
|
//
|
||
|
// Initialize or update PreferredLanNic if required.
|
||
|
//
|
||
|
bool is_nic_valid = false;
|
||
|
for (index = 0; index < NumNics; index++)
|
||
|
{
|
||
|
if ((ULONG) cUserOptions::PreferredLanNic.Get() == NicList[index])
|
||
|
{
|
||
|
is_nic_valid = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!is_nic_valid)
|
||
|
{
|
||
|
if (NumNics > 0)
|
||
|
{
|
||
|
cUserOptions::PreferredLanNic.Set(NicList[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cUserOptions::PreferredLanNic.Set(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
is_nic_valid = false;
|
||
|
for (index = 0; index < NumGSNics; index++)
|
||
|
{
|
||
|
if ((ULONG) cUserOptions::PreferredGameSpyNic.Get() == GSNicList[index])
|
||
|
{
|
||
|
is_nic_valid = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!is_nic_valid)
|
||
|
{
|
||
|
if (NumGSNics > 0)
|
||
|
{
|
||
|
cUserOptions::PreferredGameSpyNic.Set(GSNicList[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cUserOptions::PreferredGameSpyNic.Set(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
WWDEBUG_SAY((" PreferredLanNic is %u (%s)\n",
|
||
|
(ULONG) cUserOptions::PreferredLanNic.Get(),
|
||
|
cNetUtil::Address_To_String(cUserOptions::PreferredLanNic.Get())));
|
||
|
|
||
|
WWDEBUG_SAY((" PreferredGameSpyNic is %u (%s)\n",
|
||
|
(ULONG) cUserOptions::PreferredGameSpyNic.Get(),
|
||
|
cNetUtil::Address_To_String(cUserOptions::PreferredGameSpyNic.Get())));
|
||
|
|
||
|
int cleanup_rc = ::WSACleanup();
|
||
|
WWASSERT(cleanup_rc != SOCKET_ERROR);
|
||
|
}
|
||
|
*/
|
||
|
|