コード例 #1
0
ファイル: NetworkCore.cs プロジェクト: moien007/TeeSharp
        public static void SendControlMsg(UdpClient udpClient,
                                          IPEndPoint remote, int ack, bool useToken, uint token,
                                          ConnectionMessages msg, byte[] extra)
        {
            NetworkChunkConstruct packet;

            if (extra == null || extra.Length == 0)
            {
                packet = new NetworkChunkConstruct(1)
                {
                    DataSize = 1
                };
            }
            else
            {
                packet = new NetworkChunkConstruct(1 + extra.Length)
                {
                    DataSize = 1 + extra.Length
                };
                Buffer.BlockCopy(extra, 0, packet.Data, 1, extra.Length);
            }

            packet.NumChunks = 0;
            packet.Flags     = PacketFlags.CONTROL | (useToken ? PacketFlags.TOKEN : PacketFlags.NONE);
            packet.Ack       = ack;
            packet.Token     = token;
            packet.Data[0]   = (byte)msg;
            SendPacket(udpClient, remote, packet);
        }
コード例 #2
0
ファイル: NetworkCore.cs プロジェクト: moien007/TeeSharp
        public static void SendPacket(UdpClient udpClient, IPEndPoint endPoint,
                                      NetworkChunkConstruct packet)
        {
            var buffer         = new byte[MAX_PACKET_SIZE];
            var headerSize     = PACKET_HEADER_SIZE_WITHOUT_TOKEN;
            var compressedSize = -1;

            if (packet.Flags.HasFlag(PacketFlags.TOKEN))
            {
                headerSize = PACKET_HEADER_SIZE;
                packet.Token.ToByteArray(buffer, 3);
            }

            if (!packet.Flags.HasFlag(PacketFlags.CONTROL))
            {
                compressedSize = _huffman.Compress(packet.Data, 0, packet.DataSize,
                                                   buffer, headerSize, buffer.Length - headerSize);
            }

            //compressedSize = _huffman.Compress(packet.Data, 0, packet.DataSize,
            //    buffer, PACKET_HEADER_SIZE, buffer.Length - PACKET_HEADER_SIZE);

            int finalSize;

            if (compressedSize > 0 && compressedSize < packet.DataSize)
            {
                finalSize     = compressedSize;
                packet.Flags |= PacketFlags.COMPRESSION;
            }
            else
            {
                finalSize = packet.DataSize;
                Buffer.BlockCopy(packet.Data, 0, buffer, headerSize, packet.DataSize);
                packet.Flags &= ~PacketFlags.COMPRESSION;
            }

            finalSize += headerSize;
            buffer[0]  = (byte)((((int)packet.Flags << 2) & 0xfc) | ((packet.Ack >> 8) & 0x3));
            buffer[1]  = (byte)(packet.Ack & 0xff);
            buffer[2]  = (byte)packet.NumChunks;
            udpClient.Send(buffer, finalSize, endPoint);
        }
コード例 #3
0
        protected virtual void ConstructLegacyHandshake(
            NetworkChunkConstruct packet1,
            NetworkChunkConstruct packet2, uint legacyToken)
        {
            throw new NotImplementedException();

            packet1.Flags     = PacketFlags.CONTROL;
            packet1.Ack       = 0;
            packet1.NumChunks = 0;
            packet1.DataSize  = 1;
            packet1.Data[0]   = (byte)ConnectionMessages.CONNECTACCEPT;

            packet2.Flags     = PacketFlags.NONE;
            packet2.Ack       = 0;
            packet2.NumChunks = 0;
            packet2.DataSize  = 0;

            var packer = new Packer();

            packer.Reset();
            packer.AddInt(System(NetworkMessages.SV_MAP_CHANGE));
            packer.AddString("dm1");
            //packer.AddInt(4061503086);
            packer.AddInt(5805);
            AddChunk(packet2, 1, packer.Data(), packer.Size());

            packer.Reset();
            packer.AddInt(System(NetworkMessages.SV_CON_READY));
            AddChunk(packet2, 2, packer.Data(), packer.Size());

            for (var i = -2; i <= 0; i++)
            {
                packer.Reset();
                packer.AddInt(System(NetworkMessages.SV_SNAPEMPTY));
                packer.AddInt((int)(legacyToken + i));
                packer.AddInt((int)(i == -2 ? legacyToken + i + 1 : 1));
                AddChunk(packet2, -1, packer.Data(), packer.Size());
            }
        }
