public override bool Receive(ref Chunk packet, ref uint responseToken) { // TODO make multithreaded // https://docs.microsoft.com/ru-ru/dotnet/standard/io/how-to-use-named-pipes-for-network-interprocess-communication // https://blogs.msdn.microsoft.com/dotnet/2018/07/09/system-io-pipelines-high-performance-io-in-net/ while (true) { if (ChunkReceiver.FetchChunk(ref packet)) { return(true); } if (UdpClient.Available <= 0) { return(false); } var endPoint = default(IPEndPoint); byte[] data; try { data = UdpClient.Receive(ref endPoint); } catch { continue; } if (data.Length == 0) { continue; } if (!NetworkHelper.UnpackPacket(data, data.Length, ChunkReceiver.ChunkConstruct)) { continue; } if (NetworkBan.IsBanned(endPoint, out var banReason)) { NetworkHelper.SendConnectionMsg(UdpClient, endPoint, ChunkReceiver.ChunkConstruct.ResponseToken, 0, ConnectionMessages.Close, banReason); continue; } var freeSlot = -1; var foundSlot = -1; var sameIps = 0; for (var i = 0; i < Connections.Count; i++) { if (Connections[i].State == ConnectionState.Offline && freeSlot < 0) { freeSlot = i; } if (Connections[i].State != ConnectionState.Offline && Connections[i].EndPoint.Compare(endPoint, comparePorts: false)) { sameIps++; if (Connections[i].EndPoint.Port != endPoint.Port) { continue; } if (Connections[i].Feed(ChunkReceiver.ChunkConstruct, endPoint)) { if (ChunkReceiver.ChunkConstruct.DataSize > 0) { if (ChunkReceiver.ChunkConstruct.Flags.HasFlag(PacketFlags.Connless)) { packet = new Chunk() { Flags = SendFlags.Connless, EndPoint = endPoint, ClientId = i, DataSize = ChunkReceiver.ChunkConstruct.DataSize, Data = ChunkReceiver.ChunkConstruct.Data }; responseToken = TokenHelper.TokenNone; return(true); } ChunkReceiver.Start(endPoint, Connections[i], i); } } foundSlot = i; break; } } if (foundSlot >= 0) { continue; } var accept = TokenManager.ProcessMessage(endPoint, ChunkReceiver.ChunkConstruct); if (accept <= 0) { continue; } if (ChunkReceiver.ChunkConstruct.Flags.HasFlag(PacketFlags.Control)) { if (ChunkReceiver.ChunkConstruct.Data[0] == (int)ConnectionMessages.Connect) { if (sameIps >= Config.MaxClientsPerIp) { NetworkHelper.SendConnectionMsg(UdpClient, endPoint, ChunkReceiver.ChunkConstruct.ResponseToken, 0, ConnectionMessages.Close, $"Only {Config.MaxClientsPerIp} players with the same IP are allowed"); return(false); } if (freeSlot >= 0) { Connections[freeSlot].SetToken(ChunkReceiver.ChunkConstruct.Token); Connections[freeSlot].Feed(ChunkReceiver.ChunkConstruct, endPoint); OnClientConnected(freeSlot); continue; } NetworkHelper.SendConnectionMsg(UdpClient, endPoint, ChunkReceiver.ChunkConstruct.ResponseToken, 0, ConnectionMessages.Close, "This server is full"); return(false); } if (ChunkReceiver.ChunkConstruct.Data[0] == (int)ConnectionMessages.Token) { TokenCache.AddToken(endPoint, ChunkReceiver.ChunkConstruct.ResponseToken, TokenFlags.ResponseOnly); } } else if (ChunkReceiver.ChunkConstruct.Flags.HasFlag(PacketFlags.Connless)) { packet = new Chunk() { Flags = SendFlags.Connless, ClientId = -1, EndPoint = endPoint, DataSize = ChunkReceiver.ChunkConstruct.DataSize, Data = ChunkReceiver.ChunkConstruct.Data, }; responseToken = ChunkReceiver.ChunkConstruct.ResponseToken; return(true); } } }
public override bool Receive(ref Chunk packet, ref uint responseToken) { while (true) { if (ChunkReceiver.FetchChunk(ref packet)) { return(true); } if (UdpClient.Available <= 0) { return(false); } var endPoint = default(IPEndPoint); byte[] data; try { data = UdpClient.Receive(ref endPoint); } catch { continue; } if (data.Length == 0) { continue; } if (!NetworkHelper.UnpackPacket(data, data.Length, ChunkReceiver.ChunkConstruct)) { continue; } if (Connection.State != ConnectionState.Offline && Connection.State != ConnectionState.Error && Connection.EndPoint.Compare(endPoint, true)) { if (Connection.Feed(ChunkReceiver.ChunkConstruct, endPoint)) { if (!ChunkReceiver.ChunkConstruct.Flags.HasFlag(PacketFlags.Connless)) { ChunkReceiver.Start(endPoint, Connection, 0); } } } else { var accept = TokenManager.ProcessMessage(endPoint, ChunkReceiver.ChunkConstruct); if (accept == 0) { continue; } if (ChunkReceiver.ChunkConstruct.Flags.HasFlag(PacketFlags.Control)) { if (ChunkReceiver.ChunkConstruct.Data[0] == (int)ConnectionMessages.Token) { TokenCache.AddToken(endPoint, ChunkReceiver.ChunkConstruct.ResponseToken, TokenFlags.AllowBroadcast | TokenFlags.ResponseOnly); } } else if (ChunkReceiver.ChunkConstruct.Flags.HasFlag(PacketFlags.Connless) && accept != -1) { packet = new Chunk { ClientId = -1, Flags = SendFlags.Connless, EndPoint = endPoint, DataSize = ChunkReceiver.ChunkConstruct.DataSize, Data = ChunkReceiver.ChunkConstruct.Data, }; responseToken = ChunkReceiver.ChunkConstruct.ResponseToken; return(true); } } } }
public override void AddToken(IPEndPoint endPoint, uint token) { TokenCache.AddToken(endPoint, token, TokenFlags.None); }