Buffer.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  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/Math/Functions.h>
  14. #include <Engine/Base/Memory.h>
  15. #include <Engine/Base/Console.h>
  16. #include <Engine/Base/Stream.h>
  17. #include <Engine/Network/Buffer.h>
  18. // default constructor
  19. CBuffer::CBuffer(void)
  20. {
  21. bu_slAllocationStep = 1024;
  22. bu_slWriteOffset = 0;
  23. bu_slReadOffset = 0;
  24. bu_slFree = 0;
  25. bu_slSize = 0;
  26. bu_pubBuffer = NULL;
  27. }
  28. // destructor
  29. CBuffer::~CBuffer(void)
  30. {
  31. Clear();
  32. }
  33. // free buffer
  34. void CBuffer::Clear(void)
  35. {
  36. bu_slWriteOffset = 0;
  37. bu_slReadOffset = 0;
  38. if (bu_slSize>0) {
  39. ASSERT(bu_pubBuffer!=NULL);
  40. FreeMemory(bu_pubBuffer);
  41. }
  42. bu_slFree = 0;
  43. bu_slSize = 0;
  44. bu_pubBuffer = NULL;
  45. }
  46. // expand buffer to be given number of bytes in size
  47. void CBuffer::Expand(SLONG slNewSize)
  48. {
  49. ASSERT(slNewSize>0);
  50. ASSERT(bu_slSize>=0);
  51. // if not already allocated
  52. if (bu_slSize==0) {
  53. // allocate a new empty buffer
  54. ASSERT(bu_pubBuffer==NULL);
  55. bu_pubBuffer = (UBYTE*)AllocMemory(slNewSize);
  56. bu_slWriteOffset = 0;
  57. bu_slReadOffset = 0;
  58. bu_slFree = slNewSize;
  59. bu_slSize = slNewSize;
  60. // if already allocated
  61. } else {
  62. ASSERT(slNewSize>bu_slSize);
  63. SLONG slSizeDiff = slNewSize-bu_slSize;
  64. ASSERT(bu_pubBuffer!=NULL);
  65. // grow buffer
  66. GrowMemory((void**)&bu_pubBuffer, slNewSize);
  67. // if buffer is currently wrapping
  68. if (bu_slReadOffset>bu_slWriteOffset||bu_slFree==0) {
  69. // move part at the end of buffer to the end
  70. memmove(bu_pubBuffer+bu_slReadOffset+slSizeDiff, bu_pubBuffer+bu_slReadOffset,
  71. bu_slSize-bu_slReadOffset);
  72. bu_slReadOffset+=slSizeDiff;
  73. }
  74. bu_slFree += slNewSize-bu_slSize;
  75. bu_slSize = slNewSize;
  76. ASSERT(bu_slReadOffset>=0 && bu_slReadOffset<bu_slSize);
  77. ASSERT(bu_slFree>=0 && bu_slFree<=bu_slSize);
  78. }
  79. }
  80. // set how many bytes to add when buffer overflows
  81. void CBuffer::SetAllocationStep(SLONG slStep)
  82. {
  83. ASSERT(slStep>0);
  84. bu_slAllocationStep = slStep;
  85. }
  86. // read bytes from buffer
  87. SLONG CBuffer::ReadBytes(void *pv, SLONG slSize)
  88. {
  89. ASSERT(slSize>0 && pv!=NULL);
  90. UBYTE *pub = (UBYTE*)pv;
  91. // clamp size to amount of bytes actually in the buffer
  92. SLONG slUsed = bu_slSize-bu_slFree;
  93. if (slUsed<slSize) {
  94. slSize = slUsed;
  95. }
  96. // if there is nothing to read
  97. if (slSize==0) {
  98. // do nothing
  99. return 0;
  100. }
  101. // read part of block after read pointer to the end of buffer
  102. SLONG slSizeEnd = __min(bu_slSize-bu_slReadOffset, slSize);
  103. memcpy(pub, bu_pubBuffer+bu_slReadOffset, slSizeEnd);
  104. pub+=slSizeEnd;
  105. // if that is not all
  106. if (slSizeEnd<slSize) {
  107. // read rest from start of buffer
  108. memcpy(pub, bu_pubBuffer, slSize-slSizeEnd);
  109. }
  110. // move read pointer
  111. bu_slReadOffset+=slSize;
  112. bu_slReadOffset%=bu_slSize;
  113. bu_slFree+=slSize;
  114. ASSERT(bu_slReadOffset>=0 && bu_slReadOffset<bu_slSize);
  115. ASSERT(bu_slFree>=0 && bu_slFree<=bu_slSize);
  116. return slSize;
  117. }
  118. // skip bytes from buffer (read without actually reading)
  119. SLONG CBuffer::SkipBytes(SLONG slSize)
  120. {
  121. ASSERT(slSize>0);
  122. // clamp size to amount of bytes actually in the buffer
  123. SLONG slUsed = bu_slSize-bu_slFree;
  124. if (slUsed<slSize) {
  125. slSize = slUsed;
  126. }
  127. // if there is nothing to skip
  128. if (slSize==0) {
  129. // do nothing
  130. return 0;
  131. }
  132. // move read pointer
  133. bu_slReadOffset+=slSize;
  134. bu_slReadOffset%=bu_slSize;
  135. bu_slFree+=slSize;
  136. ASSERT(bu_slReadOffset>=0 && bu_slReadOffset<bu_slSize);
  137. ASSERT(bu_slFree>=0 && bu_slFree<=bu_slSize);
  138. return slSize;
  139. }
  140. // read bytes from buffer to stream
  141. SLONG CBuffer::ReadBytesToStream(CTStream &strm, SLONG slSize)
  142. {
  143. ASSERT(slSize>0);
  144. // clamp size to amount of bytes actually in the buffer
  145. SLONG slUsed = bu_slSize-bu_slFree;
  146. if (slUsed<slSize) {
  147. slSize = slUsed;
  148. }
  149. // if there is nothing to read
  150. if (slSize==0) {
  151. // do nothing
  152. return 0;
  153. }
  154. // read part of block after read pointer to the end of buffer
  155. SLONG slSizeEnd = __min(bu_slSize-bu_slReadOffset, slSize);
  156. strm.Write_t(bu_pubBuffer+bu_slReadOffset, slSizeEnd);
  157. // if that is not all
  158. if (slSizeEnd<slSize) {
  159. // read rest from start of buffer
  160. strm.Write_t(bu_pubBuffer, slSize-slSizeEnd);
  161. }
  162. // move read pointer
  163. bu_slReadOffset+=slSize;
  164. bu_slReadOffset%=bu_slSize;
  165. bu_slFree+=slSize;
  166. ASSERT(bu_slReadOffset>=0 && bu_slReadOffset<bu_slSize);
  167. ASSERT(bu_slFree>=0 && bu_slFree<=bu_slSize);
  168. return slSize;
  169. }
  170. // unread bytes from buffer
  171. void CBuffer::UnreadBytes(SLONG slSize)
  172. {
  173. ASSERT(bu_slFree>=slSize);
  174. if (slSize==0) return;
  175. bu_slReadOffset-=slSize;
  176. bu_slReadOffset%=bu_slSize;
  177. if (bu_slReadOffset<0) {
  178. bu_slReadOffset+=bu_slSize;
  179. }
  180. bu_slFree-=slSize;
  181. ASSERT(bu_slReadOffset>=0 && bu_slReadOffset<bu_slSize);
  182. ASSERT(bu_slFree>=0 && bu_slFree<=bu_slSize);
  183. }
  184. // check how many bytes are there to read
  185. SLONG CBuffer::QueryReadBytes(void)
  186. {
  187. // return amount of bytes actually in the buffer
  188. return bu_slSize-bu_slFree;
  189. }
  190. // write bytes to buffer
  191. void CBuffer::WriteBytes(const void *pv, SLONG slSize)
  192. {
  193. ASSERT(slSize>=0 && pv!=NULL);
  194. // if there is nothing to write
  195. if (slSize==0) {
  196. // do nothing
  197. return;
  198. }
  199. // check for errors
  200. if (slSize<0) {
  201. CPrintF("WARNING: WriteBytes(): slSize<0\n!");
  202. return;
  203. }
  204. // if there is not enough free space
  205. if (bu_slFree<slSize) {
  206. // expand the buffer
  207. Expand(bu_slSize+
  208. ((slSize-bu_slFree+bu_slAllocationStep-1)/bu_slAllocationStep)*bu_slAllocationStep );
  209. ASSERT(bu_slFree>=slSize);
  210. }
  211. UBYTE *pub = (UBYTE*)pv;
  212. // write part of block at the end of buffer
  213. SLONG slSizeEnd = __min(bu_slSize-bu_slWriteOffset, slSize);
  214. memcpy(bu_pubBuffer+bu_slWriteOffset, pub, slSizeEnd);
  215. pub+=slSizeEnd;
  216. memcpy(bu_pubBuffer, pub, slSize-slSizeEnd);
  217. // move write pointer
  218. bu_slWriteOffset+=slSize;
  219. bu_slWriteOffset%=bu_slSize;
  220. bu_slFree-=slSize;
  221. ASSERT(bu_slWriteOffset>=0 && bu_slWriteOffset<bu_slSize);
  222. ASSERT(bu_slFree>=0 && bu_slFree<=bu_slSize);
  223. }
  224. // move all data from another buffer to this one
  225. void CBuffer::MoveBuffer(CBuffer &buFrom)
  226. {
  227. // repeat
  228. for(;;){
  229. // read a block from the other buffer
  230. UBYTE aub[256];
  231. SLONG slSize = buFrom.ReadBytes(aub, sizeof(aub));
  232. // if nothing read
  233. if (slSize<=0) {
  234. // stop
  235. return;
  236. }
  237. // write here what was read
  238. WriteBytes(&aub, slSize);
  239. }
  240. }
  241. void CBlockBufferStats::Clear(void)
  242. {
  243. bbs_tvTimeUsed.Clear();
  244. }
  245. // get time when block of given size will be finished if started now
  246. CTimerValue CBlockBufferStats::GetBlockFinalTime(SLONG slSize)
  247. {
  248. CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
  249. // calculate how much should block be delayed due to latency and due to bandwidth
  250. CTimerValue tvBandwidth;
  251. if (bbs_fBandwidthLimit<=0.0f) {
  252. tvBandwidth = CTimerValue(0.0);
  253. } else {
  254. tvBandwidth = CTimerValue(DOUBLE((slSize*8)/bbs_fBandwidthLimit));
  255. }
  256. CTimerValue tvLatency;
  257. if (bbs_fLatencyLimit<=0.0f && bbs_fLatencyVariation<=0.0f) {
  258. tvLatency = CTimerValue(0.0);
  259. } else {
  260. tvLatency = CTimerValue(DOUBLE(bbs_fLatencyLimit+(bbs_fLatencyVariation*rand())/RAND_MAX));
  261. }
  262. // start of packet receiving is later of
  263. CTimerValue tvStart(
  264. Max(
  265. // current time plus latency and
  266. (tvNow+tvLatency).tv_llValue,
  267. // next free point in time
  268. bbs_tvTimeUsed.tv_llValue));
  269. // remember next free time and return it
  270. bbs_tvTimeUsed = tvStart+tvBandwidth;
  271. return bbs_tvTimeUsed;
  272. }
  273. // default constructor
  274. CBlockBuffer::CBlockBuffer(void)
  275. {
  276. bb_slBlockSizeRead = 0;
  277. bb_slBlockSizeWrite = 0;
  278. bb_pbbsStats = NULL;
  279. }
  280. // destructor
  281. CBlockBuffer::~CBlockBuffer(void)
  282. {
  283. bb_slBlockSizeRead = 0;
  284. bb_slBlockSizeWrite = 0;
  285. bb_pbbsStats = NULL;
  286. }
  287. // free buffer
  288. void CBlockBuffer::Clear(void)
  289. {
  290. bb_slBlockSizeRead = 0;
  291. bb_slBlockSizeWrite = 0;
  292. bb_pbbsStats = NULL;
  293. CBuffer::Clear();
  294. }
  295. struct BlockHeader {
  296. SLONG bh_slSize; // block size
  297. CTimerValue bh_tvFinalTime; // block may be read only after this moment in time
  298. };
  299. // read one block if possible
  300. BOOL CBlockBuffer::ReadBlock(void *pv, SLONG &slSize)
  301. {
  302. // must not be inside block reading
  303. ASSERT(bb_slBlockSizeRead==0);
  304. // read header of next block in incoming buffer
  305. struct BlockHeader bh;
  306. SLONG slbhSize;
  307. slbhSize = ReadBytes(&bh, sizeof(bh));
  308. // if the header information is not in buffer
  309. if (slbhSize < sizeof(bh)) {
  310. // unwind
  311. UnreadBytes(slbhSize);
  312. // nothing to receive
  313. return FALSE;
  314. }
  315. // if the block has not yet been received
  316. if (QueryReadBytes() < bh.bh_slSize) {
  317. // unwind
  318. UnreadBytes(slbhSize);
  319. // nothing to receive
  320. return FALSE;
  321. }
  322. // if there is too much data for the receiving memory space
  323. if (bh.bh_slSize > slSize) {
  324. // unwind
  325. UnreadBytes(slbhSize);
  326. // mark how much space we would need
  327. slSize = bh.bh_slSize;
  328. // nothing to receive
  329. ASSERT(FALSE); // this shouldn't happen
  330. return FALSE;
  331. }
  332. // if using stats
  333. if (bb_pbbsStats!=NULL) {
  334. // if block could not have been received yet, due to time limits
  335. if (bh.bh_tvFinalTime>_pTimer->GetHighPrecisionTimer()) {
  336. // unwind
  337. UnreadBytes(slbhSize);
  338. // nothing to receive
  339. return FALSE;
  340. }
  341. }
  342. // read the block
  343. slSize = ReadBytes(pv, bh.bh_slSize);
  344. ASSERT(slSize == bh.bh_slSize);
  345. // received
  346. return TRUE;
  347. }
  348. // read one block from buffer to stream
  349. BOOL CBlockBuffer::ReadBlockToStream(CTStream &strm)
  350. {
  351. // must not be inside block reading
  352. ASSERT(bb_slBlockSizeRead==0);
  353. // read header of next block in incoming buffer
  354. struct BlockHeader bh;
  355. SLONG slbhSize;
  356. slbhSize = ReadBytes(&bh, sizeof(bh));
  357. // if the header information is not in buffer
  358. if (slbhSize < sizeof(bh)) {
  359. // unwind
  360. UnreadBytes(slbhSize);
  361. // nothing to receive
  362. return FALSE;
  363. }
  364. // if the block has not yet been received
  365. if (QueryReadBytes() < bh.bh_slSize) {
  366. // unwind
  367. UnreadBytes(slbhSize);
  368. // nothing to receive
  369. return FALSE;
  370. }
  371. // if using stats
  372. if (bb_pbbsStats!=NULL) {
  373. // if block could not have been received yet, due to time limits
  374. if (bh.bh_tvFinalTime>_pTimer->GetHighPrecisionTimer()) {
  375. // unwind
  376. UnreadBytes(slbhSize);
  377. // nothing to receive
  378. return FALSE;
  379. }
  380. }
  381. // read from buffer to destination buffer
  382. try {
  383. SLONG slSize = ReadBytesToStream(strm, bh.bh_slSize);
  384. ASSERT(slSize == bh.bh_slSize);
  385. } catch (char *strError) {
  386. ASSERT(FALSE);
  387. CPrintF(TRANS("Buffer error reading to stream: %s\n"), strError);
  388. return FALSE;
  389. }
  390. return TRUE;
  391. }
  392. // write one block
  393. void CBlockBuffer::WriteBlock(const void *pv, SLONG slSize)
  394. {
  395. // must not be inside block writing
  396. ASSERT(bb_slBlockSizeWrite==0);
  397. // prepare block header
  398. struct BlockHeader bh;
  399. bh.bh_slSize = slSize;
  400. if (bb_pbbsStats!=NULL) {
  401. bh.bh_tvFinalTime = bb_pbbsStats->GetBlockFinalTime(slSize);
  402. } else {
  403. bh.bh_tvFinalTime.Clear();
  404. }
  405. // write the data to send-buffer
  406. WriteBytes((void*)&bh, sizeof(bh));
  407. WriteBytes(pv, slSize);
  408. }
  409. // unread one block
  410. void CBlockBuffer::UnreadBlock(SLONG slSize)
  411. {
  412. UnreadBytes(slSize+sizeof(struct BlockHeader));
  413. }
  414. // read raw block data
  415. SLONG CBlockBuffer::ReadRawBlock(void *pv, SLONG slSize)
  416. {
  417. // if inside block reading
  418. if(bb_slBlockSizeRead>0) {
  419. // clamp size to prevent reading across real blocks
  420. slSize = Min(slSize, bb_slBlockSizeRead);
  421. // read the raw block
  422. SLONG slResult = ReadBytes(pv, slSize);
  423. ASSERT(slResult==slSize);
  424. // decrement block size counter
  425. bb_slBlockSizeRead-=slResult;
  426. // must not underflow
  427. ASSERT(bb_slBlockSizeRead>=0);
  428. return slResult;
  429. // if not inside block reading
  430. } else {
  431. // read header of next block in incoming buffer
  432. struct BlockHeader bh;
  433. SLONG slbhSize;
  434. slbhSize = ReadBytes(&bh, sizeof(bh));
  435. // if the header information is not in buffer
  436. if (slbhSize < sizeof(bh)) {
  437. // unwind
  438. UnreadBytes(slbhSize);
  439. // nothing to receive
  440. return FALSE;
  441. }
  442. // if the block has not yet been received
  443. if (QueryReadBytes() < bh.bh_slSize) {
  444. // unwind
  445. UnreadBytes(slbhSize);
  446. // nothing to receive
  447. return FALSE;
  448. }
  449. // if using stats
  450. if (bb_pbbsStats!=NULL) {
  451. // if block could not have been received yet, due to time limits
  452. if (bh.bh_tvFinalTime>_pTimer->GetHighPrecisionTimer()) {
  453. // unwind
  454. UnreadBytes(slbhSize);
  455. // nothing to receive
  456. return FALSE;
  457. }
  458. }
  459. // remember block size counter
  460. bb_slBlockSizeRead = bh.bh_slSize+sizeof(struct BlockHeader);
  461. // unwind header
  462. UnreadBytes(slbhSize);
  463. // clamp size to prevent reading across real blocks
  464. slSize = Min(slSize, bb_slBlockSizeRead);
  465. // read the raw block with header
  466. SLONG slResult = ReadBytes(pv, slSize);
  467. ASSERT(slResult==slSize);
  468. // decrement block size counter
  469. bb_slBlockSizeRead-=slResult;
  470. // must not underflow
  471. ASSERT(bb_slBlockSizeRead>=0);
  472. return slResult;
  473. }
  474. }
  475. // write raw block data
  476. void CBlockBuffer::WriteRawBlock(const void *pv, SLONG slSize)
  477. {
  478. // while there is something to write
  479. while (slSize>0) {
  480. // if inside block writing
  481. if(bb_slBlockSizeWrite>0) {
  482. SLONG slToWrite = Min(bb_slBlockSizeWrite, slSize);
  483. // write the raw block
  484. WriteBytes(pv, slToWrite);
  485. slSize-=slToWrite;
  486. ((UBYTE*&)pv)+=slToWrite;
  487. // decrement block size counter
  488. bb_slBlockSizeWrite-=slToWrite;
  489. // must not underflow
  490. ASSERT(bb_slBlockSizeWrite>=0);
  491. // if not inside block writing
  492. } else {
  493. // must contain at least the header
  494. ASSERT(slSize>sizeof(struct BlockHeader));
  495. // find the header in the raw block
  496. struct BlockHeader &bh = *(struct BlockHeader*)pv;
  497. // remember block size counter
  498. bb_slBlockSizeWrite = bh.bh_slSize+sizeof(struct BlockHeader);
  499. // create new block timestamp
  500. if (bb_pbbsStats!=NULL) {
  501. bh.bh_tvFinalTime = bb_pbbsStats->GetBlockFinalTime(bb_slBlockSizeWrite);
  502. } else {
  503. bh.bh_tvFinalTime.Clear();
  504. }
  505. SLONG slToWrite = Min(bb_slBlockSizeWrite, slSize);
  506. // write the raw block, with the new header
  507. WriteBytes(pv, slToWrite);
  508. slSize-=slToWrite;
  509. ((UBYTE*&)pv)+=slToWrite;
  510. // decrement block size counter
  511. bb_slBlockSizeWrite-=slToWrite;
  512. // must not underflow
  513. ASSERT(bb_slBlockSizeWrite>=0);
  514. }
  515. }
  516. }
  517. // peek sizes of next block
  518. void CBlockBuffer::PeekBlockSize(SLONG &slExpectedSize, SLONG &slReceivedSoFar)
  519. {
  520. // if inside block reading
  521. if(bb_slBlockSizeRead>0) {
  522. // no information available
  523. slExpectedSize = 0;
  524. slReceivedSoFar = 0;
  525. // if not inside block reading
  526. } else {
  527. // read header of next block in incoming buffer
  528. struct BlockHeader bh;
  529. SLONG slbhSize;
  530. slbhSize = ReadBytes(&bh, sizeof(bh));
  531. // unwind
  532. UnreadBytes(slbhSize);
  533. // if the header information is not in buffer
  534. if (slbhSize < sizeof(bh)) {
  535. // no information available
  536. slExpectedSize = 0;
  537. slReceivedSoFar = 0;
  538. // if the header information is present
  539. } else {
  540. // total size is size of block
  541. slExpectedSize = bh.bh_slSize;
  542. // received so far is how much is really present
  543. slReceivedSoFar = QueryReadBytes()-sizeof(struct BlockHeader);
  544. }
  545. }
  546. }
  547. // unread raw block data
  548. void CBlockBuffer::UnreadRawBlock(SLONG slSize)
  549. {
  550. bb_slBlockSizeRead+=slSize;
  551. UnreadBytes(slSize);
  552. }
  553. // move all data from another buffer to this one
  554. void CBlockBuffer::MoveBlockBuffer(CBlockBuffer &buFrom)
  555. {
  556. // repeat
  557. for(;;){
  558. // read a block from the other buffer
  559. UBYTE aub[256];
  560. SLONG slSize = buFrom.ReadRawBlock(aub, sizeof(aub));
  561. // if nothing read
  562. if (slSize<=0) {
  563. // stop
  564. return;
  565. }
  566. // write here what was read
  567. WriteRawBlock(&aub, slSize);
  568. }
  569. }