Exemple #1
0
        // when you received a low level packet (eg. UDP packet), call it
        public int Input(byte[] data)
        {
            var s_una = snd_una;

            if (data.Length < IKCP_OVERHEAD)
            {
                return(0);
            }

            var offset = 0;

            while (true)
            {
                UInt32 ts     = 0;
                UInt32 sn     = 0;
                UInt32 length = 0;
                UInt32 una    = 0;
                UInt32 conv_  = 0;

                UInt16 wnd = 0;

                byte cmd = 0;
                byte frg = 0;

                if (data.Length - offset < IKCP_OVERHEAD)
                {
                    break;
                }

                offset += ikcp_decode32u(data, offset, ref conv_);

                if (conv != conv_)
                {
                    return(-1);
                }

                offset += ikcp_decode8u(data, offset, ref cmd);
                offset += ikcp_decode8u(data, offset, ref frg);
                offset += ikcp_decode16u(data, offset, ref wnd);
                offset += ikcp_decode32u(data, offset, ref ts);
                offset += ikcp_decode32u(data, offset, ref sn);
                offset += ikcp_decode32u(data, offset, ref una);
                offset += ikcp_decode32u(data, offset, ref length);

                if (data.Length - offset < length)
                {
                    return(-2);
                }

                switch (cmd)
                {
                case IKCP_CMD_PUSH:
                case IKCP_CMD_ACK:
                case IKCP_CMD_WASK:
                case IKCP_CMD_WINS:
                    break;

                default:
                    return(-3);
                }

                rmt_wnd = (UInt32)wnd;
                parse_una(una);
                shrink_buf();

                if (IKCP_CMD_ACK == cmd)
                {
                    if (_itimediff(current, ts) >= 0)
                    {
                        update_ack(_itimediff(current, ts));
                    }
                    parse_ack(sn);
                    shrink_buf();
                }
                else if (IKCP_CMD_PUSH == cmd)
                {
                    if (_itimediff(sn, rcv_nxt + rcv_wnd) < 0)
                    {
                        ack_push(sn, ts);
                        if (_itimediff(sn, rcv_nxt) >= 0)
                        {
                            //var seg = new Segment((int)length);

                            QueueNode <Segment> node = AlocSegmentNode((int)length);
                            Segment             seg  = node.item;

                            seg.conv = conv_;
                            seg.cmd  = (UInt32)cmd;
                            seg.frg  = (UInt32)frg;
                            seg.wnd  = (UInt32)wnd;
                            seg.ts   = ts;
                            seg.sn   = sn;
                            seg.una  = una;

                            if (length > 0)
                            {
                                Array.Copy(data, offset, seg.data.item.data, 0, length);
                            }

                            parse_data(node);
                        }
                    }
                }
                else if (IKCP_CMD_WASK == cmd)
                {
                    // ready to send back IKCP_CMD_WINS in Ikcp_flush
                    // tell remote my window size
                    probe |= IKCP_ASK_TELL;
                }
                else if (IKCP_CMD_WINS == cmd)
                {
                    // do nothing
                }
                else
                {
                    return(-3);
                }

                offset += (int)length;
            }

            if (_itimediff(snd_una, s_una) > 0)
            {
                if (cwnd < rmt_wnd)
                {
                    var mss_ = mss;
                    if (cwnd < ssthresh)
                    {
                        cwnd++;
                        incr += mss_;
                    }
                    else
                    {
                        if (incr < mss_)
                        {
                            incr = mss_;
                        }
                        incr += (mss_ * mss_) / incr + (mss_ / 16);
                        if ((cwnd + 1) * mss_ <= incr)
                        {
                            cwnd++;
                        }
                    }
                    if (cwnd > rmt_wnd)
                    {
                        cwnd = rmt_wnd;
                        incr = rmt_wnd * mss_;
                    }
                }
            }

            return(0);
        }
