Example #1
0
        public InboundBufferVec Send(NetworkPipelineContext ctx, InboundBufferVec inboundBuffer, ref bool needsResume, ref bool needsUpdate)
        {
            var simulator = new SimulatorUtility(m_SimulatorParams.MaxPacketCount, m_SimulatorParams.MaxPacketSize, m_SimulatorParams.PacketDelayMs);

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

            var timestamp = ctx.timestamp;

            // Packet always delayed atm
            bool delayPacket = true;

            // Inbound buffer is empty if this is a resumed receive
            if (delayPacket && inboundBuffer.buffer1.Length > 0)
            {
                if (!simulator.DelayPacket(ref ctx, inboundBuffer, ref needsUpdate, timestamp))
                {
                    return(inboundBuffer);
                }
            }

            NativeSlice <byte> returnPacket = default(NativeSlice <byte>);

            if (simulator.GetDelayedPacket(ref ctx, ref returnPacket, ref needsResume, ref needsUpdate, timestamp))
            {
                inboundBuffer.buffer1 = returnPacket;
                inboundBuffer.buffer2 = default(NativeSlice <byte>);
                return(inboundBuffer);
            }

            return(default(InboundBufferVec));
        }
Example #2
0
        public InboundBufferVec Send(NetworkPipelineContext ctx, InboundBufferVec inboundBuffer, ref bool needsResume, ref bool needsUpdate)
        {
            // Request an update to see if a queued packet needs to be resent later or if an ack packet should be sent
            needsUpdate = true;

            var header = new ReliableUtility.PacketHeader();

            unsafe
            {
                var reliable = (ReliableUtility.Context *)ctx.internalProcessBuffer.GetUnsafePtr();

                needsResume = ReliableUtility.ReleaseOrResumePackets(ctx);

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

                    ReliableUtility.Write(ctx, inboundBuffer, ref header);
                    ctx.header.WriteBytes((byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());
                    if (reliable->Resume != ReliableUtility.NullEntry)
                    {
                        needsResume = true;
                    }

                    reliable->PreviousTimestamp = ctx.timestamp;
                    return(inboundBuffer);
                }

                if (reliable->Resume != ReliableUtility.NullEntry)
                {
                    reliable->LastSentTime = ctx.timestamp;
                    var slice = ReliableUtility.ResumeSend(ctx, out header, ref needsResume);
                    ctx.header.Clear();
                    ctx.header.WriteBytes((byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());
                    inboundBuffer.buffer1       = slice;
                    inboundBuffer.buffer2       = default(NativeSlice <byte>);
                    reliable->PreviousTimestamp = ctx.timestamp;
                    return(inboundBuffer);
                }

                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.buffer1 = new NativeSlice <byte>(ctx.internalProcessBuffer, 0, 1);
                    return(inboundBuffer);
                }
                reliable->PreviousTimestamp = ctx.timestamp;
                return(inboundBuffer);
            }
        }
Example #3
0
 public InboundBufferVec Send(NetworkPipelineContext ctx, InboundBufferVec inboundBuffer, ref bool needsResume, ref bool needsUpdate)
 {
     needsResume = false;
     unsafe
     {
         var sequenceId = (int *)ctx.internalProcessBuffer.GetUnsafePtr();
         ctx.header.Write((ushort)*sequenceId);
         *sequenceId = (ushort)(*sequenceId + 1);
     }
     return(inboundBuffer);
 }
