Exemplo n.º 1
0
        /// <summary>
        /// Sends byte[] to socket.
        /// Creates datagram with frame format given as example in demonstration example.
        /// Switches state to waitingforack.
        /// Set sendAsIs when sending/resending valid datagram/frame.
        /// </summary>
        /// <param name="data">Byte array to be sent over socket</param>
        /// <param name="sendAsIs">Boolen: true - datagram has been contructed before, false - construct new datagram and send it</param>
        protected virtual async void RdtSend(byte[] data, bool sendAsIs = false)
        {
            if (sendAsIs)
            {
                socket.Send(data);
            }
            else
            {
                switch (state)
                {
                case (int)STATE.WaitingCallFromAboveOrBelow:
                {
                    byte[] newDatagram = rdt.MakeDatagram(data, senderSeq);
                    socket.Send(newDatagram);
                    previouslySentDatagram = newDatagram;
                    state = (int)STATE.WaitingForAck;
                    break;
                }

                case (int)STATE.WaitingForAck:
                {
                    RaiseOnDeliver(InvokeReason.Error, "Waiting for ACK/NACK, add to queue.");
                    messageBuffer.Add(data);
                    break;
                }
                }
            }
        }
Exemplo n.º 2
0
        private async void RdtSend(byte[] data, bool isOldDatagram = false)
        {
            if (isOldDatagram)
            {
                /*data has been sent before so it has seq nums etc*/
                socket.Send(data);
            }
            else
            {
                /*data is just new content as byte[] so new datagram is needed*/
                /*nextseqnum<base+N will fail when seqnum range overflows*/
                if (rdt.Distmod(gbnBase, gbnNextSeqNum, gbnWindowSize) < gbnWindowSize - 1)
                {
                    try
                    {
                        OnDeliver?.Invoke(InvokeReason.Debug, "4a" + PrintGbnDebug());

                        byte[] newDatagram = rdt.MakeDatagram(data, gbnNextSeqNum);
                        gbnSendDictionary[gbnNextSeqNum] = newDatagram;

                        socket.Send(gbnSendDictionary[gbnNextSeqNum]);
                        //simplify with pre-increment and combine following operations
                        gbnNextSeqNum = gbnNextSeqNum + 1;
                        gbnNextSeqNum = gbnNextSeqNum % gbnWindowSize;

                        OnDeliver?.Invoke(InvokeReason.Debug, "4b" + PrintGbnDebug());

                        if (cts != null)
                        {
                            cts.Cancel();
                        }
                        /*All standing packets are ack'd*/
                        if (gbnBase == gbnNextSeqNum)
                        {
                            //OnDeliver?.Invoke(InvokeReason.Debug, "Sending window is empty.");
                        }
                        else
                        {
                            //start new timer
                            //TODO: Check if this leaks resources
                            CancellationTokenSource aCTS = new CancellationTokenSource();
                            cts = aCTS;
                            await Timertimeout(aCTS.Token);

                            /*
                             * if (cts == aCTS)
                             * {
                             *  cts = null;
                             * }
                             */
                        }
                    }
                    catch (OperationCanceledException) { }
                }
                else //send window is full
                {
                    OnDeliver?.Invoke(InvokeReason.Error, "Sending window is full, try again later.");
                }
            }
        }
Exemplo n.º 3
0
        private void RdtReceive(byte[] datagram)
        {
            bool isOk = rdt.IsOk(datagram);

            if (isOk)
            {
                string str    = rdt.GetDatagramContentString(datagram);
                bool   isAck  = rdt.IsAck(datagram);
                byte   seqNum = (byte)rdt.GetSeqNum(datagram);

                if (isAck)
                {
                    //Mark as ack'd
                    //If seq == sendBase => move window by:
                    //Go through buffer and if packets are in window and pkt.sent = false => send it and toggle bool

                    if (rdt.IsSeqInRange(seqNum, srSendBase, (byte)(srSendBase + srWindowSize - 1)))
                    {
                        sendBucket.MarkAsAcked(seqNum);
                        OnDeliver?.Invoke(InvokeReason.Debug, "Received ACK: " + seqNum.ToString()
                                          + PrintSRDebugInfo());
                        if (seqNum == srSendBase)
                        {
                            //int i = 0;
                            //While packet is sent -> remove it from sendBucket, increment counter, add counter to srSendBase
                            while (sendBucket.IsSent(srSendBase) && sendBucket.IsAcked(srSendBase))
                            {
                                sendBucket.RemoveFromBucket(srSendBase);
                                srSendBase++;
                            }
                            //While packet in sendBucket is in new window && hasn't been sent, send it and toggle it's state
                            //E.g for each srSendBase to srSendBase + N -1, if is in sendBucket & is not sent, send it now
                            //As dictionary is not ordered, we loop over range srSendBase -> srSendBase + N - 1. Stopping early if key isn't in bucket.
                            for (byte i = srSendBase; rdt.IsSeqInRange(i, srSendBase, (byte)(srSendBase + srWindowSize - 1)); i++)
                            {
                                if (!sendBucket.ContainsKey(i))
                                {
                                    break;
                                }
                                socket.Send(sendBucket.GetDatagramBySeq(i));
                                sendBucket.MarkAsSent(i);
                                //srNextSeqNum++;
                            }
                            OnDeliver.Invoke(InvokeReason.Debug, "Sender window moved. " + PrintSRDebugInfo());
                        }
                    }
                }
                else
                {
                    if (rdt.IsSeqInRange(seqNum, (byte)(srRcvBase - srWindowSize), (byte)(srRcvBase + srWindowSize - 1)))
                    {
                        RdtSend(rdt.MakeAck(seqNum), true);
                        OnDeliver?.Invoke(InvokeReason.Debug, "Received Pkt: " + seqNum.ToString()
                                          + PrintSRDebugInfo());
                        if (rdt.IsSeqInRange(seqNum, srRcvBase, (byte)(srRcvBase + srWindowSize - 1)))
                        {
                            if (!rcvBucket.ContainsKey(seqNum))
                            {
                                rcvBucket.AddToBucket(datagram, seqNum);
                            }
                            else
                            {
                                OnDeliver.Invoke(InvokeReason.Debug, "Received duplicate: " + seqNum.ToString());
                            }

                            if (seqNum == srRcvBase)
                            {
                                /*Pass a Action delegate for handling method. Method chain removes from buffer,
                                 * handles packets, returns count of handled. Naming scheme I use is bad, I know :(*/
                                srRcvBase = (byte)(srRcvBase + ProcessValidBufferedSequence(srRcvBase,
                                                                                            DeliverDataSequenceToUpperLayer));
                                OnDeliver.Invoke(InvokeReason.Debug, "Receiver window moved. " + PrintSRDebugInfo());
                            }
                        }
                    }
                }
            }
            else
            {
                //This Kurose implementation will ignore corrupted packets and relies on timeout to recover
                //Alternative is to send SREPEAT-control message to request retransmission for seqnum-1 packet.

                OnDeliver?.Invoke(InvokeReason.Error, "Received corrupted");
            }
        }