Example #1
0
        public unsafe bool DelayPacket(ref NetworkPipelineContext ctx, InboundSendBuffer inboundBuffer,
                                       ref NetworkPipelineStage.Requests requests,
                                       long timestamp)
        {
            // Find empty slot in bookkeeping data space to track this packet
            int  packetPayloadOffset = 0;
            int  packetDataOffset    = 0;
            var  processBufferPtr    = (byte *)ctx.internalProcessBuffer;
            bool foundSlot           = GetEmptyDataSlot(processBufferPtr, ref packetPayloadOffset, ref packetDataOffset);

            if (!foundSlot)
            {
                //UnityEngine.Debug.LogWarning("No space left for delaying packet (" + m_PacketCount + " packets in queue)");
                return(false);
            }

            UnsafeUtility.MemCpy(ctx.internalProcessBuffer + packetPayloadOffset + inboundBuffer.headerPadding, inboundBuffer.buffer, inboundBuffer.bufferLength);

            var param = (SimulatorUtility.Context *)ctx.internalSharedProcessBuffer;
            // Add tracking for this packet so we can resurrect later
            DelayedPacket packet;

            packet.delayUntil          = timestamp + m_PacketDelayMs + param->Random.NextInt(m_PacketJitterMs * 2) - m_PacketJitterMs;
            packet.processBufferOffset = packetPayloadOffset;
            packet.packetSize          = (ushort)(inboundBuffer.headerPadding + inboundBuffer.bufferLength);
            packet.packetHeaderPadding = (ushort)inboundBuffer.headerPadding;
            byte *packetPtr = (byte *)&packet;

            UnsafeUtility.MemCpy(processBufferPtr + packetDataOffset, packetPtr, UnsafeUtility.SizeOf <DelayedPacket>());

            // Schedule an update call so packet can be resurrected later
            requests |= NetworkPipelineStage.Requests.Update;
            return(true);
        }
Example #2
0
            private unsafe void ProcessSendStage(int startStage, int internalBufferOffset, int internalSharedBufferOffset,
                                                 PipelineImpl p, ref NativeList <int> resumeQ, ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref bool needsUpdate)
            {
                var pipelineStage = m_StageCollection[m_StageList[p.FirstStageIndex + startStage]];

                ctx.staticInstanceBuffer        = (byte *)m_StaticInstanceBuffer.GetUnsafeReadOnlyPtr() + pipelineStage.StaticStateStart;
                ctx.staticInstanceBufferLength  = pipelineStage.StaticStateCapcity;
                ctx.internalProcessBuffer       = (byte *)sendBuffer.GetUnsafeReadOnlyPtr() + internalBufferOffset;
                ctx.internalProcessBufferLength = pipelineStage.SendCapacity;

                ctx.internalSharedProcessBuffer       = (byte *)sharedBuffer.GetUnsafeReadOnlyPtr() + internalSharedBufferOffset;
                ctx.internalSharedProcessBufferLength = pipelineStage.SharedStateCapacity;

                NetworkPipelineStage.Requests requests = NetworkPipelineStage.Requests.None;
                pipelineStage.Send.Ptr.Invoke(ref ctx, ref inboundBuffer, ref requests);
                if ((requests & NetworkPipelineStage.Requests.Resume) != 0)
                {
                    resumeQ.Add(startStage);
                }
                needsUpdate = (requests & NetworkPipelineStage.Requests.Update) != 0;
            }
Example #3
0
 private static void Receive(ref NetworkPipelineContext ctx, ref InboundRecvBuffer inboundBuffer, ref NetworkPipelineStage.Requests request)
 {
 }
Example #4
0
 private static void Receive(ref NetworkPipelineContext ctx, ref InboundRecvBuffer inboundBuffer, ref NetworkPipelineStage.Requests request)
 {
     for (int i = 0; i < inboundBuffer.bufferLength; ++i)
     {
         inboundBuffer.buffer[i] = (byte)(inboundBuffer.buffer[i] ^ 0xff);
     }
 }