Exemple #2
0
        // flush pending data
        void flush()
        {
            var current_ = current;
            var change   = 0;
            var lost     = 0;

            if (0 == updated)
            {
                return;
            }

            Segment seg = m_oTeampSeg;// new Segment(0);

            seg.ResetState();
            seg.conv = conv;
            seg.cmd  = IKCP_CMD_ACK;
            seg.wnd  = (UInt32)wnd_unused();
            seg.una  = rcv_nxt;

            // flush acknowledges
            var count  = acklist.Count / 2;
            var offset = 0;

            for (var i = 0; i < count; i++)
            {
                if (offset + IKCP_OVERHEAD > mtu)
                {
                    output(buffer, offset);
                    //Array.Clear(buffer, 0, offset);
                    offset = 0;
                }
                ack_get(i, ref seg.sn, ref seg.ts);
                offset += seg.encode(buffer, offset);
            }
            // acklist = new UInt32[0];
            acklist.Clear();

            // probe window size (if remote window size equals zero)
            if (0 == rmt_wnd)
            {
                if (0 == probe_wait)
                {
                    probe_wait = IKCP_PROBE_INIT;
                    ts_probe   = current + probe_wait;
                }
                else
                {
                    if (_itimediff(current, ts_probe) >= 0)
                    {
                        if (probe_wait < IKCP_PROBE_INIT)
                        {
                            probe_wait = IKCP_PROBE_INIT;
                        }
                        probe_wait += probe_wait / 2;
                        if (probe_wait > IKCP_PROBE_LIMIT)
                        {
                            probe_wait = IKCP_PROBE_LIMIT;
                        }
                        ts_probe = current + probe_wait;
                        probe   |= IKCP_ASK_SEND;
                    }
                }
            }
            else
            {
                ts_probe   = 0;
                probe_wait = 0;
            }

            // flush window probing commands
            if ((probe & IKCP_ASK_SEND) != 0)
            {
                seg.cmd = IKCP_CMD_WASK;
                if (offset + IKCP_OVERHEAD > (int)mtu)
                {
                    output(buffer, offset);
                    //Array.Clear(buffer, 0, offset);
                    offset = 0;
                }
                offset += seg.encode(buffer, offset);
            }

            probe = 0;

            // calculate window size
            var cwnd_ = _imin_(snd_wnd, rmt_wnd);

            if (0 == nocwnd)
            {
                cwnd_ = _imin_(cwnd, cwnd_);
            }

            count = 0;
            int nLen = snd_queue.Count;
            QueueNode <Segment> node    = null;
            Segment             segment = null;

            for (var k = 0; k < nLen; k++)
            {
                if (_itimediff(snd_nxt, snd_una + cwnd_) >= 0)
                {
                    break;
                }

                node    = snd_queue[k];
                segment = node.item;
                // var newseg = snd_queue[k];
                segment.conv     = conv;
                segment.cmd      = IKCP_CMD_PUSH;
                segment.wnd      = seg.wnd;
                segment.ts       = current_;
                segment.sn       = snd_nxt;
                segment.una      = rcv_nxt;
                segment.resendts = current_;
                segment.rto      = rx_rto;
                segment.fastack  = 0;
                segment.xmit     = 0;
                //snd_buf = append<Segment>(snd_buf, newseg);
                snd_buf.Add(node);
                snd_nxt++;
                count++;
            }

            if (0 < count)
            {
                //snd_queue = slice<Segment>(snd_queue, count, snd_queue.Length);
                snd_queue.RemoveRange(0, count);
            }

            // calculate resent
            var resent = (UInt32)fastresend;

            if (fastresend <= 0)
            {
                resent = 0xffffffff;
            }
            var rtomin = rx_rto >> 3;

            if (nodelay != 0)
            {
                rtomin = 0;
            }

            // flush data segments
            nLen = snd_buf.Count;
            //foreach (var segment in snd_buf) {
            for (int i = 0; i < nLen; ++i)
            {
                node    = snd_buf[i];
                segment = node.item;
                var needsend = false;
                _itimediff(current_, segment.resendts);
                if (0 == segment.xmit)
                {
                    needsend = true;
                    segment.xmit++;
                    segment.rto      = rx_rto;
                    segment.resendts = current_ + segment.rto + rtomin;
                }
                else if (_itimediff(current_, segment.resendts) >= 0)
                {
                    needsend = true;
                    segment.xmit++;
                    xmit++;
                    if (0 == nodelay)
                    {
                        segment.rto += rx_rto;
                    }
                    else
                    {
                        segment.rto += rx_rto / 2;
                    }
                    segment.resendts = current_ + segment.rto;
                    lost             = 1;
                }
                else if (segment.fastack >= resent)
                {
                    needsend = true;
                    segment.xmit++;
                    segment.fastack  = 0;
                    segment.resendts = current_ + segment.rto;
                    change++;
                }

                if (needsend)
                {
                    segment.ts  = current_;
                    segment.wnd = seg.wnd;
                    segment.una = rcv_nxt;

                    var need = IKCP_OVERHEAD + segment.data.item.nLen;
                    if (offset + need > mtu)
                    {
                        output(buffer, offset);
                        //Array.Clear(buffer, 0, offset);
                        offset = 0;
                    }

                    offset += segment.encode(buffer, offset);
                    if (segment.data.item.nLen > 0)
                    {
                        Array.Copy(segment.data.item.data, 0, buffer, offset, segment.data.item.nLen);
                        offset += segment.data.item.nLen;
                    }

                    if (segment.xmit >= dead_link)
                    {
                        //state = 0;
                    }
                }
            }

            // flash remain segments
            if (offset > 0)
            {
                output(buffer, offset);
                //Array.Clear(buffer, 0, offset);
                offset = 0;
            }

            // update ssthresh
            if (change != 0)
            {
                var inflight = snd_nxt - snd_una;
                ssthresh = inflight / 2;
                if (ssthresh < IKCP_THRESH_MIN)
                {
                    ssthresh = IKCP_THRESH_MIN;
                }
                cwnd = ssthresh + resent;
                incr = cwnd * mss;
            }

            if (lost != 0)
            {
                ssthresh = cwnd / 2;
                if (ssthresh < IKCP_THRESH_MIN)
                {
                    ssthresh = IKCP_THRESH_MIN;
                }
                cwnd = 1;
                incr = mss;
            }

            if (cwnd < 1)
            {
                cwnd = 1;
                incr = mss;
            }
        }
