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);
        }
Beispiel #2
0
        private static void 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;

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

                reliable->PreviousTimestamp = ctx.timestamp;
                return;
            }

            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;
            }

            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;
            }
            reliable->PreviousTimestamp = ctx.timestamp;
        }
        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);
        }
        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;
        }
Beispiel #5
0
        private static int 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((int)Error.StatusCode.NetworkPacketOverflow);
            }

            var timestamp = ctx.timestamp;

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

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

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

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

            InboundSendBuffer returnPacket = default;

            if (simulator.GetDelayedPacket(ref ctx, ref returnPacket, ref requests, timestamp))
            {
                inboundBuffer = returnPacket;
                return((int)Error.StatusCode.Success);
            }
            inboundBuffer = default;
            return((int)Error.StatusCode.Success);
        }
 private static void Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
 {
 }
Beispiel #7
0
 private static int Send(ref NetworkPipelineContext ctx, ref InboundSendBuffer inboundBuffer, ref NetworkPipelineStage.Requests requests)
 {
     return((int)Error.StatusCode.Success);
 }
Beispiel #8
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;
            }
Beispiel #9
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);
        }