Direct connection support
parent
a99b097a83
commit
fc25760c2f
Binary file not shown.
Binary file not shown.
|
|
@ -4,6 +4,7 @@ using System.Collections.Concurrent;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -18,6 +19,8 @@ namespace Lobbies
|
|||
|
||||
AutoResetEvent waitForExternalIp = new AutoResetEvent(false);
|
||||
|
||||
UdpEchoServer udpEchoServer = new UdpEchoServer();
|
||||
|
||||
private Dictionary<Guid, LobbyInfo> lobbyInformation = new Dictionary<Guid, LobbyInfo>();
|
||||
private string? host;
|
||||
private int port;
|
||||
|
|
@ -75,6 +78,8 @@ namespace Lobbies
|
|||
|
||||
public void HostLobby(Guid gameId, string name, int gameMode, int maxPlayerCount, string? password, string? ip, int port)
|
||||
{
|
||||
udpEchoServer.Start(0);
|
||||
|
||||
byte[]? hash = null, salt = null;
|
||||
|
||||
if(!string.IsNullOrEmpty(password))
|
||||
|
|
@ -91,8 +96,9 @@ namespace Lobbies
|
|||
PlayerCount = 0,
|
||||
PasswordHash = hash,
|
||||
PasswordSalt = salt,
|
||||
HostIp = ip,
|
||||
HostPort = port
|
||||
HostIps = GatherLocalIpAddresses().ToArray(),
|
||||
HostPort = port,
|
||||
HostTryPort = udpEchoServer.Port
|
||||
};
|
||||
|
||||
byte[] messageData = bufferRental.Rent();
|
||||
|
|
@ -142,7 +148,7 @@ namespace Lobbies
|
|||
});
|
||||
}
|
||||
|
||||
public void UpdateLobby(string name, int gameMode, int maxPlayerCount, int playerCount, string? password, string? ip, int port)
|
||||
public void UpdateLobby(string name, int gameMode, int maxPlayerCount, int playerCount, string? password, int port)
|
||||
{
|
||||
byte[]? hash = null, salt = null;
|
||||
|
||||
|
|
@ -159,8 +165,9 @@ namespace Lobbies
|
|||
PlayerCount = playerCount,
|
||||
PasswordHash = hash,
|
||||
PasswordSalt = salt,
|
||||
HostIp = ip,
|
||||
HostPort = port
|
||||
HostIps = GatherLocalIpAddresses().ToArray(),
|
||||
HostPort = port,
|
||||
HostTryPort = udpEchoServer.Port
|
||||
};
|
||||
|
||||
byte[] messageData = bufferRental.Rent();
|
||||
|
|
@ -170,6 +177,8 @@ namespace Lobbies
|
|||
|
||||
public void CloseLobby()
|
||||
{
|
||||
udpEchoServer.Stop();
|
||||
|
||||
var lobbyDelete = new LobbyDelete()
|
||||
{
|
||||
|
||||
|
|
@ -207,6 +216,32 @@ namespace Lobbies
|
|||
_ = Task.Run(async () => { await tcpClient.Send(messageData, 0, len); bufferRental.Return(messageData); });
|
||||
}
|
||||
|
||||
public async Task<IPAddress?> TryDirectConnection(IPAddress[] ipAddressesToTry, int tryPort)
|
||||
{
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
IPAddress? ret = null;
|
||||
using (var udpEchoClient = new UdpEchoServer())
|
||||
{
|
||||
udpEchoClient.Reached += (ep) =>
|
||||
{
|
||||
ret = ep.Address;
|
||||
};
|
||||
|
||||
udpEchoClient.Start(0);
|
||||
|
||||
foreach (var ip in ipAddressesToTry)
|
||||
{
|
||||
udpEchoClient.CheckConnectionPossible(new IPEndPoint(ip, tryPort));
|
||||
}
|
||||
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
return ret;
|
||||
});
|
||||
}
|
||||
|
||||
public static IPAddress[] GetIPsByName(string hostName, bool ip4Wanted, bool ip6Wanted)
|
||||
{
|
||||
// Check if the hostname is already an IPAddress
|
||||
|
|
@ -361,10 +396,24 @@ namespace Lobbies
|
|||
catch { }
|
||||
}
|
||||
|
||||
public IEnumerable<IPAddress> GatherLocalIpAddresses()
|
||||
{
|
||||
foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
|
||||
{
|
||||
IPInterfaceProperties ipProps = netInterface.GetIPProperties();
|
||||
|
||||
foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
|
||||
{
|
||||
yield return addr.Address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
waitForExternalIp.Dispose();
|
||||
tcpClient.Dispose();
|
||||
udpEchoServer.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,197 @@
|
|||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System;
|
||||
|
||||
namespace Lobbies
|
||||
{
|
||||
/// <summary>
|
||||
/// Small udp server to receive udp packets and echo the data back to source
|
||||
/// </summary>
|
||||
internal class UdpEchoServer : IDisposable
|
||||
{
|
||||
public const int SIO_UDP_CONNRESET = -1744830452;
|
||||
|
||||
private readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
|
||||
private bool running = false;
|
||||
private bool isDisposed = false;
|
||||
private UdpClient? serverSocketV4, serverSocketV6;
|
||||
|
||||
public delegate void ReachableEventArgs(IPEndPoint remoteEndpoint);
|
||||
/// <summary>
|
||||
/// If a valid request for a ip and port query comes in call this event with the seen remote ip and port for a lobby server client id
|
||||
/// </summary>
|
||||
public event ReachableEventArgs? Reached;
|
||||
|
||||
public int Port { get; private set; }
|
||||
private bool isRunningV4 = false, isRunningV6 = false;
|
||||
|
||||
public void CheckConnectionPossible(IPEndPoint remoteEndpoint)
|
||||
{
|
||||
if (!running || serverSocketV4 == null || serverSocketV6 == null)
|
||||
throw new Exception("Listener not running!");
|
||||
|
||||
byte[] magicRequest = new byte[] { 0 };
|
||||
for (int i = 0; i < 16; i++)
|
||||
if(remoteEndpoint.AddressFamily == AddressFamily.InterNetwork)
|
||||
serverSocketV4.Send(magicRequest, magicRequest.Length, remoteEndpoint);
|
||||
else
|
||||
serverSocketV6.Send(magicRequest, magicRequest.Length, remoteEndpoint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Listen to requests and fire events
|
||||
/// </summary>
|
||||
/// <param name="port">The port to listen on</param>
|
||||
private async void ListenV4(int port)
|
||||
{
|
||||
try
|
||||
{
|
||||
cancellationTokenSource.Token.ThrowIfCancellationRequested();
|
||||
serverSocketV4 = new UdpClient(port, AddressFamily.InterNetwork);
|
||||
serverSocketV4.Client.IOControl(
|
||||
(IOControlCode)SIO_UDP_CONNRESET,
|
||||
new byte[] { 0, 0, 0, 0 },
|
||||
null
|
||||
);
|
||||
Port = ((IPEndPoint)serverSocketV4.Client.LocalEndPoint).Port;
|
||||
byte[] magicAnswer = new byte[] { 1 };
|
||||
using (cancellationTokenSource.Token.Register(() => { serverSocketV4.Close(); }))
|
||||
{
|
||||
isRunningV4 = true;
|
||||
while (running)
|
||||
{
|
||||
var receiveResult = await serverSocketV4.ReceiveAsync();
|
||||
if (receiveResult.Buffer.Length == 1)
|
||||
{
|
||||
if (receiveResult.Buffer[0] == 0)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
serverSocketV4.Send(magicAnswer, magicAnswer.Length, receiveResult.RemoteEndPoint);
|
||||
}
|
||||
|
||||
if (receiveResult.Buffer[0] == 1)
|
||||
{
|
||||
Reached?.Invoke(receiveResult.RemoteEndPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch when (cancellationTokenSource.IsCancellationRequested || !running) //Cancel requested
|
||||
{
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
serverSocketV4?.Dispose();
|
||||
serverSocketV4 = null;
|
||||
running = false;
|
||||
isRunningV4 = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Listen to requests and fire events
|
||||
/// </summary>
|
||||
/// <param name="port">The port to listen on</param>
|
||||
private async void ListenV6(int port)
|
||||
{
|
||||
try
|
||||
{
|
||||
cancellationTokenSource.Token.ThrowIfCancellationRequested();
|
||||
serverSocketV6 = new UdpClient(port, AddressFamily.InterNetworkV6);
|
||||
serverSocketV6.Client.IOControl(
|
||||
(IOControlCode)SIO_UDP_CONNRESET,
|
||||
new byte[] { 0, 0, 0, 0 },
|
||||
null
|
||||
);
|
||||
byte[] magicAnswer = new byte[] { 1 };
|
||||
using (cancellationTokenSource.Token.Register(() => { serverSocketV6.Close(); }))
|
||||
{
|
||||
isRunningV6 = true;
|
||||
while (running)
|
||||
{
|
||||
var receiveResult = await serverSocketV6.ReceiveAsync();
|
||||
if (receiveResult.Buffer.Length == 1)
|
||||
{
|
||||
if (receiveResult.Buffer[0] == 0)
|
||||
{
|
||||
Reached?.Invoke(receiveResult.RemoteEndPoint);
|
||||
}
|
||||
|
||||
if (receiveResult.Buffer[0] == 1)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
serverSocketV6.Send(magicAnswer, magicAnswer.Length, receiveResult.RemoteEndPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch when (cancellationTokenSource.IsCancellationRequested || !running) //Cancel requested
|
||||
{
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
serverSocketV6?.Dispose();
|
||||
serverSocketV6 = null;
|
||||
running = false;
|
||||
isRunningV6 = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start udp listener
|
||||
/// </summary>
|
||||
/// <param name="port">The port to listen on</param>
|
||||
public void Start(int port)
|
||||
{
|
||||
isRunningV4 = false;
|
||||
isRunningV6 = false;
|
||||
running = true;
|
||||
_ = Task.Run(() => ListenV4(port));
|
||||
while (running && !isRunningV4)
|
||||
Thread.Yield();
|
||||
_ = Task.Run(() => ListenV6(Port));
|
||||
while (running && (!isRunningV4 || !isRunningV6))
|
||||
Thread.Yield();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop udp listener
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
running = false;
|
||||
cancellationTokenSource.Cancel();
|
||||
if (serverSocketV4 != null)
|
||||
serverSocketV4?.Close();
|
||||
if (serverSocketV6 != null)
|
||||
serverSocketV6?.Close();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!isDisposed)
|
||||
{
|
||||
Stop();
|
||||
while (isRunningV4 || isRunningV6)
|
||||
Task.Yield();
|
||||
|
||||
cancellationTokenSource.Dispose();
|
||||
isDisposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ using Lobbies;
|
|||
using LobbyClientTest;
|
||||
using LobbyServerDto;
|
||||
using System.Net;
|
||||
using System.Net.WebSockets;
|
||||
|
||||
Console.WriteLine("Starting lobby client v0.7!");
|
||||
var lobbyClient = new LobbyClient();
|
||||
|
|
@ -16,12 +17,11 @@ FakeGameHost fakeGameHost = new FakeGameHost();
|
|||
int myPort = fakeGameHost.Server(0);
|
||||
string? myExternalIp = null;
|
||||
int myExternalPort = -1;
|
||||
IPEndPoint? hostInfo = null;
|
||||
|
||||
bool running = true;
|
||||
bool connected = false;
|
||||
|
||||
_ = Task.Run(() =>
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
while (running)
|
||||
{
|
||||
|
|
@ -78,8 +78,23 @@ _ = Task.Run(() =>
|
|||
var lobbyHostInfo = lobbyEvent.EventData as LobbyHostInfo;
|
||||
var p = Console.GetCursorPosition();
|
||||
Console.SetCursorPosition(0, p.Top);
|
||||
Console.WriteLine($"Host info for lobby {lobbyHostInfo!.LobbyId} is {lobbyHostInfo.HostIp}:{lobbyHostInfo.HostPort}!");
|
||||
hostInfo = new IPEndPoint(IPAddress.Parse(lobbyHostInfo.HostIp!), lobbyHostInfo.HostPort);
|
||||
Console.WriteLine($"Host info for lobby {lobbyHostInfo!.LobbyId} is {(lobbyHostInfo.HostIps != null && lobbyHostInfo.HostIps.Length > 0 ? lobbyHostInfo.HostIps[0].ToString() : "")}:{lobbyHostInfo.HostPort}!");
|
||||
|
||||
//Try direct connection
|
||||
if (lobbyHostInfo.HostIps != null && lobbyHostInfo.HostIps.Length > 0)
|
||||
{
|
||||
Console.WriteLine($"Trying direct connection to {string.Join<IPAddress>(",", lobbyHostInfo.HostIps)} on port {lobbyHostInfo.HostTryPort}!");
|
||||
var reachableIp = await lobbyClient.TryDirectConnection(lobbyHostInfo.HostIps, lobbyHostInfo.HostTryPort);
|
||||
if(reachableIp != null)
|
||||
{
|
||||
Console.WriteLine($"Direct connection to {reachableIp.ToString()} possible, using direct connection!");
|
||||
Console.WriteLine($"Connecting game client!");
|
||||
fakeGameHost.Send(new IPEndPoint(reachableIp, lobbyHostInfo.HostPort), "Hello from Game Client!");
|
||||
Console.Write(">");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"Requesting nat punch to me!");
|
||||
lobbyClient.RequestLobbyNatPunch(lobbyHostInfo.LobbyId, null, (remoteEndpoint, messageBuffer, messageLength) => {
|
||||
fakeGameHost.Send(remoteEndpoint, messageBuffer, messageLength);
|
||||
|
|
@ -111,7 +126,7 @@ _ = Task.Run(() =>
|
|||
Console.SetCursorPosition(0, p.Top);
|
||||
Console.WriteLine($"Nat punch requested to {lobbyRequestNatPunch!.ClientIp}:{lobbyRequestNatPunch.ClientPort}!");
|
||||
|
||||
Task.Run(() =>
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
lobbyClient.QueryExternalIpAndPort((remoteEndpoint, messageData, messageLength) => {
|
||||
fakeGameHost.Send(remoteEndpoint, messageData, messageLength);
|
||||
|
|
@ -140,7 +155,6 @@ _ = Task.Run(() =>
|
|||
Console.SetCursorPosition(0, p.Top);
|
||||
Console.WriteLine($"Nat punch request done!");
|
||||
Console.WriteLine($"Connecting game client!");
|
||||
|
||||
fakeGameHost.Send(new IPEndPoint(IPAddress.Parse(lobbyNatPunchDone!.ExternalIp!), lobbyNatPunchDone.ExternalPort), "Hello from Game Client!");
|
||||
Console.Write(">");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -24,7 +25,8 @@ namespace LobbyServer
|
|||
public int MaxPlayerCount { get; set; }
|
||||
public byte[]? PasswordHash { get; set; }
|
||||
public byte[]? PasswordSalt { get; set; }
|
||||
public required string HostIp { get; set; }
|
||||
public required IPAddress[] HostIps { get; set; }
|
||||
public int HostPort { get; set; }
|
||||
public int HostTryPort { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using LobbyServer;
|
||||
using LobbyServerDto;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
using System.Net;
|
||||
|
||||
using var closing = new AutoResetEvent(false);
|
||||
using var tcpServer = new TcpServer();
|
||||
|
|
@ -42,6 +42,11 @@ tcpServer.DataReceived += (clientId, dataLength, data) =>
|
|||
if (!GameGuids.ValidGuids.Contains(lobbyCreate.GameId))
|
||||
throw new Exception("Invalid game guid!");
|
||||
|
||||
List<IPAddress> hostIpAddresses = new List<IPAddress>();
|
||||
hostIpAddresses.Add(IPAddress.Parse(tcpServer.GetClientIp(clientId)!));
|
||||
if(lobbyCreate.HostIps != null)
|
||||
hostIpAddresses.AddRange(lobbyCreate.HostIps);
|
||||
|
||||
var lobby = new Lobby
|
||||
{
|
||||
Name = lobbyCreate.Name,
|
||||
|
|
@ -52,8 +57,9 @@ tcpServer.DataReceived += (clientId, dataLength, data) =>
|
|||
PasswordHash = lobbyCreate.PasswordHash,
|
||||
PasswordSalt = lobbyCreate.PasswordSalt,
|
||||
HostClientId = clientId,
|
||||
HostIp = lobbyCreate.HostIp == null ? tcpServer.GetClientIp(clientId)! : lobbyCreate.HostIp,
|
||||
HostIps = hostIpAddresses.ToArray(),
|
||||
HostPort = lobbyCreate.HostPort,
|
||||
HostTryPort = lobbyCreate.HostTryPort
|
||||
};
|
||||
|
||||
if(lobbiesByClientId.TryGetValue(clientId, out var existingLobby))
|
||||
|
|
@ -113,10 +119,17 @@ tcpServer.DataReceived += (clientId, dataLength, data) =>
|
|||
existingLobby.PasswordHash = lobbyUpdate.PasswordHash;
|
||||
existingLobby.PasswordSalt = lobbyUpdate.PasswordSalt;
|
||||
|
||||
if (lobbyUpdate.HostIp != null)
|
||||
existingLobby.HostIp = lobbyUpdate.HostIp;
|
||||
List<IPAddress> hostIpAddresses = new List<IPAddress>();
|
||||
hostIpAddresses.Add(IPAddress.Parse(tcpServer.GetClientIp(clientId)!));
|
||||
if (lobbyUpdate.HostIps != null)
|
||||
hostIpAddresses.AddRange(lobbyUpdate.HostIps);
|
||||
|
||||
if (!Enumerable.SequenceEqual(existingLobby.HostIps, hostIpAddresses))
|
||||
existingLobby.HostIps = hostIpAddresses.ToArray();
|
||||
|
||||
existingLobby.HostPort = lobbyUpdate.HostPort;
|
||||
existingLobby.HostTryPort = lobbyUpdate.HostTryPort;
|
||||
|
||||
_ = Task.Run(() => SendLobbyUpdate(Lobby.LobbyUpdateType.Update, existingLobby));
|
||||
}
|
||||
}
|
||||
|
|
@ -221,7 +234,7 @@ tcpServer.DataReceived += (clientId, dataLength, data) =>
|
|||
|
||||
{
|
||||
var messageData = bufferRental.Rent();
|
||||
var lobbyHostInfo = new LobbyHostInfo() { LobbyId = lobby.Id, HostIp = lobby.HostIp, HostPort = lobby.HostPort };
|
||||
var lobbyHostInfo = new LobbyHostInfo() { LobbyId = lobby.Id, HostIps = lobby.HostIps, HostPort = lobby.HostPort, HostTryPort = lobby.HostTryPort };
|
||||
var messageDataLength = lobbyHostInfo.Serialize(messageData);
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
|
|
@ -426,7 +439,7 @@ Console.CancelKeyPress += (sender, args) =>
|
|||
args.Cancel = true;
|
||||
};
|
||||
|
||||
Console.WriteLine($"{DateTime.Now}: Application started v0.7");
|
||||
Console.WriteLine($"{DateTime.Now}: Application started v0.8");
|
||||
|
||||
udpServer.Start(8088);
|
||||
tcpServer.Start(8088);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Net;
|
||||
|
||||
namespace LobbyServerDto
|
||||
{
|
||||
|
|
@ -41,13 +42,17 @@ namespace LobbyServerDto
|
|||
[MaxLength(16)]
|
||||
public byte[]? PasswordSalt { get; set; }
|
||||
/// <summary>
|
||||
/// The hosts ip. Used the the host information send to clients on their request.
|
||||
/// The hosts ip addresses locally detected. Used the the host information send to clients on their request.
|
||||
/// </summary>
|
||||
[MaxLength(32)]
|
||||
public string? HostIp { get; set; }
|
||||
public IPAddress[]? HostIps { get; set; }
|
||||
/// <summary>
|
||||
/// The hosts port. Used the the host information send to clients on their request.
|
||||
/// </summary>
|
||||
public int HostPort { get; set; }
|
||||
/// <summary>
|
||||
/// The hosts echo port to try if a connection is possible.
|
||||
/// </summary>
|
||||
public int HostTryPort { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Net;
|
||||
|
||||
namespace LobbyServerDto
|
||||
{
|
||||
|
|
@ -13,13 +14,17 @@ namespace LobbyServerDto
|
|||
/// </summary>
|
||||
public Guid LobbyId { get; set; }
|
||||
/// <summary>
|
||||
/// The hosts ip, this could be an internal address
|
||||
/// The hosts ip addresses locally detected. Used the the host information send to clients on their request.
|
||||
/// </summary>
|
||||
[MaxLength(32)]
|
||||
public string? HostIp { get; set; }
|
||||
public IPAddress[]? HostIps { get; set; }
|
||||
/// <summary>
|
||||
/// The hosts port
|
||||
/// </summary>
|
||||
public int HostPort { get; set; }
|
||||
/// <summary>
|
||||
/// The hosts echo port to try if a connection is possible.
|
||||
/// </summary>
|
||||
public int HostTryPort { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Net;
|
||||
|
||||
namespace LobbyServerDto
|
||||
{
|
||||
|
|
@ -34,13 +35,17 @@ namespace LobbyServerDto
|
|||
[MaxLength(16)]
|
||||
public byte[]? PasswordSalt { get; set; }
|
||||
/// <summary>
|
||||
/// The hosts ip
|
||||
/// The hosts ip addresses locally detected. Used the the host information send to clients on their request.
|
||||
/// </summary>
|
||||
[MaxLength(32)]
|
||||
public string? HostIp { get; set; }
|
||||
public IPAddress[]? HostIps { get; set; }
|
||||
/// <summary>
|
||||
/// The hosts port
|
||||
/// The hosts port. Used the the host information send to clients on their request.
|
||||
/// </summary>
|
||||
public int HostPort { get; set; }
|
||||
/// <summary>
|
||||
/// The hosts echo port to try if a connection is possible.
|
||||
/// </summary>
|
||||
public int HostTryPort { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -74,6 +74,7 @@ namespace LobbyServerDto
|
|||
s.Append(@$"// <auto-generated />
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
|
||||
{(foundClass.Value.nameSpace is null ? null : $@"namespace {foundClass.Value.nameSpace}
|
||||
{{")}
|
||||
|
|
@ -113,6 +114,34 @@ using System.Text;
|
|||
var name = p.Identifier.ToString();
|
||||
switch(p.Type.ToString())
|
||||
{
|
||||
case "IPAddress[]":
|
||||
case "IPAddress[]?":
|
||||
s.Append($@"
|
||||
if ({name} != null)
|
||||
{{
|
||||
int maxLength = Math.Min({name}.Length, {maxLength});
|
||||
uint v = (uint)maxLength;
|
||||
while (v >= 0x80)
|
||||
{{
|
||||
buffer[offset++] = (byte)(v | 0x80);
|
||||
v >>= 7;
|
||||
}}
|
||||
buffer[offset++] = (byte)v;
|
||||
|
||||
for(int i = 0; i < maxLength; i++)
|
||||
{{
|
||||
var ipBuffer = {name}[i].GetAddressBytes();
|
||||
buffer[offset++] = (byte)ipBuffer.Length;
|
||||
Buffer.BlockCopy(ipBuffer, 0, buffer, offset, ipBuffer.Length);
|
||||
offset += ipBuffer.Length;
|
||||
}}
|
||||
}}
|
||||
else
|
||||
{{
|
||||
buffer[offset++] = 0;
|
||||
}}
|
||||
");
|
||||
break;
|
||||
case "bool":
|
||||
s.Append($@"
|
||||
buffer[offset++] = (byte)({name} == true ? 1 : 0);");
|
||||
|
|
@ -226,6 +255,42 @@ using System.Text;
|
|||
var name = p.Identifier.ToString();
|
||||
switch (p.Type.ToString())
|
||||
{
|
||||
case "IPAddress[]":
|
||||
case "IPAddress[]?":
|
||||
s.Append($@"
|
||||
{{
|
||||
int arrayLen = 0;
|
||||
int shift = 0;
|
||||
byte b;
|
||||
do {{
|
||||
// Check for a corrupted stream. Read a max of 5 bytes.
|
||||
// In a future version, add a DataFormatException.
|
||||
if (shift == 5 * 7) // 5 bytes max per Int32, shift += 7
|
||||
throw new FormatException(""Format_Bad7BitInt32"");
|
||||
|
||||
// ReadByte handles end of stream cases for us.
|
||||
b = buffer[offset++];
|
||||
arrayLen |= (b & 0x7F) << shift;
|
||||
shift += 7;
|
||||
}} while ((b & 0x80) != 0);
|
||||
|
||||
if(arrayLen > {maxLength})
|
||||
throw new FormatException(""Format_IPAddressArrayToLong"");
|
||||
|
||||
if(arrayLen > 0)
|
||||
{{
|
||||
ret.{name} = new IPAddress[arrayLen];
|
||||
for(int i=0; i < arrayLen; i++)
|
||||
{{
|
||||
var itemLen = buffer[offset++];
|
||||
if(itemLen > 16)
|
||||
throw new FormatException(""Format_IPAddressBytesArrayToLong"");
|
||||
ret.{name}[i] = new IPAddress(buffer.Slice(offset, itemLen).ToArray());
|
||||
offset += itemLen;
|
||||
}}
|
||||
}}
|
||||
}}");
|
||||
break;
|
||||
case "bool":
|
||||
s.Append($@"
|
||||
ret.{name} = buffer[offset++] == 0 ? false : true;");
|
||||
|
|
@ -236,10 +301,10 @@ using System.Text;
|
|||
break;
|
||||
case "Guid":
|
||||
s.Append($@"
|
||||
{{
|
||||
ret.{name} = new Guid(buffer.Slice(offset, 16).ToArray());
|
||||
offset+=16;
|
||||
}}");
|
||||
{{
|
||||
ret.{name} = new Guid(buffer.Slice(offset, 16).ToArray());
|
||||
offset+=16;
|
||||
}}");
|
||||
break;
|
||||
case "string":
|
||||
case "string?":
|
||||
|
|
@ -260,6 +325,9 @@ using System.Text;
|
|||
shift += 7;
|
||||
}} while ((b & 0x80) != 0);
|
||||
|
||||
if(strLen > {maxLength})
|
||||
throw new FormatException(""Format_StringToLong"");
|
||||
|
||||
if(strLen > 0)
|
||||
{{
|
||||
ret.{name} = Encoding.UTF8.GetString(buffer.Slice(offset, strLen).ToArray());
|
||||
|
|
@ -271,7 +339,7 @@ using System.Text;
|
|||
case "byte[]?":
|
||||
s.Append($@"
|
||||
{{
|
||||
int strLen = 0;
|
||||
int byteLen = 0;
|
||||
int shift = 0;
|
||||
byte b;
|
||||
do {{
|
||||
|
|
@ -282,14 +350,17 @@ using System.Text;
|
|||
|
||||
// ReadByte handles end of stream cases for us.
|
||||
b = buffer[offset++];
|
||||
strLen |= (b & 0x7F) << shift;
|
||||
byteLen |= (b & 0x7F) << shift;
|
||||
shift += 7;
|
||||
}} while ((b & 0x80) != 0);
|
||||
|
||||
if(strLen > 0)
|
||||
if(byteLen > {maxLength})
|
||||
throw new FormatException(""Format_ByteArrayToLong"");
|
||||
|
||||
if(byteLen > 0)
|
||||
{{
|
||||
ret.{name} = buffer.Slice(offset, strLen).ToArray();
|
||||
offset += strLen;
|
||||
ret.{name} = buffer.Slice(offset, byteLen).ToArray();
|
||||
offset += byteLen;
|
||||
}}
|
||||
}}");
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -16,10 +16,6 @@
|
|||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="bin\Release\netstandard2.0\\LobbyServerSourceGenerator.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
Loading…
Reference in New Issue