コード例 #4
0
        private void AddChunk(NetworkChunkConstruct packet, int sequence,
                              byte[] data, int dataSize)
        {
            Debug.Assert(packet.DataSize + NetworkCore.MAX_CHUNK_HEADER_SIZE +
                         dataSize <= packet.Data.Length, "too much data");

            var header = new NetworkChunkHeader
            {
                Flags    = sequence >= 0 ? ChunkFlags.VITAL : ChunkFlags.NONE,
                Size     = dataSize,
                Sequence = sequence >= 0 ? sequence : 0
            };

            var packetDataOffset = packet.DataSize;
            var chunkStartOffset = packetDataOffset;

            packetDataOffset = header.Pack(packet.Data, packetDataOffset);
            packet.DataSize += packetDataOffset - chunkStartOffset;

            Buffer.BlockCopy(data, 0, packet.Data, packetDataOffset, dataSize);
            packet.DataSize += dataSize;
            packet.NumChunks++;
        }
コード例 #5
0
 public ChunkReceiver()
 {
     ChunkConstruct = new NetworkChunkConstruct();
 }
コード例 #6
0
ファイル: NetworkCore.cs プロジェクト: moien007/TeeSharp
        /*
         *  Buffer.BlockCopy(shortSamples, 0, packetBytes, 0, shortSamples.Length * sizeof(short)).
         *      -And the same trick works in reverse as well:
         *  Buffer.BlockCopy(packetBytes, readPosition, shortSamples, 0, payloadLength);
         */

        public static bool UnpackPacket(byte[] buffer, int size,
                                        NetworkChunkConstruct packet)
        {
            if (size < PACKET_HEADER_SIZE_WITHOUT_TOKEN ||
                size > MAX_PACKET_SIZE)
            {
                Debug.Warning("network", $"packet too small, size={size}");
                return(false);
            }

            packet.Flags     = (PacketFlags)(buffer[0] >> 2);
            packet.Ack       = ((buffer[0] & 0x3) << 8) | buffer[1];
            packet.NumChunks = buffer[2];
            packet.DataSize  = size - PACKET_HEADER_SIZE_WITHOUT_TOKEN;
            packet.Token     = 0;

            if (packet.Flags.HasFlag(PacketFlags.CONNLESS))
            {
                if (size < DATA_OFFSET)
                {
                    Debug.Warning("network", $"connection less packet too small, size={size}");
                    return(false);
                }

                packet.Flags     = PacketFlags.CONNLESS;
                packet.Ack       = 0;
                packet.NumChunks = 0;
                packet.DataSize  = size - DATA_OFFSET;
                Buffer.BlockCopy(buffer, DATA_OFFSET, packet.Data, 0, packet.DataSize);
            }
            else
            {
                var dataStart = PACKET_HEADER_SIZE_WITHOUT_TOKEN;
                if (packet.Flags.HasFlag(PacketFlags.TOKEN))
                {
                    if (size < PACKET_HEADER_SIZE)
                    {
                        Debug.Warning("network", $"packet with token too small, {size}");
                        return(false);
                    }

                    dataStart        = PACKET_HEADER_SIZE;
                    packet.DataSize -= 4;
                    packet.Token     = buffer.ToUInt32(3);
                }

                if (packet.Flags.HasFlag(PacketFlags.COMPRESSION))
                {
                    packet.DataSize = _huffman.Decompress(buffer, dataStart, packet.DataSize,
                                                          packet.Data, 0, MAX_PAYLOAD);
                }
                else
                {
                    Buffer.BlockCopy(buffer, dataStart, packet.Data, 0, packet.DataSize);
                }

                /*if (flags.HasFlag(PacketFlags.COMPRESSION))
                 * {
                 *  if (flags.HasFlag(PacketFlags.CONTROL))
                 *      return false;
                 *
                 *  dataSize = _huffman.Decompress(buffer, PACKET_HEADER_SIZE,
                 *      dataSize, packet.Data, 0, MAX_PAYLOAD);
                 * }
                 * else
                 * {
                 *  Buffer.BlockCopy(buffer, PACKET_HEADER_SIZE, packet.Data, 0, dataSize);
                 * }
                 *
                 * packet.Flags = flags;
                 * packet.Ack = ack;
                 * packet.NumChunks = numChunks;
                 * packet.DataSize = dataSize;*/
            }

            if (packet.DataSize < 0)
            {
                Debug.Warning("network", "error during packet decoding");
                return(false);
            }

            return(true);
        }
