[Obsolete] public unsafe int Send <T>(T driver, NetworkPipeline pipeline, NetworkConnection connection, NativeSlice <byte> payloadData) where T : struct, INetworkPipelineSender { var p = m_Pipelines[pipeline.Id - 1]; var connectionId = connection.m_NetworkId; int startStage = 0; // TODO: not really read-only, just hacking the safety system NativeArray <byte> tmpBuffer = sendBuffer; int *sendBufferLock = (int *)tmpBuffer.GetUnsafeReadOnlyPtr(); sendBufferLock += connectionId * sizePerConnection[SendSizeOffset] / 4; while (Interlocked.CompareExchange(ref *sendBufferLock, 1, 0) != 0) { #if ENABLE_UNITY_COLLECTIONS_CHECKS throw new InvalidOperationException("The parallel network driver needs to process a single unique connection per job, processing a single connection multiple times in a parallel for is not supported."); #endif } NativeList <UpdatePipeline> currentUpdates = new NativeList <UpdatePipeline>(128, Allocator.Temp); ProcessPipelineSend(driver, startStage, pipeline, connection, payloadData, currentUpdates); // Move the updates requested in this iteration to the concurrent queue so it can be read/parsed in update routine for (int i = 0; i < currentUpdates.Length; ++i) { m_SendStageNeedsUpdateWrite.Enqueue(currentUpdates[i]); } Interlocked.Exchange(ref *sendBufferLock, 0); return(payloadData.Length); }
public void GetPipelineBuffers(NetworkPipeline pipelineId, NetworkPipelineStageId stageId, NetworkConnection connection, out NativeArray <byte> readProcessingBuffer, out NativeArray <byte> writeProcessingBuffer, out NativeArray <byte> sharedBuffer) { if (pipelineId.Id < 1) { throw new InvalidOperationException("The specified pipeline is not valid"); } if (stageId.IsValid == 0) { throw new InvalidOperationException("The specified pipeline stage is not valid"); } var pipeline = m_Pipelines[pipelineId.Id - 1]; int recvBufferOffset = pipeline.receiveBufferOffset + sizePerConnection[RecveiveSizeOffset] * connection.InternalId; int sendBufferOffset = pipeline.sendBufferOffset + sizePerConnection[SendSizeOffset] * connection.InternalId; int sharedBufferOffset = pipeline.sharedBufferOffset + sizePerConnection[SharedSizeOffset] * connection.InternalId; int stageIndexInList; bool stageNotFound = true; for (stageIndexInList = pipeline.FirstStageIndex; stageIndexInList < pipeline.FirstStageIndex + pipeline.NumStages; stageIndexInList++) { if (m_StageList[stageIndexInList] == stageId.Index) { stageNotFound = false; break; } sendBufferOffset += (m_StageCollection[m_StageList[stageIndexInList]].SendCapacity + AlignmentMinusOne) & (~AlignmentMinusOne); recvBufferOffset += (m_StageCollection[m_StageList[stageIndexInList]].ReceiveCapacity + AlignmentMinusOne) & (~AlignmentMinusOne); sharedBufferOffset += (m_StageCollection[m_StageList[stageIndexInList]].SharedStateCapacity + AlignmentMinusOne) & (~AlignmentMinusOne); } if (stageNotFound) { #if ENABLE_UNITY_COLLECTIONS_CHECKS throw new InvalidOperationException("Could not find stage ID " + stageId + " make sure the type for this stage ID is added when the pipeline is created."); #else writeProcessingBuffer = default; readProcessingBuffer = default; sharedBuffer = default; return; #endif } writeProcessingBuffer = ((NativeArray <byte>)m_SendBuffer).GetSubArray(sendBufferOffset, m_StageCollection[m_StageList[stageIndexInList]].SendCapacity); readProcessingBuffer = ((NativeArray <byte>)m_ReceiveBuffer).GetSubArray(recvBufferOffset, m_StageCollection[m_StageList[stageIndexInList]].ReceiveCapacity); sharedBuffer = ((NativeArray <byte>)m_SharedBuffer).GetSubArray(sharedBufferOffset, m_StageCollection[m_StageList[stageIndexInList]].SharedStateCapacity); }
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); } }
public void GetPipelineBuffers(NetworkPipeline pipelineId, int stageId, NetworkConnection connection, ref NativeSlice <byte> readProcessingBuffer, ref NativeSlice <byte> writeProcessingBuffer, ref NativeSlice <byte> sharedBuffer) { var pipeline = m_Pipelines[pipelineId.Id - 1]; int recvBufferOffset = pipeline.receiveBufferOffset + sizePerConnection[RecveiveSizeOffset] * connection.InternalId; int sendBufferOffset = pipeline.sendBufferOffset + sizePerConnection[SendSizeOffset] * connection.InternalId; int sharedBufferOffset = pipeline.sharedBufferOffset + sizePerConnection[SharedSizeOffset] * connection.InternalId; int stageIndexInList; bool stageNotFound = true; for (stageIndexInList = pipeline.FirstStageIndex; stageIndexInList < pipeline.FirstStageIndex + pipeline.NumStages; stageIndexInList++) { if (m_StageList[stageIndexInList] == stageId) { stageNotFound = false; break; } sendBufferOffset += m_StageCollection.GetSendCapacity(m_StageList[stageIndexInList]); recvBufferOffset += m_StageCollection.GetReceiveCapacity(m_StageList[stageIndexInList]); sharedBufferOffset += m_StageCollection.GetSharedStateCapacity(m_StageList[stageIndexInList]); } if (stageNotFound) #if ENABLE_UNITY_COLLECTIONS_CHECKS { throw new InvalidOperationException("Could not find stage ID " + stageId + " make sure the type for this stage ID is added when the pipeline is created."); } #else { return; } #endif writeProcessingBuffer = new NativeSlice <byte>(m_SendBuffer, sendBufferOffset, m_StageCollection.GetSendCapacity(m_StageList[stageIndexInList])); readProcessingBuffer = new NativeSlice <byte>(m_ReceiveBuffer, recvBufferOffset, m_StageCollection.GetReceiveCapacity(m_StageList[stageIndexInList])); sharedBuffer = new NativeSlice <byte>(m_SharedBuffer, sharedBufferOffset, m_StageCollection.GetSharedStateCapacity(m_StageList[stageIndexInList])); }
private static void AddSendUpdate(NetworkConnection connection, int stageId, NetworkPipeline pipelineId, NativeList <UpdatePipeline> currentUpdates) { var newUpdate = new UpdatePipeline { connection = connection, stage = stageId, pipeline = pipelineId }; bool uniqueItem = true; for (int j = 0; j < currentUpdates.Length; ++j) { if (currentUpdates[j].stage == newUpdate.stage && currentUpdates[j].pipeline.Id == newUpdate.pipeline.Id && currentUpdates[j].connection == newUpdate.connection) { uniqueItem = false; } } if (uniqueItem) { currentUpdates.Add(newUpdate); } }
public NetworkEvent.Type PopEvent(NetworkDriver driver, out DataStreamReader stream, out NetworkPipeline pipeline) { return(driver.PopEventForConnection(this, out stream, out pipeline)); }
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>); } }
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); } }
public bool Equals(NetworkPipeline connection) { return(connection.Id == Id); }
public int Send(NetworkPipeline pipe, NetworkConnection id, IntPtr data, int len) { return(m_genericConcurrent.Send(pipe, id, data, len)); }
public int Send(NetworkPipeline pipe, NetworkConnection id, DataStreamWriter strm) { return(m_genericConcurrent.Send(pipe, id, strm)); }
public int Send(NetworkPipeline pipe, NetworkConnection con, IntPtr data, int len) { return(m_genericDriver.Send(pipe, con, data, len)); }
public int Send(NetworkPipeline pipe, NetworkConnection con, DataStreamWriter strm) { return(m_genericDriver.Send(pipe, con, strm)); }
public void GetPipelineBuffers(NetworkPipeline pipeline, int stageId, NetworkConnection connection, ref NativeSlice <byte> readProcessingBuffer, ref NativeSlice <byte> writeProcessingBuffer, ref NativeSlice <byte> sharedBuffer) { m_genericDriver.GetPipelineBuffers(pipeline, stageId, connection, ref readProcessingBuffer, ref writeProcessingBuffer, ref sharedBuffer); }
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; 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) { #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; ProcessSendStage(i, internalBufferOffset, internalSharedBufferOffset, p, ref resumeQ, ref ctx, ref inboundBuffer, ref needsUpdate); if (needsUpdate) { AddSendUpdate(connection, i, pipeline, currentUpdates); } if (inboundBuffer.bufferWithHeadersLength == 0) { 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; needsUpdate = false; 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); }
public unsafe int SendHeaderCapacity(NetworkPipeline pipeline) { var p = m_Pipelines[pipeline.Id - 1]; return(p.headerCapacity); }