This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Commando/nicenum.cpp

489 lines
10 KiB
C++
Raw Permalink Normal View History

/*
** 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);
}
*/