netutil.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. //
  19. // Filename: netutil.cpp
  20. // Project: wwnet
  21. // Author: Tom Spencer-Smith
  22. // Date: June 1998
  23. // Description:
  24. //
  25. //-----------------------------------------------------------------------------
  26. #include "netutil.h" // I WANNA BE FIRST!
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include "miscutil.h"
  30. #include "mathutil.h"
  31. #include "singlepl.h"
  32. #include "wwpacket.h"
  33. #include "wwdebug.h"
  34. #include "ffactory.h"
  35. #include "ini.h"
  36. #include "systimer.h"
  37. #include "fromaddress.h"
  38. //
  39. // class statics
  40. //
  41. //const WORD cNetUtil::WS_VERSION_REQD = MAKEWORD(1, 1); // Winsock 1.1
  42. //USHORT cNetUtil::HeaderBytes;
  43. //USHORT cNetUtil::MaxPacketAppDataSize = MAX_LAN_PACKET_APP_DATA_SIZE;
  44. UINT cNetUtil::DefaultResendTimeoutMs = 200; // used for singleplayer
  45. bool cNetUtil::IsInternet = false;
  46. static const int INVALID_VALUE = -999;
  47. const USHORT cNetUtil::NETSTATS_SAMPLE_TIME_MS = 2000;
  48. const USHORT cNetUtil::KEEPALIVE_TIMEOUT_MS = 2000;
  49. const USHORT cNetUtil::MAX_RESENDS = 50;
  50. const USHORT cNetUtil::MULTI_SENDS = 10;
  51. const USHORT cNetUtil::RESEND_TIMEOUT_LAN_MS = 300;
  52. const USHORT cNetUtil::RESEND_TIMEOUT_INTERNET_MS = 500;
  53. const ULONG cNetUtil::CLIENT_CONNECTION_LOSS_TIMEOUT = 15000; // Milliseconds til client gives up on server
  54. const ULONG cNetUtil::SERVER_CONNECTION_LOSS_TIMEOUT = 15000; // Milliseconds til server gives up on client
  55. const ULONG cNetUtil::SERVER_CONNECTION_LOSS_TIMEOUT_LOADING_ALLOWANCE = 45000; // Milliseconds extra allowed til server gives up on loading client.
  56. //int cNetUtil::DefaultMultiSends = INVALID_VALUE;
  57. //int cNetUtil::DefaultMaxResends = INVALID_VALUE;
  58. //int cNetUtil::DefaultKeepaliveTimeoutMs = INVALID_VALUE;
  59. //int cNetUtil::DesiredSendBufferSizeBytes = INVALID_VALUE;
  60. //int cNetUtil::DesiredReceiveBufferSizeBytes = INVALID_VALUE;
  61. //int cNetUtil::DefaultServerPort = INVALID_VALUE;
  62. //int cNetUtil::MaxReceiveTimeMs = INVALID_VALUE;
  63. //float cNetUtil::PriorityToleranceDownwards = INVALID_VALUE;
  64. //float cNetUtil::PriorityToleranceUpwards = INVALID_VALUE;
  65. //float cNetUtil::MaxTPCorrectionDownwards = INVALID_VALUE;
  66. //float cNetUtil::MaxTPCorrectionUpwards = INVALID_VALUE;
  67. //float cNetUtil::PriorityNoiseFactor = INVALID_VALUE;
  68. //float cNetUtil::InitialThresholdPriority = INVALID_VALUE;
  69. //float cNetUtil::PriorityGrowthPerSecond = INVALID_VALUE;
  70. char cNetUtil::WorkingAddressBuffer[] = "";
  71. //-----------------------------------------------------------------------------
  72. //
  73. // Macro
  74. //
  75. #define ADD_CASE(exp) case exp: ::sprintf(error_msg, #exp); break;
  76. void cNetUtil::Wsa_Error(LPCSTR sFile, unsigned uLine)
  77. {
  78. WWDEBUG_SAY(("* %s:%d: WSA function returned error code: %s\n", sFile, uLine, Winsock_Error_Text(::WSAGetLastError())));
  79. DIE;
  80. }
  81. //-----------------------------------------------------------------------------
  82. //
  83. // Just get the text for the specified error code.
  84. //
  85. const char * cNetUtil::Winsock_Error_Text(int error_code)
  86. {
  87. static char error_msg[500];
  88. switch (error_code) {
  89. //
  90. // Windows Sockets definitions of regular Microsoft C error constants
  91. //
  92. ADD_CASE(WSAEINTR)
  93. ADD_CASE(WSAEBADF)
  94. ADD_CASE(WSAEACCES)
  95. ADD_CASE(WSAEFAULT)
  96. ADD_CASE(WSAEINVAL)
  97. ADD_CASE(WSAEMFILE)
  98. //
  99. // Windows Sockets definitions of regular Berkeley error constants
  100. //
  101. ADD_CASE(WSAEWOULDBLOCK)
  102. ADD_CASE(WSAEINPROGRESS)
  103. ADD_CASE(WSAEALREADY)
  104. ADD_CASE(WSAENOTSOCK)
  105. ADD_CASE(WSAEDESTADDRREQ)
  106. ADD_CASE(WSAEMSGSIZE)
  107. ADD_CASE(WSAEPROTOTYPE)
  108. ADD_CASE(WSAENOPROTOOPT)
  109. ADD_CASE(WSAEPROTONOSUPPORT)
  110. ADD_CASE(WSAESOCKTNOSUPPORT)
  111. ADD_CASE(WSAEOPNOTSUPP)
  112. ADD_CASE(WSAEPFNOSUPPORT)
  113. ADD_CASE(WSAEAFNOSUPPORT)
  114. ADD_CASE(WSAEADDRINUSE)
  115. ADD_CASE(WSAEADDRNOTAVAIL)
  116. ADD_CASE(WSAENETDOWN)
  117. ADD_CASE(WSAENETUNREACH)
  118. ADD_CASE(WSAENETRESET)
  119. ADD_CASE(WSAECONNABORTED)
  120. ADD_CASE(WSAECONNRESET)
  121. ADD_CASE(WSAENOBUFS)
  122. ADD_CASE(WSAEISCONN)
  123. ADD_CASE(WSAENOTCONN)
  124. ADD_CASE(WSAESHUTDOWN)
  125. ADD_CASE(WSAETOOMANYREFS)
  126. ADD_CASE(WSAETIMEDOUT)
  127. ADD_CASE(WSAECONNREFUSED)
  128. ADD_CASE(WSAELOOP)
  129. ADD_CASE(WSAENAMETOOLONG)
  130. ADD_CASE(WSAEHOSTDOWN)
  131. ADD_CASE(WSAEHOSTUNREACH)
  132. ADD_CASE(WSAENOTEMPTY)
  133. ADD_CASE(WSAEPROCLIM)
  134. ADD_CASE(WSAEUSERS)
  135. ADD_CASE(WSAEDQUOT)
  136. ADD_CASE(WSAESTALE)
  137. ADD_CASE(WSAEREMOTE)
  138. //
  139. // Extended Windows Sockets error constant definitions
  140. ///
  141. ADD_CASE(WSASYSNOTREADY)
  142. ADD_CASE(WSAVERNOTSUPPORTED)
  143. ADD_CASE(WSANOTINITIALISED)
  144. ADD_CASE(WSAEDISCON)
  145. default:
  146. ::sprintf(error_msg, "Unknown Winsock Error (%d)", error_code);
  147. break;
  148. }
  149. return(error_msg);
  150. }
  151. /*
  152. int g_c_wouldblock = 0;
  153. int g_c_nobufs = 0;
  154. */
  155. //-----------------------------------------------------------------------------
  156. bool cNetUtil::Send_Resource_Failure(LPCSTR sFile, unsigned uLine, int ret_code)
  157. {
  158. bool return_code = false;
  159. if (ret_code == SOCKET_ERROR) {
  160. int wsa_error = ::WSAGetLastError();
  161. if (wsa_error == WSAEWOULDBLOCK || wsa_error == WSAENOBUFS) {
  162. /*
  163. if (wsa_error == WSAEWOULDBLOCK) {
  164. g_c_wouldblock++;
  165. } else {
  166. g_c_nobufs++;
  167. }
  168. */
  169. return_code = true;
  170. } else {
  171. Wsa_Error(sFile, uLine);
  172. }
  173. } else {
  174. return_code = false;
  175. }
  176. return return_code;
  177. }
  178. //-----------------------------------------------------------------------------
  179. bool cNetUtil::Would_Block(LPCSTR sFile, unsigned uLine, int ret_code)
  180. {
  181. bool retcode = false;
  182. if (ret_code == SOCKET_ERROR) {
  183. if (::WSAGetLastError() == WSAEWOULDBLOCK) {
  184. retcode = true;
  185. } else {
  186. Wsa_Error(sFile, uLine);
  187. retcode = false;
  188. }
  189. } else {
  190. retcode = false;
  191. }
  192. return retcode;
  193. }
  194. //-----------------------------------------------------------------------------
  195. //
  196. // Returns up to max_addresses adapter addresses for the local host
  197. //
  198. int cNetUtil::Get_Local_Tcpip_Addresses(SOCKADDR_IN ip_address[], USHORT max_addresses)
  199. {
  200. WWDEBUG_SAY(("cNetUtil::Get_Local_Tcpip_Addresses:\n"));
  201. //
  202. // Get the local hostname
  203. //
  204. char local_host_name[200];
  205. WSA_CHECK(::gethostname(local_host_name, sizeof(local_host_name)));
  206. WWDEBUG_SAY((" Host name is %s\n", local_host_name));
  207. //
  208. // Resolve hostname for local adapter addresses. This does
  209. // a DNS lookup (name resolution)
  210. //
  211. LPHOSTENT p_hostent = ::gethostbyname(local_host_name);
  212. int num_adapters = 0;
  213. if (p_hostent == NULL) {
  214. num_adapters = 0;
  215. } else {
  216. while (num_adapters < max_addresses && p_hostent->h_addr_list[num_adapters] != NULL) {
  217. ZeroMemory(&ip_address[num_adapters], sizeof(SOCKADDR_IN));
  218. ip_address[num_adapters].sin_family = AF_INET;
  219. ip_address[num_adapters].sin_addr.s_addr =
  220. *((u_long *) (p_hostent->h_addr_list[num_adapters]));
  221. WWDEBUG_SAY((" Address: %s\n", Address_To_String(ip_address[num_adapters].sin_addr.s_addr)));
  222. num_adapters++;
  223. }
  224. }
  225. return num_adapters;
  226. }
  227. //-----------------------------------------------------------------------------
  228. bool cNetUtil::Is_Same_Address(LPSOCKADDR_IN p_address1, const SOCKADDR_IN* p_address2)
  229. {
  230. //
  231. // C disallows comparison of structs...
  232. //
  233. WWASSERT(!cSinglePlayerData::Is_Single_Player());
  234. WWASSERT(p_address1 != NULL);
  235. WWASSERT(p_address2 != NULL);
  236. return
  237. p_address1->sin_addr.s_addr == p_address2->sin_addr.s_addr &&
  238. p_address1->sin_port == p_address2->sin_port;
  239. }
  240. //-------------------------------------------------------------------------------
  241. void cNetUtil::Address_To_String(LPSOCKADDR_IN p_address, char * str, UINT len,
  242. USHORT & port)
  243. {
  244. WWASSERT(p_address != NULL);
  245. WWASSERT(str != NULL);
  246. char temp_str[1000];
  247. ::strcpy(temp_str, ::inet_ntoa(p_address->sin_addr));
  248. port = ::ntohs(p_address->sin_port);
  249. WWASSERT(::strlen(temp_str) <= len);
  250. ::strcpy(str, temp_str);
  251. }
  252. //-------------------------------------------------------------------------------
  253. LPCSTR cNetUtil::Address_To_String(ULONG ip)
  254. {
  255. IN_ADDR in_addr;
  256. in_addr.s_addr = ip;
  257. char * p = ::inet_ntoa(in_addr);
  258. if (p == NULL) {
  259. ::sprintf(WorkingAddressBuffer, "Invalid ip (%u)", ip);
  260. } else {
  261. ::strcpy(WorkingAddressBuffer, p);
  262. }
  263. return WorkingAddressBuffer;
  264. }
  265. //-------------------------------------------------------------------------------
  266. void cNetUtil::String_To_Address(LPSOCKADDR_IN p_address, LPCSTR str, USHORT port)
  267. {
  268. WWASSERT(p_address != NULL);
  269. ZeroMemory(p_address, sizeof(SOCKADDR_IN));
  270. p_address->sin_family = AF_INET;
  271. p_address->sin_addr.s_addr = ::inet_addr(str);
  272. p_address->sin_port = ::htons(port);
  273. WWASSERT(p_address->sin_addr.s_addr != INADDR_NONE);
  274. }
  275. //-------------------------------------------------------------------------------
  276. bool cNetUtil::Is_Tcpip_Present(void)
  277. {
  278. //
  279. // N.B. I tested EnumProtocols and found it unreliable.
  280. //
  281. bool retcode = true;
  282. SOCKET test_socket = ::socket(AF_INET, SOCK_DGRAM, 0);
  283. if (test_socket == INVALID_SOCKET) {
  284. if (::WSAGetLastError() == WSAEAFNOSUPPORT) {
  285. retcode = false;
  286. } else {
  287. WSA_ERROR;
  288. }
  289. } else {
  290. WSA_CHECK(::closesocket(test_socket));
  291. }
  292. return retcode;
  293. }
  294. //-------------------------------------------------------------------------------
  295. void cNetUtil::Wsa_Init()
  296. {
  297. //
  298. // winsock 1.1
  299. //
  300. WSADATA wsa_data;
  301. if (::WSAStartup(MAKEWORD(1, 1), &wsa_data) != 0) {
  302. DIE;
  303. }
  304. }
  305. //-------------------------------------------------------------------------------
  306. bool cNetUtil::Protocol_Init(bool is_internet)
  307. {
  308. IsInternet = is_internet;
  309. bool retcode = false;
  310. if (Is_Tcpip_Present()) {
  311. retcode = true;
  312. if (IsInternet) {
  313. DefaultResendTimeoutMs = RESEND_TIMEOUT_INTERNET_MS;
  314. } else {
  315. DefaultResendTimeoutMs = RESEND_TIMEOUT_LAN_MS;
  316. }
  317. } else {
  318. retcode = false;
  319. }
  320. return retcode;
  321. }
  322. /*
  323. //-------------------------------------------------------------------------------
  324. float cNetUtil::Compute_Priority_Noise()
  325. {
  326. //
  327. // Add some noise to increase the spread. This noise must be bigger
  328. // than the maximum threshold adjustment, so PriorityNoiseFactor should
  329. // be at least 1 if you are adding noise.
  330. // Do not jitter a priority of zero!
  331. //
  332. // Or maybe we can just specify a max noise now?
  333. //
  334. float noise_width = PriorityNoiseFactor * MaxTPCorrectionDownwards;
  335. return cMathUtil::Get_Hat_Pdf_Double(-noise_width / 2.0f, +noise_width / 2.0f);
  336. }
  337. */
  338. //-------------------------------------------------------------------------------
  339. void cNetUtil::Set_Socket_Buffer_Sizes(SOCKET sock, int new_size)
  340. {
  341. WWDEBUG_SAY(("cNetUtil::Set_Socket_Buffer_Sizes:\n"));
  342. int buffersize = 0;
  343. int len = 0;
  344. buffersize = 0;
  345. len = sizeof(int);
  346. WSA_CHECK(::getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&buffersize, &len));
  347. //WWDEBUG_SAY((" SO_SNDBUF = %d\n", buffersize));
  348. buffersize = 0;
  349. len = sizeof(int);
  350. WSA_CHECK(::getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&buffersize, &len));
  351. //WWDEBUG_SAY((" SO_RCVBUF = %d\n", buffersize));
  352. buffersize = new_size;
  353. len = sizeof(int);
  354. WSA_CHECK(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&buffersize, len));
  355. //WWDEBUG_SAY((" Attempting to set SO_SNDBUF = %d\n", buffersize));
  356. buffersize = new_size;
  357. len = sizeof(int);
  358. WSA_CHECK(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&buffersize, len));
  359. //WWDEBUG_SAY((" Attempting to set SO_RCVBUF = %d\n", buffersize));
  360. buffersize = 0;
  361. len = sizeof(int);
  362. WSA_CHECK(::getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&buffersize, &len));
  363. //WWDEBUG_SAY((" SO_SNDBUF = %d\n", buffersize));
  364. buffersize = 0;
  365. len = sizeof(int);
  366. WSA_CHECK(::getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&buffersize, &len));
  367. //WWDEBUG_SAY((" SO_RCVBUF = %d\n", buffersize));
  368. }
  369. /*
  370. //-------------------------------------------------------------------------------
  371. void cNetUtil::Onetime_Init()
  372. {
  373. FileClass * p_ini_file = _TheFileFactory->Get_File("netparams.ini");
  374. if (p_ini_file != NULL) {
  375. INIClass netparams_ini(*p_ini_file);
  376. WWASSERT(netparams_ini.Section_Count() == 1);
  377. const LPCSTR SECTION_NAME = "Settings";
  378. //NETSTATS_SAMPLE_TIME_MS = netparams_ini.Get_Int(SECTION_NAME, "NETSTATS_SAMPLE_TIME_MS", INVALID_VALUE);
  379. //WWASSERT(NETSTATS_SAMPLE_TIME_MS > 0);
  380. //RESEND_TIMEOUT_LAN_MS = netparams_ini.Get_Int(SECTION_NAME, "RESEND_TIMEOUT_LAN_MS", INVALID_VALUE);
  381. //WWASSERT(RESEND_TIMEOUT_LAN_MS > 0);
  382. //RESEND_TIMEOUT_INTERNET_MS = netparams_ini.Get_Int(SECTION_NAME, "RESEND_TIMEOUT_INTERNET_MS", INVALID_VALUE);
  383. //WWASSERT(RESEND_TIMEOUT_INTERNET_MS > 0);
  384. //DefaultMultiSends = netparams_ini.Get_Int(SECTION_NAME, "DefaultMultiSends", INVALID_VALUE);
  385. //WWASSERT(DefaultMultiSends > 0);
  386. //DefaultMaxResends = netparams_ini.Get_Int(SECTION_NAME, "DefaultMaxResends", INVALID_VALUE);
  387. //WWASSERT(DefaultMaxResends > 0);
  388. //DefaultKeepaliveTimeoutMs = netparams_ini.Get_Int(SECTION_NAME, "DefaultKeepaliveTimeoutMs", INVALID_VALUE);
  389. //WWASSERT(DefaultKeepaliveTimeoutMs > 0);
  390. //DesiredSendBufferSizeBytes = netparams_ini.Get_Int(SECTION_NAME, "DesiredSendBufferSizeBytes", INVALID_VALUE);
  391. //WWASSERT(DesiredSendBufferSizeBytes > 0);
  392. //DESIRED_RECEIVE_BUFFER_SIZE_BYTES = netparams_ini.Get_Int(SECTION_NAME, "DesiredReceiveBufferSizeBytes", INVALID_VALUE);
  393. //WWASSERT(DesiredReceiveBufferSizeBytes > 0);
  394. //DefaultServerPort = netparams_ini.Get_Int(SECTION_NAME, "DefaultServerPort", INVALID_VALUE);
  395. //WWASSERT(DefaultServerPort >= MIN_SERVER_PORT && DefaultServerPort <= MAX_SERVER_PORT);
  396. //MaxReceiveTimeMs = netparams_ini.Get_Int(SECTION_NAME, "MaxReceiveTimeMs", INVALID_VALUE);
  397. //WWASSERT(MaxReceiveTimeMs > 0);
  398. //PriorityToleranceDownwards = netparams_ini.Get_Float(SECTION_NAME, "PriorityToleranceDownwards", INVALID_VALUE);
  399. //WWASSERT(PriorityToleranceDownwards > -1 - MISCUTIL_EPSILON && PriorityToleranceDownwards < 1 + MISCUTIL_EPSILON);
  400. //PriorityToleranceUpwards = netparams_ini.Get_Float(SECTION_NAME, "PriorityToleranceUpwards", INVALID_VALUE);
  401. //WWASSERT(PriorityToleranceUpwards > -1 - MISCUTIL_EPSILON && PriorityToleranceUpwards < 1 + MISCUTIL_EPSILON);
  402. //MaxTPCorrectionDownwards = netparams_ini.Get_Float(SECTION_NAME, "MaxTPCorrectionDownwards", INVALID_VALUE);
  403. //WWASSERT(MaxTPCorrectionDownwards > -1 - MISCUTIL_EPSILON && MaxTPCorrectionDownwards < 1 + MISCUTIL_EPSILON);
  404. //MaxTPCorrectionUpwards = netparams_ini.Get_Float(SECTION_NAME, "MaxTPCorrectionUpwards", INVALID_VALUE);
  405. //WWASSERT(MaxTPCorrectionUpwards > -1 - MISCUTIL_EPSILON && MaxTPCorrectionUpwards < 1 + MISCUTIL_EPSILON);
  406. //PriorityNoiseFactor = netparams_ini.Get_Float(SECTION_NAME, "PriorityNoiseFactor", INVALID_VALUE);
  407. //WWASSERT(PriorityNoiseFactor >= -MISCUTIL_EPSILON);
  408. //InitialThresholdPriority = netparams_ini.Get_Float(SECTION_NAME, "InitialThresholdPriority", INVALID_VALUE);
  409. //WWASSERT(InitialThresholdPriority >= -MISCUTIL_EPSILON);
  410. //PriorityNoiseFactor = netparams_ini.Get_Float(SECTION_NAME, "PriorityNoiseFactor", INVALID_VALUE);
  411. //WWASSERT(PriorityNoiseFactor >= -MISCUTIL_EPSILON);
  412. //PriorityGrowthPerSecond = netparams_ini.Get_Float(SECTION_NAME, "PriorityGrowthPerSecond", INVALID_VALUE);
  413. //WWASSERT(PriorityGrowthPerSecond >= -MISCUTIL_EPSILON);
  414. _TheFileFactory->Return_File(p_ini_file);
  415. }
  416. }
  417. */
  418. void cNetUtil::Create_Unbound_Socket(SOCKET & sock)
  419. {
  420. sock = ::socket(AF_INET, SOCK_DGRAM, 0);
  421. if (sock == INVALID_SOCKET) {
  422. WSA_ERROR;
  423. }
  424. //
  425. // Enable broadcasts
  426. //
  427. int optval = TRUE;
  428. WSA_CHECK(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *) &optval, sizeof(optval)));
  429. //
  430. // Make socket non-blocking
  431. //
  432. u_long arg = 1L;
  433. WSA_CHECK(ioctlsocket(sock, FIONBIO, (u_long *) &arg));
  434. }
  435. //-------------------------------------------------------------------------------
  436. bool cNetUtil::Create_Bound_Socket(SOCKET & sock, USHORT port, SOCKADDR_IN & local_address)
  437. {
  438. //
  439. // TSS - is all this necessary or is above function OK?
  440. //
  441. Create_Unbound_Socket(sock);
  442. Create_Local_Address(&local_address, port);
  443. int result = ::bind(sock, (LPSOCKADDR) &local_address, sizeof(SOCKADDR_IN));
  444. if (result == 0) {
  445. return true;
  446. } else {
  447. WWASSERT(result == SOCKET_ERROR);
  448. //if (::WSAGetLastError() != WSAEADDRINUSE) {
  449. WSA_ERROR;
  450. //}
  451. return false;
  452. }
  453. }
  454. //-------------------------------------------------------------------------------
  455. void cNetUtil::Close_Socket(SOCKET & sock)
  456. {
  457. ::closesocket(sock);
  458. }
  459. //-----------------------------------------------------------------------------
  460. void cNetUtil::Broadcast(SOCKET & sock, USHORT port, cPacket & packet)
  461. {
  462. SOCKADDR_IN broadcast_address;
  463. Create_Broadcast_Address(&broadcast_address, port);
  464. int bytes_sent;
  465. //WSA_CHECK(bytes_sent = sendto(sock, packet.Data, packet.SendLength,
  466. // 0, &broadcast_address, sizeof(SOCKADDR_IN)));
  467. bytes_sent = sendto(sock, packet.Get_Data(), packet.Get_Compressed_Size_Bytes(),
  468. 0, (LPSOCKADDR) &broadcast_address, sizeof(SOCKADDR_IN));
  469. #pragma message("(TSS) WSAENOBUFS")
  470. //WWDEBUG_SAY(("Sent broadcast, length = %d bytes\n", bytes_sent));
  471. }
  472. //-------------------------------------------------------------------------------
  473. void cNetUtil::Create_Broadcast_Address(LPSOCKADDR_IN p_broadcast_address,
  474. USHORT port)
  475. {
  476. WWASSERT(p_broadcast_address != NULL);
  477. ZeroMemory(p_broadcast_address, sizeof(SOCKADDR_IN));
  478. p_broadcast_address->sin_family = AF_INET;
  479. p_broadcast_address->sin_addr.s_addr = INADDR_BROADCAST; // ::inet_addr("255.255.255.255");
  480. p_broadcast_address->sin_port = ::htons(port);
  481. }
  482. //-------------------------------------------------------------------------------
  483. void cNetUtil::Create_Local_Address(LPSOCKADDR_IN p_local_address, USHORT port)
  484. {
  485. WWASSERT(p_local_address != NULL);
  486. ZeroMemory(p_local_address, sizeof(SOCKADDR_IN));
  487. p_local_address->sin_family = AF_INET;
  488. p_local_address->sin_addr.s_addr = INADDR_ANY;
  489. p_local_address->sin_port = ::htons(port);
  490. }
  491. //-------------------------------------------------------------------------------
  492. bool cNetUtil::Get_Local_Address(LPSOCKADDR_IN p_local_address)
  493. {
  494. WWASSERT(p_local_address != NULL);
  495. /*
  496. const USHORT MAX_ADDRESSES = 1;
  497. int num_addresses = Get_Local_Tcpip_Addresses(p_local_address, MAX_ADDRESSES);
  498. return (num_addresses == 1);
  499. */
  500. const USHORT MAX_ADDRESSES = 10;
  501. SOCKADDR_IN local_address[MAX_ADDRESSES];
  502. int num_addresses = Get_Local_Tcpip_Addresses(local_address, MAX_ADDRESSES);
  503. if (num_addresses > 0) {
  504. ::memcpy(p_local_address, &local_address[0], sizeof(SOCKADDR_IN));
  505. }
  506. return (num_addresses > 0);
  507. }
  508. //-----------------------------------------------------------------------------
  509. void cNetUtil::Lan_Servicing(SOCKET & sock, LanPacketHandlerCallback p_callback)
  510. {
  511. int retcode;
  512. unsigned long start_time = TIMEGETTIME();
  513. do {
  514. cPacket packet;
  515. int address_len = sizeof(SOCKADDR_IN);
  516. //
  517. // If we appear to crash INSIDE recvfrom then this tends to indicate
  518. // that net neighbourhood broke.
  519. //
  520. retcode = recvfrom(sock, packet.Get_Data(), packet.Get_Max_Size(),
  521. 0, (LPSOCKADDR) &packet.Get_From_Address_Wrapper()->FromAddress, &address_len);
  522. if (retcode == SOCKET_ERROR) {
  523. if (::WSAGetLastError() != WSAEWOULDBLOCK) {
  524. WSA_ERROR;
  525. }
  526. } else {
  527. /*
  528. //
  529. // diagnostic
  530. //
  531. ULONG ip = packet.Get_From_Address_Wrapper()->FromAddress.sin_addr.s_addr;
  532. WWDEBUG_SAY(("cNetUtil::Lan_Servicing: %s\n", cNetUtil::Address_To_String(ip)));
  533. */
  534. //packet.Set_Received_Length(retcode);
  535. packet.Set_Bit_Length(retcode * 8);
  536. (*p_callback)(packet);
  537. }
  538. } while (retcode != SOCKET_ERROR); // this will indicate no more data
  539. unsigned long time_spent = TIMEGETTIME() - start_time;
  540. if (time_spent > 100) {
  541. WWDEBUG_SAY(("*** cNetUtil::Lan_Servicing: Too much time (%d ms)) spent receiving lan packets.\n",
  542. time_spent));
  543. }
  544. }