Example #1
0
        public override void Send(NetworkChunk packet)
        {
            if (packet.DataSize > NetworkCore.MAX_PAYLOAD)
            {
                Debug.Warning("network", $"packet payload too big, length={packet.DataSize}");
                return;
            }

            if (packet.Flags.HasFlag(SendFlags.CONNLESS))
            {
                NetworkCore.SendPacketConnless(UdpClient, packet.EndPoint,
                                               packet.Data, packet.DataSize);
                return;
            }

            Debug.Assert(packet.ClientId == 0, "wrong 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();
            }
        }
Example #2
0
        public override bool Receive(out NetworkChunk packet)
        {
            while (true)
            {
                if (ChunkReceiver.FetchChunk(out packet))
                {
                    return(true);
                }

                if (UdpClient.Available <= 0)
                {
                    return(false);
                }

                var    remote = (IPEndPoint)null;
                byte[] data;

                try
                {
                    data = UdpClient.Receive(ref remote);
                }
                catch
                {
                    continue;
                }

                if (data.Length == 0)
                {
                    continue;
                }

                if (!NetworkCore.UnpackPacket(data, data.Length, ChunkReceiver.ChunkConstruct))
                {
                    continue;
                }

                if (ChunkReceiver.ChunkConstruct.Flags.HasFlag(PacketFlags.CONNLESS))
                {
                    packet = new NetworkChunk
                    {
                        ClientId = -1,
                        Flags    = SendFlags.CONNLESS,
                        EndPoint = remote,
                        DataSize = ChunkReceiver.ChunkConstruct.DataSize,
                        Data     = ChunkReceiver.ChunkConstruct.Data
                    };

                    return(true);
                }

                if (Connection.Feed(ChunkReceiver.ChunkConstruct, remote))
                {
                    ChunkReceiver.Start(remote, Connection, 0);
                }
            }
        }
Example #3
0
 public abstract void Send(NetworkChunk packet);
Example #4
0
 public abstract bool Receive(out NetworkChunk packet);
Example #5
0
        public override bool FetchChunk(out NetworkChunk packet)
        {
            var header = new NetworkChunkHeader();
            var end    = ChunkConstruct.DataSize;

            while (true)
            {
                if (!Valid || CurrentChunk >= ChunkConstruct.NumChunks)
                {
                    Clear();
                    packet = null;
                    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();
                    packet = null;
                    return(false);
                }

                if (Connection != null && header.Flags.HasFlag(ChunkFlags.VITAL))
                {
                    if (Connection.UnknownAck ||
                        header.Sequence == (Connection.Ack + 1) % NetworkCore.MAX_SEQUENCE)
                    {
                        Connection.UnknownAck = false;
                        Connection.Ack        = (Connection.Ack + 1) % NetworkCore.MAX_SEQUENCE;
                    }
                    else
                    {
                        if (NetworkCore.IsSeqInBackroom(header.Sequence, Connection.Ack))
                        {
                            continue;
                        }

                        Debug.Log("connection",
                                  $"asking for resend {header.Sequence} {(Connection.Ack + 1) % NetworkCore.MAX_SEQUENCE}");
                        Connection.SignalResend();
                        continue;
                    }
                }

                packet = new NetworkChunk
                {
                    ClientId = ClientId,
                    EndPoint = EndPoint,
                    Flags    = (SendFlags)header.Flags,
                    DataSize = header.Size,
                    Data     = new byte[header.Size]
                };

                Buffer.BlockCopy(ChunkConstruct.Data, dataOffset, packet.Data, 0, header.Size);
                return(true);
            }
        }
Example #6
0
 public abstract bool FetchChunk(out NetworkChunk packet);
