您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

354 行
16 KiB

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Threading;
using Unity.Networking.Transport.Protocols;
using Unity.Networking.Transport.Relay;
namespace Unity.Networking.Transport.Tests
{
public class RelayServerMock : UDPSocketMock
{
private string m_Address;
private ushort m_Port;
private Dictionary<RelayAllocationId, EndPoint> m_ClientsAddresses = new Dictionary<RelayAllocationId, EndPoint>();
public RelayServerMock(string address, ushort port) : base(address, port)
{
m_Address = address;
m_Port = port;
}
// host is clientKey = 0
public RelayServerData GetRelayConnectionData(int clientKey)
{
var endpoint = NetworkEndPoint.Parse(m_Address, m_Port);
return new RelayServerData (
endpoint: ref endpoint,
nonce: 23,
allocationId: GetAllocationIdForClient(clientKey),
connectionData: "sGsP0X8REiXn+PS51+lQDPBjowDlvV5zPgh15puL5YXFd3XdQ/oHkXh0a+m8A3riVvtUdZvZloYNpsi19flB6cvfpXNvib9SQ5UUMH0V+hNVExAog21jLA7PlBPp2eLHtKeCRflhR2pSq6FmRplmXLfdu4fV3eCgruvpr/pr6lVxeATN5k13OiY4lnEv5otyUsfkKFyIO+Sann97MsEklKgoAtVmlw6QurBVb+W3GDIyAHYF15UrQkkHE46fBkCbgFdry2hDQjn+6uXnxC3LVPfJw0jS4FpdbLfiUik/qATkZyX9eu97PNLw9lL1aogDLRG/ztmpi4Slwpl3awXr",
hostConnectionData: "sGsP0X8REiXn+PS51+lQDPBjowDlvV5zPgh15puL5YXFd3XdQ/oHkXh0a+m8A3riVvtUdZvZloYNpsi19flB6cvfpXNvib9SQ5UUMH0V+hNVExAog21jLA7PlBPp2eLHtKeCRflhR2pSq6FmRplmXLfdu4fV3eCgruvpr/pr6lVxeATN5k13OiY4lnEv5otyUsfkKFyIO+Sann97MsEklKgoAtVmlw6QurBVb+W3GDIyAHYF15UrQkkHE46fBkCbgFdry2hDQjn+6uXnxC3LVPfJw0jS4FpdbLfiUik/qATkZyX9eu97PNLw9lL1aogDLRG/ztmpi4Slwpl3awXr",
key: "cSzQ2I5ZCQ7vnHMt9fDB2/+xDkL2VUKoUT7AVNYhe+kaTQLptQ0gUbco/Qgiicow89VtxOXcw92IozbdDG848w=="
);
}
public bool CompleteBind(NetworkDriver driver, int clientKey = -1)
{
SetupForBind(clientKey);
WaitForCondition(() =>
{
driver.ScheduleUpdate().Complete();
return driver.Bound;
});
return driver.Bound;
}
public bool CompleteConnect(NetworkDriver host, out (NetworkConnection hostToClient, NetworkConnection clientToHost)[] resultConnections, params NetworkDriver[] clients)
{
resultConnections = new (NetworkConnection hostToClient, NetworkConnection clientToHost)[clients.Length];
if (host.Bind(NetworkEndPoint.AnyIpv4) != 0)
return false;
if (!CompleteBind(host, 0))
return false;
if (host.Listen() != 0)
return false;
var clientId = 0;
foreach (var client in clients)
{
if (client.Bind(NetworkEndPoint.AnyIpv4) != 0)
return false;
if (!CompleteBind(client, clientId + 1))
return false;
SetupForConnect(clientId + 1);
var clientToHost = client.Connect(GetRelayConnectionData(0).Endpoint);
if (default(NetworkConnection) == clientToHost)
return false;
RelayServerMock.WaitForCondition(() =>
{
client.ScheduleUpdate(default).Complete();
host.ScheduleUpdate(default).Complete();
return client.GetConnectionState(clientToHost) == NetworkConnection.State.Connected;
});
if (client.GetConnectionState(clientToHost) != NetworkConnection.State.Connected)
return false;
if (client.PopEvent(out resultConnections[clientId].clientToHost, out var _) != NetworkEvent.Type.Connect)
return false;
if ((resultConnections[clientId].hostToClient = host.Accept()) == default)
return false;
++clientId;
}
return true;
}
public void RegisterBoundClient(RelayAllocationId allocationId, EndPoint endpoint)
{
m_ClientsAddresses[allocationId] = endpoint;
}
public void SetupForBind(int clientKey = -1)
{
ExpectPacket(BindPacket, (endpoint, data) =>
{
if (clientKey >= 0)
RegisterBoundClient(GetAllocationIdForClient(clientKey), endpoint);
Send(BindReceivedPacket, endpoint);
});
}
public void ExpectOptionalRepeatedPacket(byte[] packet)
{
Action<EndPoint, byte[]> callback = null;
callback = (endpoint, data) =>
{
ExpectPacket(packet, callback, optional:true);
};
callback(null, null);
}
public void SetupForBindRetry(int retryCount, Action onBindReceived)
{
var retriesLeft = retryCount;
Action<EndPoint, byte[]> bindReceiveMethod = null;
bindReceiveMethod = (endpoint, data) =>
{
onBindReceived?.Invoke();
if (--retriesLeft > 0)
ExpectPacket(BindPacket, bindReceiveMethod);
else
{
ExpectOptionalRepeatedPacket(BindPacket);
Send(BindReceivedPacket, endpoint);
}
};
ExpectPacket(BindPacket, bindReceiveMethod);
}
public unsafe void SetupForConnect(int clientKey)
{
var connectRequestPacket = ConnectRequestPacket;
fixed (byte* ptr = &connectRequestPacket[0])
{
*(RelayAllocationId*)(ptr + 4) = GetAllocationIdForClient(clientKey);
}
var acceptedPacket = AcceptedPacket;
fixed (byte* ptr = &acceptedPacket[0])
{
*(RelayAllocationId*)(ptr + 4) = GetAllocationIdForClient(0);
*(RelayAllocationId*)(ptr + 20) = GetAllocationIdForClient(clientKey);
}
ExpectPacket(connectRequestPacket, (endpoint, data) =>
{
Send(acceptedPacket, endpoint);
SetupForRelay(clientKey, 0, UdpCHeader.Length);
SetupForRelay(0, clientKey, UdpCHeader.Length + 2);
});
}
public unsafe void SetupForConnectRetry(int clientKey, int retryCount, Action onConnectReceived)
{
var connectRequestPacket = ConnectRequestPacket;
fixed (byte* ptr = &connectRequestPacket[0])
{
*(RelayAllocationId*)(ptr + 4) = GetAllocationIdForClient(clientKey);
}
var acceptedPacket = AcceptedPacket;
fixed (byte* ptr = &acceptedPacket[0])
{
*(RelayAllocationId*)(ptr + 4) = GetAllocationIdForClient(0);
*(RelayAllocationId*)(ptr + 20) = GetAllocationIdForClient(clientKey);
}
var retriesLeft = retryCount;
Action<EndPoint, byte[]> connectReceiveMethod = null;
connectReceiveMethod = (endpoint, data) =>
{
onConnectReceived?.Invoke();
if (--retriesLeft > 0)
ExpectPacket(connectRequestPacket, connectReceiveMethod);
else
{
ExpectOptionalRepeatedPacket(connectRequestPacket);
Send(acceptedPacket, endpoint);
SetupForRelay(clientKey, 0, UdpCHeader.Length);
SetupForRelay(0, clientKey, UdpCHeader.Length + 2);
}
};
ExpectPacket(connectRequestPacket, connectReceiveMethod);
}
public unsafe void SetupForRelay(int from, int to, ushort dataLength)
{
var relayMessage = new byte[RelayPacket.Length + dataLength];
Array.Copy(RelayPacket, relayMessage, RelayPacket.Length);
fixed (byte* ptr = &relayMessage[0])
{
*(RelayAllocationId*)(ptr + 4) = GetAllocationIdForClient(from);
*(RelayAllocationId*)(ptr + 20) = GetAllocationIdForClient(to);
*(ushort*)(ptr + 36) = RelayNetworkProtocol.SwitchEndianness(dataLength);
}
var parameters = new [] {
new PacketParameter {Offset = 38, Size = dataLength}
};
ExpectPacket(relayMessage, (endpoint, data) =>
{
if (m_ClientsAddresses.TryGetValue(GetAllocationIdForClient(to), out var toEndpoint))
Send(data, toEndpoint);
else
throw new Exception("Relay was not sent because destination client was not bound");
}, parameters);
}
public unsafe void SetupForDisconnect(int from, int to)
{
var disconnectPacket = DisconnectPacket;
fixed (byte* ptr = &disconnectPacket[0])
{
*(RelayAllocationId*)(ptr + 4) = GetAllocationIdForClient(from);
*(RelayAllocationId*)(ptr + 20) = GetAllocationIdForClient(to);
}
SetupForRelay(from, to, 4);
ExpectPacket(disconnectPacket, null);
}
static private byte[] BindPacket => new byte[] {
0xda, 0x72, 0x00, 0x00, // Header
0x00, // Accept Mode
0x17, 0x00, // Nonce
0xff, // ConnectionData Size
0xb0, 0x6b, 0x0f, 0xd1, 0x7f, 0x11, 0x12, 0x25, 0xe7, 0xf8, 0xf4, 0xb9, 0xd7, 0xe9, 0x50, 0x0c, // ConnectionData
0xf0, 0x63, 0xa3, 0x00, 0xe5, 0xbd, 0x5e, 0x73, 0x3e, 0x08, 0x75, 0xe6, 0x9b, 0x8b, 0xe5, 0x85,
0xc5, 0x77, 0x75, 0xdd, 0x43, 0xfa, 0x07, 0x91, 0x78, 0x74, 0x6b, 0xe9, 0xbc, 0x03, 0x7a, 0xe2,
0x56, 0xfb, 0x54, 0x75, 0x9b, 0xd9, 0x96, 0x86, 0x0d, 0xa6, 0xc8, 0xb5, 0xf5, 0xf9, 0x41, 0xe9,
0xcb, 0xdf, 0xa5, 0x73, 0x6f, 0x89, 0xbf, 0x52, 0x43, 0x95, 0x14, 0x30, 0x7d, 0x15, 0xfa, 0x13,
0x55, 0x13, 0x10, 0x28, 0x83, 0x6d, 0x63, 0x2c, 0x0e, 0xcf, 0x94, 0x13, 0xe9, 0xd9, 0xe2, 0xc7,
0xb4, 0xa7, 0x82, 0x45, 0xf9, 0x61, 0x47, 0x6a, 0x52, 0xab, 0xa1, 0x66, 0x46, 0x99, 0x66, 0x5c,
0xb7, 0xdd, 0xbb, 0x87, 0xd5, 0xdd, 0xe0, 0xa0, 0xae, 0xeb, 0xe9, 0xaf, 0xfa, 0x6b, 0xea, 0x55,
0x71, 0x78, 0x04, 0xcd, 0xe6, 0x4d, 0x77, 0x3a, 0x26, 0x38, 0x96, 0x71, 0x2f, 0xe6, 0x8b, 0x72,
0x52, 0xc7, 0xe4, 0x28, 0x5c, 0x88, 0x3b, 0xe4, 0x9a, 0x9e, 0x7f, 0x7b, 0x32, 0xc1, 0x24, 0x94,
0xa8, 0x28, 0x02, 0xd5, 0x66, 0x97, 0x0e, 0x90, 0xba, 0xb0, 0x55, 0x6f, 0xe5, 0xb7, 0x18, 0x32,
0x32, 0x00, 0x76, 0x05, 0xd7, 0x95, 0x2b, 0x42, 0x49, 0x07, 0x13, 0x8e, 0x9f, 0x06, 0x40, 0x9b,
0x80, 0x57, 0x6b, 0xcb, 0x68, 0x43, 0x42, 0x39, 0xfe, 0xea, 0xe5, 0xe7, 0xc4, 0x2d, 0xcb, 0x54,
0xf7, 0xc9, 0xc3, 0x48, 0xd2, 0xe0, 0x5a, 0x5d, 0x6c, 0xb7, 0xe2, 0x52, 0x29, 0x3f, 0xa8, 0x04,
0xe4, 0x67, 0x25, 0xfd, 0x7a, 0xef, 0x7b, 0x3c, 0xd2, 0xf0, 0xf6, 0x52, 0xf5, 0x6a, 0x88, 0x03,
0x2d, 0x11, 0xbf, 0xce, 0xd9, 0xa9, 0x8b, 0x84, 0xa5, 0xc2, 0x99, 0x77, 0x6b, 0x05, 0xeb,
0x51, 0x5f, 0x83, 0x86, 0x30, 0x58, 0x5f, 0x99, 0xfc, 0x95, 0x93, 0x76, 0x28, 0x41, 0x09, 0xf2, // HMAC
0x6b, 0x62, 0x43, 0x3f, 0x70, 0x29, 0x23, 0x38, 0xc0, 0xcf, 0xd5, 0xdd, 0x74, 0x78, 0x7f, 0x09
};
static private byte[] BindReceivedPacket => new byte[] { 0xda, 0x72, 0x00, 0x01 };
static private byte[] ConnectRequestPacket => new byte[] {
0xda, 0x72, 0x00, 0x03, // Header
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Allocation Id
0xFF, // ToConnectionData Size
0xb0, 0x6b, 0x0f, 0xd1, 0x7f, 0x11, 0x12, 0x25, 0xe7, 0xf8, 0xf4, 0xb9, 0xd7, 0xe9, 0x50, 0x0c, // ToConnectionData
0xf0, 0x63, 0xa3, 0x00, 0xe5, 0xbd, 0x5e, 0x73, 0x3e, 0x08, 0x75, 0xe6, 0x9b, 0x8b, 0xe5, 0x85,
0xc5, 0x77, 0x75, 0xdd, 0x43, 0xfa, 0x07, 0x91, 0x78, 0x74, 0x6b, 0xe9, 0xbc, 0x03, 0x7a, 0xe2,
0x56, 0xfb, 0x54, 0x75, 0x9b, 0xd9, 0x96, 0x86, 0x0d, 0xa6, 0xc8, 0xb5, 0xf5, 0xf9, 0x41, 0xe9,
0xcb, 0xdf, 0xa5, 0x73, 0x6f, 0x89, 0xbf, 0x52, 0x43, 0x95, 0x14, 0x30, 0x7d, 0x15, 0xfa, 0x13,
0x55, 0x13, 0x10, 0x28, 0x83, 0x6d, 0x63, 0x2c, 0x0e, 0xcf, 0x94, 0x13, 0xe9, 0xd9, 0xe2, 0xc7,
0xb4, 0xa7, 0x82, 0x45, 0xf9, 0x61, 0x47, 0x6a, 0x52, 0xab, 0xa1, 0x66, 0x46, 0x99, 0x66, 0x5c,
0xb7, 0xdd, 0xbb, 0x87, 0xd5, 0xdd, 0xe0, 0xa0, 0xae, 0xeb, 0xe9, 0xaf, 0xfa, 0x6b, 0xea, 0x55,
0x71, 0x78, 0x04, 0xcd, 0xe6, 0x4d, 0x77, 0x3a, 0x26, 0x38, 0x96, 0x71, 0x2f, 0xe6, 0x8b, 0x72,
0x52, 0xc7, 0xe4, 0x28, 0x5c, 0x88, 0x3b, 0xe4, 0x9a, 0x9e, 0x7f, 0x7b, 0x32, 0xc1, 0x24, 0x94,
0xa8, 0x28, 0x02, 0xd5, 0x66, 0x97, 0x0e, 0x90, 0xba, 0xb0, 0x55, 0x6f, 0xe5, 0xb7, 0x18, 0x32,
0x32, 0x00, 0x76, 0x05, 0xd7, 0x95, 0x2b, 0x42, 0x49, 0x07, 0x13, 0x8e, 0x9f, 0x06, 0x40, 0x9b,
0x80, 0x57, 0x6b, 0xcb, 0x68, 0x43, 0x42, 0x39, 0xfe, 0xea, 0xe5, 0xe7, 0xc4, 0x2d, 0xcb, 0x54,
0xf7, 0xc9, 0xc3, 0x48, 0xd2, 0xe0, 0x5a, 0x5d, 0x6c, 0xb7, 0xe2, 0x52, 0x29, 0x3f, 0xa8, 0x04,
0xe4, 0x67, 0x25, 0xfd, 0x7a, 0xef, 0x7b, 0x3c, 0xd2, 0xf0, 0xf6, 0x52, 0xf5, 0x6a, 0x88, 0x03,
0x2d, 0x11, 0xbf, 0xce, 0xd9, 0xa9, 0x8b, 0x84, 0xa5, 0xc2, 0x99, 0x77, 0x6b, 0x05, 0xeb,
};
static private byte[] AcceptedPacket => new byte[] {
0xda, 0x72, 0x00, 0x06, // Header
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // From Allocation Id
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // To Allocation Id
};
static private byte[] RelayPacket => new byte[] {
0xda, 0x72, 0x00, 0x0a, // Header
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // From Allocation Id
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // To Allocation Id
0x00, 0x00, // Data Length
// Content...
};
static private byte[] DisconnectPacket => new byte[] {
0xda, 0x72, 0x00, 0x09, // Header
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // From Allocation Id
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // To Allocation Id
};
static private byte[] PingPacket => new byte[] {
0xda, 0x72, 0x00, 0x02, // Header
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // From Allocation Id
};
static private RelayAllocationId GetAllocationIdForClient(int clientKey)
{
var allocationId = new RelayAllocationId();
if (clientKey == 0)
clientKey = -1;
unsafe
{
*(int*)allocationId.Value = clientKey;
}
return allocationId;
}
static public void WaitForCondition(Func<bool> condition, long timeout = 1000)
{
var stopwatch = Stopwatch.StartNew();
while(stopwatch.ElapsedMilliseconds <= timeout)
{
if (condition())
break;
Thread.Sleep(5);
}
}
}
}