Example #4
0
        public unsafe NativeSlice <byte> Receive(NetworkPipelineContext ctx, NativeSlice <byte> inboundBuffer, ref bool needsResume, ref bool needsUpdate, ref bool needsSendUpdate)
        {
            var param     = (SimulatorUtility.Context *)ctx.internalSharedProcessBuffer.GetUnsafePtr();
            var simulator = new SimulatorUtility(m_SimulatorParams.MaxPacketCount, m_SimulatorParams.MaxPacketSize, m_SimulatorParams.PacketDelayMs);

            if (inboundBuffer.Length > m_SimulatorParams.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(inboundBuffer);
            }

            var timestamp = ctx.timestamp;

            if (inboundBuffer.Length > 0)
            {
                param->PacketCount++;
            }

            bool delayPacket = param->PacketDelayMs > 0;

            // Inbound buffer is empty if this is a resumed receive
            if (delayPacket && inboundBuffer.Length > 0)
            {
                var bufferVec = default(InboundBufferVec);
                bufferVec.buffer1 = inboundBuffer;
                if (!simulator.DelayPacket(ref ctx, bufferVec, ref needsUpdate, timestamp))
                {
                    return(inboundBuffer);
                }
            }

            if (simulator.ShouldDropPacket(param, m_SimulatorParams, timestamp))
            {
                param->PacketDropCount++;
                return(new NativeSlice <byte>());
            }

            NativeSlice <byte> returnPacket = default(NativeSlice <byte>);

            if (simulator.GetDelayedPacket(ref ctx, ref returnPacket, ref needsResume, ref needsUpdate, timestamp))
            {
                return(returnPacket);
            }

            // Pass packet through, nothing was done with it. Or return empty buffer if no inbound buffer is here (then nothing is being resurrected)
            if (!delayPacket && inboundBuffer.Length > 0)
            {
                return(inboundBuffer);
            }
            return(new NativeSlice <byte>());
        }
Example #5
0
        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>));
        }
Example #6
0
        public NativeSlice <byte> InvokeReceive(int pipelineStageId, NetworkPipelineContext ctx, NativeSlice <byte> inboundBuffer, ref bool needsResume, ref bool needsUpdate, ref bool needsSendUpdate)
        {
            switch (pipelineStageId)
            {
            case 0:
                return(m_SimulatorPipelineStage.Receive(ctx, inboundBuffer, ref needsResume, ref needsUpdate, ref needsSendUpdate));

            case 1:
                return(m_SimulatorPipelineStageInSend.Receive(ctx, inboundBuffer, ref needsResume, ref needsUpdate, ref needsSendUpdate));

            case 2:
                return(m_NullPipelineStage.Receive(ctx, inboundBuffer, ref needsResume, ref needsUpdate, ref needsSendUpdate));

            case 3:
                return(m_UnreliableSequencedPipelineStage.Receive(ctx, inboundBuffer, ref needsResume, ref needsUpdate, ref needsSendUpdate));

            case 4:
                return(m_ReliableSequencedPipelineStage.Receive(ctx, inboundBuffer, ref needsResume, ref needsUpdate, ref needsSendUpdate));
            }
            return(inboundBuffer);
        }
Example #7
0
        public InboundBufferVec InvokeSend(int pipelineStageId, NetworkPipelineContext ctx, InboundBufferVec inboundBuffer, ref bool needsResume, ref bool needsUpdate)
        {
            switch (pipelineStageId)
            {
            case 0:
                return(m_SimulatorPipelineStage.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate));

            case 1:
                return(m_SimulatorPipelineStageInSend.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate));

            case 2:
                return(m_NullPipelineStage.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate));

            case 3:
                return(m_UnreliableSequencedPipelineStage.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate));

            case 4:
                return(m_ReliableSequencedPipelineStage.Send(ctx, inboundBuffer, ref needsResume, ref needsUpdate));
            }
            return(inboundBuffer);
        }
Example #8
0
 public InboundBufferVec Send(NetworkPipelineContext ctx, InboundBufferVec inboundBuffer, ref bool needsResume, ref bool needsUpdate)
 {
     return(inboundBuffer);
 }
Example #9
0
 public NativeSlice <byte> Receive(NetworkPipelineContext ctx, NativeSlice <byte> inboundBuffer, ref bool needsResume, ref bool needsUpdate, ref bool needsSendUpdate)
 {
     return(new NativeSlice <byte>(inboundBuffer, 0, inboundBuffer.Length));
 }
