Exemple #1
0
        /**
         * user/upper level send, returns below zero for error
         *
         * @param buffer
         * @return
         */
        public int Send(ByteBuf buffer)
        {
            if (buffer.ReadableBytes() == 0)
            {
                return(-1);
            }
            // append to previous segment in streaming mode (if possible)
            if (this.stream && this.snd_queue.Count > 0)
            {
                Segment seg = snd_queue.Last();
                if (seg.data != null && seg.data.ReadableBytes() < mss)
                {
                    int capacity = mss - seg.data.ReadableBytes();
                    int extend   = (buffer.ReadableBytes() < capacity) ? buffer.ReadableBytes() : capacity;
                    seg.data.WriteBytes(buffer, extend);
                    if (buffer.ReadableBytes() == 0)
                    {
                        return(0);
                    }
                }
            }
            int count;

            if (buffer.ReadableBytes() <= mss)
            {
                count = 1;
            }
            else
            {
                count = (buffer.ReadableBytes() + mss - 1) / mss;
            }
            if (count > 255)
            {
                return(-2);
            }
            if (count == 0)
            {
                count = 1;
            }
            //fragment
            for (int i = 0; i < count; i++)
            {
                int     size = buffer.ReadableBytes() > mss ? mss : buffer.ReadableBytes();
                Segment seg  = new Segment(size);
                seg.data.WriteBytes(buffer, size);
                seg.frg = this.stream?0:count - i - 1;
                snd_queue.Add(seg);
            }
            return(0);
        }
Exemple #2
0
            /**
             * encode a segment into buffer
             *
             * @param buf
             * @param offset
             * @return
             */
            public int Encode(ByteBuf buf)
            {
                int off = buf.WriterIndex();

                buf.WriteIntLE(conv);
                buf.WriteByte(cmd);
                buf.WriteByte((byte)frg);
                buf.WriteShortLE((short)wnd);
                buf.WriteIntLE(ts);
                buf.WriteIntLE(sn);
                buf.WriteIntLE(una);
                buf.WriteIntLE(data == null ? 0 : data.ReadableBytes());
                return(buf.WriterIndex() - off);
            }
