Exemplo n.º 1
0
        public unsafe int AppendPacket(NetworkEndPoint address, UdpCHeader header, int dataLen)
        {
            int count = 0;

            switch ((UdpCProtocol)header.Type)
            {
            case UdpCProtocol.ConnectionRequest:
            {
                if (!Listening)
                {
                    return(0);
                }

                Connection c;
                if ((c = GetNewConnection(address, header.SessionToken)) == Connection.Null || c.State == NetworkConnection.State.Disconnected)
                {
                    int id;
                    var sessionId = m_SessionIdCounter[0];
                    m_SessionIdCounter[0] = (ushort)(m_SessionIdCounter[0] + 1);
                    if (!m_FreeList.TryDequeue(out id))
                    {
                        id = m_ConnectionList.Length;
                        m_ConnectionList.Add(new Connection {
                                Id = id, Version = 1
                            });
                    }

                    int ver = m_ConnectionList[id].Version;
                    c = new Connection
                    {
                        Id           = id,
                        Version      = ver,
                        ReceiveToken = sessionId,
                        SendToken    = header.SessionToken,
                        State        = NetworkConnection.State.Connected,
                        Address      = address,
                        Attempts     = 1,
                        LastAttempt  = m_updateTime
                    };
                    SetConnection(c);
                    m_NetworkAcceptQueue.Enqueue(id);
                    count++;
                }
                else
                {
                    c.Attempts++;
                    c.LastAttempt = m_updateTime;
                    SetConnection(c);
                }

                SendPacket(UdpCProtocol.ConnectionAccept,
                           new NetworkConnection {
                        m_NetworkId = c.Id, m_NetworkVersion = c.Version
                    });
            }
            break;

            case UdpCProtocol.ConnectionReject:
            {
                // m_EventQ.Enqueue(Id, (int)NetworkEvent.Connect);
            }
            break;

            case UdpCProtocol.ConnectionAccept:
            {
                if (header.Flags != 1)
                {
                    UnityEngine.Debug.LogError("Accept message received without flag set");
                    return(0);
                }

                Connection c = GetConnection(address, header.SessionToken);
                if (c != Connection.Null)
                {
                    c.DidReceiveData = 1;

                    if (c.State == NetworkConnection.State.Connected)
                    {
                        //DebugLog("Dropping connect request for an already connected endpoint [" + address + "]");
                        return(0);
                    }

                    if (c.State == NetworkConnection.State.Connecting)
                    {
                        var sliceOffset = m_DataStream.Length;
                        m_DataStream.WriteBytesWithUnsafePointer(2);
                        var dataStreamReader = new DataStreamReader(m_DataStream, sliceOffset, 2);
                        var context          = default(DataStreamReader.Context);
                        c.SendToken = dataStreamReader.ReadUShort(ref context);
                        m_DataStream.WriteBytesWithUnsafePointer(-2);

                        c.State = NetworkConnection.State.Connected;
                        UpdateConnection(c);
                        AddConnection(c.Id);
                        count++;
                    }
                }
            }
            break;

            case UdpCProtocol.Disconnect:
            {
                Connection c = GetConnection(address, header.SessionToken);
                if (c != Connection.Null)
                {
                    if (RemoveConnection(c))
                    {
                        AddDisconnection(c.Id);
                    }
                    count++;
                }
            }
            break;

            case UdpCProtocol.Data:
            {
                Connection c = GetConnection(address, header.SessionToken);
                if (c == Connection.Null)
                {
                    return(0);
                }

                c.DidReceiveData = 1;
                c.LastAttempt    = m_updateTime;
                UpdateConnection(c);

                var length = dataLen - UdpCHeader.Length;

                if (c.State == NetworkConnection.State.Connecting)
                {
                    if (header.Flags != 1)
                    {
                        UnityEngine.Debug.LogError("Received data without connection (no send token)");
                        return(0);
                    }

                    var tokenOffset = m_DataStream.Length + length - 2;
                    m_DataStream.WriteBytesWithUnsafePointer(length);
                    var dataStreamReader = new DataStreamReader(m_DataStream, tokenOffset, 2);
                    var context          = default(DataStreamReader.Context);
                    c.SendToken = dataStreamReader.ReadUShort(ref context);
                    m_DataStream.WriteBytesWithUnsafePointer(-length);

                    c.State = NetworkConnection.State.Connected;
                    UpdateConnection(c);
                    Assert.IsTrue(!Listening);
                    AddConnection(c.Id);
                    count++;
                }

                if (header.Flags == 1)
                {
                    length -= 2;
                }

                var sliceOffset = m_DataStream.Length;
                m_DataStream.WriteBytesWithUnsafePointer(length);

                m_EventQueue.PushEvent(new NetworkEvent
                    {
                        connectionId = c.Id,
                        type         = NetworkEvent.Type.Data,
                        offset       = sliceOffset,
                        size         = length
                    });
                count++;
            } break;
            }

            return(count);
        }
 /// <summary>
 /// Receive an event for this specific connection. Should be called until it returns <see cref="NetworkEvent.Type.Empty"/>, even if the socket is disconnected.
 /// </summary>
 /// <param name="driver">The driver that owns the virtual connection.</param>
 /// <param name="strm">A DataStreamReader, that will only be populated if a <see cref="NetworkEvent.Type.Data"/>
 /// event was received.
 /// </param>
 public NetworkEvent.Type PopEvent <T>(T driver, out DataStreamReader stream) where T : struct, INetworkDriver
 {
     return(driver.PopEventForConnection(this, out stream));
 }