Example #10
0
        public NativeSlice <byte> Receive(NetworkPipelineContext ctx, NativeSlice <byte> inboundBuffer, ref bool needsResume, ref bool needsUpdate, ref bool needsSendUpdate)
        {
            needsResume = false;
            // Request a send update to see if a queued packet needs to be resent later or if an ack packet should be sent
            needsSendUpdate = true;

            var context = default(DataStreamReader.Context);
            var header  = default(ReliableUtility.PacketHeader);
            var slice   = default(NativeSlice <byte>);

            unsafe
            {
                ReliableUtility.Context *      reliable = (ReliableUtility.Context *)ctx.internalProcessBuffer.GetUnsafePtr();
                ReliableUtility.SharedContext *shared   = (ReliableUtility.SharedContext *)ctx.internalSharedProcessBuffer.GetUnsafePtr();
                shared->errorCode = 0;
                if (reliable->Resume == ReliableUtility.NullEntry)
                {
                    if (inboundBuffer.Length <= 0)
                    {
                        return(slice);
                    }
                    var reader = new DataStreamReader(inboundBuffer);
                    reader.ReadBytes(ref context, (byte *)&header, UnsafeUtility.SizeOf <ReliableUtility.PacketHeader>());

                    if (header.Type == (ushort)ReliableUtility.PacketType.Ack)
                    {
                        ReliableUtility.ReadAckPacket(ctx, header);
                        inboundBuffer = new NativeSlice <byte>();
                        return(inboundBuffer);
                    }

                    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);
                }
            }
            return(slice);
        }
Example #11
0
        private void ProcessReceiveStage(int stage, NetworkPipeline pipeline, int internalBufferOffset, int internalSharedBufferOffset, ref NetworkPipelineContext ctx, ref NativeSlice <byte> inboundBuffer, ref NativeList <int> resumeQ, ref bool needsUpdate, ref bool needsSendUpdate)
        {
            bool needsResume = false;
            var  p           = m_Pipelines[pipeline.Id - 1];

            ctx.internalProcessBuffer =
                new NativeSlice <byte>(m_ReceiveBuffer, internalBufferOffset, m_StageCollection.GetReceiveCapacity(m_StageList[p.FirstStageIndex + stage]));
            ctx.internalSharedProcessBuffer =
                new NativeSlice <byte>(m_SharedBuffer, internalSharedBufferOffset, m_StageCollection.GetSharedStateCapacity(m_StageList[p.FirstStageIndex + stage]));
            var stageId = m_StageList[p.FirstStageIndex + stage];

            inboundBuffer = m_StageCollection.InvokeReceive(stageId, ctx, inboundBuffer, ref needsResume, ref needsUpdate, ref needsSendUpdate);

            if (needsResume)
            {
                resumeQ.Add(stage);
            }
        }