Example #5
0
        private static int Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
        {
            var fragContext = (FragContext *)ctx.internalProcessBuffer;
            var dataBuffer  = ctx.internalProcessBuffer + sizeof(FragContext);
            var param       = (FragmentationUtility.Parameters *)ctx.staticInstanceBuffer;

            FragFlags flags          = FragFlags.First;
            int       headerCapacity = ctx.header.Capacity;

            var systemHeaderCapacity      = sizeof(UdpCHeader) + 1 + 2;                     // Extra byte is for pipeline id, two bytes for footer
            var maxBlockLength            = NetworkParameterConstants.MTU - systemHeaderCapacity - inboundBuffer.headerPadding;
            var maxBlockLengthFirstPacket = maxBlockLength - ctx.accumulatedHeaderCapacity; // The first packet has the headers for all pipeline stages before this one

            if (fragContext->endIndex > fragContext->startIndex)
            {
                var isResume = 0 == inboundBuffer.bufferLength;
                if (!isResume)
                {
                    throw new InvalidOperationException("Internal error: we encountered data in the fragmentation buffer, but this is not a resume call.");
                }

                // We have data left over from a previous call
                flags &= ~FragFlags.First;
                var blockLength = fragContext->endIndex - fragContext->startIndex;
                if (blockLength > maxBlockLength)
                {
                    blockLength = maxBlockLength;
                }
                var blockStart = dataBuffer + fragContext->startIndex;
                inboundBuffer.buffer                  = blockStart;
                inboundBuffer.bufferWithHeaders       = blockStart - inboundBuffer.headerPadding;
                inboundBuffer.bufferLength            = blockLength;
                inboundBuffer.bufferWithHeadersLength = blockLength + inboundBuffer.headerPadding;
                fragContext->startIndex              += blockLength;
            }
            else if (inboundBuffer.bufferLength > maxBlockLengthFirstPacket)
            {
                var payloadCapacity = param->PayloadCapacity;
                var excessLength    = inboundBuffer.bufferLength - maxBlockLengthFirstPacket;
                var excessStart     = inboundBuffer.buffer + maxBlockLengthFirstPacket;
                if (excessLength + inboundBuffer.headerPadding > payloadCapacity)
                {
                    throw new InvalidOperationException($"Fragmentation capacity exceeded. Capacity:{payloadCapacity} Payload:{excessLength + inboundBuffer.headerPadding}");
                }
                UnsafeUtility.MemCpy(dataBuffer + inboundBuffer.headerPadding, excessStart, excessLength);
                fragContext->startIndex = inboundBuffer.headerPadding; // Leaving room for header
                fragContext->endIndex   = excessLength + inboundBuffer.headerPadding;
                inboundBuffer.bufferWithHeadersLength -= excessLength;
                inboundBuffer.bufferLength            -= excessLength;
            }

            if (fragContext->endIndex > fragContext->startIndex)
            {
                requests |= NetworkPipelineStage.Requests.Resume;
            }
            else
            {
                flags |= FragFlags.Last;
            }

            var sequence = fragContext->sequence++;

            var combined = (sequence & (int)FragFlags.SeqMask) | (int)flags;    // lower 14 bits sequence, top 2 bits flags

            ctx.header.WriteShort((short)combined);

#if FRAGMENTATION_DEBUG
            // For debugging - this allows WireShark to identify fragmentation packets
            ctx.header.WriteByte((byte)'@');
            ctx.header.WriteByte((byte)'@');
            ctx.header.WriteByte((byte)'@');
            ctx.header.WriteByte((byte)'@');
#endif
            return((int)Error.StatusCode.Success);
        }
 private static void Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
 {
 }
        private static int Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
        {
            var sequenceId = (int *)ctx.internalProcessBuffer;

            ctx.header.WriteUShort((ushort)*sequenceId);
            *sequenceId = (ushort)(*sequenceId + 1);
            return((int)Error.StatusCode.Success);
        }
Example #8
0
 private static void Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests request)
 {
     ctx.header.WriteInt((int)2);
 }
Example #9
0
        private static void Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests request)
        {
            var sendData = (int *)ctx.internalProcessBuffer;

            for (int i = 1; i <= 3; ++i)
            {
                Assert.AreEqual(*sendData, i * 10);
                sendData++;
            }
            var sharedData = (int *)ctx.internalSharedProcessBuffer;

            for (int i = 7; i <= 8; ++i)
            {
                Assert.AreEqual(*sharedData, i * 10);
                sharedData++;
            }
        }
        private static void Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
        {
            var sequenceId = (int *)ctx.internalProcessBuffer;

            ctx.header.WriteUShort((ushort)*sequenceId);
            *sequenceId = (ushort)(*sequenceId + 1);
        }
