678 lines
No EOL
20 KiB
C++
678 lines
No EOL
20 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: netutil.cpp
|
|
// Project: wwnet
|
|
// Author: Tom Spencer-Smith
|
|
// Date: June 1998
|
|
// Description:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#include "netutil.h" // I WANNA BE FIRST!
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "miscutil.h"
|
|
#include "mathutil.h"
|
|
#include "singlepl.h"
|
|
#include "wwpacket.h"
|
|
#include "wwdebug.h"
|
|
#include "ffactory.h"
|
|
#include "ini.h"
|
|
#include "systimer.h"
|
|
#include "fromaddress.h"
|
|
|
|
//
|
|
// class statics
|
|
//
|
|
//const WORD cNetUtil::WS_VERSION_REQD = MAKEWORD(1, 1); // Winsock 1.1
|
|
//USHORT cNetUtil::HeaderBytes;
|
|
//USHORT cNetUtil::MaxPacketAppDataSize = MAX_LAN_PACKET_APP_DATA_SIZE;
|
|
UINT cNetUtil::DefaultResendTimeoutMs = 200; // used for singleplayer
|
|
bool cNetUtil::IsInternet = false;
|
|
|
|
static const int INVALID_VALUE = -999;
|
|
|
|
const USHORT cNetUtil::NETSTATS_SAMPLE_TIME_MS = 2000;
|
|
const USHORT cNetUtil::KEEPALIVE_TIMEOUT_MS = 2000;
|
|
const USHORT cNetUtil::MAX_RESENDS = 50;
|
|
const USHORT cNetUtil::MULTI_SENDS = 10;
|
|
const USHORT cNetUtil::RESEND_TIMEOUT_LAN_MS = 300;
|
|
const USHORT cNetUtil::RESEND_TIMEOUT_INTERNET_MS = 500;
|
|
const ULONG cNetUtil::CLIENT_CONNECTION_LOSS_TIMEOUT = 15000; // Milliseconds til client gives up on server
|
|
const ULONG cNetUtil::SERVER_CONNECTION_LOSS_TIMEOUT = 15000; // Milliseconds til server gives up on client
|
|
const ULONG cNetUtil::SERVER_CONNECTION_LOSS_TIMEOUT_LOADING_ALLOWANCE = 45000; // Milliseconds extra allowed til server gives up on loading client.
|
|
|
|
|
|
//int cNetUtil::DefaultMultiSends = INVALID_VALUE;
|
|
//int cNetUtil::DefaultMaxResends = INVALID_VALUE;
|
|
//int cNetUtil::DefaultKeepaliveTimeoutMs = INVALID_VALUE;
|
|
//int cNetUtil::DesiredSendBufferSizeBytes = INVALID_VALUE;
|
|
//int cNetUtil::DesiredReceiveBufferSizeBytes = INVALID_VALUE;
|
|
//int cNetUtil::DefaultServerPort = INVALID_VALUE;
|
|
//int cNetUtil::MaxReceiveTimeMs = INVALID_VALUE;
|
|
|
|
//float cNetUtil::PriorityToleranceDownwards = INVALID_VALUE;
|
|
//float cNetUtil::PriorityToleranceUpwards = INVALID_VALUE;
|
|
//float cNetUtil::MaxTPCorrectionDownwards = INVALID_VALUE;
|
|
//float cNetUtil::MaxTPCorrectionUpwards = INVALID_VALUE;
|
|
//float cNetUtil::PriorityNoiseFactor = INVALID_VALUE;
|
|
//float cNetUtil::InitialThresholdPriority = INVALID_VALUE;
|
|
//float cNetUtil::PriorityGrowthPerSecond = INVALID_VALUE;
|
|
|
|
char cNetUtil::WorkingAddressBuffer[] = "";
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Macro
|
|
//
|
|
#define ADD_CASE(exp) case exp: ::sprintf(error_msg, #exp); break;
|
|
|
|
void cNetUtil::Wsa_Error(LPCSTR sFile, unsigned uLine)
|
|
{
|
|
WWDEBUG_SAY(("* %s:%d: WSA function returned error code: %s\n", sFile, uLine, Winsock_Error_Text(::WSAGetLastError())));
|
|
DIE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Just get the text for the specified error code.
|
|
//
|
|
const char * cNetUtil::Winsock_Error_Text(int error_code)
|
|
{
|
|
static char error_msg[500];
|
|
|
|
switch (error_code) {
|
|
|
|
//
|
|
// Windows Sockets definitions of regular Microsoft C error constants
|
|
//
|
|
ADD_CASE(WSAEINTR)
|
|
ADD_CASE(WSAEBADF)
|
|
ADD_CASE(WSAEACCES)
|
|
ADD_CASE(WSAEFAULT)
|
|
ADD_CASE(WSAEINVAL)
|
|
ADD_CASE(WSAEMFILE)
|
|
|
|
//
|
|
// Windows Sockets definitions of regular Berkeley error constants
|
|
//
|
|
ADD_CASE(WSAEWOULDBLOCK)
|
|
ADD_CASE(WSAEINPROGRESS)
|
|
ADD_CASE(WSAEALREADY)
|
|
ADD_CASE(WSAENOTSOCK)
|
|
ADD_CASE(WSAEDESTADDRREQ)
|
|
ADD_CASE(WSAEMSGSIZE)
|
|
ADD_CASE(WSAEPROTOTYPE)
|
|
ADD_CASE(WSAENOPROTOOPT)
|
|
ADD_CASE(WSAEPROTONOSUPPORT)
|
|
ADD_CASE(WSAESOCKTNOSUPPORT)
|
|
ADD_CASE(WSAEOPNOTSUPP)
|
|
ADD_CASE(WSAEPFNOSUPPORT)
|
|
ADD_CASE(WSAEAFNOSUPPORT)
|
|
ADD_CASE(WSAEADDRINUSE)
|
|
ADD_CASE(WSAEADDRNOTAVAIL)
|
|
ADD_CASE(WSAENETDOWN)
|
|
ADD_CASE(WSAENETUNREACH)
|
|
ADD_CASE(WSAENETRESET)
|
|
ADD_CASE(WSAECONNABORTED)
|
|
ADD_CASE(WSAECONNRESET)
|
|
ADD_CASE(WSAENOBUFS)
|
|
ADD_CASE(WSAEISCONN)
|
|
ADD_CASE(WSAENOTCONN)
|
|
ADD_CASE(WSAESHUTDOWN)
|
|
ADD_CASE(WSAETOOMANYREFS)
|
|
ADD_CASE(WSAETIMEDOUT)
|
|
ADD_CASE(WSAECONNREFUSED)
|
|
ADD_CASE(WSAELOOP)
|
|
ADD_CASE(WSAENAMETOOLONG)
|
|
ADD_CASE(WSAEHOSTDOWN)
|
|
ADD_CASE(WSAEHOSTUNREACH)
|
|
ADD_CASE(WSAENOTEMPTY)
|
|
ADD_CASE(WSAEPROCLIM)
|
|
ADD_CASE(WSAEUSERS)
|
|
ADD_CASE(WSAEDQUOT)
|
|
ADD_CASE(WSAESTALE)
|
|
ADD_CASE(WSAEREMOTE)
|
|
|
|
//
|
|
// Extended Windows Sockets error constant definitions
|
|
///
|
|
ADD_CASE(WSASYSNOTREADY)
|
|
ADD_CASE(WSAVERNOTSUPPORTED)
|
|
ADD_CASE(WSANOTINITIALISED)
|
|
ADD_CASE(WSAEDISCON)
|
|
|
|
default:
|
|
::sprintf(error_msg, "Unknown Winsock Error (%d)", error_code);
|
|
break;
|
|
}
|
|
|
|
return(error_msg);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
int g_c_wouldblock = 0;
|
|
int g_c_nobufs = 0;
|
|
*/
|
|
//-----------------------------------------------------------------------------
|
|
bool cNetUtil::Send_Resource_Failure(LPCSTR sFile, unsigned uLine, int ret_code)
|
|
{
|
|
bool return_code = false;
|
|
|
|
if (ret_code == SOCKET_ERROR) {
|
|
int wsa_error = ::WSAGetLastError();
|
|
if (wsa_error == WSAEWOULDBLOCK || wsa_error == WSAENOBUFS) {
|
|
|
|
/*
|
|
if (wsa_error == WSAEWOULDBLOCK) {
|
|
g_c_wouldblock++;
|
|
} else {
|
|
g_c_nobufs++;
|
|
}
|
|
*/
|
|
|
|
return_code = true;
|
|
} else {
|
|
Wsa_Error(sFile, uLine);
|
|
}
|
|
} else {
|
|
return_code = false;
|
|
}
|
|
|
|
return return_code;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool cNetUtil::Would_Block(LPCSTR sFile, unsigned uLine, int ret_code)
|
|
{
|
|
bool retcode = false;
|
|
|
|
if (ret_code == SOCKET_ERROR) {
|
|
if (::WSAGetLastError() == WSAEWOULDBLOCK) {
|
|
retcode = true;
|
|
} else {
|
|
Wsa_Error(sFile, uLine);
|
|
retcode = false;
|
|
}
|
|
} else {
|
|
retcode = false;
|
|
}
|
|
|
|
return retcode;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Returns up to max_addresses adapter addresses for the local host
|
|
//
|
|
int cNetUtil::Get_Local_Tcpip_Addresses(SOCKADDR_IN ip_address[], USHORT max_addresses)
|
|
{
|
|
WWDEBUG_SAY(("cNetUtil::Get_Local_Tcpip_Addresses:\n"));
|
|
|
|
//
|
|
// Get the local hostname
|
|
//
|
|
char local_host_name[200];
|
|
WSA_CHECK(::gethostname(local_host_name, sizeof(local_host_name)));
|
|
WWDEBUG_SAY((" Host name is %s\n", local_host_name));
|
|
|
|
//
|
|
// Resolve hostname for local adapter addresses. This does
|
|
// a DNS lookup (name resolution)
|
|
//
|
|
LPHOSTENT p_hostent = ::gethostbyname(local_host_name);
|
|
|
|
int num_adapters = 0;
|
|
|
|
if (p_hostent == NULL) {
|
|
num_adapters = 0;
|
|
} else {
|
|
while (num_adapters < max_addresses && p_hostent->h_addr_list[num_adapters] != NULL) {
|
|
|
|
ZeroMemory(&ip_address[num_adapters], sizeof(SOCKADDR_IN));
|
|
ip_address[num_adapters].sin_family = AF_INET;
|
|
ip_address[num_adapters].sin_addr.s_addr =
|
|
*((u_long *) (p_hostent->h_addr_list[num_adapters]));
|
|
WWDEBUG_SAY((" Address: %s\n", Address_To_String(ip_address[num_adapters].sin_addr.s_addr)));
|
|
num_adapters++;
|
|
}
|
|
}
|
|
|
|
return num_adapters;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool cNetUtil::Is_Same_Address(LPSOCKADDR_IN p_address1, const SOCKADDR_IN* p_address2)
|
|
{
|
|
//
|
|
// C disallows comparison of structs...
|
|
//
|
|
|
|
WWASSERT(!cSinglePlayerData::Is_Single_Player());
|
|
WWASSERT(p_address1 != NULL);
|
|
WWASSERT(p_address2 != NULL);
|
|
|
|
return
|
|
p_address1->sin_addr.s_addr == p_address2->sin_addr.s_addr &&
|
|
p_address1->sin_port == p_address2->sin_port;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
void cNetUtil::Address_To_String(LPSOCKADDR_IN p_address, char * str, UINT len,
|
|
USHORT & port)
|
|
{
|
|
WWASSERT(p_address != NULL);
|
|
WWASSERT(str != NULL);
|
|
|
|
char temp_str[1000];
|
|
|
|
::strcpy(temp_str, ::inet_ntoa(p_address->sin_addr));
|
|
port = ::ntohs(p_address->sin_port);
|
|
|
|
WWASSERT(::strlen(temp_str) <= len);
|
|
::strcpy(str, temp_str);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
LPCSTR cNetUtil::Address_To_String(ULONG ip)
|
|
{
|
|
IN_ADDR in_addr;
|
|
in_addr.s_addr = ip;
|
|
char * p = ::inet_ntoa(in_addr);
|
|
if (p == NULL) {
|
|
::sprintf(WorkingAddressBuffer, "Invalid ip (%u)", ip);
|
|
} else {
|
|
::strcpy(WorkingAddressBuffer, p);
|
|
}
|
|
|
|
return WorkingAddressBuffer;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
void cNetUtil::String_To_Address(LPSOCKADDR_IN p_address, LPCSTR str, USHORT port)
|
|
{
|
|
WWASSERT(p_address != NULL);
|
|
ZeroMemory(p_address, sizeof(SOCKADDR_IN));
|
|
|
|
p_address->sin_family = AF_INET;
|
|
p_address->sin_addr.s_addr = ::inet_addr(str);
|
|
p_address->sin_port = ::htons(port);
|
|
|
|
WWASSERT(p_address->sin_addr.s_addr != INADDR_NONE);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
bool cNetUtil::Is_Tcpip_Present(void)
|
|
{
|
|
//
|
|
// N.B. I tested EnumProtocols and found it unreliable.
|
|
//
|
|
|
|
bool retcode = true;
|
|
|
|
SOCKET test_socket = ::socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (test_socket == INVALID_SOCKET) {
|
|
if (::WSAGetLastError() == WSAEAFNOSUPPORT) {
|
|
retcode = false;
|
|
} else {
|
|
WSA_ERROR;
|
|
}
|
|
} else {
|
|
WSA_CHECK(::closesocket(test_socket));
|
|
}
|
|
|
|
return retcode;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
void cNetUtil::Wsa_Init()
|
|
{
|
|
//
|
|
// winsock 1.1
|
|
//
|
|
|
|
WSADATA wsa_data;
|
|
if (::WSAStartup(MAKEWORD(1, 1), &wsa_data) != 0) {
|
|
DIE;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
bool cNetUtil::Protocol_Init(bool is_internet)
|
|
{
|
|
IsInternet = is_internet;
|
|
|
|
bool retcode = false;
|
|
|
|
if (Is_Tcpip_Present()) {
|
|
retcode = true;
|
|
|
|
if (IsInternet) {
|
|
DefaultResendTimeoutMs = RESEND_TIMEOUT_INTERNET_MS;
|
|
} else {
|
|
DefaultResendTimeoutMs = RESEND_TIMEOUT_LAN_MS;
|
|
}
|
|
} else {
|
|
retcode = false;
|
|
}
|
|
|
|
return retcode;
|
|
}
|
|
|
|
/*
|
|
//-------------------------------------------------------------------------------
|
|
float cNetUtil::Compute_Priority_Noise()
|
|
{
|
|
//
|
|
// Add some noise to increase the spread. This noise must be bigger
|
|
// than the maximum threshold adjustment, so PriorityNoiseFactor should
|
|
// be at least 1 if you are adding noise.
|
|
// Do not jitter a priority of zero!
|
|
//
|
|
// Or maybe we can just specify a max noise now?
|
|
//
|
|
float noise_width = PriorityNoiseFactor * MaxTPCorrectionDownwards;
|
|
return cMathUtil::Get_Hat_Pdf_Double(-noise_width / 2.0f, +noise_width / 2.0f);
|
|
}
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------------
|
|
void cNetUtil::Set_Socket_Buffer_Sizes(SOCKET sock, int new_size)
|
|
{
|
|
WWDEBUG_SAY(("cNetUtil::Set_Socket_Buffer_Sizes:\n"));
|
|
|
|
int buffersize = 0;
|
|
int len = 0;
|
|
|
|
buffersize = 0;
|
|
len = sizeof(int);
|
|
WSA_CHECK(::getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&buffersize, &len));
|
|
//WWDEBUG_SAY((" SO_SNDBUF = %d\n", buffersize));
|
|
|
|
buffersize = 0;
|
|
len = sizeof(int);
|
|
WSA_CHECK(::getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&buffersize, &len));
|
|
//WWDEBUG_SAY((" SO_RCVBUF = %d\n", buffersize));
|
|
|
|
buffersize = new_size;
|
|
len = sizeof(int);
|
|
WSA_CHECK(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&buffersize, len));
|
|
//WWDEBUG_SAY((" Attempting to set SO_SNDBUF = %d\n", buffersize));
|
|
|
|
buffersize = new_size;
|
|
len = sizeof(int);
|
|
WSA_CHECK(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&buffersize, len));
|
|
//WWDEBUG_SAY((" Attempting to set SO_RCVBUF = %d\n", buffersize));
|
|
|
|
buffersize = 0;
|
|
len = sizeof(int);
|
|
WSA_CHECK(::getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&buffersize, &len));
|
|
//WWDEBUG_SAY((" SO_SNDBUF = %d\n", buffersize));
|
|
|
|
buffersize = 0;
|
|
len = sizeof(int);
|
|
WSA_CHECK(::getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&buffersize, &len));
|
|
//WWDEBUG_SAY((" SO_RCVBUF = %d\n", buffersize));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
//-------------------------------------------------------------------------------
|
|
void cNetUtil::Onetime_Init()
|
|
{
|
|
FileClass * p_ini_file = _TheFileFactory->Get_File("netparams.ini");
|
|
|
|
if (p_ini_file != NULL) {
|
|
|
|
INIClass netparams_ini(*p_ini_file);
|
|
|
|
WWASSERT(netparams_ini.Section_Count() == 1);
|
|
|
|
const LPCSTR SECTION_NAME = "Settings";
|
|
|
|
//NETSTATS_SAMPLE_TIME_MS = netparams_ini.Get_Int(SECTION_NAME, "NETSTATS_SAMPLE_TIME_MS", INVALID_VALUE);
|
|
//WWASSERT(NETSTATS_SAMPLE_TIME_MS > 0);
|
|
|
|
//RESEND_TIMEOUT_LAN_MS = netparams_ini.Get_Int(SECTION_NAME, "RESEND_TIMEOUT_LAN_MS", INVALID_VALUE);
|
|
//WWASSERT(RESEND_TIMEOUT_LAN_MS > 0);
|
|
|
|
//RESEND_TIMEOUT_INTERNET_MS = netparams_ini.Get_Int(SECTION_NAME, "RESEND_TIMEOUT_INTERNET_MS", INVALID_VALUE);
|
|
//WWASSERT(RESEND_TIMEOUT_INTERNET_MS > 0);
|
|
|
|
//DefaultMultiSends = netparams_ini.Get_Int(SECTION_NAME, "DefaultMultiSends", INVALID_VALUE);
|
|
//WWASSERT(DefaultMultiSends > 0);
|
|
|
|
//DefaultMaxResends = netparams_ini.Get_Int(SECTION_NAME, "DefaultMaxResends", INVALID_VALUE);
|
|
//WWASSERT(DefaultMaxResends > 0);
|
|
|
|
//DefaultKeepaliveTimeoutMs = netparams_ini.Get_Int(SECTION_NAME, "DefaultKeepaliveTimeoutMs", INVALID_VALUE);
|
|
//WWASSERT(DefaultKeepaliveTimeoutMs > 0);
|
|
|
|
//DesiredSendBufferSizeBytes = netparams_ini.Get_Int(SECTION_NAME, "DesiredSendBufferSizeBytes", INVALID_VALUE);
|
|
//WWASSERT(DesiredSendBufferSizeBytes > 0);
|
|
|
|
//DESIRED_RECEIVE_BUFFER_SIZE_BYTES = netparams_ini.Get_Int(SECTION_NAME, "DesiredReceiveBufferSizeBytes", INVALID_VALUE);
|
|
//WWASSERT(DesiredReceiveBufferSizeBytes > 0);
|
|
|
|
//DefaultServerPort = netparams_ini.Get_Int(SECTION_NAME, "DefaultServerPort", INVALID_VALUE);
|
|
//WWASSERT(DefaultServerPort >= MIN_SERVER_PORT && DefaultServerPort <= MAX_SERVER_PORT);
|
|
|
|
//MaxReceiveTimeMs = netparams_ini.Get_Int(SECTION_NAME, "MaxReceiveTimeMs", INVALID_VALUE);
|
|
//WWASSERT(MaxReceiveTimeMs > 0);
|
|
|
|
//PriorityToleranceDownwards = netparams_ini.Get_Float(SECTION_NAME, "PriorityToleranceDownwards", INVALID_VALUE);
|
|
//WWASSERT(PriorityToleranceDownwards > -1 - MISCUTIL_EPSILON && PriorityToleranceDownwards < 1 + MISCUTIL_EPSILON);
|
|
|
|
//PriorityToleranceUpwards = netparams_ini.Get_Float(SECTION_NAME, "PriorityToleranceUpwards", INVALID_VALUE);
|
|
//WWASSERT(PriorityToleranceUpwards > -1 - MISCUTIL_EPSILON && PriorityToleranceUpwards < 1 + MISCUTIL_EPSILON);
|
|
|
|
//MaxTPCorrectionDownwards = netparams_ini.Get_Float(SECTION_NAME, "MaxTPCorrectionDownwards", INVALID_VALUE);
|
|
//WWASSERT(MaxTPCorrectionDownwards > -1 - MISCUTIL_EPSILON && MaxTPCorrectionDownwards < 1 + MISCUTIL_EPSILON);
|
|
|
|
//MaxTPCorrectionUpwards = netparams_ini.Get_Float(SECTION_NAME, "MaxTPCorrectionUpwards", INVALID_VALUE);
|
|
//WWASSERT(MaxTPCorrectionUpwards > -1 - MISCUTIL_EPSILON && MaxTPCorrectionUpwards < 1 + MISCUTIL_EPSILON);
|
|
|
|
//PriorityNoiseFactor = netparams_ini.Get_Float(SECTION_NAME, "PriorityNoiseFactor", INVALID_VALUE);
|
|
//WWASSERT(PriorityNoiseFactor >= -MISCUTIL_EPSILON);
|
|
|
|
//InitialThresholdPriority = netparams_ini.Get_Float(SECTION_NAME, "InitialThresholdPriority", INVALID_VALUE);
|
|
//WWASSERT(InitialThresholdPriority >= -MISCUTIL_EPSILON);
|
|
|
|
//PriorityNoiseFactor = netparams_ini.Get_Float(SECTION_NAME, "PriorityNoiseFactor", INVALID_VALUE);
|
|
//WWASSERT(PriorityNoiseFactor >= -MISCUTIL_EPSILON);
|
|
|
|
//PriorityGrowthPerSecond = netparams_ini.Get_Float(SECTION_NAME, "PriorityGrowthPerSecond", INVALID_VALUE);
|
|
//WWASSERT(PriorityGrowthPerSecond >= -MISCUTIL_EPSILON);
|
|
|
|
_TheFileFactory->Return_File(p_ini_file);
|
|
}
|
|
}
|
|
*/
|
|
|
|
void cNetUtil::Create_Unbound_Socket(SOCKET & sock)
|
|
{
|
|
sock = ::socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (sock == INVALID_SOCKET) {
|
|
WSA_ERROR;
|
|
}
|
|
|
|
//
|
|
// Enable broadcasts
|
|
//
|
|
int optval = TRUE;
|
|
WSA_CHECK(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *) &optval, sizeof(optval)));
|
|
|
|
//
|
|
// Make socket non-blocking
|
|
//
|
|
u_long arg = 1L;
|
|
WSA_CHECK(ioctlsocket(sock, FIONBIO, (u_long *) &arg));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
bool cNetUtil::Create_Bound_Socket(SOCKET & sock, USHORT port, SOCKADDR_IN & local_address)
|
|
{
|
|
//
|
|
// TSS - is all this necessary or is above function OK?
|
|
//
|
|
|
|
Create_Unbound_Socket(sock);
|
|
|
|
Create_Local_Address(&local_address, port);
|
|
int result = ::bind(sock, (LPSOCKADDR) &local_address, sizeof(SOCKADDR_IN));
|
|
if (result == 0) {
|
|
return true;
|
|
} else {
|
|
WWASSERT(result == SOCKET_ERROR);
|
|
//if (::WSAGetLastError() != WSAEADDRINUSE) {
|
|
WSA_ERROR;
|
|
//}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
void cNetUtil::Close_Socket(SOCKET & sock)
|
|
{
|
|
::closesocket(sock);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void cNetUtil::Broadcast(SOCKET & sock, USHORT port, cPacket & packet)
|
|
{
|
|
SOCKADDR_IN broadcast_address;
|
|
Create_Broadcast_Address(&broadcast_address, port);
|
|
int bytes_sent;
|
|
//WSA_CHECK(bytes_sent = sendto(sock, packet.Data, packet.SendLength,
|
|
// 0, &broadcast_address, sizeof(SOCKADDR_IN)));
|
|
bytes_sent = sendto(sock, packet.Get_Data(), packet.Get_Compressed_Size_Bytes(),
|
|
0, (LPSOCKADDR) &broadcast_address, sizeof(SOCKADDR_IN));
|
|
#pragma message("(TSS) WSAENOBUFS")
|
|
//WWDEBUG_SAY(("Sent broadcast, length = %d bytes\n", bytes_sent));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
void cNetUtil::Create_Broadcast_Address(LPSOCKADDR_IN p_broadcast_address,
|
|
USHORT port)
|
|
{
|
|
WWASSERT(p_broadcast_address != NULL);
|
|
ZeroMemory(p_broadcast_address, sizeof(SOCKADDR_IN));
|
|
|
|
p_broadcast_address->sin_family = AF_INET;
|
|
p_broadcast_address->sin_addr.s_addr = INADDR_BROADCAST; // ::inet_addr("255.255.255.255");
|
|
p_broadcast_address->sin_port = ::htons(port);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
void cNetUtil::Create_Local_Address(LPSOCKADDR_IN p_local_address, USHORT port)
|
|
{
|
|
WWASSERT(p_local_address != NULL);
|
|
ZeroMemory(p_local_address, sizeof(SOCKADDR_IN));
|
|
|
|
p_local_address->sin_family = AF_INET;
|
|
p_local_address->sin_addr.s_addr = INADDR_ANY;
|
|
p_local_address->sin_port = ::htons(port);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
bool cNetUtil::Get_Local_Address(LPSOCKADDR_IN p_local_address)
|
|
{
|
|
WWASSERT(p_local_address != NULL);
|
|
|
|
/*
|
|
const USHORT MAX_ADDRESSES = 1;
|
|
int num_addresses = Get_Local_Tcpip_Addresses(p_local_address, MAX_ADDRESSES);
|
|
|
|
return (num_addresses == 1);
|
|
*/
|
|
|
|
const USHORT MAX_ADDRESSES = 10;
|
|
SOCKADDR_IN local_address[MAX_ADDRESSES];
|
|
int num_addresses = Get_Local_Tcpip_Addresses(local_address, MAX_ADDRESSES);
|
|
|
|
if (num_addresses > 0) {
|
|
::memcpy(p_local_address, &local_address[0], sizeof(SOCKADDR_IN));
|
|
}
|
|
|
|
return (num_addresses > 0);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void cNetUtil::Lan_Servicing(SOCKET & sock, LanPacketHandlerCallback p_callback)
|
|
{
|
|
int retcode;
|
|
|
|
unsigned long start_time = TIMEGETTIME();
|
|
|
|
do {
|
|
cPacket packet;
|
|
int address_len = sizeof(SOCKADDR_IN);
|
|
|
|
//
|
|
// If we appear to crash INSIDE recvfrom then this tends to indicate
|
|
// that net neighbourhood broke.
|
|
//
|
|
retcode = recvfrom(sock, packet.Get_Data(), packet.Get_Max_Size(),
|
|
0, (LPSOCKADDR) &packet.Get_From_Address_Wrapper()->FromAddress, &address_len);
|
|
|
|
if (retcode == SOCKET_ERROR) {
|
|
if (::WSAGetLastError() != WSAEWOULDBLOCK) {
|
|
WSA_ERROR;
|
|
}
|
|
} else {
|
|
/*
|
|
//
|
|
// diagnostic
|
|
//
|
|
ULONG ip = packet.Get_From_Address_Wrapper()->FromAddress.sin_addr.s_addr;
|
|
WWDEBUG_SAY(("cNetUtil::Lan_Servicing: %s\n", cNetUtil::Address_To_String(ip)));
|
|
*/
|
|
|
|
//packet.Set_Received_Length(retcode);
|
|
packet.Set_Bit_Length(retcode * 8);
|
|
(*p_callback)(packet);
|
|
}
|
|
} while (retcode != SOCKET_ERROR); // this will indicate no more data
|
|
|
|
unsigned long time_spent = TIMEGETTIME() - start_time;
|
|
if (time_spent > 100) {
|
|
WWDEBUG_SAY(("*** cNetUtil::Lan_Servicing: Too much time (%d ms)) spent receiving lan packets.\n",
|
|
time_spent));
|
|
}
|
|
} |