Example #12
0
        private void ProcessReceiveStagesFrom <T>(T driver, int startStage, NetworkPipeline pipeline, NetworkConnection connection, NativeSlice <byte> buffer) where T : struct, INetworkPipelineReceiver
        {
            var p            = m_Pipelines[pipeline.Id - 1];
            var connectionId = connection.m_NetworkId;
            var resumeQ      = new NativeList <int>(16, Allocator.Temp);
            int resumeQStart = 0;

            NetworkPipelineContext ctx = default(NetworkPipelineContext);

            ctx.timestamp = Timestamp;
            var inboundBuffer = new NativeSlice <byte>(buffer, 0, buffer.Length);

            ctx.header = default(DataStreamWriter);
            NativeList <UpdatePipeline> sendUpdates = new NativeList <UpdatePipeline>(128, Allocator.Temp);

            while (true)
            {
                bool needsUpdate                = false;
                bool needsSendUpdate            = false;
                int  internalBufferOffset       = p.receiveBufferOffset + sizePerConnection[RecveiveSizeOffset] * connectionId;
                int  internalSharedBufferOffset = p.sharedBufferOffset + sizePerConnection[SharedSizeOffset] * connectionId;

                // Adjust offset accounting for stages in front of the starting stage, since we're parsing the stages in reverse order
                for (int st = 0; st < startStage; ++st)
                {
                    internalBufferOffset       += m_StageCollection.GetReceiveCapacity(m_StageList[p.FirstStageIndex + st]);
                    internalSharedBufferOffset += m_StageCollection.GetSharedStateCapacity(m_StageList[p.FirstStageIndex + st]);
                }

                for (int i = startStage; i >= 0; --i)
                {
                    ProcessReceiveStage(i, pipeline, internalBufferOffset, internalSharedBufferOffset, ref ctx, ref inboundBuffer, ref resumeQ, ref needsUpdate, ref needsSendUpdate);
                    if (needsUpdate)
                    {
                        var newUpdate = new UpdatePipeline
                        {
                            connection = connection, stage = i, pipeline = pipeline
                        };
                        bool uniqueItem = true;
                        for (int j = 0; j < m_ReceiveStageNeedsUpdate.Length; ++j)
                        {
                            if (m_ReceiveStageNeedsUpdate[j].stage == newUpdate.stage &&
                                m_ReceiveStageNeedsUpdate[j].pipeline.Id == newUpdate.pipeline.Id &&
                                m_ReceiveStageNeedsUpdate[j].connection == newUpdate.connection)
                            {
                                uniqueItem = false;
                            }
                        }
                        if (uniqueItem)
                        {
                            m_ReceiveStageNeedsUpdate.Add(newUpdate);
                        }
                    }

                    if (needsSendUpdate)
                    {
                        AddSendUpdate(connection, i, pipeline, m_SendStageNeedsUpdate);
                    }

                    if (inboundBuffer.Length == 0)
                    {
                        break;
                    }

                    // Offset needs to be adjusted for the next pipeline (the one in front of this one)
                    if (i > 0)
                    {
                        internalBufferOffset -=
                            m_StageCollection.GetReceiveCapacity(m_StageList[p.FirstStageIndex + i - 1]);
                        internalSharedBufferOffset -=
                            m_StageCollection.GetSharedStateCapacity(m_StageList[p.FirstStageIndex + i - 1]);
                    }

                    needsUpdate = false;
                }

                if (inboundBuffer.Length != 0)
                {
                    driver.PushDataEvent(connection, inboundBuffer);
                }

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

                startStage    = resumeQ[resumeQStart++];
                inboundBuffer = default(NativeSlice <byte>);
            }
        }
Example #13
0
            private void ProcessSendStage(int startStage, int internalBufferOffset, int internalSharedBufferOffset,
                                          PipelineImpl p, ref NativeList <int> resumeQ, ref NetworkPipelineContext ctx, ref InboundBufferVec inboundBuffer, ref bool needsUpdate)
            {
                bool needsResume = false;

                ctx.internalProcessBuffer = Unsafe_GetSliceFromReadOnlyArray(sendBuffer, internalBufferOffset,
                                                                             m_StageCollection.GetSendCapacity(m_StageList[p.FirstStageIndex + startStage]));

                ctx.internalSharedProcessBuffer =
                    Unsafe_GetSliceFromReadOnlyArray(sharedBuffer, internalSharedBufferOffset,
                                                     m_StageCollection.GetSharedStateCapacity(m_StageList[p.FirstStageIndex + startStage]));

                inboundBuffer = m_StageCollection.InvokeSend(m_StageList[p.FirstStageIndex + startStage], ctx,
                                                             inboundBuffer, ref needsResume, ref needsUpdate);
                if (needsResume)
                {
                    resumeQ.Add(startStage);
                }
            }