Example #11
0
        private static void Receive(ref NetworkPipelineContext ctx, ref InboundRecvBuffer inboundBuffer, ref NetworkPipelineStage.Requests request)
        {
            byte idx = ctx.staticInstanceBuffer[1];

            if (ctx.staticInstanceBuffer[0] == idx)
            {
                // Drop the packet
                inboundBuffer = default;
            }
            *ctx.staticInstanceBuffer += 1;
        }
            internal unsafe int ProcessPipelineSend(NetworkDriver.Concurrent driver, int startStage, NetworkPipeline pipeline, NetworkConnection connection,
                                                    NetworkInterfaceSendHandle sendHandle, int headerSize, NativeList <UpdatePipeline> currentUpdates)
            {
                int retval = sendHandle.size;
                NetworkPipelineContext ctx = default(NetworkPipelineContext);

                ctx.timestamp = m_timestamp[0];
                var p            = m_Pipelines[pipeline.Id - 1];
                var connectionId = connection.m_NetworkId;

                var resumeQ      = new NativeList <int>(16, Allocator.Temp);
                int resumeQStart = 0;

#if ENABLE_UNITY_COLLECTIONS_CHECKS
                if (headerSize != p.headerCapacity + UnsafeUtility.SizeOf <UdpCHeader>() + 1 && sendHandle.data != IntPtr.Zero)
                {
                    throw new InvalidOperationException("Invalid header size.");
                }
#endif
                var inboundBuffer = default(InboundSendBuffer);
                if (sendHandle.data != IntPtr.Zero)
                {
                    inboundBuffer.bufferWithHeaders       = (byte *)sendHandle.data + UnsafeUtility.SizeOf <UdpCHeader>() + 1;
                    inboundBuffer.bufferWithHeadersLength = sendHandle.size - UnsafeUtility.SizeOf <UdpCHeader>() - 1;
                    inboundBuffer.buffer       = inboundBuffer.bufferWithHeaders + p.headerCapacity;
                    inboundBuffer.bufferLength = inboundBuffer.bufferWithHeadersLength - p.headerCapacity;
                }

                while (true)
                {
                    headerSize = p.headerCapacity;

                    int internalBufferOffset       = p.sendBufferOffset + sizePerConnection[SendSizeOffset] * connectionId;
                    int internalSharedBufferOffset = p.sharedBufferOffset + sizePerConnection[SharedSizeOffset] * connectionId;

                    // If this is not the first stage we need to fast forward the buffer offset to the correct place
                    if (startStage > 0)
                    {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                        if (inboundBuffer.bufferWithHeadersLength > 0)
                        {
                            throw new InvalidOperationException("Can't start from a stage with a buffer");
                        }
#endif
                        for (int i = 0; i < startStage; ++i)
                        {
                            internalBufferOffset       += (m_StageCollection[m_StageList[p.FirstStageIndex + i]].SendCapacity + AlignmentMinusOne) & (~AlignmentMinusOne);
                            internalSharedBufferOffset += (m_StageCollection[m_StageList[p.FirstStageIndex + i]].SharedStateCapacity + AlignmentMinusOne) & (~AlignmentMinusOne);
                            headerSize -= m_StageCollection[m_StageList[p.FirstStageIndex + i]].HeaderCapacity;
                        }
                    }

                    for (int i = startStage; i < p.NumStages; ++i)
                    {
                        int stageHeaderCapacity = m_StageCollection[m_StageList[p.FirstStageIndex + i]].HeaderCapacity;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                        if (stageHeaderCapacity > headerSize)
                        {
                            throw new InvalidOperationException("Not enough header space");
                        }
#endif
                        inboundBuffer.headerPadding = headerSize;
                        headerSize -= stageHeaderCapacity;
                        if (stageHeaderCapacity > 0 && inboundBuffer.bufferWithHeadersLength > 0)
                        {
                            var headerArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray <byte>(inboundBuffer.bufferWithHeaders + headerSize, stageHeaderCapacity, Allocator.Invalid);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                            NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref headerArray, AtomicSafetyHandle.GetTempMemoryHandle());
#endif
                            ctx.header = new DataStreamWriter(headerArray);
                        }
                        else
                        {
                            ctx.header = new DataStreamWriter(stageHeaderCapacity, Allocator.Temp);
                        }
                        var prevInbound = inboundBuffer;
                        NetworkPipelineStage.Requests requests = NetworkPipelineStage.Requests.None;
                        ProcessSendStage(i, internalBufferOffset, internalSharedBufferOffset, p, ref resumeQ, ref ctx, ref inboundBuffer, ref requests);

                        if ((requests & NetworkPipelineStage.Requests.Update) != 0)
                        {
                            AddSendUpdate(connection, i, pipeline, currentUpdates);
                        }
                        if (inboundBuffer.bufferWithHeadersLength == 0)
                        {
                            if ((requests & NetworkPipelineStage.Requests.Error) != 0 && sendHandle.data != IntPtr.Zero)
                            {
                                retval = -1;
                            }
                            break;
                        }

#if ENABLE_UNITY_COLLECTIONS_CHECKS
                        if (inboundBuffer.headerPadding != prevInbound.headerPadding)
                        {
                            throw new InvalidOperationException("Changing the header padding in a pipeline is not supported");
                        }
#endif
                        if (inboundBuffer.buffer != prevInbound.buffer)
                        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                            if (inboundBuffer.buffer != inboundBuffer.bufferWithHeaders + inboundBuffer.headerPadding ||
                                inboundBuffer.bufferLength + inboundBuffer.headerPadding > inboundBuffer.bufferWithHeadersLength)
                            {
                                throw new InvalidOperationException("When creating an internal buffer in piplines the buffer must be a subset of the buffer width headers");
                            }
#endif

                            // Copy header to new buffer so it is part of the payload
                            UnsafeUtility.MemCpy(inboundBuffer.bufferWithHeaders + headerSize, ctx.header.AsNativeArray().GetUnsafeReadOnlyPtr(), ctx.header.Length);
                        }
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                        else
                        {
                            if (inboundBuffer.bufferWithHeaders != prevInbound.bufferWithHeaders)
                            {
                                throw new InvalidOperationException("Changing the send buffer with headers without changing the buffer is not supported");
                            }
                        }
#endif
                        if (ctx.header.Length < stageHeaderCapacity)
                        {
                            int wastedSpace = stageHeaderCapacity - ctx.header.Length;
                            // Remove wasted space in the header
                            UnsafeUtility.MemMove(inboundBuffer.buffer - wastedSpace, inboundBuffer.buffer, inboundBuffer.bufferLength);
                        }

                        // Update the inbound buffer for next iteration
                        inboundBuffer.buffer       = inboundBuffer.bufferWithHeaders + headerSize;
                        inboundBuffer.bufferLength = ctx.header.Length + inboundBuffer.bufferLength;


                        internalBufferOffset       += (ctx.internalProcessBufferLength + AlignmentMinusOne) & (~AlignmentMinusOne);
                        internalSharedBufferOffset += (ctx.internalSharedProcessBufferLength + AlignmentMinusOne) & (~AlignmentMinusOne);
                    }

                    if (inboundBuffer.bufferLength != 0)
                    {
                        if (sendHandle.data != IntPtr.Zero && inboundBuffer.bufferWithHeaders == (byte *)sendHandle.data + UnsafeUtility.SizeOf <UdpCHeader>() + 1)
                        {
                            // Actually send the data - after collapsing it again
                            if (inboundBuffer.buffer != inboundBuffer.bufferWithHeaders)
                            {
                                UnsafeUtility.MemMove(inboundBuffer.bufferWithHeaders, inboundBuffer.buffer, inboundBuffer.bufferLength);
                                inboundBuffer.buffer = inboundBuffer.bufferWithHeaders;
                            }
                            ((byte *)sendHandle.data)[UnsafeUtility.SizeOf <UdpCHeader>()] = (byte)pipeline.Id;
                            int sendSize = UnsafeUtility.SizeOf <UdpCHeader>() + 1 + inboundBuffer.bufferLength;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                            if (sendSize > sendHandle.size)
                            {
                                throw new InvalidOperationException("Pipeline increased the data in the buffer, this is not allowed");
                            }
#endif
                            sendHandle.size = sendSize;
                            retval          = driver.CompleteSend(connection, sendHandle);
                            sendHandle      = default;
                        }
                        else
                        {
                            // Sending without pipeline, the correct pipeline will be added by the default flags when this is called
                            var writer = driver.BeginSend(connection);
                            writer.WriteByte((byte)pipeline.Id);
                            writer.WriteBytes(inboundBuffer.buffer, inboundBuffer.bufferLength);
                            if (writer.HasFailedWrites)
                            {
                                driver.AbortSend(writer);
                            }
                            else
                            {
                                driver.EndSend(writer);
                            }
                        }
                    }

                    if (resumeQStart >= resumeQ.Length)
                    {
                        break;
                    }

                    startStage = resumeQ[resumeQStart++];

                    inboundBuffer = default(InboundSendBuffer);
                }
                if (sendHandle.data != IntPtr.Zero)
                {
                    driver.AbortSend(sendHandle);
                }
                return(retval);
            }