Exemple #3
0
        // user/upper level send, returns below zero for error
        public int Send(byte[] buffer, int nBufferSize)
        {
            if (0 == nBufferSize)
            {
                return(-1);
            }

            var count = 0;

            if (nBufferSize < mss)
            {
                count = 1;
            }
            else
            {
                count = (int)(nBufferSize + mss - 1) / (int)mss;
            }

            if (255 < count)
            {
                return(-2);
            }

            if (0 == count)
            {
                count = 1;
            }

            var offset = 0;

            QueueNode <Segment> node = null;
            Segment             seg  = null;

            for (var i = 0; i < count; i++)
            {
                var size = 0;
                if (nBufferSize - offset > mss)
                {
                    size = (int)mss;
                }
                else
                {
                    size = nBufferSize - offset;
                }


                node = AlocSegmentNode(size);
                seg  = node.item;
                Array.Copy(buffer, offset, seg.data.item.data, 0, size);
                offset += size;
                seg.frg = (UInt32)(count - i - 1);
                snd_queue.Add(node);

                /*
                 * var seg = new Segment(size);
                 * Array.Copy(buffer, offset, seg.data.item.data, 0, size);
                 * offset += size;
                 * seg.frg = (UInt32)(count - i - 1);
                 * snd_queue = append<Segment>(snd_queue, seg);
                 */
            }

            return(0);
        }
