public int Read(byte[] recieveBuffer, ref IPEndPoint ipFrom)
        {
            lock (messagesBuffer)
            {
                if (messageDetails.Count == 0)
                {
                    return(0);
                }

                MessageDetail detail = messageDetails.Dequeue();

                // If no more details remain all messages have been read from buffer, reset index
                // so future messages can re-use the messagesBuffer.
                //
                // ASSUMPTION: We will never receive more messages than messageBuffer can hold
                //             between reads to read all messages
                //
                if (messageDetails.Count == 0)
                {
                    messagesBufferIndex = 0;
                }

                // Try assign ipFrom to IPEndPoint message received from
                if (!IPEndPoint.TryParse(detail.RemoteAddress.RawName, detail.RemotePort, out ipFrom))
                {
                    localPeer.Log(LogLevel.Error, String.Format("Failed to parse remote end point: {0}:{1}", detail.RemoteAddress.RawName, detail.RemotePort));
                    return(0);
                }

                System.Buffer.BlockCopy(messagesBuffer, detail.Index, recieveBuffer, 0, detail.Count);

                return(detail.Count);
            }
        }
Exemplo n.º 2
0
        private void Run()
        {
            while (socket.IsBound)
            {
                int size = 0;
                try
                {
                    size = socket.ReceiveFrom(lastDatagramBuffer, ref placeHolderEndPoint);
                }
                catch (SocketException ex)
                {
                    localPeer.Log(LogLevel.Error, "SocketException ReceiveFrom " + ex.Message);
                    continue;
                }

                if (size == 0)
                {
                    continue;
                }
                if (size > FalconPeer.MaxDatagramSize)
                {
                    continue;
                }

                lock (receivedDatagramsBuffer)
                {
                    var detail = new DatagramDetail();
                    detail.Index = receivedDatagramsIndex;
                    detail.Count = size;
                    detail.IP    = (IPEndPoint)placeHolderEndPoint;
                    receivedDatagramDetails.Enqueue(detail);

                    if (size > 0 && ((receivedDatagramsIndex + size) < receivedDatagramsBuffer.Length))
                    {
                        Buffer.BlockCopy(lastDatagramBuffer, 0, receivedDatagramsBuffer, receivedDatagramsIndex, size);
                        Interlocked.Exchange(ref receivedDatagramsIndex, (receivedDatagramsIndex + size));
                    }
                }
            }
        }
Exemplo n.º 3
0
        // returns 0 if fatal failure receiving from epFrom
        public int Read(byte[] receiveBuffer, ref IPEndPoint ipFrom)
        {
            int size = 0;

            try
            {
                size   = socket.ReceiveFrom(receiveBuffer, ref placeHolderEndPoint);
                ipFrom = (IPEndPoint)placeHolderEndPoint;
            }
            catch (SocketException se)
            {
                localPeer.Log(LogLevel.Error, String.Format("Socket Exception {0} {1}, while receiving from {2}."
#if WINDOWS_UWP
                                                            , se.SocketErrorCode
#else
                                                            , se.ErrorCode
#endif
                                                            , se.Message
                                                            , ipFrom));
            }
            return(size);
        }
Exemplo n.º 4
0
        internal void EmitDiscoverySignal()
        {
            foreach (IPEndPoint ep in endPointsToSendTo)
            {
                // check we haven't already discovered the peer we are about to try discover!
                if (endPointsReceivedReplyFrom.Exists(dp => dp.FastEquals(ep)))
                {
                    continue;
                }

                falconPeer.Log(LogLevel.Debug, String.Format("Emitting discovery signal to: {0}, with token: {1}.", ep, token.HasValue ? token.Value.ToString() : "None"));

                int count = token.HasValue ? signal.Length : Const.DISCOVER_PACKET.Length;

                //-------------------------------------------------------
                falconPeer.Transceiver.Send(signal, 0, count, ep, false);
                //-------------------------------------------------------
            }
        }
