ClientInterface.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "stdh.h"
  13. #include <Engine/Base/CTString.h>
  14. #include <Engine/Base/Console.h>
  15. #include <Engine/Base/ErrorReporting.h>
  16. #include <Engine/Base/ErrorTable.h>
  17. #include <Engine/Base/Lists.h>
  18. #include <Engine/Base/Stream.h>
  19. #include <Engine/Base/Translation.h>
  20. #include <Engine/Network/ClientInterface.h>
  21. #include <Engine/Network/CPacket.h>
  22. #include <Engine/Base/Listiterator.inl>
  23. // how many acknowledges can fit into one UDP packet
  24. #define MAX_ACKS_PER_PACKET (MAX_UDP_BLOCK_SIZE/sizeof(ULONG))
  25. extern FLOAT net_fDropPackets;
  26. extern INDEX net_bReportPackets;
  27. CClientInterface::CClientInterface(void)
  28. {
  29. Clear();
  30. };
  31. CClientInterface::~CClientInterface(void)
  32. {
  33. Clear();
  34. };
  35. void CClientInterface::Clear(void)
  36. {
  37. ci_bUsed = FALSE;
  38. ci_bReliableComplete = FALSE;
  39. ci_pbInputBuffer.Clear();
  40. ci_pbOutputBuffer.Clear();
  41. ci_pbReliableInputBuffer.Clear();
  42. ci_pbWaitAckBuffer.Clear();
  43. ci_adrAddress.Clear();
  44. ci_strAddress = "";
  45. ci_pciOther = NULL;
  46. ci_ulSequence = 0;
  47. };
  48. // mark the client interface as local for this computer
  49. void CClientInterface::SetLocal(CClientInterface *pciOther)
  50. {
  51. Clear();
  52. ci_bUsed = TRUE;
  53. ci_bClientLocal = TRUE;
  54. ci_pciOther = pciOther;
  55. if (pciOther!=NULL) {
  56. pciOther->ci_pciOther = this;
  57. }
  58. ci_adrAddress.Clear();
  59. };
  60. // send a message through this client interface - reliable messages are not limited in size
  61. void CClientInterface::Send(const void *pvSend, SLONG slSize,BOOL bReliable)
  62. {
  63. ASSERT (ci_bUsed == TRUE);
  64. ASSERT(pvSend != NULL && slSize>0);
  65. // unreliable messages must fit within one UDP packet
  66. ASSERT(bReliable != UDP_PACKET_UNRELIABLE || slSize < MAX_UDP_BLOCK_SIZE);
  67. UBYTE ubPacketReliable;
  68. UBYTE* pubData;
  69. SLONG slSizeToSend;
  70. SLONG slTransferSize;
  71. ULONG ulSequence;
  72. CPacket* ppaNewPacket;
  73. //if the message is reliable, make sure the first packet is marked as a head of the message
  74. if (bReliable) {
  75. ubPacketReliable = UDP_PACKET_RELIABLE | UDP_PACKET_RELIABLE_HEAD;
  76. if (slSize <= MAX_UDP_BLOCK_SIZE) {
  77. ubPacketReliable |= UDP_PACKET_RELIABLE_TAIL;
  78. }
  79. } else {
  80. ubPacketReliable = UDP_PACKET_UNRELIABLE;
  81. }
  82. pubData = (UBYTE*) pvSend;
  83. slSizeToSend = slSize;
  84. slTransferSize = slSizeToSend;
  85. // split large reliable messages into packets, and put them in the output buffer
  86. while (slSizeToSend>MAX_UDP_BLOCK_SIZE) {
  87. ppaNewPacket = new CPacket;
  88. // for each packet, increment the sequence (very important)
  89. ulSequence = (++ci_ulSequence);
  90. ppaNewPacket->WriteToPacket(pubData,MAX_UDP_BLOCK_SIZE,ubPacketReliable,ulSequence,ci_adrAddress.adr_uwID,slTransferSize);
  91. ppaNewPacket->pa_adrAddress.adr_ulAddress = ci_adrAddress.adr_ulAddress;
  92. ppaNewPacket->pa_adrAddress.adr_uwPort = ci_adrAddress.adr_uwPort;
  93. ppaNewPacket->pa_adrAddress.adr_uwID = ci_adrAddress.adr_uwID;
  94. ci_pbOutputBuffer.AppendPacket(*ppaNewPacket,TRUE);
  95. // turn off udp head flag, if exists (since we just put a packet in the output buffer, the next
  96. // packet cannot be the head
  97. ubPacketReliable &= UDP_PACKET_RELIABLE;
  98. slSizeToSend -= MAX_UDP_BLOCK_SIZE;
  99. pubData += MAX_UDP_BLOCK_SIZE;
  100. }
  101. // what remains is a tail of a reliable message, or an unreliable packet
  102. if (ubPacketReliable != UDP_PACKET_UNRELIABLE) {
  103. ubPacketReliable |= UDP_PACKET_RELIABLE_TAIL;
  104. }
  105. // so send it
  106. ppaNewPacket = new CPacket;
  107. ulSequence = (++ci_ulSequence);
  108. ppaNewPacket->WriteToPacket(pubData,slSizeToSend,ubPacketReliable,ulSequence,ci_adrAddress.adr_uwID,slTransferSize);
  109. ppaNewPacket->pa_adrAddress.adr_ulAddress = ci_adrAddress.adr_ulAddress;
  110. ppaNewPacket->pa_adrAddress.adr_uwPort = ci_adrAddress.adr_uwPort;
  111. ppaNewPacket->pa_adrAddress.adr_uwID = ci_adrAddress.adr_uwID;
  112. ci_pbOutputBuffer.AppendPacket(*ppaNewPacket,TRUE);
  113. };
  114. // send a message through this client interface, to the provided address
  115. void CClientInterface::SendTo(const void *pvSend, SLONG slSize,const CAddress adrAdress,BOOL bReliable)
  116. {
  117. ASSERT (ci_bUsed);
  118. ASSERT(pvSend != NULL && slSize>0);
  119. // unreliable packets must fit within one UDP packet
  120. ASSERT(bReliable != UDP_PACKET_UNRELIABLE || slSize < MAX_UDP_BLOCK_SIZE);
  121. UBYTE ubPacketReliable;
  122. UBYTE* pubData;
  123. SLONG slSizeToSend;
  124. SLONG slTransferSize;
  125. ULONG ulSequence;
  126. CPacket* ppaNewPacket;
  127. //if the message is reliable, make sure the first packet is marked as a head of the message
  128. if (bReliable) {
  129. ubPacketReliable = UDP_PACKET_RELIABLE | UDP_PACKET_RELIABLE_HEAD;
  130. if (slSize <= MAX_UDP_BLOCK_SIZE) {
  131. ubPacketReliable |= UDP_PACKET_RELIABLE_TAIL;
  132. }
  133. } else {
  134. ubPacketReliable = UDP_PACKET_UNRELIABLE;
  135. }
  136. pubData = (UBYTE*) pvSend;
  137. slSizeToSend = slSize;
  138. slTransferSize = slSizeToSend;
  139. // split large reliable messages into packets, and put them in the output buffer
  140. while (slSizeToSend>MAX_UDP_BLOCK_SIZE) {
  141. ppaNewPacket = new CPacket;
  142. // for each packet, increment the sequence (very important)
  143. ulSequence = (++ci_ulSequence);
  144. ppaNewPacket->WriteToPacket(pubData,MAX_UDP_BLOCK_SIZE,ubPacketReliable,ulSequence,adrAdress.adr_uwID,slTransferSize);
  145. ppaNewPacket->pa_adrAddress.adr_ulAddress = adrAdress.adr_ulAddress;
  146. ppaNewPacket->pa_adrAddress.adr_uwPort = adrAdress.adr_uwPort;
  147. ppaNewPacket->pa_adrAddress.adr_uwID = adrAdress.adr_uwID;
  148. ci_pbOutputBuffer.AppendPacket(*ppaNewPacket,TRUE);
  149. // turn off udp head flag, if exists (since we just put a packet in the output buffer, the next
  150. // packet cannot be the head
  151. ubPacketReliable &= UDP_PACKET_RELIABLE;
  152. slSizeToSend -= MAX_UDP_BLOCK_SIZE;
  153. pubData += MAX_UDP_BLOCK_SIZE;
  154. }
  155. // what remains is a tail of a reliable message, or an unreliable packet
  156. if (ubPacketReliable != UDP_PACKET_UNRELIABLE) {
  157. ubPacketReliable |= UDP_PACKET_RELIABLE_TAIL;
  158. }
  159. ppaNewPacket = new CPacket;
  160. ulSequence = (++ci_ulSequence);
  161. ppaNewPacket->WriteToPacket(pubData,slSizeToSend,ubPacketReliable,ulSequence,adrAdress.adr_uwID,slTransferSize);
  162. ppaNewPacket->pa_adrAddress.adr_ulAddress = adrAdress.adr_ulAddress;
  163. ppaNewPacket->pa_adrAddress.adr_uwPort = adrAdress.adr_uwPort;
  164. ppaNewPacket->pa_adrAddress.adr_uwID = adrAdress.adr_uwID;
  165. ci_pbOutputBuffer.AppendPacket(*ppaNewPacket,TRUE);
  166. };
  167. // receive a message through the interface, discard originating address
  168. BOOL CClientInterface::Receive(void *pvReceive, SLONG &slSize,BOOL bReliable)
  169. {
  170. ASSERT (slSize>0);
  171. ASSERT (pvReceive != NULL);
  172. // we'll use the other receive procedure, and tell it to ignore the address
  173. return ReceiveFrom(pvReceive,slSize,NULL,bReliable);
  174. };
  175. // receive a message through the interface, and fill in the originating address
  176. BOOL CClientInterface::ReceiveFrom(void *pvReceive, SLONG &slSize, CAddress *padrAdress,BOOL bReliable)
  177. {
  178. CPacket* ppaPacket;
  179. UBYTE* pubData = (UBYTE*) pvReceive;
  180. SLONG slDummySize;
  181. UBYTE ubReliable;
  182. // if a reliable message is requested
  183. if (bReliable) {
  184. // if there is no complete reliable message ready
  185. if (ci_pbReliableInputBuffer.CheckSequence(slDummySize) == FALSE) {
  186. return FALSE;
  187. // if the ready message is longer than the expected size
  188. } else if ( GetCurrentReliableSize() > slSize) {
  189. return FALSE;
  190. // if everything is ok, compose the message and kill the packets
  191. } else {
  192. // fill in the originating address (if necessary)
  193. if (padrAdress != NULL) {
  194. ppaPacket = ci_pbReliableInputBuffer.PeekFirstPacket();
  195. padrAdress->adr_ulAddress = ppaPacket->pa_adrAddress.adr_ulAddress;
  196. padrAdress->adr_uwPort = ppaPacket->pa_adrAddress.adr_uwPort;
  197. padrAdress->adr_uwID = ppaPacket->pa_adrAddress.adr_uwID;
  198. }
  199. slSize = 0;
  200. do {
  201. ppaPacket = ci_pbReliableInputBuffer.GetFirstPacket();
  202. ubReliable = ppaPacket->pa_ubReliable;
  203. slDummySize = ppaPacket->pa_slSize - MAX_HEADER_SIZE;
  204. ppaPacket->ReadFromPacket(pubData,slDummySize);
  205. pubData += slDummySize;
  206. slSize += slDummySize;
  207. delete ppaPacket;
  208. } while (!(ubReliable & UDP_PACKET_RELIABLE_TAIL));
  209. return TRUE;
  210. }
  211. // if an unreliable message is requested
  212. } else {
  213. // if there are no packets in the input buffer, return
  214. if (ci_pbInputBuffer.pb_ulNumOfPackets == 0) {
  215. return FALSE;
  216. }
  217. ppaPacket = ci_pbInputBuffer.PeekFirstPacket();
  218. // if the reliable buffer is not empty, nothing can be accepted from the input buffer
  219. // because it would be accepted out-of order (before earlier sequences have been read)
  220. if (ci_pbReliableInputBuffer.pb_ulNumOfPackets != 0) {
  221. return FALSE;
  222. // if the first packet in the input buffer is not unreliable
  223. } else if (ppaPacket->pa_ubReliable != UDP_PACKET_UNRELIABLE) {
  224. return FALSE;
  225. // if the ready message is longer than the expected size
  226. } else if ( ppaPacket->pa_slTransferSize > slSize) {
  227. return FALSE;
  228. // if everything is ok, read the packet data, and kill the packet
  229. } else {
  230. // fill in the originating address (if necessary)
  231. if (padrAdress != NULL) {
  232. padrAdress->adr_ulAddress = ppaPacket->pa_adrAddress.adr_ulAddress;
  233. padrAdress->adr_uwPort = ppaPacket->pa_adrAddress.adr_uwPort;
  234. padrAdress->adr_uwID = ppaPacket->pa_adrAddress.adr_uwID;
  235. }
  236. slSize = ppaPacket->pa_slSize - MAX_HEADER_SIZE;
  237. ppaPacket->ReadFromPacket(pubData,slSize);
  238. // remove the packet from the buffer, and delete it from memory
  239. ci_pbInputBuffer.RemoveFirstPacket(TRUE);
  240. return TRUE;
  241. }
  242. }
  243. return FALSE;
  244. };
  245. // receive a message through the interface, discard originating address
  246. BOOL CClientInterface::Receive(CTStream &strmReceive,UBYTE bReliable)
  247. {
  248. CPacket* ppaPacket;
  249. UBYTE ubReliable;
  250. SLONG slDummySize;
  251. // if a reliable message is requested
  252. if (bReliable) {
  253. // if there is no complete reliable message ready
  254. if (ci_pbReliableInputBuffer.CheckSequence(slDummySize) == FALSE) {
  255. return FALSE;
  256. // if everything is ok, compose the message and kill the packets
  257. } else {
  258. do {
  259. ppaPacket = ci_pbReliableInputBuffer.GetFirstPacket();
  260. ubReliable = ppaPacket->pa_ubReliable;
  261. strmReceive.Write_t(ppaPacket->pa_pubPacketData + MAX_HEADER_SIZE,ppaPacket->pa_slSize - MAX_HEADER_SIZE);
  262. if (ci_pbInputBuffer.pb_ulLastSequenceOut < ppaPacket->pa_ulSequence) {
  263. ci_pbInputBuffer.pb_ulLastSequenceOut = ppaPacket->pa_ulSequence;
  264. }
  265. delete ppaPacket;
  266. } while (!(ubReliable & UDP_PACKET_RELIABLE_TAIL));
  267. return TRUE;
  268. }
  269. // if an unreliable message is requested
  270. } else {
  271. ppaPacket = ci_pbInputBuffer.PeekFirstPacket();
  272. // if the reliable buffer is not empty, nothing can be accepted from the input buffer
  273. // because it would be accepted out-of order (before earlier sequences have been read)
  274. if (ci_pbReliableInputBuffer.pb_ulNumOfPackets != 0) {
  275. return FALSE;
  276. // if the first packet in the input buffer is not unreliable
  277. } else if (ppaPacket->pa_ubReliable != UDP_PACKET_RELIABLE) {
  278. return FALSE;
  279. // if everything is ok, read the packet data, and kill the packet
  280. } else {
  281. strmReceive.Write_t(ppaPacket->pa_pubPacketData + MAX_HEADER_SIZE,ppaPacket->pa_slSize - MAX_HEADER_SIZE);
  282. // remove the packet from the buffer, and delete it from memory
  283. if (ci_pbInputBuffer.pb_ulLastSequenceOut < ppaPacket->pa_ulSequence) {
  284. ci_pbInputBuffer.pb_ulLastSequenceOut = ppaPacket->pa_ulSequence;
  285. }
  286. ci_pbInputBuffer.RemoveFirstPacket(TRUE);
  287. return TRUE;
  288. }
  289. }
  290. return FALSE;
  291. };
  292. // exchanges packets beetween this socket and it's local partner
  293. // from output of this buffet to the input of the other and vice versa
  294. void CClientInterface::ExchangeBuffers(void)
  295. {
  296. ASSERT (ci_pciOther != NULL);
  297. CPacket* ppaPacket;
  298. CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
  299. // take the output from this interface and give it to it's partner socket
  300. while (ci_pbOutputBuffer.pb_ulNumOfPackets > 0) {
  301. ppaPacket = ci_pbOutputBuffer.PeekFirstPacket();
  302. if (ppaPacket->pa_tvSendWhen < tvNow) {
  303. ci_pbOutputBuffer.RemoveFirstPacket(FALSE);
  304. if (ci_pciOther->ci_pbInputBuffer.InsertPacket(*ppaPacket,FALSE) == FALSE) {
  305. delete ppaPacket;
  306. }
  307. } else {
  308. break;
  309. }
  310. }
  311. // and the other way around
  312. while (ci_pciOther->ci_pbOutputBuffer.pb_ulNumOfPackets > 0) {
  313. ppaPacket = ci_pciOther->ci_pbOutputBuffer.PeekFirstPacket();
  314. if (ppaPacket->pa_tvSendWhen < tvNow) {
  315. ppaPacket = ci_pciOther->ci_pbOutputBuffer.GetFirstPacket();
  316. if (ci_pbInputBuffer.InsertPacket(*ppaPacket,FALSE) == FALSE) {
  317. delete ppaPacket;
  318. };
  319. } else {
  320. break;
  321. }
  322. }
  323. };
  324. // update interface's input buffer (transfer from input buffer to the reliable buffer...),
  325. // for incoming acknowledge packets, remove acknowledged packets from the output buffers,
  326. // and generate acknowledge messages for incoming reliable packets
  327. BOOL CClientInterface::UpdateInputBuffers(void)
  328. {
  329. BOOL bSomethingDone;
  330. ULONG pulGenAck[MAX_ACKS_PER_PACKET];
  331. ULONG ulAckCount=0;
  332. CTimerValue tvNow;
  333. // if there are packets in the input buffer, process them
  334. FORDELETELIST(CPacket,pa_lnListNode,ci_pbInputBuffer.pb_lhPacketStorage,ppaPacket) {
  335. CPacket &paPacket = *ppaPacket;
  336. // if it's an acknowledge packet, remove the acknowledged packets from the wait acknowledge buffer
  337. if (ppaPacket->pa_ubReliable & UDP_PACKET_ACKNOWLEDGE) {
  338. ULONG *pulAck;
  339. SLONG slSize;
  340. ULONG ulSequence;
  341. slSize = ppaPacket->pa_slSize - MAX_HEADER_SIZE;
  342. // if slSize isn't rounded to the size of ulSequence, abort
  343. ASSERT (slSize % sizeof(ULONG) == 0);
  344. // get the pointer to the start of acknowledged sequences
  345. pulAck = (ULONG*) (ppaPacket->pa_pubPacketData + MAX_HEADER_SIZE);
  346. // for each acknowledged sequence number
  347. while (slSize>0) {
  348. ulSequence = *pulAck;
  349. // report the packet info to the console
  350. if (net_bReportPackets == TRUE) {
  351. tvNow = _pTimer->GetHighPrecisionTimer();
  352. CPrintF("%lu: Received acknowledge for packet sequence %d\n",(ULONG) tvNow.GetMilliseconds(),ulSequence);
  353. }
  354. // remove the matching packet from the wait acknowledge buffer
  355. ci_pbWaitAckBuffer.RemovePacket(ulSequence,TRUE);
  356. // if the packet is waiting to be resent it's in the outgoing buffer, so remove it
  357. ci_pbOutputBuffer.RemovePacket(ulSequence,TRUE);
  358. pulAck++;
  359. slSize -= sizeof(ULONG);
  360. }
  361. // take this packet out of the input buffer and kill it
  362. ci_pbInputBuffer.RemovePacket(ppaPacket->pa_ulSequence,FALSE);
  363. delete ppaPacket;
  364. bSomethingDone = TRUE;
  365. // if the packet is reliable
  366. } else if (ppaPacket->pa_ubReliable & UDP_PACKET_RELIABLE) {
  367. // generate packet acknowledge
  368. // if the packet is from the broadcast address, send the acknowledge for that packet only
  369. if (ppaPacket->pa_adrAddress.adr_uwID == '//' || ppaPacket->pa_adrAddress.adr_uwID == 0) {
  370. CPacket *ppaAckPacket = new CPacket;
  371. ppaAckPacket->pa_adrAddress.adr_ulAddress = ppaPacket->pa_adrAddress.adr_ulAddress;
  372. ppaAckPacket->pa_adrAddress.adr_uwPort = ppaPacket->pa_adrAddress.adr_uwPort;
  373. ppaAckPacket->WriteToPacket(&(ppaPacket->pa_ulSequence),sizeof(ULONG),UDP_PACKET_ACKNOWLEDGE,++ci_ulSequence,'//',sizeof(ULONG));
  374. ci_pbOutputBuffer.AppendPacket(*ppaAckPacket,TRUE);
  375. if (net_bReportPackets == TRUE) {
  376. CPrintF("Acknowledging broadcast packet sequence %d\n",ppaPacket->pa_ulSequence);
  377. }
  378. ci_pbInputBuffer.RemovePacket(ppaPacket->pa_ulSequence,FALSE);
  379. } else {
  380. // if we have filled the packet to the maximum with acknowledges (an extremely rare event)
  381. // finish this packet and start the next one
  382. if (ulAckCount == MAX_ACKS_PER_PACKET) {
  383. CPacket *ppaAckPacket = new CPacket;
  384. ppaAckPacket->pa_adrAddress.adr_ulAddress = ci_adrAddress.adr_ulAddress;
  385. ppaAckPacket->pa_adrAddress.adr_uwPort = ci_adrAddress.adr_uwPort;
  386. ppaAckPacket->WriteToPacket(pulGenAck,ulAckCount*sizeof(ULONG),UDP_PACKET_ACKNOWLEDGE,++ci_ulSequence,ci_adrAddress.adr_uwID,ulAckCount*sizeof(ULONG));
  387. ci_pbOutputBuffer.AppendPacket(*ppaAckPacket,TRUE);
  388. ulAckCount = 0;
  389. }
  390. // add the acknowledge for this packet
  391. pulGenAck[ulAckCount] = ppaPacket->pa_ulSequence;
  392. // report the packet info to the console
  393. if (net_bReportPackets == TRUE) {
  394. tvNow = _pTimer->GetHighPrecisionTimer();
  395. CPrintF("%lu: Acknowledging packet sequence %d\n",(ULONG) tvNow.GetMilliseconds(),ppaPacket->pa_ulSequence);
  396. }
  397. ulAckCount++;
  398. }
  399. // take this packet out of the input buffer
  400. ci_pbInputBuffer.RemovePacket(ppaPacket->pa_ulSequence,FALSE);
  401. if (ppaPacket->pa_ulSequence == 8) {
  402. ppaPacket->pa_ulSequence = 8;
  403. }
  404. // a packet can be accepted from the broadcast ID only if it is an acknowledge packet or
  405. // if it is a connection confirmation response packet and the client isn't already connected
  406. if (ppaPacket->pa_adrAddress.adr_uwID == '//' || ppaPacket->pa_adrAddress.adr_uwID == 0) {
  407. if (((!ci_bUsed) && (ppaPacket->pa_ubReliable & UDP_PACKET_CONNECT_RESPONSE)) ||
  408. (ppaPacket->pa_ubReliable & UDP_PACKET_ACKNOWLEDGE) || ci_bClientLocal) {
  409. /* if (ci_pbReliableInputBuffer.pb_ulLastSequenceOut >= ppaPacket->pa_ulSequence) {
  410. delete ppaPacket;
  411. } else*/
  412. ppaPacket->pa_ulSequence = 0;
  413. if (ci_pbReliableInputBuffer.InsertPacket(*ppaPacket,FALSE) == FALSE) {
  414. delete ppaPacket;
  415. }
  416. } else {
  417. delete ppaPacket;
  418. }
  419. // reject duplicates
  420. } else if (ppaPacket->pa_ulSequence > ci_pbReliableInputBuffer.pb_ulLastSequenceOut &&
  421. !(ci_pbReliableInputBuffer.IsSequenceInBuffer(ppaPacket->pa_ulSequence))) {
  422. if (ci_pbReliableInputBuffer.InsertPacket(*ppaPacket,FALSE) == FALSE) {
  423. delete ppaPacket;
  424. }
  425. } else {
  426. delete ppaPacket;
  427. }
  428. // if the packet is unreliable, leave it in the input buffer
  429. // when it is needed, the message will be pulled from there
  430. } else {
  431. // reject duplicates
  432. ci_pbInputBuffer.RemovePacket(ppaPacket->pa_ulSequence,FALSE);
  433. if (ppaPacket->pa_ulSequence > ci_pbInputBuffer.pb_ulLastSequenceOut &&
  434. !(ci_pbReliableInputBuffer.IsSequenceInBuffer(ppaPacket->pa_ulSequence))) {
  435. if (ci_pbInputBuffer.InsertPacket(*ppaPacket,FALSE) == FALSE) {
  436. delete ppaPacket;
  437. }
  438. } else {
  439. delete ppaPacket;
  440. }
  441. }
  442. }
  443. // if there are any remaining unsent acknowldges, put them into a packet and send it
  444. if (ulAckCount >0) {
  445. CPacket *ppaAckPacket = new CPacket;
  446. ppaAckPacket->pa_adrAddress.adr_ulAddress = ci_adrAddress.adr_ulAddress;
  447. ppaAckPacket->pa_adrAddress.adr_uwPort = ci_adrAddress.adr_uwPort;
  448. ppaAckPacket->WriteToPacket(pulGenAck,ulAckCount*sizeof(ULONG),UDP_PACKET_ACKNOWLEDGE,++ci_ulSequence,ci_adrAddress.adr_uwID,ulAckCount*sizeof(ULONG));
  449. ci_pbOutputBuffer.AppendPacket(*ppaAckPacket,TRUE);
  450. }
  451. return TRUE;
  452. };
  453. // update socket input buffer (transfer from input buffer to the reliable buffer...),
  454. // for incoming acknowledge packets, remove acknowledged packets from the output buffers,
  455. // and generate acknowledge messages for incoming reliable packets
  456. // this method is different than the previous becoause it sends acknowledges for each
  457. // packet separately, instead of grouping them together
  458. BOOL CClientInterface::UpdateInputBuffersBroadcast(void)
  459. {
  460. BOOL bSomethingDone;
  461. CTimerValue tvNow;
  462. // if there are packets in the input buffer, process them
  463. FORDELETELIST(CPacket,pa_lnListNode,ci_pbInputBuffer.pb_lhPacketStorage,ppaPacket) {
  464. CPacket &paPacket = *ppaPacket;
  465. // if it's an acknowledge packet, remove the acknowledged packets from the wait acknowledge buffer
  466. if (ppaPacket->pa_ubReliable & UDP_PACKET_ACKNOWLEDGE) {
  467. ULONG *pulAck;
  468. SLONG slSize;
  469. ULONG ulSequence;
  470. slSize = ppaPacket->pa_slSize - MAX_HEADER_SIZE;
  471. // if slSize isn't rounded to the size of ulSequence, abort
  472. ASSERT (slSize % sizeof(ULONG) == 0);
  473. // get the pointer to the start of acknowledged sequences
  474. pulAck = (ULONG*) (ppaPacket->pa_pubPacketData + MAX_HEADER_SIZE);
  475. // for each acknowledged sequence number
  476. while (slSize>0) {
  477. ulSequence = *pulAck;
  478. // report the packet info to the console
  479. if (net_bReportPackets == TRUE) {
  480. tvNow = _pTimer->GetHighPrecisionTimer();
  481. CPrintF("%lu: Received acknowledge for broadcast packet sequence %d\n",(ULONG) tvNow.GetMilliseconds(),ulSequence);
  482. }
  483. // remove the matching packet from the wait acknowledge buffer
  484. ci_pbWaitAckBuffer.RemovePacket(ulSequence,TRUE);
  485. // if the packet is waiting to be resent it's in the outgoing buffer, so remove it
  486. ci_pbOutputBuffer.RemovePacket(ulSequence,TRUE);
  487. pulAck++;
  488. slSize -= sizeof(ULONG);
  489. }
  490. ci_pbInputBuffer.RemovePacket(ppaPacket->pa_ulSequence,FALSE);
  491. bSomethingDone = TRUE;
  492. delete ppaPacket;
  493. // if the packet is reliable
  494. } else if (ppaPacket->pa_ubReliable & UDP_PACKET_RELIABLE) {
  495. // generate packet acknowledge (each reliable broadcast packet is acknowledged separately
  496. // because the broadcast interface can receive packets from any number of different addresses
  497. CPacket *ppaAckPacket = new CPacket;
  498. ppaAckPacket->pa_adrAddress.adr_ulAddress = ppaPacket->pa_adrAddress.adr_ulAddress;
  499. ppaAckPacket->pa_adrAddress.adr_uwPort = ppaPacket->pa_adrAddress.adr_uwPort;
  500. ppaAckPacket->WriteToPacket(&(ppaPacket->pa_ulSequence),sizeof(ULONG),UDP_PACKET_ACKNOWLEDGE,ci_ulSequence++,ppaPacket->pa_adrAddress.adr_uwID,sizeof(ULONG));
  501. ci_pbOutputBuffer.AppendPacket(*ppaAckPacket,TRUE);
  502. // report the packet info to the console
  503. if (net_bReportPackets == TRUE) {
  504. tvNow = _pTimer->GetHighPrecisionTimer();
  505. CPrintF("%lu: Acknowledging broadcast packet sequence %d\n",(ULONG) tvNow.GetMilliseconds(),ppaPacket->pa_ulSequence);
  506. }
  507. ci_pbInputBuffer.RemovePacket(ppaPacket->pa_ulSequence,FALSE);
  508. if (ci_pbReliableInputBuffer.InsertPacket(*ppaPacket,FALSE) == FALSE) {
  509. delete ppaPacket;
  510. }
  511. } else {
  512. // if the packet is unreliable, leave it in the input buffer
  513. // when it is needed, the message will be pulled from there
  514. // have to check for duplicates
  515. ci_pbInputBuffer.RemovePacket(ppaPacket->pa_ulSequence,FALSE);
  516. if (ppaPacket->pa_ulSequence > ci_pbInputBuffer.pb_ulLastSequenceOut &&
  517. !(ci_pbReliableInputBuffer.IsSequenceInBuffer(ppaPacket->pa_ulSequence))) {
  518. if (ci_pbInputBuffer.InsertPacket(*ppaPacket,FALSE) == FALSE) {
  519. delete ppaPacket;
  520. }
  521. } else {
  522. delete ppaPacket;
  523. }
  524. }
  525. }
  526. return TRUE;
  527. };
  528. // take a look at the wait acknowledge buffer and resend any packets that heve reached the timeout
  529. // if there is a packet that can't be sent sucessfully (RS_NOTATALL), signal it
  530. BOOL CClientInterface::UpdateOutputBuffers(void)
  531. {
  532. CPacket* ppaPacket;
  533. UBYTE ubRetry;
  534. // handle resends
  535. while (ci_pbWaitAckBuffer.pb_ulNumOfPackets > 0) {
  536. ppaPacket = ci_pbWaitAckBuffer.PeekFirstPacket();
  537. ubRetry = ppaPacket->CanRetry();
  538. switch (ubRetry) {
  539. // if it's time to retry sending the packet
  540. case RS_NOW: { ci_pbWaitAckBuffer.RemoveFirstPacket(FALSE);
  541. ci_pbOutputBuffer.Retry(*ppaPacket);
  542. break;
  543. }
  544. // if the packet cannot be sent now, no other packets can be sent, so exit
  545. case RS_NOTNOW: { return TRUE; }
  546. // if the packet has reached the retry limit - close the client's connection
  547. case RS_NOTATALL: { Clear();
  548. return FALSE;
  549. }
  550. }
  551. }
  552. return TRUE;
  553. };
  554. // get the next available packet from the output buffer
  555. CPacket* CClientInterface::GetPendingPacket(void)
  556. {
  557. CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
  558. if (ci_pbOutputBuffer.pb_ulNumOfPackets == 0) {
  559. return NULL;
  560. }
  561. CPacket* ppaPacket = ci_pbOutputBuffer.PeekFirstPacket();
  562. // if it's time to send the packet
  563. if (ppaPacket->pa_tvSendWhen <= tvNow) {
  564. ci_pbOutputBuffer.RemoveFirstPacket(FALSE);
  565. return ppaPacket;
  566. }
  567. return NULL;
  568. };
  569. // reads the expected size of current realiable message in the reliable input buffer
  570. SLONG CClientInterface::GetExpectedReliableSize(void)
  571. {
  572. if (ci_pbReliableInputBuffer.pb_ulNumOfPackets == 0) {
  573. return 0;
  574. }
  575. CPacket* ppaPacket = ci_pbReliableInputBuffer.PeekFirstPacket();
  576. return ppaPacket->pa_slTransferSize;
  577. };
  578. // reads the expected size of current realiable message in the reliable input buffer
  579. SLONG CClientInterface::GetCurrentReliableSize(void)
  580. {
  581. SLONG slSize;
  582. ci_pbReliableInputBuffer.CheckSequence(slSize);
  583. return slSize;
  584. };