public NativeSlice <byte> Receive(NetworkPipelineContext ctx, NativeSlice <byte> inboundBuffer, ref bool needsResume, ref bool needsUpdate, ref bool needsSendUpdate)
        {
            needsResume = false;
            var reader  = new DataStreamReader(inboundBuffer);
            var context = default(DataStreamReader.Context);

            unsafe
            {
                var    oldSequenceId = (int *)ctx.internalProcessBuffer.GetUnsafePtr();
                ushort sequenceId    = reader.ReadUShort(ref context);

                if (SequenceHelpers.GreaterThan16(sequenceId, (ushort)*oldSequenceId))
                {
                    *oldSequenceId = sequenceId;
                    // Skip over the part of the buffer which contains the header
                    return(inboundBuffer.Slice(sizeof(ushort)));
                }
            }
            return(default(NativeSlice <byte>));
        }
        private static void Receive(ref NetworkPipelineContext ctx, ref InboundRecvBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
        {
            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    oldSequenceId = (int *)ctx.internalProcessBuffer;
            ushort sequenceId    = reader.ReadUShort();

            if (SequenceHelpers.GreaterThan16(sequenceId, (ushort)*oldSequenceId))
            {
                *oldSequenceId = sequenceId;
                // Skip over the part of the buffer which contains the header
                inboundBuffer = inboundBuffer.Slice(sizeof(ushort));
                return;
            }
            inboundBuffer = default;
        }
        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);
        }