Exemplo n.º 5
0
        // returns true if datagram is valid, otherwise it should be dropped any additional packets in it should not be processed
        internal bool TryAddReceivedPacket(
            ushort datagramSeq,
            PacketType type,
            byte[]      buffer,
            int index,
            int count,
            bool isFirstPacketInDatagram,
            out bool applicationPacketAdded)
        {
            applicationPacketAdded = false; // until proven otherwise

            float ordinalPacketSeq;

            if (isFirstPacketInDatagram)
            {
                // If datagram requries ACK - send it! Do this before checking not duplicate or in-
                // order as peer could be re-sending as it never got ACK.
                if (isReliable)
                {
                    remotePeer.ACK(datagramSeq, channelType);
                }

                // TODO Needs a re-think as doing this means if application is sending fast enough
                //      on a Reliable channel re-sending a packet that got dropped will be far
                //      behind subsequent sends will be out-of-range by this check so repetadly be
                //      dropped and eventually cause the remote peer to drop us. The reason we are
                //      doing this is so we know when we can reset ordinalSeq and
                //      maxReadDatagramSeq. For now set default to 100 (previously was 8) to
                //      mitigate issue.

                // validate seq in range

                ushort min = unchecked ((ushort)(lastReceivedPacketSeq - localPeer.OutOfOrderTolerance));
                ushort max = unchecked ((ushort)(lastReceivedPacketSeq + localPeer.OutOfOrderTolerance));

                // NOTE: Max could be less than min if exceeded MaxValue, likewise min could be
                //       greater than max if less than 0. So have to check seq between min - max range
                //       which is a loop, inclusive.

                if (datagramSeq > max && datagramSeq < min)
                {
                    localPeer.Log(LogLevel.Warning, String.Format("Out-of-order packet from: {0} dropped, out-of-order from last by: {1}.", remotePeer.PeerName, datagramSeq - lastReceivedPacketSeq));
                    return(false);
                }

                // validate not duplicate

                if (datagramsSeqRecentlyRead.Contains(datagramSeq))
                {
                    localPeer.Log(LogLevel.Warning, String.Format("Duplicate datagram from: {0} dropped.", remotePeer.PeerName));
                    return(false);
                }

                if (datagramsSeqRecentlyRead.Count == numberOfDatagramSequencesReadToKeep)
                {
                    datagramsSeqRecentlyRead.RemoveAt(0);
                }
                datagramsSeqRecentlyRead.Add(datagramSeq);

                ordinalPacketSeq = datagramSeq;
                int diff = Math.Abs(datagramSeq - (int)lastReceivedPacketSeq);
                if (diff > localPeer.OutOfOrderTolerance)
                {
                    if (datagramSeq < lastReceivedPacketSeq) // i.e. seq must have looped since we have already validated seq in range
                    {
                        ordinalPacketSeq += ushort.MaxValue;
                    }
                }

                // if datagram required to be in order check after max read, if not drop it
                if (isInOrder)
                {
                    if (ordinalPacketSeq < maxReadDatagramSeq)
                    {
                        return(false);
                    }
                }
            }
            else // i.e. additional packet
            {
                // lastReceived Seq will be ordinal seq for previous packet in datagram
                ordinalPacketSeq = lastReceivedPacketSeq + 0.01f;
            }

            lastReceivedPacketSeq = ordinalPacketSeq;

            if (type == PacketType.KeepAlive)
            {
                if (!remotePeer.IsKeepAliveMaster)
                {
                    // To have received a KeepAlive from this peer who is not the KeepAlive master
                    // is only valid when the peer never received a KeepAlive from us for
                    // FalconPeer.KeepAliveProbeInterval for which the most common cause would be
                    // we disappered though we must be back up again to have received it!

                    localPeer.Log(LogLevel.Warning, String.Format("Received KeepAlive from: {0} who's not the KeepAlive master!", remotePeer.PeerName));
                }

                // nothing else to do - would have already ACKd this datagram

                return(true);
            }

            if (type == PacketType.AcceptJoin)
            {
                // Probably our ACK did not get through so the remote peer is re-sending,
                // nothing else to do - would have already ACKd this datagram.

                return(true);
            }

            // Must be Application packet

            Packet packet = localPeer.PacketPool.Borrow();

            packet.WriteBytes(buffer, index, count);
            packet.ResetAndMakeReadOnly(remotePeer.Id);
            packet.DatagramSeq = datagramSeq;

            // Add packet
            receivedPackets.Add(ordinalPacketSeq, packet);

            if (isReliable)
            {
                // re-calc number of continuous seq from first
                Count = 1;
                int key = receivedPackets[receivedPackets.Keys[0]].DatagramSeq;
                for (int i = 1; i < receivedPackets.Count; i++)
                {
                    int next = receivedPackets[receivedPackets.Keys[i]].DatagramSeq;
                    if (next == key)
                    {
                        // NOTE: This must be an additional packet with the same
                        //       datagram seq.

                        Count++;
                    }
                    else if (next == (key + 1))
                    {
                        Count++;
                        key = next;
                    }
                    else
                    {
                        break;
                    }
                }
            }
            else
            {
                Count++;
            }

            applicationPacketAdded = true;

            return(true);
        }
