Skip to content

Commit

Permalink
Added UDP hole punching, updated protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
Rackover committed Jul 30, 2020
1 parent c730955 commit d3d8390
Show file tree
Hide file tree
Showing 10 changed files with 326 additions and 59 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[*.cs]

# CS4014: Because this call is not awaited, execution of the current method continues before the call is completed
dotnet_diagnostic.CS4014.severity = suggestion
5 changes: 5 additions & 0 deletions Broadcast.sln
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BroadcastClient", "Broadcas
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BroadcastTester", "BroadcastTester\BroadcastTester.csproj", "{73A3F722-B492-4226-ACBE-45D7E525BB08}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C965B5AD-84D5-4F3C-A4C4-7F139431FEAA}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down
4 changes: 4 additions & 0 deletions Broadcast/Broadcast.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
<PublishReadyToRun Condition="'$(RuntimeIdentifier)'=='win-x64' or '$(RuntimeIdentifier)'=='win-x86'">true</PublishReadyToRun>
<PublishSingleFile Condition="'$(RuntimeIdentifier)'=='win-x64' or '$(RuntimeIdentifier)'=='win-x86'">true</PublishSingleFile>
</PropertyGroup>

<ItemGroup>
<None Include="..\.editorconfig" Link=".editorconfig" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Net.Primitives" Version="4.3.1" />
Expand Down
96 changes: 86 additions & 10 deletions Broadcast/Server.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
Expand All @@ -20,6 +21,8 @@ public class Server
Dictionary<Lobby, DateTime> lastHeardAbout = new Dictionary<Lobby, DateTime>();
Logger logger;

Dictionary<TcpClient, byte[]> pendingPunchRequests = new Dictionary<TcpClient, byte[]>();

public Server()
{
logger = new Logger(programName:"B_Server", outputToFile:true);
Expand All @@ -30,7 +33,8 @@ public Server()
{Networking.PROTOCOL_SUBMIT, HandleSubmit },
{Networking.PROTOCOL_QUERY, HandleQuery },
{Networking.PROTOCOL_DELETE, HandleDelete },
{Networking.PROTOCOL_HELLO, HandleHello }
{Networking.PROTOCOL_HELLO, HandleHello },
{Networking.PROTOCOL_PUNCH, HandlePunch }
};


Expand Down Expand Up @@ -68,12 +72,12 @@ public Server()
}
}
catch (IOException e) {
logger.Info("Client ["+clientId+"] had an IOException (see debug)");
logger.Info("Client ["+clientId+"] triggered an IOException (see debug)");
logger.Debug(e.ToString());
break;
}
catch (SocketException e) {
logger.Info("Client [" + clientId + "] had an SocketException (see debug)");
logger.Info("Client [" + clientId + "] triggered a SocketException (see debug)");
logger.Debug(e.ToString());
break;
}
Expand Down Expand Up @@ -121,8 +125,29 @@ void CleanLobbies()
void HandleHello(byte[] _, TcpClient client, uint clientId)
{
var helloMsg = Encoding.UTF8.GetBytes("Hello!");
client.GetStream().WriteData(helloMsg);
logger.Info("Sent a HELLO to client [{0}] ({1} bytes)".Format(clientId, helloMsg.Length));
var msg = new List<byte>() { Networking.PROTOCOL_HELLO};
msg.AddRange(helloMsg);

var byteMsg = msg.ToArray();
bool isRequestingPunch = false;

if (pendingPunchRequests.ContainsKey(client))
{
byteMsg = pendingPunchRequests[client];
pendingPunchRequests.Remove(client);
isRequestingPunch = true;
}

client.GetStream().WriteData(byteMsg);

if (isRequestingPunch)
{
logger.Info("Sent a PUNCH request client [{0}] ({1} bytes)".Format(clientId, byteMsg.Length));
}
else
{
logger.Info("Sent a HELLO to client [{0}] ({1} bytes)".Format(clientId, byteMsg.Length));
}
}

