您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
372 行
17 KiB
372 行
17 KiB
using System;
|
|
using AOT;
|
|
using Unity.Burst;
|
|
using Unity.Collections;
|
|
using Unity.Collections.LowLevel.Unsafe;
|
|
using Unity.Networking.Transport.Protocols;
|
|
using UnityEngine.Assertions;
|
|
|
|
namespace Unity.Networking.Transport
|
|
{
|
|
[BurstCompile]
|
|
internal struct UnityTransportProtocol : INetworkProtocol
|
|
{
|
|
public void Initialize(INetworkParameter[] netParams) {}
|
|
public void Dispose() {}
|
|
|
|
public int Bind(INetworkInterface networkInterface, ref NetworkInterfaceEndPoint localEndPoint)
|
|
{
|
|
if (networkInterface.Bind(localEndPoint) != 0)
|
|
return -1;
|
|
|
|
return 2;
|
|
}
|
|
|
|
public unsafe int Connect(INetworkInterface networkInterface, NetworkEndPoint endpoint, out NetworkInterfaceEndPoint address)
|
|
{
|
|
return networkInterface.CreateInterfaceEndPoint(endpoint, out address);
|
|
}
|
|
|
|
public NetworkEndPoint GetRemoteEndPoint(INetworkInterface networkInterface, NetworkInterfaceEndPoint address)
|
|
{
|
|
return networkInterface.GetGenericEndPoint(address);
|
|
}
|
|
|
|
public NetworkProtocol CreateProtocolInterface()
|
|
{
|
|
return new NetworkProtocol (
|
|
computePacketAllocationSize: new TransportFunctionPointer<NetworkProtocol.ComputePacketAllocationSizeDelegate>(ComputePacketAllocationSize),
|
|
processReceive: new TransportFunctionPointer<NetworkProtocol.ProcessReceiveDelegate>(ProcessReceive),
|
|
processSend: new TransportFunctionPointer<NetworkProtocol.ProcessSendDelegate>(ProcessSend),
|
|
processSendConnectionAccept: new TransportFunctionPointer<NetworkProtocol.ProcessSendConnectionAcceptDelegate>(ProcessSendConnectionAccept),
|
|
processSendConnectionRequest: new TransportFunctionPointer<NetworkProtocol.ProcessSendConnectionRequestDelegate>(ProcessSendConnectionRequest),
|
|
processSendDisconnect: new TransportFunctionPointer<NetworkProtocol.ProcessSendDisconnectDelegate>(ProcessSendDisconnect),
|
|
update: new TransportFunctionPointer<NetworkProtocol.UpdateDelegate>(Update),
|
|
needsUpdate: false, // Update is no-op
|
|
userData: IntPtr.Zero,
|
|
maxHeaderSize: UdpCHeader.Length,
|
|
maxFooterSize: 2
|
|
);
|
|
}
|
|
|
|
[BurstCompile(DisableDirectCall = true)]
|
|
[MonoPInvokeCallback(typeof(NetworkProtocol.ComputePacketAllocationSizeDelegate))]
|
|
public static int ComputePacketAllocationSize(ref NetworkDriver.Connection connection, ref int dataCapacity, out int dataOffset)
|
|
{
|
|
dataOffset = UdpCHeader.Length;
|
|
var footerSize = connection.DidReceiveData == 0 ? 2 : 0;
|
|
|
|
if (dataCapacity == 0)
|
|
dataCapacity = NetworkParameterConstants.MTU - dataOffset - footerSize;
|
|
|
|
return dataOffset + dataCapacity + footerSize;
|
|
}
|
|
|
|
[BurstCompile(DisableDirectCall = true)]
|
|
[MonoPInvokeCallback(typeof(NetworkProtocol.ProcessReceiveDelegate))]
|
|
public static void ProcessReceive(IntPtr stream, ref NetworkInterfaceEndPoint endpoint, int size, ref NetworkSendInterface sendInterface, ref NetworkSendQueueHandle queueHandle, IntPtr userData, ref ProcessPacketCommand command)
|
|
{
|
|
unsafe
|
|
{
|
|
var data = (byte*)stream;
|
|
var header = *(UdpCHeader*)data;
|
|
|
|
if (size < UdpCHeader.Length)
|
|
{
|
|
UnityEngine.Debug.LogError("Received an invalid message header");
|
|
command.Type = ProcessPacketCommandType.Drop;
|
|
return;
|
|
}
|
|
|
|
switch ((UdpCProtocol)header.Type)
|
|
{
|
|
case UdpCProtocol.ConnectionAccept:
|
|
if ((header.Flags & UdpCHeader.HeaderFlags.HasConnectToken) == 0)
|
|
{
|
|
UnityEngine.Debug.LogError("Received an invalid ConnectionAccept without a token");
|
|
command.Type = ProcessPacketCommandType.Drop;
|
|
return;
|
|
}
|
|
|
|
if ((header.Flags & UdpCHeader.HeaderFlags.HasPipeline) != 0)
|
|
{
|
|
UnityEngine.Debug.LogError("Received an invalid ConnectionAccept with pipeline");
|
|
command.Type = ProcessPacketCommandType.Drop;
|
|
return;
|
|
}
|
|
|
|
if (size != UdpCHeader.Length + 2)
|
|
{
|
|
UnityEngine.Debug.LogError("Received an invalid ConnectionAccept with wrongh length");
|
|
command.Type = ProcessPacketCommandType.Drop;
|
|
return;
|
|
}
|
|
|
|
command.Type = ProcessPacketCommandType.ConnectionAccept;
|
|
command.AsConnectionAccept.Address = endpoint;
|
|
command.AsConnectionAccept.SessionId = header.SessionToken;
|
|
command.AsConnectionAccept.ConnectionToken = *(ushort*)(stream + UdpCHeader.Length);
|
|
return;
|
|
|
|
case UdpCProtocol.ConnectionReject:
|
|
command.Type = ProcessPacketCommandType.ConnectionReject;
|
|
return;
|
|
|
|
case UdpCProtocol.ConnectionRequest:
|
|
if ((header.Flags & UdpCHeader.HeaderFlags.HasPipeline) != 0)
|
|
{
|
|
UnityEngine.Debug.LogError("Received an invalid ConnectionRequest with pipeline");
|
|
command.Type = ProcessPacketCommandType.Drop;
|
|
return;
|
|
}
|
|
|
|
command.Type = ProcessPacketCommandType.ConnectionRequest;
|
|
command.AsConnectionRequest.Address = endpoint;
|
|
command.AsConnectionRequest.SessionId = header.SessionToken;
|
|
return;
|
|
|
|
case UdpCProtocol.Disconnect:
|
|
if ((header.Flags & UdpCHeader.HeaderFlags.HasPipeline) != 0)
|
|
{
|
|
UnityEngine.Debug.LogError("Received an invalid Disconnect with pipeline");
|
|
command.Type = ProcessPacketCommandType.Drop;
|
|
return;
|
|
}
|
|
|
|
command.Type = ProcessPacketCommandType.Disconnect;
|
|
command.AsDisconnect.SessionId = header.SessionToken;
|
|
command.AsDisconnect.Address = endpoint;
|
|
return;
|
|
|
|
case UdpCProtocol.Data:
|
|
var payloadLength = size - UdpCHeader.Length;
|
|
var hasPipeline = (header.Flags & UdpCHeader.HeaderFlags.HasPipeline) != 0 ? (byte)1 : (byte)0;
|
|
var hasConnectionToken = (header.Flags & UdpCHeader.HeaderFlags.HasConnectToken) != 0;
|
|
|
|
if (hasConnectionToken)
|
|
{
|
|
payloadLength -= 2;
|
|
command.Type = ProcessPacketCommandType.DataWithImplicitConnectionAccept;
|
|
command.AsDataWithImplicitConnectionAccept = new ProcessPacketCommandDataWithImplicitConnectionAccept
|
|
{
|
|
SessionId = header.SessionToken,
|
|
Offset = UdpCHeader.Length,
|
|
Length = payloadLength,
|
|
HasPipelineByte = hasPipeline,
|
|
ConnectionToken = *(ushort*)(stream + UdpCHeader.Length + payloadLength)
|
|
};
|
|
command.AsDataWithImplicitConnectionAccept.Address = endpoint;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
command.Type = ProcessPacketCommandType.Data;
|
|
command.AsData = new ProcessPacketCommandData
|
|
{
|
|
SessionId = header.SessionToken,
|
|
Offset = UdpCHeader.Length,
|
|
Length = payloadLength,
|
|
HasPipelineByte = hasPipeline,
|
|
};
|
|
command.AsData.Address = endpoint;
|
|
return;
|
|
}
|
|
}
|
|
|
|
command.Type = ProcessPacketCommandType.Drop;
|
|
}
|
|
}
|
|
|
|
[BurstCompile(DisableDirectCall = true)]
|
|
[MonoPInvokeCallback(typeof(NetworkProtocol.ProcessSendDelegate))]
|
|
public static int ProcessSend(ref NetworkDriver.Connection connection, bool hasPipeline, ref NetworkSendInterface sendInterface, ref NetworkInterfaceSendHandle sendHandle, ref NetworkSendQueueHandle queueHandle, IntPtr userData)
|
|
{
|
|
WriteSendMessageHeader(ref connection, hasPipeline, ref sendHandle, 0);
|
|
return sendInterface.EndSendMessage.Ptr.Invoke(ref sendHandle, ref connection.Address, sendInterface.UserData, ref queueHandle);
|
|
}
|
|
|
|
internal static unsafe int WriteSendMessageHeader(ref NetworkDriver.Connection connection, bool hasPipeline, ref NetworkInterfaceSendHandle sendHandle, int offset)
|
|
{
|
|
unsafe
|
|
{
|
|
var flags = default(UdpCHeader.HeaderFlags);
|
|
var capacity = sendHandle.capacity - offset;
|
|
var size = sendHandle.size - offset;
|
|
|
|
if (connection.DidReceiveData == 0)
|
|
{
|
|
flags |= UdpCHeader.HeaderFlags.HasConnectToken;
|
|
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
if (size + 2 > capacity)
|
|
throw new InvalidOperationException("SendHandle capacity overflow");
|
|
#endif
|
|
ushort* connectionToken = (ushort*)((byte*)sendHandle.data + sendHandle.size);
|
|
*connectionToken = connection.ReceiveToken;
|
|
sendHandle.size += 2;
|
|
}
|
|
|
|
if (hasPipeline)
|
|
{
|
|
flags |= UdpCHeader.HeaderFlags.HasPipeline;
|
|
}
|
|
|
|
UdpCHeader* header = (UdpCHeader*)(sendHandle.data + offset);
|
|
*header = new UdpCHeader
|
|
{
|
|
Type = (byte)UdpCProtocol.Data,
|
|
SessionToken = connection.SendToken,
|
|
Flags = flags
|
|
};
|
|
|
|
return sendHandle.size - offset;
|
|
}
|
|
}
|
|
|
|
[BurstCompile(DisableDirectCall = true)]
|
|
[MonoPInvokeCallback(typeof(NetworkProtocol.ProcessSendConnectionAcceptDelegate))]
|
|
public static void ProcessSendConnectionAccept(ref NetworkDriver.Connection connection, ref NetworkSendInterface sendInterface, ref NetworkSendQueueHandle queueHandle, IntPtr userData)
|
|
{
|
|
unsafe
|
|
{
|
|
NetworkInterfaceSendHandle sendHandle;
|
|
if (sendInterface.BeginSendMessage.Ptr.Invoke(out sendHandle, sendInterface.UserData, UdpCHeader.Length + 2) != 0)
|
|
{
|
|
UnityEngine.Debug.LogError("Failed to send a ConnectionAccept packet");
|
|
return;
|
|
}
|
|
|
|
byte* packet = (byte*) sendHandle.data;
|
|
var size = WriteConnectionAcceptMessage(ref connection, packet, sendHandle.capacity);
|
|
|
|
if (size < 0)
|
|
{
|
|
sendInterface.AbortSendMessage.Ptr.Invoke(ref sendHandle, sendInterface.UserData);
|
|
UnityEngine.Debug.LogError("Failed to send a ConnectionAccept packet");
|
|
return;
|
|
}
|
|
|
|
sendHandle.size = size;
|
|
|
|
if (sendInterface.EndSendMessage.Ptr.Invoke(ref sendHandle, ref connection.Address, sendInterface.UserData, ref queueHandle) < 0)
|
|
{
|
|
UnityEngine.Debug.LogError("Failed to send a ConnectionAccept packet");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static int GetConnectionAcceptMessageMaxLength() => UdpCHeader.Length + 2;
|
|
|
|
internal static unsafe int WriteConnectionAcceptMessage(ref NetworkDriver.Connection connection, byte* packet, int capacity)
|
|
{
|
|
var size = UdpCHeader.Length;
|
|
|
|
if (connection.DidReceiveData == 0)
|
|
size += 2;
|
|
|
|
if (size > capacity)
|
|
{
|
|
UnityEngine.Debug.LogError("Failed to create a ConnectionAccept packet: size exceeds capacity");
|
|
return -1;
|
|
}
|
|
|
|
var header = (UdpCHeader*) packet;
|
|
*header = new UdpCHeader
|
|
{
|
|
Type = (byte) UdpCProtocol.ConnectionAccept,
|
|
SessionToken = connection.SendToken,
|
|
Flags = 0
|
|
};
|
|
|
|
if (connection.DidReceiveData == 0)
|
|
{
|
|
header->Flags |= UdpCHeader.HeaderFlags.HasConnectToken;
|
|
*(ushort*)(packet + UdpCHeader.Length) = connection.ReceiveToken;
|
|
}
|
|
|
|
Assert.IsTrue(size <= GetConnectionAcceptMessageMaxLength());
|
|
|
|
return size;
|
|
}
|
|
|
|
[BurstCompile(DisableDirectCall = true)]
|
|
[MonoPInvokeCallback(typeof(NetworkProtocol.ProcessSendConnectionRequestDelegate))]
|
|
public static void ProcessSendConnectionRequest(ref NetworkDriver.Connection connection, ref NetworkSendInterface sendInterface, ref NetworkSendQueueHandle queueHandle, IntPtr userData)
|
|
{
|
|
unsafe
|
|
{
|
|
NetworkInterfaceSendHandle sendHandle;
|
|
if (sendInterface.BeginSendMessage.Ptr.Invoke(out sendHandle, sendInterface.UserData, UdpCHeader.Length) != 0)
|
|
{
|
|
UnityEngine.Debug.LogError("Failed to send a ConnectionRequest packet");
|
|
return;
|
|
}
|
|
|
|
byte* packet = (byte*) sendHandle.data;
|
|
sendHandle.size = UdpCHeader.Length;
|
|
if (sendHandle.size > sendHandle.capacity)
|
|
{
|
|
sendInterface.AbortSendMessage.Ptr.Invoke(ref sendHandle, sendInterface.UserData);
|
|
UnityEngine.Debug.LogError("Failed to send a ConnectionRequest packet");
|
|
return;
|
|
}
|
|
var header = (UdpCHeader*) packet;
|
|
*header = new UdpCHeader
|
|
{
|
|
Type = (byte) UdpCProtocol.ConnectionRequest,
|
|
SessionToken = connection.ReceiveToken,
|
|
Flags = 0
|
|
};
|
|
if (sendInterface.EndSendMessage.Ptr.Invoke(ref sendHandle, ref connection.Address, sendInterface.UserData, ref queueHandle) < 0)
|
|
{
|
|
UnityEngine.Debug.LogError("Failed to send a ConnectionRequest packet");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
[BurstCompile(DisableDirectCall = true)]
|
|
[MonoPInvokeCallback(typeof(NetworkProtocol.ProcessSendDisconnectDelegate))]
|
|
public static void ProcessSendDisconnect(ref NetworkDriver.Connection connection, ref NetworkSendInterface sendInterface, ref NetworkSendQueueHandle queueHandle, IntPtr userData)
|
|
{
|
|
unsafe
|
|
{
|
|
NetworkInterfaceSendHandle sendHandle;
|
|
if (sendInterface.BeginSendMessage.Ptr.Invoke(out sendHandle, sendInterface.UserData, UdpCHeader.Length) != 0)
|
|
{
|
|
UnityEngine.Debug.LogError("Failed to send a Disconnect packet");
|
|
return;
|
|
}
|
|
|
|
byte* packet = (byte*) sendHandle.data;
|
|
sendHandle.size = UdpCHeader.Length;
|
|
if (sendHandle.size > sendHandle.capacity)
|
|
{
|
|
sendInterface.AbortSendMessage.Ptr.Invoke(ref sendHandle, sendInterface.UserData);
|
|
UnityEngine.Debug.LogError("Failed to send a Disconnect packet");
|
|
return;
|
|
}
|
|
var header = (UdpCHeader*) packet;
|
|
*header = new UdpCHeader
|
|
{
|
|
Type = (byte) UdpCProtocol.Disconnect,
|
|
SessionToken = connection.SendToken,
|
|
Flags = 0
|
|
};
|
|
if (sendInterface.EndSendMessage.Ptr.Invoke(ref sendHandle, ref connection.Address, sendInterface.UserData, ref queueHandle) < 0)
|
|
{
|
|
UnityEngine.Debug.LogError("Failed to send a Disconnect packet");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
[BurstCompile(DisableDirectCall = true)]
|
|
[MonoPInvokeCallback(typeof(NetworkProtocol.UpdateDelegate))]
|
|
public static void Update(long updateTime, ref NetworkSendInterface sendInterface, ref NetworkSendQueueHandle queueHandle, IntPtr userData)
|
|
{
|
|
// No-op
|
|
}
|
|
}
|
|
}
|