Exemplo n.º 6
0
        private bool TrySendDatagram(Datagram datagram, bool hasAlreadyBeenDelayed = false)
        {
            // If we are the keep alive master (i.e. this remote peer is not) and this
            // packet is reliable: update ellpasedMilliseondsAtLastRealiablePacket[Sent]
            if (!IsKeepAliveMaster && datagram.IsReliable)
            {
                ellapasedSecondsSinceLastRealiablePacket = 0.0f;
            }

            // simulate packet loss
            if (localPeer.SimulatePacketLossProbability > 0.0)
            {
                if (SingleRandom.NextDouble() < localPeer.SimulatePacketLossProbability)
                {
                    localPeer.Log(LogLevel.Info, String.Format("DROPPED packet to send - simulate packet loss set at: {0}", localPeer.SimulatePacketLossChance));
                    return(true);
                }
            }

            // if reliable and not already delayed update time sent used to measure RTT when ACK response received
            if (datagram.IsReliable && !hasAlreadyBeenDelayed)
            {
                datagram.EllapsedAtSent = localPeer.Stopwatch.Elapsed;
            }

            // simulate delay
            if (localPeer.SimulateLatencySeconds > 0.0f &&
                !hasAlreadyBeenDelayed &&
                datagram.Type != PacketType.Bye)    // if Bye we don't delay as if closing will not be sent
            {
                float delay = localPeer.SimulateLatencySeconds;

                // jitter
                if (localPeer.SimulateJitterSeconds > 0.0f)
                {
                    float jitter = localPeer.SimulateJitterSeconds * (float)SingleRandom.NextDouble();
                    if (SingleRandom.NextDouble() < 0.5)
                    {
                        jitter *= -1;
                    }

                    delay += jitter;
                }

                DelayedDatagram delayedDatagram = new DelayedDatagram(delay, datagram);

                localPeer.Log(LogLevel.Debug, String.Format("...DELAYED Sending datagram to: {0}, seq {1}, channel: {2}, total size: {3}; by {4}s...",
                                                            endPoint.ToString(),
                                                            datagram.Sequence.ToString(),
                                                            datagram.SendOptions.ToString(),
                                                            datagram.Count.ToString(),
                                                            delayedDatagram.EllapsedSecondsRemainingToDelay.ToString()));

                delayedDatagrams.Add(delayedDatagram);

                return(true);
            }

            localPeer.Log(LogLevel.Debug, String.Format("--> Sending datagram to: {0}, seq {1}, channel: {2}, total size: {3}...",
                                                        endPoint.ToString(),
                                                        datagram.Sequence.ToString(),
                                                        datagram.SendOptions.ToString(),
                                                        datagram.Count.ToString()));

            // Expedite send if less than 5% of recent reliable packets have to be re-sent
            bool expedite = qualityOfService.ResendRatio < 0.05f;

            //-----------------------------------------------------------------------------------------------------------------
            bool success = localPeer.Transceiver.Send(datagram.BackingBuffer, datagram.Offset, datagram.Count, endPoint, expedite);

            //-----------------------------------------------------------------------------------------------------------------

            if (success)
            {
                if (localPeer.IsCollectingStatistics)
                {
                    localPeer.Statistics.AddBytesSent(datagram.Count);
                }

                // return the datagram to pool for re-use if we are not waiting for an ACK
                if (!datagram.IsReliable)
                {
                    sendDatagramsPool.Return(datagram);
                }
            }
            else
            {
                // something fatal has gone wrong and this peer can no longer be sent to
                localPeer.RemovePeerOnNextUpdate(this);
            }

            return(success);
        }