public override void SendPacketConnless(IPEndPoint endPoint, byte[] data, int dataSize, SendCallbackData callbackData = null) { var token = GetToken(endPoint); if (token != TokenHelper.TokenNone) { NetworkHelper.SendPacketConnless(Client, endPoint, token, TokenManager.GenerateToken(endPoint), data, dataSize); } else { FetchToken(endPoint); var now = Time.Get(); var info = new ConnlessPacketInfo(dataSize) { EndPoint = endPoint, Expiry = now + Time.Freq() * TokenHelper.TokenCachePacketExpiry, LastTokenRequest = now, }; if (callbackData != null) { info.SendCallback = callbackData.Callback; info.CallbackContext = callbackData.Context; callbackData.TrackID = info.TrackID; } else { info.SendCallback = null; info.CallbackContext = null; } Buffer.BlockCopy(data, 0, info.Data, 0, dataSize); ConnlessPacketList.Add(info); } }
/* * [5c22fc7f][unpack]: 1 * [5c22fc7f][test]: token=4294967295 res=3569422453 * [5c22fc7f][test]: bytes=520 accept 0 1 * [5c22fc7f][unpack]: 8 * [5c22fc7f][test]: token=157418043 res=4168385603 * [5c22fc7f][check]: cur=157418043 seed=1257701721 * [5c22fc7f][test]: bytes=22 accept 1 8 * */ public override int ProcessMessage(IPEndPoint endPoint, ChunkConstruct packet) { var broadcastResponse = false; // TODO ODODODO if (packet.Token != TokenHelper.TokenNone && !CheckToken(endPoint, packet.Token, packet.ResponseToken, ref broadcastResponse)) { return(0); } var verified = packet.Token != TokenHelper.TokenNone; var tokenMessage = packet.Flags.HasFlag(PacketFlags.Control) && packet.Data[0] == (int)ConnectionMessages.Token; if (packet.Flags.HasFlag(PacketFlags.Connless)) { return((verified && !broadcastResponse) ? 1 : 0); } if (!tokenMessage) { return((verified && !broadcastResponse) ? 1 : 0); } if (verified) { return(broadcastResponse ? -1 : 1); } if (packet.DataSize >= TokenHelper.TokenRequestDataSize) { NetworkHelper.SendConnectionMsgWithToken(Client, endPoint, packet.ResponseToken, 0, ConnectionMessages.Token, GenerateToken(endPoint), false); } return(0); }
public override bool Open(NetworkServerConfig config) { if (!NetworkHelper.UdpClient(config.BindEndPoint, out var socket)) { return(false); } UdpClient = socket; TokenManager.Init(UdpClient); TokenCache.Init(UdpClient, TokenManager); Config = CheckConfig(config); Connections = new BaseNetworkConnection[Config.MaxClients]; for (var i = 0; i < Connections.Count; i++) { Connections[i] = Kernel.Get <BaseNetworkConnection>(); Connections[i].Init(UdpClient, Config.ConnectionConfig); } return(true); }
public override bool FetchChunk(ref Chunk packet) { var header = new ChunkHeader(); var end = ChunkConstruct.DataSize; while (true) { if (!Valid || CurrentChunk >= ChunkConstruct.NumChunks) { Clear(); return(false); } var dataOffset = 0; for (var i = 0; i < CurrentChunk; i++) { dataOffset = header.Unpack(ChunkConstruct.Data, dataOffset); dataOffset += header.Size; } dataOffset = header.Unpack(ChunkConstruct.Data, dataOffset); CurrentChunk++; if (dataOffset + header.Size > end) { Clear(); return(false); } if (header.Flags.HasFlag(ChunkFlags.Vital)) { if (header.Sequence == (Connection.Ack + 1) % NetworkHelper.MaxSequence) { Connection.Ack = (Connection.Ack + 1) % NetworkHelper.MaxSequence; } else { if (NetworkHelper.IsSequenceInBackroom(header.Sequence, Connection.Ack)) { continue; } Debug.Log("connection", $"asking for resend {header.Sequence} {(Connection.Ack + 1) % NetworkHelper.MaxSequence}"); Connection.SignalResend(); continue; } } packet = new Chunk { ClientId = ClientId, EndPoint = EndPoint, Flags = header.Flags.HasFlag(ChunkFlags.Vital) ? SendFlags.Vital : SendFlags.None, DataSize = header.Size, Data = new byte[header.Size] }; Buffer.BlockCopy(ChunkConstruct.Data, dataOffset, packet.Data, 0, header.Size); return(true); } }
public override void FetchToken(IPEndPoint endPoint) { NetworkHelper.SendConnectionMsgWithToken(Client, endPoint, TokenHelper.TokenNone, 0, ConnectionMessages.Token, TokenManager.GenerateToken(endPoint), 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 Send(Chunk packet, uint token = TokenHelper.TokenNone, SendCallbackData callbackData = null) { if (packet.Flags.HasFlag(SendFlags.Connless)) { if (packet.DataSize > NetworkHelper.MaxPayload) { Debug.Warning("network", $"packet payload too big, length={packet.DataSize}"); return; } if (packet.ClientId == -1 && Connection.EndPoint != null && packet.EndPoint.Compare(Connection.EndPoint, true)) { packet.ClientId = 0; } if (token != TokenHelper.TokenNone) { NetworkHelper.SendPacketConnless(UdpClient, packet.EndPoint, token, TokenManager.GenerateToken(packet.EndPoint), packet.Data, packet.DataSize); } else { if (packet.ClientId == -1) { TokenCache.SendPacketConnless(packet.EndPoint, packet.Data, packet.DataSize, callbackData); } else { Debug.Assert(packet.ClientId == 0, "errornous client id"); Connection.SendPacketConnless(packet.Data, packet.DataSize); } } } else { if (packet.DataSize + NetworkHelper.MaxChunkHeaderSize >= NetworkHelper.MaxPayload) { Debug.Warning("network", $"chunk payload too big, length={packet.DataSize} dropping chunk"); return; } Debug.Assert(packet.ClientId == 0, "errornous client id"); var flags = ChunkFlags.None; if (packet.Flags.HasFlag(SendFlags.Vital)) { flags = ChunkFlags.Vital; } Connection.QueueChunk(flags, packet.Data, packet.DataSize); if (packet.Flags.HasFlag(SendFlags.Flush)) { Connection.Flush(); } } }
public override void SendPacketConnless(byte[] data, int dataSize) { NetworkHelper.SendPacketConnless(UdpClient, EndPoint, PeerToken, Token, data, dataSize); }
protected override void SendConnectionMsgWithToken(ConnectionMessages msg) { LastSendTime = Time.Get(); NetworkHelper.SendConnectionMsgWithToken(UdpClient, EndPoint, PeerToken, 0, msg, Token, true); }
protected override void SendConnectionMsg(ConnectionMessages msg, string extra) { LastSendTime = Time.Get(); NetworkHelper.SendConnectionMsg(UdpClient, EndPoint, PeerToken, Ack, msg, extra); }
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 Send(Chunk packet, uint token = TokenHelper.TokenNone) { if (packet.Flags.HasFlag(SendFlags.Connless)) { if (packet.DataSize >= NetworkHelper.MaxPayload) { Debug.Warning("netserver", $"packet payload too big ({packet.DataSize}). dropping packet"); return(false); } if (packet.ClientId == -1) { for (var i = 0; i < Connections.Count; i++) { if (Connections[i].State != ConnectionState.Offline && Connections[i].EndPoint != null && Connections[i].EndPoint.Compare(packet.EndPoint, comparePorts: true)) { packet.ClientId = i; break; } } } if (token != TokenHelper.TokenNone) { NetworkHelper.SendPacketConnless(UdpClient, packet.EndPoint, token, TokenManager.GenerateToken(packet.EndPoint), packet.Data, packet.DataSize); } else { if (packet.ClientId == -1) { TokenCache.SendPacketConnless(packet.EndPoint, packet.Data, packet.DataSize); } else { Debug.Assert(packet.ClientId >= 0 && packet.ClientId < Connections.Count, "errornous client id"); Connections[packet.ClientId].SendPacketConnless(packet.Data, packet.DataSize); } } } else { if (packet.DataSize + NetworkHelper.MaxChunkHeaderSize >= NetworkHelper.MaxPayload) { Debug.Warning("netserver", $"packet payload too big ({packet.DataSize}). dropping packet"); return(false); } Debug.Assert(packet.ClientId >= 0 && packet.ClientId < Connections.Count, "errornous client id"); var flags = packet.Flags.HasFlag(SendFlags.Vital) ? ChunkFlags.Vital : ChunkFlags.None; if (Connections[packet.ClientId].QueueChunk(flags, packet.Data, packet.DataSize)) { if (packet.Flags.HasFlag(SendFlags.Flush)) { Connections[packet.ClientId].Flush(); } } else { Drop(packet.ClientId, "Error sending data"); } } return(true); }