void HandleQuery(byte[] deserializable, TcpClient client, uint clientId)
Expand Down Expand Up @@ -175,7 +200,12 @@ void HandleSubmit(byte[] deserializable, TcpClient client, uint clientId)
logger.Debug("Auto-filled lobby submission address with v4:{1}/v6:{2} for client [{0}]".Format(clientId, string.Join(".", lobby.address), lobby.strAddress));
}

var index = lobbies.FindIndex(o => o.id == lobby.id || (o.port == lobby.port && o.address.IsSameAs(lobby.address) && o.strAddress == lobby.strAddress));
var index = lobbies.FindIndex(o =>
o.GetOwner() == client ||
o.id == lobby.id ||
(o.port == lobby.port && o.address.IsSameAs(lobby.address) && o.strAddress == lobby.strAddress)
);

uint uIntId = 0;
if (index > -1) {
uIntId = lobbies[index].id;
Expand All @@ -192,6 +222,7 @@ void HandleSubmit(byte[] deserializable, TcpClient client, uint clientId)
lastHeardAbout[lobby] = DateTime.UtcNow;
var id = BitConverter.GetBytes(uIntId);
client.GetStream().WriteData(id); // I return the ID of the lobby
lobby.SetOwner(client);

logger.Info("Finished processing lobby submission from client [{0}] (gave them ID {1} for their lobby)!".Format(clientId, uIntId));
}
Expand All @@ -200,12 +231,57 @@ void HandleDelete(byte[] deserializable, TcpClient client, uint clientId)
{
logger.Debug("Preparing to remove a lobby requested by client [{0}]".Format(clientId));

var targetLobby = BitConverter.ToUInt32(deserializable, 0);
var targetLobbyId = BitConverter.ToUInt32(deserializable, 0);
var targetLobby = lobbies.Find(o => o.id == targetLobbyId);

if (targetLobby == null)
{
logger.Info("Client [{0}] tried to remove lobby {1} but it does not exist. Doing nothing.".Format(clientId, targetLobbyId));
return;
}

if (targetLobby.GetOwner() != client)
{
logger.Info("Client [{0}] tried to remove lobby {1} but they're not the owner. Doing nothing.".Format(clientId, targetLobbyId));
return;
}

lock (lobbies) {
var removed = lobbies.RemoveAll(o => o.id == targetLobby);
logger.Debug("Removed {1} lobbies (every lobby with ID {2}) as requested by client [{0}]".Format(clientId, removed, targetLobby)) ;
var removed = lobbies.RemoveAll(o => o.id == targetLobby.id);
logger.Debug("Removed {1} lobbies (every lobby with ID {2}) as requested by client [{0}]".Format(clientId, removed, targetLobbyId)) ;
}
logger.Info("Finished removing lobby {1} as requested by client [{0}]".Format(clientId, targetLobbyId));
}

void HandlePunch(byte[] deserializable, TcpClient client, uint clientId)
{
logger.Debug("Preparing to punch a lobby for client [{0}]".Format(clientId));

var targetLobby = BitConverter.ToUInt32(deserializable, 0);
var lobby = lobbies.Find(o => o.id == targetLobby);

if (lobby == null)
{
logger.Warn("Asked to punch a NON-EXISTENT lobby {1} as requested by client [{0}]. Doing nothing.".Format(clientId, targetLobby));
return;
}
logger.Info("Finished removing lobby {1} as requested by client [{0}]".Format(clientId, targetLobby));

var portBytes = BitConverter.GetBytes(lobby.port);

var endpoint = ((IPEndPoint)lobby.GetOwner().Client.RemoteEndPoint);

pendingPunchRequests[lobby.GetOwner()] = new byte[]
{
Networking.PROTOCOL_PUNCH,
lobby.address[0],
lobby.address[1],
lobby.address[2],
lobby.address[3],
portBytes[0],
portBytes[1]
};

logger.Info("Added pending PUNCH paquet to {0}:{1} (the owner of lobby {2})".Format(endpoint.Address, endpoint.Port, lobby.id));
}
}
}
Loading

0 comments on commit d3d8390

Please sign in to comment.