Example #7
0
        public override bool Receive(out NetworkChunk packet)
        {
            while (true)
            {
                if (ChunkReceiver.FetchChunk(out packet))
                {
                    return(true);
                }

                if (UdpClient.Available <= 0)
                {
                    return(false);
                }

                var    remote = (IPEndPoint)null;
                byte[] data;

                try
                {
                    data = UdpClient.Receive(ref remote);
                }
                catch
                {
                    continue;
                }

                if (data.Length <= 0)
                {
                    continue;
                }

                if (!NetworkCore.UnpackPacket(data, data.Length, ChunkReceiver.ChunkConstruct))
                {
                    continue;
                }

                var useToken = false;
                var token    = (uint)0;

                if (ChunkReceiver.ChunkConstruct.Flags.HasFlag(PacketFlags.TOKEN))
                {
                    useToken = true;
                    token    = ChunkReceiver.ChunkConstruct.Token;
                }
                else if (ChunkReceiver.ChunkConstruct.Flags.HasFlag(PacketFlags.CONTROL) &&
                         ChunkReceiver.ChunkConstruct.Data[0] == (int)ConnectionMessages.CONNECT &&
                         ChunkReceiver.ChunkConstruct.DataSize >= 1 + 512)
                {
                    useToken = true;
                    token    = ChunkReceiver.ChunkConstruct.Data.ToUInt32(5);
                }

                if (NetworkBan.IsBanned(remote, out var reason))
                {
                    NetworkCore.SendControlMsg(UdpClient, remote, 0, useToken, token,
                                               ConnectionMessages.CLOSE, reason);
                    continue;
                }

                if (ChunkReceiver.ChunkConstruct.Flags.HasFlag(PacketFlags.CONNLESS))
                {
                    packet = new NetworkChunk
                    {
                        ClientId = -1,
                        Flags    = SendFlags.CONNLESS,
                        EndPoint = remote,
                        DataSize = ChunkReceiver.ChunkConstruct.DataSize,
                        Data     = ChunkReceiver.ChunkConstruct.Data
                    };

                    return(true);
                }

                var clientId = FindSlot(remote, true);

                if (ChunkReceiver.ChunkConstruct.Flags.HasFlag(PacketFlags.CONTROL) &&
                    ChunkReceiver.ChunkConstruct.Data[0] == (int)ConnectionMessages.CONNECT)
                {
                    if (clientId != -1)
                    {
                        continue;
                    }

                    if (ChunkReceiver.ChunkConstruct.DataSize >= 1 + 512)
                    {
                        var connectAccept = new byte[4];
                        GetToken(remote).ToByteArray(connectAccept, 0);
                        NetworkCore.SendControlMsg(UdpClient, remote, 0, true, token,
                                                   ConnectionMessages.CONNECTACCEPT, connectAccept);
                        Debug.Log("netserver", "got connect, sending connect+accept challenge");
                    }
                    else if (Config["SvAllowOldClients"].AsBoolean() && string.IsNullOrWhiteSpace(Config["Password"].AsString()))
                    {
                        if (LegacyRateLimit())
                        {
                            Debug.Log("netserver", "dropping legacy connect due to ratelimit");
                            continue;
                        }

                        var packets = new NetworkChunkConstruct[]
                        {
                            new NetworkChunkConstruct(),
                            new NetworkChunkConstruct(),
                        };
                        var legacyToken = GetLegacyToken(remote);

                        ConstructLegacyHandshake(packets[0], packets[1], legacyToken);
                        for (var i = 0; i < 2; i++)
                        {
                            NetworkCore.SendPacket(UdpClient, remote, packets[i]);
                        }
                        Debug.Log("netserver", "got legacy connect, sending legacy challenge");
                    }
                    else
                    {
                        Debug.Log("netserver", $"dropping short connect packet, size={ChunkReceiver.ChunkConstruct.DataSize}");
                    }
                }
                else
                {
                    if (clientId == -1)
                    {
                        if (!useToken || !IsCorrectToken(remote, token))
                        {
                            if (!useToken && Config["SvAllowOldClients"].AsBoolean())
                            {
                                ChunkReceiver.Start(remote, null, -1);
                                var chunk   = new NetworkChunk();
                                var correct = false;

                                while (ChunkReceiver.FetchChunk(out chunk))
                                {
                                    if (DecodeLegacyHandShake(chunk.Data, chunk.DataSize, out var legacyToken))
                                    {
                                        if (IsCorrectLegacyToken(remote, legacyToken))
                                        {
                                            correct = true;
                                            break;
                                        }
                                    }
                                }

                                ChunkReceiver.Clear();

                                if (!correct)
                                {
                                    continue;
                                }
                            }
                            else
                            {
                                Debug.Log("netserver",
                                          !useToken
                                        ? "dropping packet with missing token"
                                        : $"dropping packet with invalid token, token={token}");
                                continue;
                            }
                        }

                        var sameIps = 0;

                        for (var i = 0; i < Connections.Length; i++)
                        {
                            if (Connections[i].State == ConnectionState.OFFLINE)
                            {
                                if (clientId < 0)
                                {
                                    clientId = i;
                                }
                                continue;
                            }

                            if (!NetworkCore.CompareEndPoints(Connections[i].EndPoint, remote, false))
                            {
                                continue;
                            }

                            sameIps++;
                            if (sameIps >= ServerConfig.MaxClientsPerIp)
                            {
                                NetworkCore.SendControlMsg(UdpClient, remote, 0, useToken, token, ConnectionMessages.CLOSE,
                                                           $"Only {ServerConfig.MaxClientsPerIp} players with the same IP are allowed");
                                return(false);
                            }
                        }

                        if (clientId < 0)
                        {
                            for (var i = 0; i < Connections.Length; i++)
                            {
                                if (Connections[i].State == ConnectionState.OFFLINE)
                                {
                                    clientId = i;
                                    break;
                                }
                            }
                        }

                        if (clientId < 0)
                        {
                            NetworkCore.SendControlMsg(UdpClient, remote, 0, useToken, token,
                                                       ConnectionMessages.CLOSE, "This server is full");
                            return(false);
                        }

                        if (useToken)
                        {
                            Connections[clientId].Accept(remote, token);
                        }
                        else
                        {
                            Connections[clientId].AcceptLegacy(remote);
                        }

                        NewClientCallback?.Invoke(clientId, !useToken);
                        if (!useToken)
                        {
                            continue;
                        }

                        Connections[clientId].Feed(ChunkReceiver.ChunkConstruct, remote);
                    }

                    if (Connections[clientId].Feed(ChunkReceiver.ChunkConstruct, remote))
                    {
                        if (ChunkReceiver.ChunkConstruct.DataSize != 0)
                        {
                            ChunkReceiver.Start(remote, Connections[clientId], clientId);
                        }
                    }
                }
            }
        }