Example #13
0
 private static int Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests request)
 {
     ctx.header.WriteInt((int)2);
     return((int)Error.StatusCode.Success);
 }
Example #14
0
        private static int Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests request)
        {
            var sendData = (int *)ctx.internalProcessBuffer;

            for (int i = 1; i <= 3; ++i)
            {
                Assert.AreEqual(*sendData, i);
                sendData++;
            }
            var sharedData = (int *)ctx.internalSharedProcessBuffer;

            for (int i = 7; i <= 8; ++i)
            {
                Assert.AreEqual(*sharedData, i);
                sharedData++;
            }
            return((int)Error.StatusCode.Success);
        }
Example #15
0
        private static unsafe void Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests request)
        {
            var len = inboundBuffer.bufferLength;

            for (int i = 0; i < len; ++i)
            {
                ctx.internalProcessBuffer[inboundBuffer.headerPadding + i] = (byte)(inboundBuffer.buffer[i] ^ 0xff);
            }
            var nextInbound = default(InboundSendBuffer);

            nextInbound.bufferWithHeaders       = ctx.internalProcessBuffer;
            nextInbound.bufferWithHeadersLength = len + inboundBuffer.headerPadding;
            nextInbound.SetBufferFrombufferWithHeaders();
            inboundBuffer = nextInbound;
        }
