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)); }
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); }
public static Vector3 ReadPackedVector3(this DataStreamReader reader, NetworkCompressionModel compressionModel) => reader.ReadPackedFloat3(compressionModel);
/// <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)); }
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; }
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; }