Exemplo n.º 3
0
        public NetworkEvent.Type PopEventForConnection(NetworkConnection connectionId, out DataStreamReader slice)
        {
            int offset, size;

            slice = default(DataStreamReader);
            if (connectionId.m_NetworkId < 0 || connectionId.m_NetworkId >= m_ConnectionList.Length ||
                m_ConnectionList[connectionId.m_NetworkId].Version != connectionId.m_NetworkVersion)
            {
                return((int)NetworkEvent.Type.Empty);
            }
            var type = m_EventQueue.PopEventForConnection(connectionId.m_NetworkId, out offset, out size);

            if (size > 0)
            {
                slice = new DataStreamReader(m_DataStream, offset, size);
            }
            return(type);
        }
Exemplo n.º 4
0
 public static Vector3 ReadPackedVector3(this DataStreamReader reader, NetworkCompressionModel compressionModel) =>
 reader.ReadPackedFloat3(compressionModel);
Exemplo n.º 5
0
 /// <summary>
 /// Receive an event for this specific connection. Should be called until it returns <see cref="NetworkEvent.Type.Empty"/>, even if the socket is disconnected.
 /// </summary>
 /// <param name="driver">The driver that owns the virtual connection.</param>
 /// <param name="strm">A DataStreamReader, that will only be populated if a <see cref="NetworkEvent.Type.Data"/>
 /// event was received.
 /// </param>
 public NetworkEvent.Type PopEvent(NetworkDriver driver, out DataStreamReader stream)
 {
     return(driver.PopEventForConnection(this, out stream));
 }