Example #16
0
        private static void Receive(ref NetworkPipelineContext ctx, ref InboundRecvBuffer inboundBuffer, ref NetworkPipelineStage.Requests request)
        {
            var receiveData = (int *)ctx.internalProcessBuffer;

            for (int i = 4; i <= 6; ++i)
            {
                Assert.AreEqual(*receiveData, i * 10);
                receiveData++;
            }
            var sharedData = (int *)ctx.internalSharedProcessBuffer;

            for (int i = 7; i <= 8; ++i)
            {
                Assert.AreEqual(*sharedData, i * 10);
                sharedData++;
            }
        }
        private static int Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
        {
            // Request an update to see if a queued packet needs to be resent later or if an ack packet should be sent
            requests = NetworkPipelineStage.Requests.Update;
            bool needsResume = false;

            var header   = new ReliableUtility.PacketHeader();
            var reliable = (ReliableUtility.Context *)ctx.internalProcessBuffer;

            needsResume = ReliableUtility.ReleaseOrResumePackets(ctx);
            if (needsResume)
            {
                requests |= NetworkPipelineStage.Requests.Resume;
            }

            if (inboundBuffer.bufferLength > 0)
            {
                reliable->LastSentTime = ctx.timestamp;

                if (ReliableUtility.Write(ctx, inboundBuffer, ref header) < 0)
                {
                    // We failed to store the packet for possible later resends, abort and report this as a send error
                    inboundBuffer = default;
                    requests     |= NetworkPipelineStage.Requests.Error;
                    return((int)Error.StatusCode.NetworkSendQueueFull);
                }
                ctx.header.WriteBytes((byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());
                if (reliable->Resume != ReliableUtility.NullEntry)
                {
                    requests |= NetworkPipelineStage.Requests.Resume;
                }

                reliable->PreviousTimestamp = ctx.timestamp;
                return((int)Error.StatusCode.Success);
            }

            if (reliable->Resume != ReliableUtility.NullEntry)
            {
                reliable->LastSentTime = ctx.timestamp;
                inboundBuffer          = ReliableUtility.ResumeSend(ctx, out header, ref needsResume);
                if (needsResume)
                {
                    requests |= NetworkPipelineStage.Requests.Resume;
                }
                ctx.header.Clear();
                ctx.header.WriteBytes((byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());
                reliable->PreviousTimestamp = ctx.timestamp;
                return((int)Error.StatusCode.Success);
            }

            if (ReliableUtility.ShouldSendAck(ctx))
            {
                reliable->LastSentTime = ctx.timestamp;

                ReliableUtility.WriteAckPacket(ctx, ref header);
                ctx.header.WriteBytes((byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());
                reliable->PreviousTimestamp = ctx.timestamp;

                // TODO: Sending dummy byte over since the pipeline won't send an empty payload (ignored on receive)
                inboundBuffer.bufferWithHeadersLength = inboundBuffer.headerPadding + 1;
                inboundBuffer.bufferWithHeaders       = (byte *)UnsafeUtility.Malloc(inboundBuffer.bufferWithHeadersLength, 8, Allocator.Temp);
                inboundBuffer.SetBufferFrombufferWithHeaders();
                return((int)Error.StatusCode.Success);
            }
            reliable->PreviousTimestamp = ctx.timestamp;
            return((int)Error.StatusCode.Success);
        }
Example #18
0
        private static void Receive(ref NetworkPipelineContext ctx, ref InboundRecvBuffer inboundBuffer, ref NetworkPipelineStage.Requests request)
        {
            var headerData = (int *)inboundBuffer.buffer;

            if (*headerData != 2)
            {
                throw new InvalidOperationException("Header data invalid, got " + *headerData);
            }

            inboundBuffer = inboundBuffer.Slice(4);
        }
        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;
        }
        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;
        }
Example #21
0
 private static int Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
 {
     return((int)Error.StatusCode.Success);
 }
        private static void Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
        {
            var context = (SimulatorUtility.Context *)ctx.internalSharedProcessBuffer;
            var param   = *(SimulatorUtility.Parameters *)ctx.staticInstanceBuffer;

            var simulator = new SimulatorUtility(param.MaxPacketCount, param.MaxPacketSize, param.PacketDelayMs, param.PacketJitterMs);

            if (inboundBuffer.headerPadding + inboundBuffer.bufferLength > param.MaxPacketSize)
            {
                //UnityEngine.Debug.LogWarning("Incoming packet too large for internal storage buffer. Passing through. [buffer=" + (inboundBuffer.headerPadding+inboundBuffer.buffer.Length) + " packet=" + param.MaxPacketSize + "]");
                return;
            }

            var timestamp = ctx.timestamp;

            if (inboundBuffer.bufferLength > 0)
            {
                context->PacketCount++;

                if (simulator.ShouldDropPacket(context, param, timestamp))
                {
                    context->PacketDropCount++;
                    inboundBuffer = default;
                    return;
                }

                if (context->FuzzFactor > 0)
                {
                    simulator.FuzzPacket(context, ref inboundBuffer);
                }

                if (context->PacketDelayMs == 0 ||
                    !simulator.DelayPacket(ref ctx, inboundBuffer, ref requests, timestamp))
                {
                    return;
                }
            }

            InboundSendBuffer returnPacket = default;

            if (simulator.GetDelayedPacket(ref ctx, ref returnPacket, ref requests, timestamp))
            {
                inboundBuffer = returnPacket;
                return;
            }
            inboundBuffer = default;
        }
Example #23
0
        public unsafe bool GetDelayedPacket(ref NetworkPipelineContext ctx, ref InboundSendBuffer delayedPacket,
                                            ref NetworkPipelineStage.Requests requests, long currentTimestamp)
        {
            requests = NetworkPipelineStage.Requests.None;

            var   dataSize          = UnsafeUtility.SizeOf <DelayedPacket>();
            byte *processBufferPtr  = (byte *)ctx.internalProcessBuffer;
            var   simCtx            = (Context *)ctx.internalSharedProcessBuffer;
            int   oldestPacketIndex = -1;
            long  oldestTime        = long.MaxValue;
            int   readyPackets      = 0;
            int   packetsInQueue    = 0;

            for (int i = 0; i < m_PacketCount; i++)
            {
                DelayedPacket *packet = (DelayedPacket *)(processBufferPtr + dataSize * i);
                if ((int)packet->delayUntil == 0)
                {
                    continue;
                }
                packetsInQueue++;

                if (packet->delayUntil > currentTimestamp)
                {
                    continue;
                }
                readyPackets++;

                if (oldestTime <= packet->delayUntil)
                {
                    continue;
                }
                oldestPacketIndex = i;
                oldestTime        = packet->delayUntil;
            }

            simCtx->ReadyPackets   = readyPackets;
            simCtx->WaitingPackets = packetsInQueue;
            simCtx->NextPacketTime = oldestTime;
            simCtx->StatsTime      = currentTimestamp;

            // If more than one item has expired timer we need to resume this pipeline stage
            if (readyPackets > 1)
            {
                requests |= NetworkPipelineStage.Requests.Resume;
            }
            // If more than one item is present (but doesn't have expired timer) we need to re-run the pipeline
            // in a later update call
            else if (packetsInQueue > 0)
            {
                requests |= NetworkPipelineStage.Requests.Update;
            }

            if (oldestPacketIndex >= 0)
            {
                DelayedPacket *packet = (DelayedPacket *)(processBufferPtr + dataSize * oldestPacketIndex);
                packet->delayUntil = 0;

                delayedPacket.bufferWithHeaders       = ctx.internalProcessBuffer + packet->processBufferOffset;
                delayedPacket.bufferWithHeadersLength = packet->packetSize;
                delayedPacket.headerPadding           = packet->packetHeaderPadding;
                delayedPacket.SetBufferFrombufferWithHeaders();
                return(true);
            }

            return(false);
        }
        private static void Receive(ref NetworkPipelineContext ctx, ref InboundRecvBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
        {
            var context   = (SimulatorUtility.Context *)ctx.internalSharedProcessBuffer;
            var param     = *(SimulatorUtility.Parameters *)ctx.staticInstanceBuffer;
            var simulator = new SimulatorUtility(param.MaxPacketCount, param.MaxPacketSize, param.PacketDelayMs, param.PacketJitterMs);

            if (inboundBuffer.bufferLength > param.MaxPacketSize)
            {
                //UnityEngine.Debug.LogWarning("Incoming packet too large for internal storage buffer. Passing through. [buffer=" + inboundBuffer.Length + " packet=" + param->MaxPacketSize + "]");
                // TODO: Add error code for this
                return;
            }

            var timestamp = ctx.timestamp;

            // Inbound buffer is empty if this is a resumed receive
            if (inboundBuffer.bufferLength > 0)
            {
                context->PacketCount++;

                if (simulator.ShouldDropPacket(context, param, timestamp))
                {
                    context->PacketDropCount++;
                    inboundBuffer = default;
                    return;
                }

                var bufferVec = default(InboundSendBuffer);
                bufferVec.bufferWithHeaders       = inboundBuffer.buffer;
                bufferVec.bufferWithHeadersLength = inboundBuffer.bufferLength;
                bufferVec.buffer        = inboundBuffer.buffer;
                bufferVec.bufferLength  = inboundBuffer.bufferLength;
                bufferVec.headerPadding = 0;
                if (context->PacketDelayMs == 0 ||
                    !simulator.DelayPacket(ref ctx, bufferVec, ref requests, timestamp))
                {
                    return;
                }
            }

            InboundSendBuffer returnPacket = default;

            if (simulator.GetDelayedPacket(ref ctx, ref returnPacket, ref requests, timestamp))
            {
                inboundBuffer.buffer       = returnPacket.bufferWithHeaders;
                inboundBuffer.bufferLength = returnPacket.bufferWithHeadersLength;
                return;
            }

            inboundBuffer = default;
        }
Example #25
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;
        }