Program.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. 
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Net;
  5. using System.Net.Sockets;
  6. using System.Text;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. namespace Peer2PeerMasterServer
  10. {
  11. class Program
  12. {
  13. static async Task Main(string[] args)
  14. {
  15. Console.WriteLine("Server Started");
  16. var registeredHosts = new Dictionary<IPEndPoint, AvailableGame>();
  17. int port = 6000;
  18. using var udp = new UdpClient(port);
  19. var cts = new CancellationTokenSource();
  20. Console.WriteLine($"Listening on UDP port {port}");
  21. Console.WriteLine("Press Ctrl+C to quit");
  22. Console.CancelKeyPress += (s, e) => {
  23. e.Cancel = true;
  24. cts.Cancel();
  25. };
  26. try
  27. {
  28. while (!cts.Token.IsCancellationRequested)
  29. {
  30. var receiveTask = udp.ReceiveAsync();
  31. var completedTask = await Task.WhenAny(receiveTask, Task.Delay(10, cts.Token));
  32. if (completedTask == receiveTask)
  33. {
  34. var result = receiveTask.Result;
  35. await HandleMessageAsync(result.Buffer, result.RemoteEndPoint, udp, registeredHosts);
  36. }
  37. }
  38. }
  39. catch (OperationCanceledException) { }
  40. finally
  41. {
  42. udp.Close();
  43. Console.WriteLine("Server shutting down");
  44. }
  45. }
  46. static async Task HandleMessageAsync(byte[] buffer, IPEndPoint sender, UdpClient udp, Dictionary<IPEndPoint, AvailableGame> registeredHosts)
  47. {
  48. if (buffer.Length == 0) return;
  49. var action = buffer[0];
  50. var ms = new System.IO.MemoryStream(buffer, 1, buffer.Length - 1);
  51. var reader = new System.IO.BinaryReader(ms, Encoding.UTF8);
  52. switch (action)
  53. {
  54. case 0: // Register new game
  55. if (!registeredHosts.ContainsKey(sender))
  56. {
  57. var game = new AvailableGame
  58. {
  59. Count = reader.ReadInt32(),
  60. GamerTag = reader.ReadString(),
  61. PrivateGamerSlots = reader.ReadInt32(),
  62. MaxGamers = reader.ReadInt32(),
  63. IsHost = reader.ReadBoolean(),
  64. InternalIP = ReadIPEndPoint(reader),
  65. ExternalIP = sender,
  66. Game = reader.ReadString()
  67. };
  68. registeredHosts.Add(game.ExternalIP, game);
  69. Console.WriteLine($"Got registration for host {game}");
  70. }
  71. break;
  72. case 1: // Client wants list of registered hosts
  73. string appid = reader.ReadString();
  74. Console.WriteLine($"Sending list of {registeredHosts.Count} hosts to client {sender}");
  75. foreach (var g1 in registeredHosts.Values)
  76. {
  77. if (g1.Game == appid)
  78. {
  79. var om = new System.IO.MemoryStream();
  80. var w = new System.IO.BinaryWriter(om, Encoding.UTF8);
  81. w.Write((byte)1); // response type
  82. w.Write(g1.Count);
  83. w.Write(g1.GamerTag);
  84. w.Write(g1.PrivateGamerSlots);
  85. w.Write(g1.MaxGamers);
  86. w.Write(g1.IsHost);
  87. WriteIPEndPoint(w, g1.InternalIP);
  88. WriteIPEndPoint(w, g1.ExternalIP);
  89. await udp.SendAsync(om.ToArray(), (int)om.Length, sender);
  90. }
  91. }
  92. break;
  93. case 2: // Client wants to connect to a specific host
  94. var clientInternal = ReadIPEndPoint(reader);
  95. var hostExternal = ReadIPEndPoint(reader);
  96. var token = reader.ReadString();
  97. Console.WriteLine($"{sender} requesting introduction to {hostExternal} (token {token})");
  98. foreach (var elist in registeredHosts.Values)
  99. {
  100. if (elist.ExternalIP.Equals(hostExternal))
  101. {
  102. Console.WriteLine("Sending introduction...");
  103. // Send introduction to both client and host
  104. var om = new System.IO.MemoryStream();
  105. var w = new System.IO.BinaryWriter(om, Encoding.UTF8);
  106. w.Write((byte)2); // response type
  107. WriteIPEndPoint(w, elist.InternalIP);
  108. WriteIPEndPoint(w, elist.ExternalIP);
  109. WriteIPEndPoint(w, clientInternal);
  110. WriteIPEndPoint(w, sender);
  111. w.Write(token);
  112. await udp.SendAsync(om.ToArray(), (int)om.Length, sender);
  113. }
  114. }
  115. break;
  116. case 3: // Remove host
  117. if (registeredHosts.ContainsKey(sender))
  118. {
  119. var game = registeredHosts[sender];
  120. var tag = reader.ReadString();
  121. var gamename = reader.ReadString();
  122. if (game.GamerTag == tag)
  123. {
  124. Console.WriteLine($"Remove for host {game.ExternalIP}");
  125. registeredHosts.Remove(game.ExternalIP);
  126. }
  127. }
  128. break;
  129. case 4: // Update host
  130. if (registeredHosts.ContainsKey(sender))
  131. {
  132. var game = registeredHosts[sender];
  133. var count = reader.ReadInt32();
  134. var tag = reader.ReadString();
  135. if (game.GamerTag == tag)
  136. {
  137. Console.WriteLine($"Update for host {game.ExternalIP}");
  138. game.Count = count;
  139. game.PrivateGamerSlots = reader.ReadInt32();
  140. game.MaxGamers = reader.ReadInt32();
  141. game.IsHost = reader.ReadBoolean();
  142. game.InternalIP = ReadIPEndPoint(reader);
  143. game.Game = reader.ReadString();
  144. }
  145. }
  146. break;
  147. }
  148. }
  149. static IPEndPoint ReadIPEndPoint(System.IO.BinaryReader reader)
  150. {
  151. var ipLen = reader.ReadInt32();
  152. var ipBytes = reader.ReadBytes(ipLen);
  153. var ip = new IPAddress(ipBytes);
  154. var port = reader.ReadInt32();
  155. return new IPEndPoint(ip, port);
  156. }
  157. static void WriteIPEndPoint(System.IO.BinaryWriter writer, IPEndPoint ep)
  158. {
  159. var ipBytes = ep.Address.GetAddressBytes();
  160. writer.Write(ipBytes.Length);
  161. writer.Write(ipBytes);
  162. writer.Write(ep.Port);
  163. }
  164. }
  165. class AvailableGame
  166. {
  167. public IPEndPoint ExternalIP { get; set; }
  168. public IPEndPoint InternalIP { get; set; }
  169. public int Count { get; set; }
  170. public string GamerTag { get; set; }
  171. public int PrivateGamerSlots { get; set; }
  172. public int MaxGamers { get; set; }
  173. public bool IsHost { get; set; }
  174. public string Game { get; set; }
  175. public override string ToString()
  176. {
  177. return $"External {ExternalIP}\n Internal {InternalIP} GamerTag {GamerTag}\n";
  178. }
  179. }
  180. }