diff --git a/Lidgren.Network/NetIncomingMessageType.cs b/Lidgren.Network/NetIncomingMessageType.cs index c2f39e5..043832b 100644 --- a/Lidgren.Network/NetIncomingMessageType.cs +++ b/Lidgren.Network/NetIncomingMessageType.cs @@ -41,6 +41,6 @@ namespace Lidgren.Network DebugMessage = 1 << 8, // Data (string) WarningMessage = 1 << 9, // Data (string) ErrorMessage = 1 << 10, // Data (string) - NatIntroduction = 1 << 11, // IPEndPoint + NatIntroductionSuccess = 1 << 11, // Data (as passed to master server) } } diff --git a/Lidgren.Network/NetMessageType.cs b/Lidgren.Network/NetMessageType.cs index 55ff633..506ea0c 100644 --- a/Lidgren.Network/NetMessageType.cs +++ b/Lidgren.Network/NetMessageType.cs @@ -48,8 +48,8 @@ namespace Lidgren.Network Disconnect = 8, Discovery = 9, DiscoveryResponse = 10, - NatPunchMessage = 11, - NatIntroduction = 12, + NatPunchMessage = 11, // send between peers + NatIntroduction = 12, // send to master server } internal enum NetMessageType : byte diff --git a/Lidgren.Network/NetNatIntroduction.cs b/Lidgren.Network/NetNatIntroduction.cs index 31d3938..0861629 100644 --- a/Lidgren.Network/NetNatIntroduction.cs +++ b/Lidgren.Network/NetNatIntroduction.cs @@ -6,44 +6,94 @@ namespace Lidgren.Network { public partial class NetPeer { - public void Introduce(IPEndPoint host, IPEndPoint client) + public void Introduce( + IPEndPoint hostInternal, + IPEndPoint hostExternal, + IPEndPoint clientInternal, + IPEndPoint clientExternal, + string token) { // send message to client - NetOutgoingMessage msg = CreateMessage(10); + NetOutgoingMessage msg = CreateMessage(10 + token.Length + 1); msg.Write(false); msg.WritePadBits(); - msg.Write(host); - SendUnconnectedLibraryMessage(msg, NetMessageLibraryType.NatIntroduction, client); + msg.Write(hostInternal); + msg.Write(hostExternal); + msg.Write(token); + SendUnconnectedLibraryMessage(msg, NetMessageLibraryType.NatIntroduction, clientExternal); // send message to host - msg = CreateMessage(10); + msg = CreateMessage(10 + token.Length + 1); msg.Write(true); msg.WritePadBits(); - msg.Write(client); - SendUnconnectedLibraryMessage(msg, NetMessageLibraryType.NatIntroduction, host); + msg.Write(clientInternal); + msg.Write(clientExternal); + msg.Write(token); + SendUnconnectedLibraryMessage(msg, NetMessageLibraryType.NatIntroduction, hostExternal); } - private void HandleNatIntroduction(int ptr, IPEndPoint senderEndpoint) + /// + /// Called when host/client receives a NatIntroduction message from a master server + /// + private void HandleNatIntroduction(int ptr) { VerifyNetworkThread(); // read intro NetIncomingMessage tmp = new NetIncomingMessage(m_receiveBuffer, 1000); // never mind length tmp.Position = (ptr * 8); - bool isHost = (tmp.ReadByte() == 0 ? false : true); - IPEndPoint ep = tmp.ReadIPEndpoint(); + byte hostByte = tmp.ReadByte(); + IPEndPoint remoteInternal = tmp.ReadIPEndpoint(); + IPEndPoint remoteExternal = tmp.ReadIPEndpoint(); + string token = tmp.ReadString(); + bool isHost = (hostByte != 0); - // quickly; send nat punch - NetOutgoingMessage punch = CreateMessage(0); - SendUnconnectedLibraryMessage(punch, NetMessageLibraryType.NatPunchMessage, ep); + NetOutgoingMessage punch; - if (!isHost) + if (!isHost && m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.NatIntroductionSuccess) == false) + return; // no need to punch - we're not listening for nat intros! + + // send internal punch + punch = CreateMessage(1); + punch.Write(hostByte); + if (hostByte == 0) { - NetIncomingMessage intro = CreateIncomingMessage(NetIncomingMessageType.NatIntroduction, 10); - intro.Write(ep); - intro.m_senderEndpoint = senderEndpoint; - ReleaseMessage(intro); + // only client needs to send token + punch.Write(token); } + SendUnconnectedLibraryMessage(punch, NetMessageLibraryType.NatPunchMessage, remoteInternal); + + // send external punch + punch = CreateMessage(1); + punch.Write(hostByte); + if (hostByte == 0) + { + // only client needs to send token + punch.Write(token); + } + SendUnconnectedLibraryMessage(punch, NetMessageLibraryType.NatPunchMessage, remoteExternal); + } + + /// + /// Called when receiving a NatPunchMessage from a remote endpoint + /// + private void HandleNatPunch(int ptr, IPEndPoint senderEndpoint) + { + NetIncomingMessage tmp = new NetIncomingMessage(m_receiveBuffer, 1000); // never mind length + tmp.Position = (ptr * 8); + + byte hostByte = tmp.ReadByte(); + if (hostByte != 0) + return; // don't alert hosts about nat punch successes; only clients + string token = tmp.ReadString(); + + // + // Release punch success to client; enabling him to Connect() to msg.SenderIPEndPoint if token is ok + // + NetIncomingMessage punchSuccess = CreateIncomingMessage(NetIncomingMessageType.NatIntroductionSuccess, 10); + punchSuccess.m_senderEndpoint = senderEndpoint; + punchSuccess.Write(token); + ReleaseMessage(punchSuccess); } } } diff --git a/Lidgren.Network/NetPeer.Internal.cs b/Lidgren.Network/NetPeer.Internal.cs index a5da5d6..357297f 100644 --- a/Lidgren.Network/NetPeer.Internal.cs +++ b/Lidgren.Network/NetPeer.Internal.cs @@ -422,7 +422,7 @@ namespace Lidgren.Network // Handle nat introduction // if (libType == NetMessageLibraryType.NatIntroduction) - HandleNatIntroduction(ptr, senderEndpoint); + HandleNatIntroduction(ptr); // // Handle Discovery diff --git a/Samples/MasterServerSample/MasterServer/Program.cs b/Samples/MasterServerSample/MasterServer/Program.cs index 02b3706..70f35ef 100644 --- a/Samples/MasterServerSample/MasterServer/Program.cs +++ b/Samples/MasterServerSample/MasterServer/Program.cs @@ -16,7 +16,7 @@ namespace MasterServer { static void Main(string[] args) { - List registeredHosts = new List(); + List registeredHosts = new List(); NetPeerConfiguration config = new NetPeerConfiguration("masterserver"); @@ -42,24 +42,48 @@ namespace MasterServer { case MasterServerMessageType.RegisterHost: // It's a host wanting to register its presence - registeredHosts.Add(msg.SenderEndpoint); + IPEndPoint[] eps = new IPEndPoint[] + { + msg.ReadIPEndpoint(), // internal + msg.SenderEndpoint // external + }; + registeredHosts.Add(eps); break; case MasterServerMessageType.RequestHostList: // It's a client wanting a list of registered hosts - foreach (IPEndPoint ep in registeredHosts) + foreach (IPEndPoint[] ep in registeredHosts) { // send registered host to client NetOutgoingMessage om = peer.CreateMessage(); - om.Write(ep); + om.Write(ep[0]); + om.Write(ep[1]); peer.SendUnconnectedMessage(om, msg.SenderEndpoint); } break; case MasterServerMessageType.RequestIntroduction: - // It's a client wanting to connect to a specific host - IPEndPoint rh = msg.ReadIPEndpoint(); - peer.Introduce(rh, msg.SenderEndpoint); + // It's a client wanting to connect to a specific (external) host + IPEndPoint clientInternal = msg.ReadIPEndpoint(); + IPEndPoint hostExternal = msg.ReadIPEndpoint(); + string token = msg.ReadString(); + + // find in list + foreach (IPEndPoint[] elist in registeredHosts) + { + if (elist[1].Equals(hostExternal)) + { + // found in list - introduce client and host to eachother + peer.Introduce( + elist[0], // host internal + elist[1], // host external + clientInternal, // client internal + msg.SenderEndpoint, // client external + token // request token + ); + break; + } + } break; } break;