Exemple #3
0
        /**
         * flush pending data
         */
        private void Flush()
        {
            int cur    = current;
            int change = 0;
            int lost   = 0;

            if (updated == 0)
            {
                return;
            }
            Segment seg = new Segment(0);

            seg.conv = conv;
            seg.cmd  = IKCP_CMD_ACK;
            seg.wnd  = wnd_unused();
            seg.una  = rcv_nxt;
            // flush acknowledges
            int c = acklist.Count / 2;

            for (int i = 0; i < c; i++)
            {
                if (buffer.ReadableBytes() + IKCP_OVERHEAD > mtu)
                {
                    this.output.output(buffer, this, user);
                    buffer = new ByteBuf((mtu + IKCP_OVERHEAD) * 3);
                }
                seg.sn = acklist[i * 2 + 0];
                seg.ts = acklist[i * 2 + 1];
                seg.Encode(buffer);
            }
            acklist.Clear();
            // probe window size (if remote window size equals zero)
            if (rmt_wnd == 0)
            {
                if (probe_wait == 0)
                {
                    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 (buffer.ReadableBytes() + IKCP_OVERHEAD > mtu)
                {
                    this.output.output(buffer, this, user);
                    buffer = new ByteBuf((mtu + IKCP_OVERHEAD) * 3);
                }
                seg.Encode(buffer);
            }
            // flush window probing commands
            if ((probe & IKCP_ASK_TELL) != 0)
            {
                seg.cmd = IKCP_CMD_WINS;
                if (buffer.ReadableBytes() + IKCP_OVERHEAD > mtu)
                {
                    this.output.output(buffer, this, user);
                    buffer = new ByteBuf((mtu + IKCP_OVERHEAD) * 3);
                }
                seg.Encode(buffer);
            }
            probe = 0;
            // calculate window size
            int cwnd_temp = Math.Min(snd_wnd, rmt_wnd);

            if (nocwnd == 0)
            {
                cwnd_temp = Math.Min(cwnd, cwnd_temp);
            }
            // move data from snd_queue to snd_buf
            c = 0;
            for (int i = 0; i < snd_queue.Count; i++)
            {
                Segment item = snd_queue[i];
                if (_itimediff(snd_nxt, snd_una + cwnd_temp) >= 0)
                {
                    break;
                }
                Segment newseg = item;
                newseg.conv     = conv;
                newseg.cmd      = IKCP_CMD_PUSH;
                newseg.wnd      = seg.wnd;
                newseg.ts       = cur;
                newseg.sn       = snd_nxt++;
                newseg.una      = rcv_nxt;
                newseg.resendts = cur;
                newseg.rto      = rx_rto;
                newseg.fastack  = 0;
                newseg.xmit     = 0;
                snd_buf.Add(newseg);
                c++;
            }
            if (c > 0)
            {
                snd_queue.RemoveRange(0, c);
            }
            // calculate resent
            int resent = (fastresend > 0) ? fastresend : int.MaxValue;
            int rtomin = (nodelay == 0) ? (rx_rto >> 3) : 0;

            // flush data segments
            for (int i = 0; i < snd_buf.Count; i++)
            {
                Segment segment  = snd_buf[i];
                bool    needsend = false;
                if (segment.xmit == 0)
                {
                    needsend = true;
                    segment.xmit++;
                    segment.rto      = rx_rto;
                    segment.resendts = cur + segment.rto + rtomin;
                }
                else if (_itimediff(cur, segment.resendts) >= 0)
                {
                    needsend = true;
                    segment.xmit++;
                    xmit++;
                    if (nodelay == 0)
                    {
                        segment.rto += rx_rto;
                    }
                    else
                    {
                        segment.rto += rx_rto / 2;
                    }
                    segment.resendts = cur + segment.rto;
                    lost             = 1;
                }
                else if (segment.fastack >= resent)
                {
                    needsend = true;
                    segment.xmit++;
                    segment.fastack  = 0;
                    segment.resendts = cur + segment.rto;
                    change++;
                }
                if (needsend)
                {
                    segment.ts  = cur;
                    segment.wnd = seg.wnd;
                    segment.una = rcv_nxt;
                    int need = IKCP_OVERHEAD + segment.data.ReadableBytes();
                    if (buffer.ReadableBytes() + need > mtu)
                    {
                        this.output.output(buffer, this, user);
                        buffer = new ByteBuf((mtu + IKCP_OVERHEAD) * 3);
                    }
                    segment.Encode(buffer);
                    if (segment.data.ReadableBytes() > 0)
                    {
                        buffer.WriteBytes(segment.data.Duplicate());
                    }
                    if (segment.xmit >= dead_link)
                    {
                        state = -1;
                    }
                }
            }
            // flash remain segments
            if (buffer.ReadableBytes() > 0)
            {
                this.output.output(buffer, this, user);
                buffer = new ByteBuf((mtu + IKCP_OVERHEAD) * 3);
            }
            // update ssthresh
            if (change != 0)
            {
                int 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 #4
0
        /**
         *
         * when you received a low level packet (eg. UDP packet), call it
         *
         * @param data
         * @return
         */
        public int Input(ByteBuf data)
        {
            int una_temp = snd_una;
            int flag = 0, maxack = 0;

            if (data == null || data.ReadableBytes() < IKCP_OVERHEAD)
            {
                return(-1);
            }
            while (true)
            {
                bool readed = false;
                int  ts;
                int  sn;
                int  len;
                int  una;
                int  conv_;
                int  wnd;
                byte cmd;
                byte frg;
                if (data.ReadableBytes() < IKCP_OVERHEAD)
                {
                    break;
                }
                conv_ = data.ReadIntLE();
                if (this.conv != conv_)
                {
                    return(-1);
                }
                cmd = data.ReadByte();
                frg = data.ReadByte();
                wnd = data.ReadShortLE();
                ts  = data.ReadIntLE();
                sn  = data.ReadIntLE();
                una = data.ReadIntLE();
                len = data.ReadIntLE();
                if (data.ReadableBytes() < len)
                {
                    return(-2);
                }
                switch ((int)cmd)
                {
                case IKCP_CMD_PUSH:
                case IKCP_CMD_ACK:
                case IKCP_CMD_WASK:
                case IKCP_CMD_WINS:
                    break;

                default:
                    return(-3);
                }
                rmt_wnd = wnd & 0x0000ffff;
                Parse_una(una);
                Shrink_buf();
                switch (cmd)
                {
                case IKCP_CMD_ACK:
                    if (_itimediff(current, ts) >= 0)
                    {
                        Update_ack(_itimediff(current, ts));
                    }
                    Parse_ack(sn);
                    Shrink_buf();
                    if (flag == 0)
                    {
                        flag   = 1;
                        maxack = sn;
                    }
                    else if (_itimediff(sn, maxack) > 0)
                    {
                        maxack = sn;
                    }
                    break;

                case IKCP_CMD_PUSH:
                    if (_itimediff(sn, rcv_nxt + rcv_wnd) < 0)
                    {
                        Ack_push(sn, ts);
                        if (_itimediff(sn, rcv_nxt) >= 0)
                        {
                            Segment seg = new Segment(len);
                            seg.conv = conv_;
                            seg.cmd  = cmd;
                            seg.frg  = frg & 0x000000ff;
                            seg.wnd  = wnd;
                            seg.ts   = ts;
                            seg.sn   = sn;
                            seg.una  = una;
                            if (len > 0)
                            {
                                seg.data.WriteBytes(data, len);
                                readed = true;
                            }
                            Parse_data(seg);
                        }
                    }
                    break;

                case IKCP_CMD_WASK:
                    // ready to send back IKCP_CMD_WINS in Ikcp_flush
                    // tell remote my window size
                    probe |= IKCP_ASK_TELL;
                    break;

                case IKCP_CMD_WINS:
                    // do nothing
                    break;

                default:
                    return(-3);
                }
                if (!readed)
                {
                    data.SkipBytes(len);
                }
            }
            if (flag != 0)
            {
                Parse_fastack(maxack);
            }
            if (_itimediff(snd_una, una_temp) > 0)
            {
                if (this.cwnd < this.rmt_wnd)
                {
                    if (this.cwnd < this.ssthresh)
                    {
                        this.cwnd++;
                        this.incr += mss;
                    }
                    else
                    {
                        if (this.incr < mss)
                        {
                            this.incr = mss;
                        }
                        this.incr += (mss * mss) / this.incr + (mss / 16);
                        if ((this.cwnd + 1) * mss <= this.incr)
                        {
                            this.cwnd++;
                        }
                    }
                    if (this.cwnd > this.rmt_wnd)
                    {
                        this.cwnd = this.rmt_wnd;
                        this.incr = this.rmt_wnd * mss;
                    }
                }
            }
            return(0);
        }
 public override void output(ByteBuf msg, Kcp kcp, Object user)
 {
     this.client.Send(msg.GetRaw(), msg.ReadableBytes());
 }