Example #14
0
            internal unsafe void ProcessPipelineSend <T>(T driver, int startStage, NetworkPipeline pipeline, NetworkConnection connection,
                                                         NativeSlice <byte> payloadBuffer, NativeList <UpdatePipeline> currentUpdates) where T : struct, INetworkPipelineSender
            {
                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;

                ctx.header = new DataStreamWriter(p.headerCapacity, Allocator.Temp);

                var inboundBuffer = default(InboundBufferVec);

                inboundBuffer.buffer1 = payloadBuffer;

                var prevHeader = new DataStreamWriter(p.headerCapacity, Allocator.Temp);

                while (true)
                {
                    int internalBufferOffset       = p.sendBufferOffset + sizePerConnection[SendSizeOffset] * connectionId;
                    int internalSharedBufferOffset = p.sharedBufferOffset + sizePerConnection[SharedSizeOffset] * connectionId;

                    bool needsUpdate = false;
                    // If this is not the first stage we need to fast forward the buffer offset to the correct place
                    if (startStage > 0)
                    {
                        for (int i = 0; i < startStage; ++i)
                        {
                            internalBufferOffset       += m_StageCollection.GetSendCapacity(m_StageList[p.FirstStageIndex + i]);
                            internalSharedBufferOffset += m_StageCollection.GetSharedStateCapacity(m_StageList[p.FirstStageIndex + i]);
                        }
                    }

                    for (int i = startStage; i < p.NumStages; ++i)
                    {
                        var prevInbound = inboundBuffer;
                        ProcessSendStage(i, internalBufferOffset, internalSharedBufferOffset, p, ref resumeQ, ref ctx, ref inboundBuffer, ref needsUpdate);
                        if (inboundBuffer.buffer1 == prevInbound.buffer1 &&
                            inboundBuffer.buffer2 == prevInbound.buffer2)
                        {
                            if (ctx.header.Length > 0)
                            {
                                if (prevHeader.Length > 0)
                                {
                                    ctx.header.WriteBytes(prevHeader.GetUnsafeReadOnlyPtr(), prevHeader.Length);
                                }
                                prevHeader.Clear();
                                var tempHeader = ctx.header;
                                ctx.header = prevHeader;
                                prevHeader = tempHeader;
                                if (inboundBuffer.buffer2.Length == 0)
                                {
                                    inboundBuffer.buffer2 = inboundBuffer.buffer1;
                                }
                                inboundBuffer.buffer1 = prevHeader.GetNativeSlice(0, prevHeader.Length);
                            }
                        }
                        else
                        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                            if (inboundBuffer.buffer2.Length > 0)
                            {
                                throw new InvalidOperationException("Pipeline send stages must return either the unmodified inbound buffers or a consolidated version with a single buffer");
                            }
#endif
                            // Prev header is now part of payload
                            prevHeader.Clear();
                            if (ctx.header.Length > 0)
                            {
                                var tempHeader = ctx.header;
                                ctx.header            = prevHeader;
                                prevHeader            = tempHeader;
                                inboundBuffer.buffer2 = inboundBuffer.buffer1;
                                inboundBuffer.buffer1 = prevHeader.GetNativeSlice(0, prevHeader.Length);
                            }
                        }
                        if (needsUpdate)
                        {
                            AddSendUpdate(connection, i, pipeline, currentUpdates);
                        }
                        if (inboundBuffer.buffer1.Length == 0)
                        {
                            break;
                        }

                        needsUpdate = false;

                        internalBufferOffset       += ctx.internalProcessBuffer.Length;
                        internalSharedBufferOffset += ctx.internalSharedProcessBuffer.Length;
                    }

                    if (inboundBuffer.buffer1.Length != 0)
                    {
                        var iov        = stackalloc network_iovec[4];
                        var pipelineId = pipeline.Id;
                        iov[0].buf = &pipelineId;
                        iov[0].len = 1;
                        iov[1].buf = ctx.header.GetUnsafePtr();
                        iov[1].len = ctx.header.Length;
                        iov[2].buf = inboundBuffer.buffer1.GetUnsafeReadOnlyPtr();
                        iov[2].len = inboundBuffer.buffer1.Length;
                        if (inboundBuffer.buffer2.Length > 0)
                        {
                            iov[3].buf = inboundBuffer.buffer2.GetUnsafeReadOnlyPtr();
                            iov[3].len = inboundBuffer.buffer2.Length;
                            // FIXME: handle send errors
                            driver.Send(connection, iov, 4);
                        }
                        else
                        {
                            driver.Send(connection, iov, 3);
                        }
                    }

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

                    startStage = resumeQ[resumeQStart++];

                    prevHeader.Clear();
                    inboundBuffer = default(InboundBufferVec);
                }
            }
Example #15
0
 public NativeSlice <byte> InvokeReceive(int pipelineStageId, NetworkPipelineContext ctx, NativeSlice <byte> inboundBuffer, ref bool needsResume, ref bool needsUpdate, ref bool needsSendUpdate)
 {
     return(inboundBuffer);
 }
Example #16
0
 public InboundBufferVec InvokeSend(int pipelineStageId, NetworkPipelineContext ctx, InboundBufferVec inboundBuffer, ref bool needsResume, ref bool needsUpdate)
 {
     return(inboundBuffer);
 }