Exemple #4
0
        void parse_data(QueueNode <Segment> newNode)
        {
            var sn = newNode.item.sn;

            if (_itimediff(sn, rcv_nxt + rcv_wnd) >= 0 || _itimediff(sn, rcv_nxt) < 0)
            {
                return;
            }

            var n                    = rcv_buf.Count - 1;
            var after_idx            = -1;
            var repeat               = false;
            QueueNode <Segment> node = null;
            Segment             seg  = null;

            for (int i = n; i >= 0; i--)
            {
                node = rcv_buf[i];
                seg  = node.item;
                if (seg.sn == sn)
                {
                    repeat = true;
                    break;
                }

                if (_itimediff(sn, seg.sn) > 0)
                {
                    after_idx = i;
                    break;
                }
            }

            if (!repeat)
            {
                /*
                 * if (after_idx == -1)
                 * {
                 *  //rcv_buf = append<Segment>(new Segment[1] { newseg }, rcv_buf);
                 *  rcv_buf.Insert(0, newNode);
                 * }
                 *
                 * else
                 * {
                 *  //rcv_buf = append<Segment>(slice<Segment>(rcv_buf, 0, after_idx + 1), append<Segment>(new Segment[1] { newseg }, slice<Segment>(rcv_buf, after_idx + 1, rcv_buf.Length)));
                 *
                 *  rcv_buf.Insert(after_idx + 1, newNode);
                 *
                 * }
                 */



                rcv_buf.Insert(after_idx + 1, newNode);
            }

            // move available data from rcv_buf -> rcv_queue
            MoveRecvBuff2RecvQueue();

            /*
             *          // move available data from rcv_buf -> rcv_queue
             *          var count = 0;
             *      foreach (var seg in rcv_buf) {
             *          if (seg.sn == rcv_nxt && rcv_queue.Length < rcv_wnd)
             *          {
             *              rcv_queue = append<Segment>(rcv_queue, seg);
             *              rcv_nxt++;
             *              count++;
             *          }
             *          else
             *          {
             *              break;
             *          }
             *      }
             *
             *      if (0 < count) {
             *          rcv_buf = slice<Segment>(rcv_buf, count, rcv_buf.Length);
             *      }
             */
        }
Exemple #5
0
 internal void Clear()
 {
     ResetState();
     data = null;
 }
Exemple #6
0
 internal Segment()
 {
     data = null;
 }
Exemple #7
0
        // Determine when should you invoke ikcp_update:
        // returns when you should invoke ikcp_update in millisec, if there
        // is no ikcp_input/_send calling. you can call ikcp_update in that
        // time, instead of call update repeatly.
        // Important to reduce unnacessary ikcp_update invoking. use it to
        // schedule ikcp_update (eg. implementing an epoll-like mechanism,
        // or optimize ikcp_update when handling massive kcp connections)
        public UInt32 Check(UInt32 current_)
        {
            if (0 == updated)
            {
                return(current_);
            }

            var ts_flush_ = ts_flush;
            var tm_flush_ = 0x7fffffff;
            var tm_packet = 0x7fffffff;
            var minimal   = 0;

            if (_itimediff(current_, ts_flush_) >= 10000 || _itimediff(current_, ts_flush_) < -10000)
            {
                ts_flush_ = current_;
            }

            if (_itimediff(current_, ts_flush_) >= 0)
            {
                return(current_);
            }

            tm_flush_ = (int)_itimediff(ts_flush_, current_);

            QueueNode <Segment> node = null;


            int nCount = snd_buf.Count;

            for (int i = 0; i < nCount; ++i)
            {
                node = snd_buf[i];
                Segment seg  = node.item;
                var     diff = _itimediff(seg.resendts, current_);
                if (diff <= 0)
                {
                    return(current_);
                }
                if (diff < tm_packet)
                {
                    tm_packet = (int)diff;
                }
            }

            /*
             * foreach (var seg in snd_buf) {
             * var diff = _itimediff(seg.resendts, current_);
             * if (diff <= 0) return current_;
             * if (diff < tm_packet) tm_packet = (int)diff;
             * }
             */

            minimal = (int)tm_packet;
            if (tm_packet >= tm_flush_)
            {
                minimal = (int)tm_flush_;
            }
            if (minimal >= interval)
            {
                minimal = (int)interval;
            }

            return(current_ + (UInt32)minimal);
        }
Exemple #8
0
 //压入节点(在生产者线程调用)
 public void Push(QueueNode <ByteData> node)
 {
     m_oDataQueue.Push(node);
 }
Exemple #9
0
 //回收节点(在消费者线程调用)
 public void Recycle(ref QueueNode <ByteData> node)
 {
     m_oRecycleQueue.Push(node);
 }