udp.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. /*
  2. ** Command & Conquer Generals(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. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: Udp.cpp //////////////////////////////////////////////////////////////
  24. // Implementation of UDP socket wrapper class (taken from wnet lib)
  25. // Author: Matthew D. Campbell, July 2001
  26. ///////////////////////////////////////////////////////////////////////////////
  27. // SYSTEM INCLUDES ////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. // USER INCLUDES //////////////////////////////////////////////////////////////
  30. #include "Common/GameEngine.h"
  31. //#include "GameNetwork/NetworkInterface.h"
  32. #include "GameNetwork/udp.h"
  33. #ifdef _INTERNAL
  34. // for occasional debugging...
  35. //#pragma optimize("", off)
  36. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  37. #endif
  38. //-------------------------------------------------------------------------
  39. #if defined(_DEBUG) || defined(_INTERNAL)
  40. #define CASE(x) case (x): return #x;
  41. AsciiString GetWSAErrorString( Int error )
  42. {
  43. switch (error)
  44. {
  45. CASE(WSABASEERR)
  46. CASE(WSAEINTR)
  47. CASE(WSAEBADF)
  48. CASE(WSAEACCES)
  49. CASE(WSAEFAULT)
  50. CASE(WSAEINVAL)
  51. CASE(WSAEMFILE)
  52. CASE(WSAEWOULDBLOCK)
  53. CASE(WSAEINPROGRESS)
  54. CASE(WSAEALREADY)
  55. CASE(WSAENOTSOCK)
  56. CASE(WSAEDESTADDRREQ)
  57. CASE(WSAEMSGSIZE)
  58. CASE(WSAEPROTOTYPE)
  59. CASE(WSAENOPROTOOPT)
  60. CASE(WSAEPROTONOSUPPORT)
  61. CASE(WSAESOCKTNOSUPPORT)
  62. CASE(WSAEOPNOTSUPP)
  63. CASE(WSAEPFNOSUPPORT)
  64. CASE(WSAEAFNOSUPPORT)
  65. CASE(WSAEADDRINUSE)
  66. CASE(WSAEADDRNOTAVAIL)
  67. CASE(WSAENETDOWN)
  68. CASE(WSAENETUNREACH)
  69. CASE(WSAENETRESET)
  70. CASE(WSAECONNABORTED)
  71. CASE(WSAECONNRESET)
  72. CASE(WSAENOBUFS)
  73. CASE(WSAEISCONN)
  74. CASE(WSAENOTCONN)
  75. CASE(WSAESHUTDOWN)
  76. CASE(WSAETOOMANYREFS)
  77. CASE(WSAETIMEDOUT)
  78. CASE(WSAECONNREFUSED)
  79. CASE(WSAELOOP)
  80. CASE(WSAENAMETOOLONG)
  81. CASE(WSAEHOSTDOWN)
  82. CASE(WSAEHOSTUNREACH)
  83. CASE(WSAENOTEMPTY)
  84. CASE(WSAEPROCLIM)
  85. CASE(WSAEUSERS)
  86. CASE(WSAEDQUOT)
  87. CASE(WSAESTALE)
  88. CASE(WSAEREMOTE)
  89. CASE(WSAEDISCON)
  90. CASE(WSASYSNOTREADY)
  91. CASE(WSAVERNOTSUPPORTED)
  92. CASE(WSANOTINITIALISED)
  93. CASE(WSAHOST_NOT_FOUND)
  94. CASE(WSATRY_AGAIN)
  95. CASE(WSANO_RECOVERY)
  96. CASE(WSANO_DATA)
  97. default:
  98. {
  99. AsciiString ret;
  100. ret.format("Not a Winsock error (%d)", error);
  101. return ret;
  102. }
  103. }
  104. return AsciiString::TheEmptyString; // will not be hit, ever.
  105. }
  106. #undef CASE
  107. #endif // defined(_DEBUG) || defined(_INTERNAL)
  108. //-------------------------------------------------------------------------
  109. UDP::UDP()
  110. {
  111. fd=0;
  112. }
  113. UDP::~UDP()
  114. {
  115. if (fd)
  116. closesocket(fd);
  117. }
  118. Int UDP::Bind(const char *Host,UnsignedShort port)
  119. {
  120. char hostName[100];
  121. struct hostent *hostStruct;
  122. struct in_addr *hostNode;
  123. if (isdigit(Host[0]))
  124. return ( Bind( ntohl(inet_addr(Host)), port) );
  125. strcpy(hostName, Host);
  126. hostStruct = gethostbyname(Host);
  127. if (hostStruct == NULL)
  128. return (0);
  129. hostNode = (struct in_addr *) hostStruct->h_addr;
  130. return ( Bind(ntohl(hostNode->s_addr),port) );
  131. }
  132. // You must call bind, implicit binding is for sissies
  133. // Well... you can get implicit binding if you pass 0 for either arg
  134. Int UDP::Bind(UnsignedInt IP,UnsignedShort Port)
  135. {
  136. int retval;
  137. int status;
  138. IP=htonl(IP);
  139. Port=htons(Port);
  140. addr.sin_family=AF_INET;
  141. addr.sin_port=Port;
  142. addr.sin_addr.s_addr=IP;
  143. fd=socket(AF_INET,SOCK_DGRAM,DEFAULT_PROTOCOL);
  144. #ifdef _WINDOWS
  145. if (fd==SOCKET_ERROR)
  146. fd=-1;
  147. #endif
  148. if (fd==-1)
  149. return(UNKNOWN);
  150. retval=bind(fd,(struct sockaddr *)&addr,sizeof(addr));
  151. #ifdef _WINDOWS
  152. if (retval==SOCKET_ERROR)
  153. {
  154. retval=-1;
  155. m_lastError = WSAGetLastError();
  156. }
  157. #endif
  158. if (retval==-1)
  159. {
  160. status=GetStatus();
  161. //CERR("Bind failure (" << status << ") IP " << IP << " PORT " << Port )
  162. return(status);
  163. }
  164. int namelen=sizeof(addr);
  165. getsockname(fd, (struct sockaddr *)&addr, &namelen);
  166. myIP=ntohl(addr.sin_addr.s_addr);
  167. myPort=ntohs(addr.sin_port);
  168. retval=SetBlocking(FALSE);
  169. if (retval==-1)
  170. fprintf(stderr,"Couldn't set nonblocking mode!\n");
  171. return(OK);
  172. }
  173. Int UDP::getLocalAddr(UnsignedInt &ip, UnsignedShort &port)
  174. {
  175. ip=myIP;
  176. port=myPort;
  177. return(OK);
  178. }
  179. // private function
  180. Int UDP::SetBlocking(Int block)
  181. {
  182. #ifdef _WINDOWS
  183. unsigned long flag=1;
  184. if (block)
  185. flag=0;
  186. int retval;
  187. retval=ioctlsocket(fd,FIONBIO,&flag);
  188. if (retval==SOCKET_ERROR)
  189. return(UNKNOWN);
  190. else
  191. return(OK);
  192. #else // UNIX
  193. int flags = fcntl(fd, F_GETFL, 0);
  194. if (block==FALSE) // set nonblocking
  195. flags |= O_NONBLOCK;
  196. else // set blocking
  197. flags &= ~(O_NONBLOCK);
  198. if (fcntl(fd, F_SETFL, flags) < 0)
  199. {
  200. return(UNKNOWN);
  201. }
  202. return(OK);
  203. #endif
  204. }
  205. Int UDP::Write(const unsigned char *msg,UnsignedInt len,UnsignedInt IP,UnsignedShort port)
  206. {
  207. Int retval;
  208. struct sockaddr_in to;
  209. // This happens frequently
  210. if ((IP==0)||(port==0)) return(ADDRNOTAVAIL);
  211. #ifdef _UNIX
  212. errno=0;
  213. #endif
  214. to.sin_port=htons(port);
  215. to.sin_addr.s_addr=htonl(IP);
  216. to.sin_family=AF_INET;
  217. ClearStatus();
  218. retval=sendto(fd,(const char *)msg,len,0,(struct sockaddr *)&to,sizeof(to));
  219. #ifdef _WINDOWS
  220. if (retval==SOCKET_ERROR)
  221. {
  222. retval=-1;
  223. m_lastError = WSAGetLastError();
  224. #ifdef DEBUG_LOGGING
  225. static Int errCount = 0;
  226. #endif
  227. DEBUG_ASSERTLOG(errCount++ > 100, ("UDP::Write() - WSA error is %s\n", GetWSAErrorString(WSAGetLastError()).str()));
  228. }
  229. #endif
  230. return(retval);
  231. }
  232. Int UDP::Read(unsigned char *msg,UnsignedInt len,sockaddr_in *from)
  233. {
  234. Int retval;
  235. int alen=sizeof(sockaddr_in);
  236. if (from!=NULL)
  237. {
  238. retval=recvfrom(fd,(char *)msg,len,0,(struct sockaddr *)from,&alen);
  239. #ifdef _WINDOWS
  240. if (retval == SOCKET_ERROR)
  241. {
  242. if (WSAGetLastError() != WSAEWOULDBLOCK)
  243. {
  244. // failing because of a blocking error isn't really such a bad thing.
  245. m_lastError = WSAGetLastError();
  246. #ifdef DEBUG_LOGGING
  247. static Int errCount = 0;
  248. #endif
  249. DEBUG_ASSERTLOG(errCount++ > 100, ("UDP::Read() - WSA error is %s\n", GetWSAErrorString(WSAGetLastError()).str()));
  250. retval = -1;
  251. } else {
  252. retval = 0;
  253. }
  254. }
  255. #endif
  256. }
  257. else
  258. {
  259. retval=recvfrom(fd,(char *)msg,len,0,NULL,NULL);
  260. #ifdef _WINDOWS
  261. if (retval==SOCKET_ERROR)
  262. {
  263. if (WSAGetLastError() != WSAEWOULDBLOCK)
  264. {
  265. // failing because of a blocking error isn't really such a bad thing.
  266. m_lastError = WSAGetLastError();
  267. #ifdef DEBUG_LOGGING
  268. static Int errCount = 0;
  269. #endif
  270. DEBUG_ASSERTLOG(errCount++ > 100, ("UDP::Read() - WSA error is %s\n", GetWSAErrorString(WSAGetLastError()).str()));
  271. retval = -1;
  272. } else {
  273. retval = 0;
  274. }
  275. }
  276. #endif
  277. }
  278. return(retval);
  279. }
  280. void UDP::ClearStatus(void)
  281. {
  282. #ifndef _WINDOWS
  283. errno=0;
  284. #endif
  285. m_lastError = 0;
  286. }
  287. UDP::sockStat UDP::GetStatus(void)
  288. {
  289. Int status = m_lastError;
  290. #ifdef _WINDOWS
  291. //int status=WSAGetLastError();
  292. if (status==0) return(OK);
  293. else if (status==WSAEINTR) return(INTR);
  294. else if (status==WSAEINPROGRESS) return(INPROGRESS);
  295. else if (status==WSAECONNREFUSED) return(CONNREFUSED);
  296. else if (status==WSAEINVAL) return(INVAL);
  297. else if (status==WSAEISCONN) return(ISCONN);
  298. else if (status==WSAENOTSOCK) return(NOTSOCK);
  299. else if (status==WSAETIMEDOUT) return(TIMEDOUT);
  300. else if (status==WSAEALREADY) return(ALREADY);
  301. else if (status==WSAEWOULDBLOCK) return(WOULDBLOCK);
  302. else if (status==WSAEBADF) return(BADF);
  303. else return((UDP::sockStat)status);
  304. #else
  305. //int status=errno;
  306. if (status==0) return(OK);
  307. else if (status==EINTR) return(INTR);
  308. else if (status==EINPROGRESS) return(INPROGRESS);
  309. else if (status==ECONNREFUSED) return(CONNREFUSED);
  310. else if (status==EINVAL) return(INVAL);
  311. else if (status==EISCONN) return(ISCONN);
  312. else if (status==ENOTSOCK) return(NOTSOCK);
  313. else if (status==ETIMEDOUT) return(TIMEDOUT);
  314. else if (status==EALREADY) return(ALREADY);
  315. else if (status==EAGAIN) return(AGAIN);
  316. else if (status==EWOULDBLOCK) return(WOULDBLOCK);
  317. else if (status==EBADF) return(BADF);
  318. else return(UNKNOWN);
  319. #endif
  320. }
  321. /*
  322. //
  323. // Wait for net activity on this socket
  324. //
  325. int UDP::Wait(Int sec,Int usec,fd_set &returnSet)
  326. {
  327. fd_set inputSet;
  328. FD_ZERO(&inputSet);
  329. FD_SET(fd,&inputSet);
  330. return(Wait(sec,usec,inputSet,returnSet));
  331. }
  332. */
  333. /*
  334. //
  335. // Wait for net activity on a list of sockets
  336. //
  337. int UDP::Wait(Int sec,Int usec,fd_set &givenSet,fd_set &returnSet)
  338. {
  339. Wtime timeout,timenow,timethen;
  340. fd_set backupSet;
  341. int retval=0,done,givenMax;
  342. Bool noTimeout=FALSE;
  343. timeval tv;
  344. returnSet=givenSet;
  345. backupSet=returnSet;
  346. if ((sec==-1)&&(usec==-1))
  347. noTimeout=TRUE;
  348. timeout.SetSec(sec);
  349. timeout.SetUsec(usec);
  350. timethen+=timeout;
  351. givenMax=fd;
  352. for (UnsignedInt i=0; i<(sizeof(fd_set)*8); i++) // i=maxFD+1
  353. {
  354. if (FD_ISSET(i,&givenSet))
  355. givenMax=i;
  356. }
  357. ///DBGMSG("WAIT fd="<<fd<<" givenMax="<<givenMax);
  358. done=0;
  359. while( ! done)
  360. {
  361. if (noTimeout)
  362. retval=select(givenMax+1,&returnSet,0,0,NULL);
  363. else
  364. {
  365. timeout.GetTimevalMT(tv);
  366. retval=select(givenMax+1,&returnSet,0,0,&tv);
  367. }
  368. if (retval>=0)
  369. done=1;
  370. else if ((retval==-1)&&(errno==EINTR)) // in case of signal
  371. {
  372. if (noTimeout==FALSE)
  373. {
  374. timenow.Update();
  375. timeout=timethen-timenow;
  376. }
  377. if ((noTimeout==FALSE)&&(timenow.GetSec()==0)&&(timenow.GetUsec()==0))
  378. done=1;
  379. else
  380. returnSet=backupSet;
  381. }
  382. else // maybe out of memory?
  383. {
  384. done=1;
  385. }
  386. }
  387. ///DBGMSG("Wait retval: "<<retval);
  388. return(retval);
  389. }
  390. */
  391. // Set the kernel buffer sizes for incoming, and outgoing packets
  392. //
  393. // Linux seems to have a buffer max of 32767 bytes for this,
  394. // (which is the default). If you try and set the size to
  395. // greater than the default it just sets it to 32767.
  396. Int UDP::SetInputBuffer(UnsignedInt bytes)
  397. {
  398. int retval,arg=bytes;
  399. retval=setsockopt(fd,SOL_SOCKET,SO_RCVBUF,
  400. (char *)&arg,sizeof(int));
  401. if (retval==0)
  402. return(TRUE);
  403. else
  404. return(FALSE);
  405. }
  406. // Same note goes for the output buffer
  407. Int UDP::SetOutputBuffer(UnsignedInt bytes)
  408. {
  409. int retval,arg=bytes;
  410. retval=setsockopt(fd,SOL_SOCKET,SO_SNDBUF,
  411. (char *)&arg,sizeof(int));
  412. if (retval==0)
  413. return(TRUE);
  414. else
  415. return(FALSE);
  416. }
  417. // Get the system buffer sizes
  418. int UDP::GetInputBuffer(void)
  419. {
  420. int retval,arg=0,len=sizeof(int);
  421. retval=getsockopt(fd,SOL_SOCKET,SO_RCVBUF,
  422. (char *)&arg,&len);
  423. return(arg);
  424. }
  425. int UDP::GetOutputBuffer(void)
  426. {
  427. int retval,arg=0,len=sizeof(int);
  428. retval=getsockopt(fd,SOL_SOCKET,SO_SNDBUF,
  429. (char *)&arg,&len);
  430. return(arg);
  431. }
  432. Int UDP::AllowBroadcasts(Bool status)
  433. {
  434. int retval;
  435. BOOL val = status;
  436. retval = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *)&val, sizeof(BOOL));
  437. if (retval == 0)
  438. return TRUE;
  439. else
  440. return FALSE;
  441. }