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