Exemplo n.º 6
0
        private static void Receive(ref NetworkPipelineContext ctx, ref InboundRecvBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
        {
            var fragContext = (FragContext *)ctx.internalProcessBuffer;
            var dataBuffer  = ctx.internalProcessBuffer + sizeof(FragContext);
            var param       = (FragmentationUtility.Parameters *)ctx.staticInstanceBuffer;

            var inboundArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray <byte>(inboundBuffer.buffer, inboundBuffer.bufferLength, Allocator.Invalid);

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            var safetyHandle = AtomicSafetyHandle.GetTempMemoryHandle();
            NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref inboundArray, safetyHandle);
#endif
            var reader = new DataStreamReader(inboundArray);

            var combined      = reader.ReadShort();
            var foundSequence = combined & (int)FragFlags.SeqMask;
            var flags         = (FragFlags)combined & ~FragFlags.SeqMask;
            inboundBuffer = inboundBuffer.Slice(FragHeaderCapacity);

            var expectedSequence = fragContext->sequence;
            var isFirst          = 0 != (flags & FragFlags.First);
            var isLast           = 0 != (flags & FragFlags.Last);

            if (isFirst)
            {
                expectedSequence         = foundSequence;
                fragContext->packetError = false;
                fragContext->endIndex    = 0;
            }

            if (foundSequence != expectedSequence)
            {
                // We've missed a packet.
                fragContext->packetError = true;
                fragContext->endIndex    = 0;     // Discard data we have already collected
            }

            if (!fragContext->packetError)
            {
                if (!isLast || fragContext->endIndex > 0)
                {
                    if (fragContext->endIndex + inboundBuffer.bufferLength > param->PayloadCapacity)
                    {
                        throw new InvalidOperationException($"Fragmentation capacity exceeded");
                    }
                    // Append the data to the end
                    UnsafeUtility.MemCpy(dataBuffer + fragContext->endIndex, inboundBuffer.buffer, inboundBuffer.bufferLength);
                    fragContext->endIndex += inboundBuffer.bufferLength;
                }

                if (isLast && fragContext->endIndex > 0)
                {
                    // Data is complete
                    inboundBuffer = new InboundRecvBuffer
                    {
                        buffer       = dataBuffer,
                        bufferLength = fragContext->endIndex
                    };
                }
            }

            if (!isLast || fragContext->packetError)
            {
                // No output if we expect more data, or if data is incomplete due to packet loss
                inboundBuffer = default;
            }

            fragContext->sequence = (foundSequence + 1) & (int)FragFlags.SeqMask;
        }
Exemplo n.º 7
0
        private static void Receive(ref NetworkPipelineContext ctx, ref InboundRecvBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
        {
            // Request a send update to see if a queued packet needs to be resent later or if an ack packet should be sent
            requests = NetworkPipelineStage.Requests.SendUpdate;
            bool needsResume = false;

            var header = default(ReliableUtility.PacketHeader);
            var slice  = default(InboundRecvBuffer);

            ReliableUtility.Context *      reliable = (ReliableUtility.Context *)ctx.internalProcessBuffer;
            ReliableUtility.SharedContext *shared   = (ReliableUtility.SharedContext *)ctx.internalSharedProcessBuffer;
            shared->errorCode = 0;
            if (reliable->Resume == ReliableUtility.NullEntry)
            {
                if (inboundBuffer.bufferLength <= 0)
                {
                    inboundBuffer = slice;
                    return;
                }
                var inboundArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray <byte>(inboundBuffer.buffer, inboundBuffer.bufferLength, Allocator.Invalid);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                var safetyHandle = AtomicSafetyHandle.GetTempMemoryHandle();
                NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref inboundArray, safetyHandle);
#endif
                var reader = new DataStreamReader(inboundArray);
                reader.ReadBytes((byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());

                if (header.Type == (ushort)ReliableUtility.PacketType.Ack)
                {
                    ReliableUtility.ReadAckPacket(ctx, header);
                    inboundBuffer = default;
                    return;
                }

                var result = ReliableUtility.Read(ctx, header);

                if (result >= 0)
                {
                    var nextExpectedSequenceId = (ushort)(reliable->Delivered + 1);
                    if (result == nextExpectedSequenceId)
                    {
                        reliable->Delivered = result;
                        slice = inboundBuffer.Slice(UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());

                        if (needsResume = SequenceHelpers.GreaterThan16((ushort)shared->ReceivedPackets.Sequence,
                                                                        (ushort)result))
                        {
                            reliable->Resume = (ushort)(result + 1);
                        }
                    }
                    else
                    {
                        ReliableUtility.SetPacket(ctx.internalProcessBuffer, result, inboundBuffer.Slice(UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>()));
                        slice = ReliableUtility.ResumeReceive(ctx, reliable->Delivered + 1, ref needsResume);
                    }
                }
            }
            else
            {
                slice = ReliableUtility.ResumeReceive(ctx, reliable->Resume, ref needsResume);
            }
            if (needsResume)
            {
                requests |= NetworkPipelineStage.Requests.Resume;
            }
            inboundBuffer = slice;
        }