コード例 #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);
                        }
                    }
                }
            }
        }
コード例 #8
0
 public abstract bool Feed(NetworkChunkConstruct packet, IPEndPoint remote);
コード例 #9
0
 public NetworkConnection()
 {
     Error = string.Empty;
     ResendQueueConstruct = new NetworkChunkConstruct();
     ResendQueue          = new Queue <NetworkChunkResend>();
 }
コード例 #10
0
        public override bool Feed(NetworkChunkConstruct packet, IPEndPoint remote)
        {
            if (packet.Flags.HasFlag(PacketFlags.RESEND))
            {
                Resend();
            }

            if (UseToken)
            {
                if (!packet.Flags.HasFlag(PacketFlags.TOKEN))
                {
                    if (!packet.Flags.HasFlag(PacketFlags.CONTROL) || packet.DataSize < 1)
                    {
                        Debug.Log("connection", "dropping msg without token");
                        return(false);
                    }

                    if (packet.Data[0] == (int)ConnectionMessages.CONNECTACCEPT)
                    {
                        if (!Config["ClAllowOldServers"])
                        {
                            Debug.Log("connection", "dropping connect+accept without token");
                            return(false);
                        }
                    }
                    else
                    {
                        Debug.Log("connection", "dropping ctrl msg without token");
                        return(false);
                    }
                }
                else
                {
                    if (packet.Token != Token)
                    {
                        Debug.Log("connection", $"dropping msg with invalid token, wanted={Token} got={packet.Token}");
                        return(false);
                    }
                }
            }

            if (Sequence >= PeerAck)
            {
                if (packet.Ack < PeerAck || packet.Ack > Sequence)
                {
                    return(false);
                }
            }
            else
            {
                if (packet.Ack < PeerAck && packet.Ack > Sequence)
                {
                    return(false);
                }
            }

            PeerAck = packet.Ack;
            if (packet.Flags.HasFlag(PacketFlags.RESEND))
            {
                Resend();
            }

            if (packet.Flags.HasFlag(PacketFlags.CONTROL))
            {
                var msg = (ConnectionMessages)packet.Data[0];
                if (msg == ConnectionMessages.CLOSE)
                {
                    if (!NetworkCore.CompareEndPoints(EndPoint, remote, true))
                    {
                        return(false);
                    }

                    State        = ConnectionState.ERROR;
                    RemoteClosed = true;

                    var reason = "";
                    if (packet.DataSize > 1)
                    {
                        reason = Encoding.UTF8.GetString(packet.Data, 1, Math.Clamp(packet.DataSize - 1, 1, 128));
                    }

                    Error = reason;
                    Debug.Log("connection", $"closed reason='{reason}'");
                    return(false);
                }
                else
                {
                    if (State == ConnectionState.CONNECT)
                    {
                        if (msg == ConnectionMessages.CONNECTACCEPT)
                        {
                            if (packet.Flags.HasFlag(PacketFlags.TOKEN))
                            {
                                if (packet.DataSize < 1 + 4)
                                {
                                    Debug.Log("connection", $"got short connect+accept, size={packet.DataSize}");
                                    return(true);
                                }

                                Token = packet.Data.ToUInt32(1);
                            }
                            else
                            {
                                UseToken = false;
                            }

                            LastReceiveTime = Time.Get();
                            State           = ConnectionState.ONLINE;
                            Debug.Log("connection", "got connect+accept, sending accept. connection online");
                        }
                    }
                }
            }

            if (State == ConnectionState.ONLINE)
            {
                LastReceiveTime = Time.Get();
                AckChunks(packet.Ack);
            }

            return(true);
        }