Kcp.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  1. using System;
  2. using System.Collections.Generic;
  3. namespace IFramework.Net.KCP
  4. {
  5. public class Kcp
  6. {
  7. private class Segment
  8. {
  9. internal uint conv = 0;
  10. internal uint cmd = 0;
  11. internal uint frg = 0;
  12. internal uint wnd = 0;
  13. internal uint ts = 0;
  14. internal uint sn = 0;
  15. internal uint una = 0;
  16. internal uint rto = 0;
  17. internal uint xmit = 0;
  18. internal uint resendts = 0;
  19. internal uint fastack = 0;
  20. internal uint acked = 0;
  21. internal BufferQueue data;
  22. private class Pool : ObjectPool<Segment>
  23. {
  24. protected override Segment CreateNew(IEventArgs arg)
  25. {
  26. return null;
  27. }
  28. }
  29. private static Pool _pool = new Pool();
  30. public static Segment Get(int size)
  31. {
  32. if (_pool.count > 0)
  33. {
  34. var seg = _pool.Get();
  35. seg.data = BufferQueue.Allocate(size, true);
  36. return seg;
  37. }
  38. return new Segment(size);
  39. }
  40. public static void Put(Segment seg)
  41. {
  42. seg.Reset();
  43. _pool.Set(seg);
  44. }
  45. private Segment(int size)
  46. {
  47. data = BufferQueue.Allocate(size, true);
  48. }
  49. // encode a segment into buffer
  50. internal int Encode(byte[] ptr, int offset)
  51. {
  52. var offset_ = offset;
  53. offset += KcpTool.Encode(ptr, offset, conv);
  54. offset += KcpTool.Encode(ptr, offset, (byte)cmd);
  55. offset += KcpTool.Encode(ptr, offset, (byte)frg);
  56. offset += KcpTool.Encode(ptr, offset, (UInt16)wnd);
  57. offset += KcpTool.Encode(ptr, offset, ts);
  58. offset += KcpTool.Encode(ptr, offset, sn);
  59. offset += KcpTool.Encode(ptr, offset, una);
  60. offset += KcpTool.Encode(ptr, offset, (uint)data.canRead);
  61. return offset - offset_;
  62. }
  63. internal void Reset()
  64. {
  65. conv = 0;
  66. cmd = 0;
  67. frg = 0;
  68. wnd = 0;
  69. ts = 0;
  70. sn = 0;
  71. una = 0;
  72. rto = 0;
  73. xmit = 0;
  74. resendts = 0;
  75. fastack = 0;
  76. acked = 0;
  77. data.Clear();
  78. data.Dispose();
  79. data = null;
  80. }
  81. }
  82. private struct Ack
  83. {
  84. internal uint sn;
  85. internal uint ts;
  86. }
  87. private DateTime _startTime = DateTime.Now;
  88. public uint time
  89. {
  90. get
  91. {
  92. var ts = DateTime.Now.Subtract(_startTime);
  93. return (uint)ts.TotalMilliseconds;
  94. }
  95. }
  96. uint conv; uint mtu; uint mss; uint state;
  97. uint snd_una; uint snd_nxt; uint rcv_nxt;
  98. uint ts_recent; uint ts_lastack; uint ssthresh;
  99. uint rx_rttval; uint rx_srtt;
  100. uint rx_rto; uint rx_minrto;
  101. uint snd_wnd; uint rcv_wnd; uint rmt_wnd; uint cwnd; uint probe;
  102. uint interval; uint ts_flush;
  103. uint nodelay; uint updated;
  104. uint ts_probe; uint probe_wait;
  105. uint dead_link; uint incr;
  106. Int32 fastresend;//快速重发间隔片个数
  107. bool nocwnd;//关闭拥塞控制
  108. public bool stream;//是否启用流控
  109. List<Segment> snd_queue = new List<Segment>(16);
  110. List<Segment> rcv_queue = new List<Segment>(16);
  111. List<Segment> snd_buf = new List<Segment>(16);
  112. List<Segment> rcv_buf = new List<Segment>(16);
  113. List<Ack> acklist = new List<Ack>(16);
  114. byte[] buffer;
  115. Int32 reserved;
  116. IKcpSocket _sender; // buffer, size
  117. public uint sendWindow { get { return snd_wnd; } }
  118. public uint recWindow { get { return rcv_wnd; } }
  119. public uint RmtWnd { get { return rmt_wnd; } }
  120. /// <summary>
  121. /// 每个分片最大 大小
  122. /// </summary>
  123. public uint Mss { get { return mss; } }
  124. // get how many packet is waiting to be sent
  125. public int waitToSend { get { return snd_buf.Count + snd_queue.Count; } }
  126. // create a new kcp control object, 'conv' must equal in two endpoint
  127. // from the same connection.
  128. public Kcp(uint conv_, IKcpSocket sender)
  129. {
  130. conv = conv_;
  131. snd_wnd = KcpTool.IKCP_WND_SND;
  132. rcv_wnd = KcpTool.IKCP_WND_RCV;
  133. rmt_wnd = KcpTool.IKCP_WND_RCV;
  134. mtu = KcpTool.IKCP_MTU_DEF;
  135. mss = mtu - KcpTool.IKCP_OVERHEAD;
  136. rx_rto = KcpTool.IKCP_RTO_DEF;
  137. rx_minrto = KcpTool.IKCP_RTO_MIN;
  138. interval = KcpTool.IKCP_INTERVAL;
  139. ts_flush = KcpTool.IKCP_INTERVAL;
  140. ssthresh = KcpTool.IKCP_THRESH_INIT;
  141. dead_link = KcpTool.IKCP_DEADLINK;
  142. buffer = new byte[mtu];
  143. _sender = sender;
  144. }
  145. // check the size of next message in the recv queue
  146. public int PeekSize()
  147. {
  148. if (0 == rcv_queue.Count) return -1;
  149. var seq = rcv_queue[0];
  150. if (0 == seq.frg) return seq.data.canRead;
  151. if (rcv_queue.Count < seq.frg + 1) return -1;
  152. int length = 0;
  153. foreach (var item in rcv_queue)
  154. {
  155. length += item.data.canRead;
  156. if (0 == item.frg)
  157. break;
  158. }
  159. return length;
  160. }
  161. public int Recv(byte[] buffer, int index, int length)
  162. {
  163. var peekSize = PeekSize();
  164. if (peekSize < 0)return -1;
  165. if (peekSize > length)return -2;
  166. var fast_recover = false;
  167. if (rcv_queue.Count >= rcv_wnd)
  168. fast_recover = true;
  169. // merge fragment.
  170. var count = 0;
  171. var n = index;
  172. foreach (var seg in rcv_queue)
  173. {
  174. // copy fragment data into buffer.
  175. Buffer.BlockCopy(seg.data.buffer, seg.data.reader, buffer, n, seg.data.canRead);
  176. n += seg.data.canRead;
  177. count++;
  178. var fragment = seg.frg;
  179. Segment.Put(seg);
  180. if (0 == fragment) break;
  181. }
  182. if (count > 0) rcv_queue.RemoveRange(0, count);
  183. // move available data from rcv_buf -> rcv_queue
  184. count = 0;
  185. foreach (var seg in rcv_buf)
  186. {
  187. if (seg.sn == rcv_nxt && rcv_queue.Count + count < rcv_wnd)
  188. {
  189. rcv_queue.Add(seg);
  190. rcv_nxt++;
  191. count++;
  192. }
  193. else
  194. {
  195. break;
  196. }
  197. }
  198. if (count > 0)
  199. {
  200. rcv_buf.RemoveRange(0, count);
  201. }
  202. // fast recover
  203. if (rcv_queue.Count < rcv_wnd && fast_recover)
  204. {
  205. // ready to send back IKCP_CMD_WINS in ikcp_flush
  206. // tell remote my window size
  207. probe |= KcpTool.IKCP_ASK_TELL;
  208. }
  209. return n - index;
  210. }
  211. // user/upper level send, returns below zero for error
  212. public int Send(byte[] buffer, int index, int length)
  213. {
  214. if (0 == length) return -1;
  215. if (stream)
  216. {
  217. var n = snd_queue.Count;
  218. if (n > 0)
  219. {
  220. var seg = snd_queue[n - 1];
  221. if (seg.data.canRead < mss)
  222. {
  223. var capacity = (int)(mss - seg.data.canRead);
  224. var writen = Math.Min(capacity, length);
  225. seg.data.WriteBytes(buffer, index, writen);
  226. index += writen;
  227. length -= writen;
  228. }
  229. }
  230. }
  231. if (length == 0)
  232. return 0;
  233. var count = 0;
  234. if (length <= mss)
  235. count = 1;
  236. else
  237. count = (int)(((length) + mss - 1) / mss);
  238. if (count > 255) return -2;
  239. if (count == 0) count = 1;
  240. for (var i = 0; i < count; i++)
  241. {
  242. var size = Math.Min(length, (int)mss);
  243. var seg = Segment.Get(size);
  244. seg.data.WriteBytes(buffer, index, size);
  245. index += size;
  246. length -= size;
  247. seg.frg = (!stream ? (byte)(count - i - 1) : (byte)0);
  248. snd_queue.Add(seg);
  249. }
  250. return 0;
  251. }
  252. // update ack.
  253. void update_ack(Int32 rtt)
  254. {
  255. // https://tools.ietf.org/html/rfc6298
  256. if (0 == rx_srtt)
  257. {
  258. rx_srtt = (uint)rtt;
  259. rx_rttval = (uint)rtt >> 1;
  260. }
  261. else
  262. {
  263. Int32 delta = (Int32)((uint)rtt - rx_srtt);
  264. rx_srtt += (uint)(delta >> 3);
  265. if (0 > delta) delta = -delta;
  266. if (rtt < rx_srtt - rx_rttval)
  267. {
  268. // if the new RTT sample is below the bottom of the range of
  269. // what an RTT measurement is expected to be.
  270. // give an 8x reduced weight versus its normal weighting
  271. rx_rttval += (uint)((delta - rx_rttval) >> 5);
  272. }
  273. else
  274. {
  275. rx_rttval += (uint)((delta - rx_rttval) >> 2);
  276. }
  277. }
  278. var rto = (int)(rx_srtt + KcpTool.Max(interval, rx_rttval << 2));
  279. rx_rto = KcpTool.Clamp(rx_minrto, (uint)rto, KcpTool.IKCP_RTO_MAX);
  280. }
  281. void shrink_buf()
  282. {
  283. if (snd_buf.Count > 0)
  284. snd_una = snd_buf[0].sn;
  285. else
  286. snd_una = snd_nxt;
  287. }
  288. void parse_ack(uint sn)
  289. {
  290. if (KcpTool.Subtract(sn, snd_una) < 0 || KcpTool.Subtract(sn, snd_nxt) >= 0) return;
  291. foreach (var seg in snd_buf)
  292. {
  293. if (sn == seg.sn)
  294. {
  295. // mark and free space, but leave the segment here,
  296. // and wait until `una` to delete this, then we don't
  297. // have to shift the segments behind forward,
  298. // which is an expensive operation for large window
  299. seg.acked = 1;
  300. break;
  301. }
  302. if (KcpTool.Subtract(sn, seg.sn) < 0)
  303. break;
  304. }
  305. }
  306. void parse_fastack(uint sn, uint ts)
  307. {
  308. if (KcpTool.Subtract(sn, snd_una) < 0 || KcpTool.Subtract(sn, snd_nxt) >= 0)
  309. return;
  310. foreach (var seg in snd_buf)
  311. {
  312. if (KcpTool.Subtract(sn, seg.sn) < 0)
  313. break;
  314. else if (sn != seg.sn && KcpTool.Subtract(seg.ts, ts) <= 0)
  315. seg.fastack++;
  316. }
  317. }
  318. void parse_una(uint una)
  319. {
  320. var count = 0;
  321. foreach (var seg in snd_buf)
  322. {
  323. if (KcpTool.Subtract(una, seg.sn) > 0)
  324. {
  325. count++;
  326. Segment.Put(seg);
  327. }
  328. else
  329. break;
  330. }
  331. if (count > 0)
  332. snd_buf.RemoveRange(0, count);
  333. }
  334. void ack_push(uint sn, uint ts)
  335. {
  336. acklist.Add(new Ack { sn = sn, ts = ts });
  337. }
  338. bool parse_data(Segment newseg)
  339. {
  340. var sn = newseg.sn;
  341. if (KcpTool.Subtract(sn, rcv_nxt + rcv_wnd) >= 0 || KcpTool.Subtract(sn, rcv_nxt) < 0)
  342. return true;
  343. var n = rcv_buf.Count - 1;
  344. var insert_idx = 0;
  345. var repeat = false;
  346. for (var i = n; i >= 0; i--)
  347. {
  348. var seg = rcv_buf[i];
  349. if (seg.sn == sn)
  350. {
  351. repeat = true;
  352. break;
  353. }
  354. if (KcpTool.Subtract(sn, seg.sn) > 0)
  355. {
  356. insert_idx = i + 1;
  357. break;
  358. }
  359. }
  360. if (!repeat)
  361. {
  362. if (insert_idx == n + 1)
  363. rcv_buf.Add(newseg);
  364. else
  365. rcv_buf.Insert(insert_idx, newseg);
  366. }
  367. // move available data from rcv_buf -> rcv_queue
  368. var count = 0;
  369. foreach (var seg in rcv_buf)
  370. {
  371. if (seg.sn == rcv_nxt && rcv_queue.Count + count < rcv_wnd)
  372. {
  373. rcv_nxt++;
  374. count++;
  375. }
  376. else
  377. {
  378. break;
  379. }
  380. }
  381. if (count > 0)
  382. {
  383. for (var i = 0; i < count; i++)
  384. rcv_queue.Add(rcv_buf[i]);
  385. rcv_buf.RemoveRange(0, count);
  386. }
  387. return repeat;
  388. }
  389. // Input when you received a low level packet (eg. UDP packet), call it
  390. // regular indicates a regular packet has received(not from FEC)
  391. //
  392. // 'ackNoDelay' will trigger immediate ACK, but surely it will not be efficient in bandwidth
  393. public int Input(byte[] data, int offset, int size, bool regular, bool ackNoDelay)
  394. {
  395. var s_una = snd_una;
  396. if (size < KcpTool.IKCP_OVERHEAD) return -1;
  397. Int32 _offset = offset;
  398. uint latest = 0;
  399. int flag = 0;
  400. UInt64 inSegs = 0;
  401. while (true)
  402. {
  403. uint ts = 0;
  404. uint sn = 0;
  405. uint length = 0;
  406. uint una = 0;
  407. uint conv_ = 0;
  408. UInt16 wnd = 0;
  409. byte cmd = 0;
  410. byte frg = 0;
  411. if (size - (_offset - offset) < KcpTool.IKCP_OVERHEAD) break;
  412. _offset += KcpTool.Decode(data, _offset, ref conv_);
  413. if (conv != conv_) return -1;
  414. _offset += KcpTool.Decode(data, _offset, ref cmd);
  415. _offset += KcpTool.Decode(data, _offset, ref frg);
  416. _offset += KcpTool.Decode(data, _offset, ref wnd);
  417. _offset += KcpTool.Decode(data, _offset, ref ts);
  418. _offset += KcpTool.Decode(data, _offset, ref sn);
  419. _offset += KcpTool.Decode(data, _offset, ref una);
  420. _offset += KcpTool.Decode(data, _offset, ref length);
  421. if (size - (_offset - offset) < length) return -2;
  422. switch (cmd)
  423. {
  424. case KcpTool.IKCP_CMD_PUSH:
  425. case KcpTool.IKCP_CMD_ACK:
  426. case KcpTool.IKCP_CMD_WASK:
  427. case KcpTool.IKCP_CMD_WINS:
  428. break;
  429. default:
  430. return -3;
  431. }
  432. // only trust window updates from regular packets. i.e: latest update
  433. if (regular) rmt_wnd = wnd;
  434. parse_una(una);
  435. shrink_buf();
  436. switch (cmd)
  437. {
  438. case KcpTool.IKCP_CMD_PUSH:
  439. var repeat = true;
  440. if (KcpTool.Subtract(sn, rcv_nxt + rcv_wnd) < 0)
  441. {
  442. ack_push(sn, ts);
  443. if (KcpTool.Subtract(sn, rcv_nxt) >= 0)
  444. {
  445. var seg = Segment.Get((int)length);
  446. seg.conv = conv_;
  447. seg.cmd = (uint)cmd;
  448. seg.frg = (uint)frg;
  449. seg.wnd = (uint)wnd;
  450. seg.ts = ts;
  451. seg.sn = sn;
  452. seg.una = una;
  453. seg.data.WriteBytes(data, _offset, (int)length);
  454. repeat = parse_data(seg);
  455. }
  456. }
  457. break;
  458. case KcpTool.IKCP_CMD_ACK:
  459. parse_ack(sn);
  460. parse_fastack(sn, ts);
  461. flag |= 1;
  462. latest = ts;
  463. break;
  464. case KcpTool.IKCP_CMD_WASK:
  465. probe |= KcpTool.IKCP_ASK_TELL;
  466. break;
  467. case KcpTool.IKCP_CMD_WINS:
  468. break;
  469. default:
  470. return -3;
  471. }
  472. inSegs++;
  473. _offset += (int)length;
  474. }
  475. // update rtt with the latest ts
  476. // ignore the FEC packet
  477. if (flag != 0 && regular)
  478. {
  479. var current = time;
  480. if (KcpTool.Subtract(current, latest) >= 0)
  481. {
  482. update_ack(KcpTool.Subtract(current, latest));
  483. }
  484. }
  485. // cwnd update when packet arrived
  486. if (!nocwnd)
  487. {
  488. if (KcpTool.Subtract(snd_una, s_una) > 0)
  489. {
  490. if (cwnd < rmt_wnd)
  491. {
  492. var _mss = mss;
  493. if (cwnd < ssthresh)
  494. {
  495. cwnd++;
  496. incr += _mss;
  497. }
  498. else
  499. {
  500. if (incr < _mss)
  501. {
  502. incr = _mss;
  503. }
  504. incr += (_mss * _mss) / incr + (_mss) / 16;
  505. if ((cwnd + 1) * _mss <= incr)
  506. {
  507. if (_mss > 0)
  508. cwnd = (incr + _mss - 1) / _mss;
  509. else
  510. cwnd = incr + _mss - 1;
  511. }
  512. }
  513. if (cwnd > rmt_wnd)
  514. {
  515. cwnd = rmt_wnd;
  516. incr = rmt_wnd * _mss;
  517. }
  518. }
  519. }
  520. }
  521. // ack immediately
  522. if (ackNoDelay && acklist.Count > 0)
  523. {
  524. Flush(true);
  525. }
  526. return 0;
  527. }
  528. UInt16 wnd_unused()
  529. {
  530. if (rcv_queue.Count < rcv_wnd)
  531. return (UInt16)(rcv_wnd - rcv_queue.Count);
  532. return 0;
  533. }
  534. // flush pending data
  535. public uint Flush(bool ackOnly)
  536. {
  537. var seg = Segment.Get(32);
  538. seg.conv = conv;
  539. seg.cmd = KcpTool.IKCP_CMD_ACK;
  540. seg.wnd = (uint)wnd_unused();
  541. seg.una = rcv_nxt;
  542. var writeIndex = reserved;
  543. Action<int> makeSpace = (space) =>
  544. {
  545. if (writeIndex + space > mtu)
  546. {
  547. _sender.Send(buffer, writeIndex);
  548. writeIndex = reserved;
  549. }
  550. };
  551. Action flushBuffer = () =>
  552. {
  553. if (writeIndex > reserved)
  554. {
  555. _sender.Send(buffer, writeIndex);
  556. }
  557. };
  558. // flush acknowledges
  559. for (var i = 0; i < acklist.Count; i++)
  560. {
  561. makeSpace(KcpTool.IKCP_OVERHEAD);
  562. var ack = acklist[i];
  563. if (KcpTool.Subtract(ack.sn, rcv_nxt) >= 0 || acklist.Count - 1 == i)
  564. {
  565. seg.sn = ack.sn;
  566. seg.ts = ack.ts;
  567. writeIndex += seg.Encode(buffer, writeIndex);
  568. }
  569. }
  570. acklist.Clear();
  571. // flash remain ack segments
  572. if (ackOnly)
  573. {
  574. flushBuffer();
  575. return interval;
  576. }
  577. uint current = 0;
  578. // probe window size (if remote window size equals zero)
  579. if (0 == rmt_wnd)
  580. {
  581. current = time;
  582. if (0 == probe_wait)
  583. {
  584. probe_wait = KcpTool.IKCP_PROBE_INIT;
  585. ts_probe = current + probe_wait;
  586. }
  587. else
  588. {
  589. if (KcpTool.Subtract(current, ts_probe) >= 0)
  590. {
  591. if (probe_wait < KcpTool.IKCP_PROBE_INIT)
  592. probe_wait = KcpTool.IKCP_PROBE_INIT;
  593. probe_wait += probe_wait / 2;
  594. if (probe_wait > KcpTool.IKCP_PROBE_LIMIT)
  595. probe_wait = KcpTool.IKCP_PROBE_LIMIT;
  596. ts_probe = current + probe_wait;
  597. probe |= KcpTool.IKCP_ASK_SEND;
  598. }
  599. }
  600. }
  601. else
  602. {
  603. ts_probe = 0;
  604. probe_wait = 0;
  605. }
  606. // flush window probing commands
  607. if ((probe & KcpTool.IKCP_ASK_SEND) != 0)
  608. {
  609. seg.cmd = KcpTool.IKCP_CMD_WASK;
  610. makeSpace(KcpTool.IKCP_OVERHEAD);
  611. writeIndex += seg.Encode(buffer, writeIndex);
  612. }
  613. if ((probe & KcpTool.IKCP_ASK_TELL) != 0)
  614. {
  615. seg.cmd = KcpTool.IKCP_CMD_WINS;
  616. makeSpace(KcpTool.IKCP_OVERHEAD);
  617. writeIndex += seg.Encode(buffer, writeIndex);
  618. }
  619. probe = 0;
  620. // calculate window size
  621. var cwnd_ = KcpTool.Min(snd_wnd, rmt_wnd);
  622. if (!nocwnd)
  623. cwnd_ = KcpTool.Min(cwnd, cwnd_);
  624. // sliding window, controlled by snd_nxt && sna_una+cwnd
  625. var newSegsCount = 0;
  626. for (var k = 0; k < snd_queue.Count; k++)
  627. {
  628. if (KcpTool.Subtract(snd_nxt, snd_una + cwnd_) >= 0)
  629. break;
  630. var newseg = snd_queue[k];
  631. newseg.conv = conv;
  632. newseg.cmd = KcpTool.IKCP_CMD_PUSH;
  633. newseg.sn = snd_nxt;
  634. snd_buf.Add(newseg);
  635. snd_nxt++;
  636. newSegsCount++;
  637. }
  638. if (newSegsCount > 0)
  639. {
  640. snd_queue.RemoveRange(0, newSegsCount);
  641. }
  642. // calculate resent
  643. var resent = (uint)fastresend;
  644. if (fastresend <= 0) resent = 0xffffffff;
  645. // check for retransmissions
  646. current = time;
  647. UInt64 change = 0; UInt64 lostSegs = 0; UInt64 fastRetransSegs = 0; UInt64 earlyRetransSegs = 0;
  648. var minrto = (Int32)interval;
  649. for (var k = 0; k < snd_buf.Count; k++)
  650. {
  651. var segment = snd_buf[k];
  652. var needsend = false;
  653. if (segment.acked == 1)
  654. continue;
  655. if (segment.xmit == 0) // initial transmit
  656. {
  657. needsend = true;
  658. segment.rto = rx_rto;
  659. segment.resendts = current + segment.rto;
  660. }
  661. else if (segment.fastack >= resent) // fast retransmit
  662. {
  663. needsend = true;
  664. segment.fastack = 0;
  665. segment.rto = rx_rto;
  666. segment.resendts = current + segment.rto;
  667. change++;
  668. fastRetransSegs++;
  669. }
  670. else if (segment.fastack > 0 && newSegsCount == 0) // early retransmit
  671. {
  672. needsend = true;
  673. segment.fastack = 0;
  674. segment.rto = rx_rto;
  675. segment.resendts = current + segment.rto;
  676. change++;
  677. earlyRetransSegs++;
  678. }
  679. else if (KcpTool.Subtract(current, segment.resendts) >= 0) // RTO
  680. {
  681. needsend = true;
  682. if (nodelay == 0)
  683. segment.rto += rx_rto;
  684. else
  685. segment.rto += rx_rto / 2;
  686. segment.fastack = 0;
  687. segment.resendts = current + segment.rto;
  688. lostSegs++;
  689. }
  690. if (needsend)
  691. {
  692. current = time;
  693. segment.xmit++;
  694. segment.ts = current;
  695. segment.wnd = seg.wnd;
  696. segment.una = seg.una;
  697. var need = KcpTool.IKCP_OVERHEAD + segment.data.canRead;
  698. makeSpace(need);
  699. writeIndex += segment.Encode(buffer, writeIndex);
  700. Buffer.BlockCopy(segment.data.buffer, segment.data.reader, buffer, writeIndex, segment.data.canRead);
  701. writeIndex += segment.data.canRead;
  702. if (segment.xmit >= dead_link)
  703. {
  704. state = 0xFFFFFFFF;
  705. }
  706. }
  707. // get the nearest rto
  708. var _rto = KcpTool.Subtract(segment.resendts, current);
  709. if (_rto > 0 && _rto < minrto)
  710. {
  711. minrto = _rto;
  712. }
  713. }
  714. // flash remain segments
  715. flushBuffer();
  716. // cwnd update
  717. if (!nocwnd )
  718. {
  719. // update ssthresh
  720. // rate halving, https://tools.ietf.org/html/rfc6937
  721. if (change > 0)
  722. {
  723. var inflght = snd_nxt - snd_una;
  724. ssthresh = inflght / 2;
  725. if (ssthresh < KcpTool.IKCP_THRESH_MIN)
  726. ssthresh = KcpTool.IKCP_THRESH_MIN;
  727. cwnd = ssthresh + resent;
  728. incr = cwnd * mss;
  729. }
  730. // congestion control, https://tools.ietf.org/html/rfc5681
  731. if (lostSegs > 0)
  732. {
  733. ssthresh = cwnd / 2;
  734. if (ssthresh < KcpTool.IKCP_THRESH_MIN)
  735. ssthresh = KcpTool.IKCP_THRESH_MIN;
  736. cwnd = 1;
  737. incr = mss;
  738. }
  739. if (cwnd < 1)
  740. {
  741. cwnd = 1;
  742. incr = mss;
  743. }
  744. }
  745. return (uint)minrto;
  746. }
  747. // update state (call it repeatedly, every 10ms-100ms), or you can ask
  748. // ikcp_check when to call it again (without ikcp_input/_send calling).
  749. // 'current' - current timestamp in millisec.
  750. public void Update()
  751. {
  752. var current = time;
  753. if (0 == updated)
  754. {
  755. updated = 1;
  756. ts_flush = current;
  757. }
  758. var slap = KcpTool.Subtract(current, ts_flush);
  759. if (slap >= 10000 || slap < -10000)
  760. {
  761. ts_flush = current;
  762. slap = 0;
  763. }
  764. if (slap >= 0)
  765. {
  766. ts_flush += interval;
  767. if (KcpTool.Subtract(current, ts_flush) >= 0)
  768. ts_flush = current + interval;
  769. Flush(false);
  770. }
  771. }
  772. // Determine when should you invoke ikcp_update:
  773. // returns when you should invoke ikcp_update in millisec, if there
  774. // is no ikcp_input/_send calling. you can call ikcp_update in that
  775. // time, instead of call update repeatly.
  776. // Important to reduce unnacessary ikcp_update invoking. use it to
  777. // schedule ikcp_update (eg. implementing an epoll-like mechanism,
  778. // or optimize ikcp_update when handling massive kcp connections)
  779. public uint Check()
  780. {
  781. var ts_flush_ = ts_flush;
  782. var tm_flush_ = 0x7fffffff;
  783. var tm_packet = 0x7fffffff;
  784. var minimal = 0;
  785. if (updated == 0)
  786. return time;
  787. if (KcpTool.Subtract(time, ts_flush_) >= 10000 || KcpTool.Subtract(time, ts_flush_) < -10000)
  788. ts_flush_ = time;
  789. if (KcpTool.Subtract(time, ts_flush_) >= 0)
  790. return time;
  791. tm_flush_ = (int)KcpTool.Subtract(ts_flush_, time);
  792. foreach (var seg in snd_buf)
  793. {
  794. var diff = KcpTool.Subtract(seg.resendts, time);
  795. if (diff <= 0)
  796. return time;
  797. if (diff < tm_packet)
  798. tm_packet = (int)diff;
  799. }
  800. minimal = (int)tm_packet;
  801. if (tm_packet >= tm_flush_)
  802. minimal = (int)tm_flush_;
  803. if (minimal >= interval)
  804. minimal = (int)interval;
  805. return time + (uint)minimal;
  806. }
  807. // change MTU size, default is 1024
  808. public int SetMtu(Int32 mtu_)
  809. {
  810. if (mtu_ < 50 || mtu_ < (Int32)KcpTool.IKCP_OVERHEAD)
  811. return -1;
  812. if (reserved >= (int)(mtu - KcpTool.IKCP_OVERHEAD) || reserved < 0)
  813. return -1;
  814. var buffer_ = new byte[mtu_];
  815. if (null == buffer_)
  816. return -2;
  817. mtu = (uint)mtu_;
  818. mss = mtu - KcpTool.IKCP_OVERHEAD - (uint)reserved;
  819. buffer = buffer_;
  820. return 0;
  821. }
  822. // normal: 0, 40, 2, true
  823. // fast: 0, 30, 2, true
  824. // fast2: 1, 20, 2, true
  825. // fast3: 1, 10, 2, true
  826. // fastest: ikcp_nodelay(kcp, 1, 20, 2, 1)
  827. // nodelay: 0:disable(default), 1:enable
  828. // interval: internal update timer interval in millisec, default is 100ms
  829. // resend: 0:disable fast resend(default), 1:enable fast resend
  830. // nc: 0:normal congestion control(default), 1:disable congestion control
  831. public int NoDelay(int nodelay_, int interval_, int resend_, bool nc_=false)
  832. {
  833. if (nodelay_ > 0)
  834. {
  835. nodelay = (uint)nodelay_;
  836. if (nodelay_ != 0)
  837. rx_minrto = KcpTool.IKCP_RTO_NDL;
  838. else
  839. rx_minrto = KcpTool.IKCP_RTO_MIN;
  840. }
  841. if (interval_ >= 0)
  842. {
  843. if (interval_ > 5000)
  844. interval_ = 5000;
  845. else if (interval_ < 10)
  846. interval_ = 10;
  847. interval = (uint)interval_;
  848. }
  849. if (resend_ >= 0)
  850. fastresend = resend_;
  851. nocwnd = nc_;
  852. return 0;
  853. }
  854. // set maximum window size: sndwnd=32, rcvwnd=32 by default
  855. public int SetWIndow(int sndwnd, int rcvwnd)
  856. {
  857. if (sndwnd > 0)
  858. snd_wnd = (uint)sndwnd;
  859. if (rcvwnd > 0)
  860. rcv_wnd = (uint)rcvwnd;
  861. return 0;
  862. }
  863. public bool ReserveBytes(int reservedSize)
  864. {
  865. if (reservedSize >= (mtu - KcpTool.IKCP_OVERHEAD) || reservedSize < 0)
  866. return false;
  867. reserved = reservedSize;
  868. mss = mtu - KcpTool.IKCP_OVERHEAD - (uint)(reservedSize);
  869. return true;
  870. }
  871. }
  872. }