diff --git a/Assets/NetworkLobbyClient/Runtime/LobbyClient.dll b/Assets/NetworkLobbyClient/Runtime/LobbyClient.dll
index ec17251..f867f38 100644
Binary files a/Assets/NetworkLobbyClient/Runtime/LobbyClient.dll and b/Assets/NetworkLobbyClient/Runtime/LobbyClient.dll differ
diff --git a/LobbyClient/LobbyClient.cs b/LobbyClient/LobbyClient.cs
index ab6c703..caf24bf 100644
--- a/LobbyClient/LobbyClient.cs
+++ b/LobbyClient/LobbyClient.cs
@@ -123,9 +123,25 @@ namespace Lobbies
_ = Task.Run(async () => { await tcpClient.Send(messageData, 0, len); bufferRental.Return(messageData); });
}
-
+ ///
+ /// This callback is called if the nat punch requires the game server/client udp sockets sends a packet to a server so that
+ /// the external mapped port by the firewall can be seen by the external point.
+ ///
+ /// The endpoint to send data to
+ /// The message byte buffer to send
+ /// Length of the data to send
public delegate void SendUdpMessageCallback(IPEndPoint remoteEndpoint, byte[] messageBuffer, int messageLength);
- public void RequestLobbyNatPunch(Guid lobbyId, string? password, SendUdpMessageCallback sendUdpCallback)
+
+ ///
+ /// This function requests a nat punch for this client from the game host. First the external port for our game client is detected by
+ /// sending a udp packet to the lobby server who then forwards the nat punch request to the host with the seen external ip and port.
+ /// The game host then sends a udp packet to the client to open it's nat bridge and when done sends a event to the client via the lobby server.
+ /// The client receives the external port and ip seen by the lobby server for the host and can connect to the host.
+ ///
+ /// The lobby to request a nat punch for
+ /// Optional password of lobby
+ /// A callback to send udp data if you have a udp game client ready and bound
+ public void RequestLobbyNatPunch(Guid lobbyId, string? password, SendUdpMessageCallback sendUdpToGetExternalPortMappingCallback)
{
byte[]? passwordHash = null;
if (!string.IsNullOrEmpty(password) && lobbyInformation.ContainsKey(lobbyId) && lobbyInformation[lobbyId].PasswordSalt != null)
@@ -133,7 +149,45 @@ namespace Lobbies
Task.Run(() =>
{
- QueryExternalIpAndPort(sendUdpCallback);
+ QueryExternalIpAndPort(sendUdpToGetExternalPortMappingCallback);
+ var lobbyRequestNatPunch = new LobbyRequestNatPunch()
+ {
+ LobbyId = lobbyId,
+ PasswordHash = passwordHash,
+ ClientIp = externalIp,
+ ClientPort = externalPort
+ };
+
+ byte[] messageData = bufferRental.Rent();
+ var len = lobbyRequestNatPunch.Serialize(messageData);
+ _ = Task.Run(async () => { await tcpClient.Send(messageData, 0, len); bufferRental.Return(messageData); });
+ });
+ }
+
+ ///
+ /// This function requests a nat punch for this client from the game host. First the external port for our game client is detected by
+ /// sending a udp packet to the lobby server who then forwards the nat punch request to the host with the seen external ip and port.
+ /// The game host then sends a udp packet to the client to open it's nat bridge and when done sends a event to the client via the lobby server.
+ /// The client receives the external port and ip seen by the lobby server for the host and can connect to the host.
+ ///
+ /// The lobby to request a nat punch for
+ /// Optional password of lobby
+ /// The port the game client will later use. We create a udp socket on it and send a packet to the lobby server to get the firewall to map that port for a short period of time
+ /// after that the udp client will be disposed
+ public void RequestLobbyNatPunch(Guid lobbyId, string? password, int port = 0)
+ {
+ byte[]? passwordHash = null;
+ if (!string.IsNullOrEmpty(password) && lobbyInformation.ContainsKey(lobbyId) && lobbyInformation[lobbyId].PasswordSalt != null)
+ passwordHash = PasswordHash.Hash(password, lobbyInformation[lobbyId].PasswordSalt!);
+
+ Task.Run(() =>
+ {
+ using (var udpEchoServer = new UdpEchoServer())
+ {
+ udpEchoServer.Start(port);
+ QueryExternalIpAndPort(udpEchoServer.Send);
+ }
+
var lobbyRequestNatPunch = new LobbyRequestNatPunch()
{
LobbyId = lobbyId,
diff --git a/LobbyClient/UdpEchoServer.cs b/LobbyClient/UdpEchoServer.cs
index db63b30..b00d937 100644
--- a/LobbyClient/UdpEchoServer.cs
+++ b/LobbyClient/UdpEchoServer.cs
@@ -40,6 +40,18 @@ namespace Lobbies
serverSocketV6.Send(magicRequest, magicRequest.Length, remoteEndpoint);
}
+ public void Send(IPEndPoint remoteEndpoint, byte[] messageData, int messageLength)
+ {
+ if (!running || serverSocketV4 == null || serverSocketV6 == null)
+ throw new Exception("Listener not running!");
+
+ for (int i = 0; i < 16; i++)
+ if (remoteEndpoint.AddressFamily == AddressFamily.InterNetwork)
+ serverSocketV4.Send(messageData, messageLength, remoteEndpoint);
+ else
+ serverSocketV6.Send(messageData, messageLength, remoteEndpoint);
+ }
+
///
/// Listen to requests and fire events
///
diff --git a/LobbyClientTest/Program.cs b/LobbyClientTest/Program.cs
index 8d044a0..16bed99 100644
--- a/LobbyClientTest/Program.cs
+++ b/LobbyClientTest/Program.cs
@@ -21,12 +21,12 @@ int myExternalPort = -1;
bool running = true;
bool connected = false;
-_ = Task.Run(async () =>
+_ = Task.Run(() =>
{
while (running)
{
foreach (var lobbyEvent in lobbyClient.ReadEvents(20))
- {
+ {
switch (lobbyEvent.EventType)
{
case LobbyClientEventTypes.Connected:
@@ -80,7 +80,7 @@ _ = Task.Run(async () =>
Console.WriteLine($"Direct connection to {result.IPAddress!.ToString()} possible, using direct connection!");
Console.WriteLine($"Connecting game client!");
fakeGameHost.Send(new IPEndPoint(result.IPAddress!, currentLobbyHostInfo!.HostPort), "Hello from Game Client!");
- Console.Write(">");
+ Console.Write(">");
}
else
{
@@ -130,9 +130,9 @@ _ = Task.Run(async () =>
var p = Console.GetCursorPosition();
Console.SetCursorPosition(0, p.Top);
- Console.WriteLine($"Received my external ip {seenExternalIpAndPort!.Ip}:{seenExternalIpAndPort.Port}");
+ Console.WriteLine($"Received my external ip {seenExternalIpAndPort!.Ip}:{seenExternalIpAndPort.Port}");
Console.Write(">");
-
+
connected = true;
}
}
@@ -146,7 +146,8 @@ _ = Task.Run(async () =>
_ = Task.Run(() =>
{
- lobbyClient.QueryExternalIpAndPort((remoteEndpoint, messageData, messageLength) => {
+ lobbyClient.QueryExternalIpAndPort((remoteEndpoint, messageData, messageLength) =>
+ {
fakeGameHost.Send(remoteEndpoint, messageData, messageLength);
});