/*
** 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 .
*/
//
// Filename: netutil.cpp
// Project: wwnet
// Author: Tom Spencer-Smith
// Date: June 1998
// Description:
//
//-----------------------------------------------------------------------------
#include "netutil.h" // I WANNA BE FIRST!
#include
#include
#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));
}
}