예제 #1
0
        public void TickSocket(Socket sock, ref byte[] rd, ref int rdsf)
        {
            int avail = sock.Available;

            if (avail <= 0)
            {
                return;
            }
            if (avail + rdsf > MAX)
            {
                avail = MAX - rdsf;
                if (avail == 0)
                {
                    throw new Exception("Received overly massive packet?!");
                }
            }
            sock.Receive(rd, rdsf, avail, SocketFlags.None);
            rdsf += avail;
            if (rdsf < 5)
            {
                return;
            }
            while (true)
            {
                byte[] len_bytes = new byte[4];
                Array.Copy(rd, len_bytes, 4);
                int len = Utilities.BytesToInt(len_bytes);
                if (len + 5 > MAX)
                {
                    throw new Exception("Unreasonably huge packet!");
                }
                if (rdsf < 5 + len)
                {
                    return;
                }
                ServerToClientPacket packetID = (ServerToClientPacket)rd[4];
                byte[] data = new byte[len];
                Array.Copy(rd, 5, data, 0, len);
                byte[] rem_data = new byte[rdsf - (len + 5)];
                if (rem_data.Length > 0)
                {
                    Array.Copy(rd, len + 5, rem_data, 0, rem_data.Length);
                    Array.Copy(rem_data, rd, rem_data.Length);
                }
                rdsf -= len + 5;
                AbstractPacketIn packet;
                bool             asyncable = false;
                NetUsageType     usage;
                switch (packetID) // TODO: Packet registry!
                {
                case ServerToClientPacket.PING:
                    packet = new PingPacketIn();
                    usage  = NetUsageType.PINGS;
                    break;

                case ServerToClientPacket.YOUR_POSITION:
                    packet = new YourPositionPacketIn();
                    usage  = NetUsageType.PLAYERS;
                    break;

                case ServerToClientPacket.SPAWN_ENTITY:
                    packet = new SpawnEntityPacketIn();
                    usage  = NetUsageType.ENTITIES;
                    break;

                case ServerToClientPacket.PHYSICS_ENTITY_UPDATE:
                    packet = new PhysicsEntityUpdatePacketIn();
                    usage  = NetUsageType.ENTITIES;
                    break;

                case ServerToClientPacket.MESSAGE:
                    packet = new MessagePacketIn();
                    usage  = NetUsageType.GENERAL;
                    break;

                case ServerToClientPacket.CHARACTER_UPDATE:
                    packet = new CharacterUpdatePacketIn();
                    usage  = NetUsageType.PLAYERS;
                    break;

                case ServerToClientPacket.TOPS:
                    packet = new TopsPacketIn();
                    usage  = NetUsageType.CHUNKS;
                    break;

                case ServerToClientPacket.DESPAWN_ENTITY:
                    packet = new DespawnEntityPacketIn();
                    usage  = NetUsageType.ENTITIES;
                    break;

                case ServerToClientPacket.NET_STRING:
                    packet = new NetStringPacketIn();
                    usage  = NetUsageType.GENERAL;
                    break;

                case ServerToClientPacket.SPAWN_ITEM:
                    packet = new SpawnItemPacketIn();
                    usage  = NetUsageType.GENERAL;
                    break;

                case ServerToClientPacket.YOUR_STATUS:
                    packet = new YourStatusPacketIn();
                    usage  = NetUsageType.PLAYERS;
                    break;

                case ServerToClientPacket.ADD_JOINT:
                    packet = new AddJointPacketIn();
                    usage  = NetUsageType.ENTITIES;
                    break;

                case ServerToClientPacket.YOUR_EID:
                    packet = new YourEIDPacketIn();
                    usage  = NetUsageType.GENERAL;
                    break;

                case ServerToClientPacket.DESTROY_JOINT:
                    packet = new DestroyJointPacketIn();
                    usage  = NetUsageType.ENTITIES;
                    break;

                case ServerToClientPacket.TOPS_DATA:
                    packet = new TopsDataPacketIn();
                    usage  = NetUsageType.CHUNKS;
                    break;

                case ServerToClientPacket.PRIMITIVE_ENTITY_UPDATE:
                    packet = new PrimitiveEntityUpdatePacketIn();
                    usage  = NetUsageType.ENTITIES;
                    break;

                case ServerToClientPacket.ANIMATION:
                    packet = new AnimationPacketIn();
                    usage  = NetUsageType.PLAYERS;
                    break;

                case ServerToClientPacket.FLASHLIGHT:
                    packet = new FlashLightPacketIn();
                    usage  = NetUsageType.PLAYERS;
                    break;

                case ServerToClientPacket.REMOVE_ITEM:
                    packet = new RemoveItemPacketIn();
                    usage  = NetUsageType.GENERAL;
                    break;

                case ServerToClientPacket.SET_ITEM:
                    packet = new SetItemPacketIn();
                    usage  = NetUsageType.GENERAL;
                    break;

                case ServerToClientPacket.CVAR_SET:
                    packet = new CVarSetPacketIn();
                    usage  = NetUsageType.GENERAL;
                    break;

                case ServerToClientPacket.SET_HELD_ITEM:
                    packet = new SetHeldItemPacketIn();
                    usage  = NetUsageType.GENERAL;
                    break;

                case ServerToClientPacket.CHUNK_INFO:
                    packet = new ChunkInfoPacketIn();
                    usage  = NetUsageType.CHUNKS;
                    break;

                case ServerToClientPacket.BLOCK_EDIT:
                    packet = new BlockEditPacketIn();
                    usage  = NetUsageType.CHUNKS;
                    break;

                case ServerToClientPacket.SUN_ANGLE:
                    packet = new SunAnglePacketIn();
                    usage  = NetUsageType.EFFECTS;
                    break;

                case ServerToClientPacket.TELEPORT:
                    packet = new TeleportPacketIn();
                    usage  = NetUsageType.PLAYERS;
                    break;

                case ServerToClientPacket.OPERATION_STATUS:
                    packet = new OperationStatusPacketIn();
                    usage  = NetUsageType.GENERAL;
                    break;

                case ServerToClientPacket.PARTICLE_EFFECT:
                    packet = new ParticleEffectPacketIn();
                    usage  = NetUsageType.EFFECTS;
                    break;

                case ServerToClientPacket.PATH:
                    packet = new PathPacketIn();
                    usage  = NetUsageType.EFFECTS;
                    break;

                case ServerToClientPacket.CHUNK_FORGET:
                    packet = new ChunkForgetPacketIn();
                    usage  = NetUsageType.CHUNKS;
                    break;

                case ServerToClientPacket.FLAG_ENTITY:
                    packet = new FlagEntityPacketIn();
                    usage  = NetUsageType.ENTITIES;
                    break;

                case ServerToClientPacket.DEFAULT_SOUND:
                    packet = new DefaultSoundPacketIn();
                    usage  = NetUsageType.EFFECTS;
                    break;

                case ServerToClientPacket.GAIN_CONTROL_OF_VEHICLE:
                    packet = new GainControlOfVehiclePacketIn();
                    usage  = NetUsageType.ENTITIES;
                    break;

                case ServerToClientPacket.ADD_CLOUD:
                    packet = new AddCloudPacketIn();
                    usage  = NetUsageType.CLOUDS;
                    break;

                case ServerToClientPacket.REMOVE_CLOUD:
                    packet = new RemoveCloudPacketIn();
                    usage  = NetUsageType.CLOUDS;
                    break;

                case ServerToClientPacket.ADD_TO_CLOUD:
                    packet = new AddToCloudPacketIn();
                    usage  = NetUsageType.CLOUDS;
                    break;

                case ServerToClientPacket.YOUR_VEHICLE:
                    packet = new YourVehiclePacketIn();
                    usage  = NetUsageType.ENTITIES;
                    break;

                case ServerToClientPacket.SET_STATUS:
                    packet = new SetStatusPacketIn();
                    usage  = NetUsageType.PLAYERS;
                    break;

                case ServerToClientPacket.HIGHLIGHT:
                    packet = new HighlightPacketIn();
                    usage  = NetUsageType.EFFECTS;
                    break;

                case ServerToClientPacket.PLAY_SOUND:
                    packet = new PlaySoundPacketIn();
                    usage  = NetUsageType.EFFECTS;
                    break;

                case ServerToClientPacket.LOD_MODEL:
                    packet = new LODModelPacketIn();
                    usage  = NetUsageType.ENTITIES;
                    break;

                case ServerToClientPacket.LOSE_CONTROL_OF_VEHICLE:
                    packet = new LoseControlOfVehiclePacketIn();
                    usage  = NetUsageType.ENTITIES;
                    break;

                case ServerToClientPacket.JOINT_UPDATE:
                    packet = new JointUpdatePacketIn();
                    usage  = NetUsageType.ENTITIES;
                    break;

                default:
                    throw new Exception("Invalid packet ID: " + packetID);
                }
                UsagesThisSecond[(int)usage] += 5 + data.Length;
                UsagesTotal[(int)usage]      += 5 + data.Length;
                packet.TheClient              = TheClient;
                packet.ChunkN = sock == ChunkSocket;
                ServerToClientPacket pid = packetID;
                if (asyncable)
                {
                    // TODO: StartAsyncTask?
                    if (!packet.ParseBytesAndExecute(data))
                    {
                        SysConsole.Output(OutputType.ERROR, "Bad async packet (ID=" + pid + ") data!");
                    }
                }
                else
                {
                    TheClient.Schedule.ScheduleSyncTask(() =>
                    {
                        try
                        {
                            if (!packet.ParseBytesAndExecute(data))
                            {
                                SysConsole.Output(OutputType.ERROR, "Bad sync packet (ID=" + pid + ") data!");
                            }
                        }
                        catch (Exception ex)
                        {
                            if (ex is ThreadAbortException)
                            {
                                throw ex;
                            }
                            SysConsole.Output(OutputType.ERROR, "Bad sync packet (ID=" + pid + ") data: " + ex.ToString());
                        }
                    });
                }
            }
        }
예제 #2
0
        public void Tick(double delta)
        {
            try
            {
                Time += delta;
                if (!GotBase && Time >= MaxTime)
                {
                    throw new Exception("Connection timed out!");
                }
                int avail = PrimarySocket.Available;
                if (avail <= 0)
                {
                    return;
                }
                if (avail + recdsofar > MAX)
                {
                    avail = MAX - recdsofar;
                    if (avail == 0)
                    {
                        throw new Exception("Received overly massive packet?!");
                    }
                }
                PrimarySocket.Receive(recd, recdsofar, avail, SocketFlags.None);
                recdsofar += avail;
                if (recdsofar < 5)
                {
                    return;
                }
                if (trying)
                {
                    return;
                }
                if (GotBase)
                {
                    while (true)
                    {
                        byte[] len_bytes = new byte[4];
                        Array.Copy(recd, len_bytes, 4);
                        int len = Utilities.BytesToInt(len_bytes);
                        if (len + 5 > MAX)
                        {
                            throw new Exception("Unreasonably huge packet!");
                        }
                        if (recdsofar < 5 + len)
                        {
                            return;
                        }
                        ClientToServerPacket packetID = (ClientToServerPacket)recd[4];
                        byte[] data = new byte[len];
                        Array.Copy(recd, 5, data, 0, len);
                        byte[] rem_data = new byte[recdsofar - (len + 5)];
                        if (rem_data.Length > 0)
                        {
                            Array.Copy(recd, len + 5, rem_data, 0, rem_data.Length);
                            Array.Copy(rem_data, recd, rem_data.Length);
                        }
                        recdsofar -= len + 5;
                        AbstractPacketIn packet;
                        switch (packetID) // TODO: Packet registry?
                        {
                        case ClientToServerPacket.PING:
                            packet = new PingPacketIn();
                            break;

                        case ClientToServerPacket.KEYS:
                            packet = new KeysPacketIn();
                            break;

                        case ClientToServerPacket.COMMAND:
                            packet = new CommandPacketIn();
                            break;

                        case ClientToServerPacket.HOLD_ITEM:
                            packet = new HoldItemPacketIn();
                            break;

                        case ClientToServerPacket.DISCONNECT:
                            packet = new DisconnectPacketIn();
                            break;

                        case ClientToServerPacket.SET_STATUS:
                            packet = new SetStatusPacketIn();
                            break;

                        case ClientToServerPacket.PLEASE_REDEFINE:
                            packet = new PleaseRedefinePacketIn();
                            break;

                        default:
                            throw new Exception("Invalid packet ID: " + packetID);
                        }
                        packet.Chunk  = PE.ChunkNetwork == this;
                        packet.Player = PE;
                        DataReader dr = new DataReader(new DataStream(data));
                        PE.TheRegion.TheWorld.Schedule.ScheduleSyncTask(() =>
                        {
                            if (!packet.ParseBytesAndExecute(dr))
                            {
                                throw new Exception("Imperfect packet data for " + packetID);
                            }
                        });
                    }
                }
                else
                {
                    if (recd[0] == 'G' && recd[1] == 'E' && recd[2] == 'T' && recd[3] == ' ' && recd[4] == '/')
                    {
                        // HTTP GET
                        if (recd[recdsofar - 1] == '\n' && (recd[recdsofar - 2] == '\n' || recd[recdsofar - 3] == '\n'))
                        {
                            WebPage wp = new WebPage(TheServer, this);
                            wp.Init(FileHandler.encoding.GetString(recd, 0, recdsofar));
                            PrimarySocket.Send(wp.GetFullData());
                            PrimarySocket.Close(5);
                            Alive = false;
                        }
                    }
                    else if (recd[0] == 'P' && recd[1] == 'O' && recd[2] == 'S' && recd[3] == 'T' && recd[4] == ' ')
                    {
                        // HTTP POST
                        throw new NotImplementedException("HTTP POST not yet implemented");
                    }
                    else if (recd[0] == 'H' && recd[1] == 'E' && recd[2] == 'A' && recd[3] == 'D' && recd[4] == ' ')
                    {
                        // HTTP HEAD
                        if (recd[recdsofar - 1] == '\n' && (recd[recdsofar - 2] == '\n' || recd[recdsofar - 3] == '\n'))
                        {
                            WebPage wp = new WebPage(TheServer, this);
                            wp.Init(FileHandler.encoding.GetString(recd, 0, recdsofar));
                            PrimarySocket.Send(FileHandler.encoding.GetBytes(wp.GetHeaders()));
                            PrimarySocket.Close(5);
                            Alive = false;
                        }
                    }
                    else if (recd[0] == 'V' && recd[1] == 'O' && recd[2] == 'X' && recd[3] == 'p' && recd[4] == '_')
                    {
                        // VOXALIA ping
                        if (recd[recdsofar - 1] == '\n')
                        {
                            PrimarySocket.Send(FileHandler.encoding.GetBytes("SUCCESS\rVoxalia Server Online\n"));
                            PrimarySocket.Close(5);
                            Alive = false;
                        }
                    }
                    else if (recd[0] == 'V' && recd[1] == 'O' && recd[2] == 'X' && recd[3] == '_' && recd[4] == '_')
                    {
                        // VOXALIA connect
                        if (recd[recdsofar - 1] == '\n')
                        {
                            string   data   = FileHandler.encoding.GetString(recd, 6, recdsofar - 7);
                            string[] datums = data.SplitFast('\r');
                            if (datums.Length != 5)
                            {
                                throw new Exception("Invalid VOX__ connection details!");
                            }
                            string   name  = datums[0];
                            string   key   = datums[1];
                            string   host  = datums[2];
                            string   port  = datums[3];
                            string   rdist = datums[4];
                            string[] rds   = rdist.SplitFast(',');
                            if (rds.Length != 7)
                            {
                                throw new Exception("Invalid VOX__ connection details: RenderDist!");
                            }
                            if (!Utilities.ValidateUsername(name))
                            {
                                throw new Exception("Invalid connection - unreasonable username!");
                            }
                            trying = true;
                            TheServer.Schedule.StartAsyncTask(() =>
                            {
                                try
                                {
                                    CheckWebSession(name, key);
                                    TheServer.LoadedWorlds[0].Schedule.ScheduleSyncTask(() =>
                                    {
                                        // TODO: Additional details?
                                        // TODO: Choose a world smarter.
                                        PlayerEntity player = new PlayerEntity(TheServer.LoadedWorlds[0].MainRegion, this, name)
                                        {
                                            SessionKey          = key,
                                            Host                = host,
                                            Port                = port,
                                            IP                  = PrimarySocket.RemoteEndPoint.ToString(),
                                            ViewRadiusInChunks  = Math.Min(TheServer.CVars.g_maxrenderdist.ValueI, Math.Max(1, Utilities.StringToInt(rds[0]))),
                                            ViewRadExtra2       = Math.Min(TheServer.CVars.g_maxrenderdist.ValueI, Math.Max(0, Utilities.StringToInt(rds[1]))),
                                            ViewRadExtra2Height = Math.Min(TheServer.CVars.g_maxrenderdist.ValueI, Math.Max(0, Utilities.StringToInt(rds[2]))),
                                            ViewRadExtra5       = Math.Min(TheServer.CVars.g_maxrenderdist.ValueI, Math.Max(0, Utilities.StringToInt(rds[3]))),
                                            ViewRadExtra5Height = Math.Min(TheServer.CVars.g_maxrenderdist.ValueI, Math.Max(0, Utilities.StringToInt(rds[4]))),
                                            ViewRadExtra6       = Math.Min(TheServer.CVars.g_maxlodrenderdist.ValueI, Math.Max(0, Utilities.StringToInt(rds[5]))),
                                            ViewRadExtra15      = Math.Min(TheServer.CVars.g_maxlodrenderdist.ValueI, Math.Max(0, Utilities.StringToInt(rds[6])))
                                        };
                                        PE          = player;
                                        player.Host = host;
                                        TheServer.Schedule.ScheduleSyncTask(() =>
                                        {
                                            TheServer.PlayersWaiting.Add(player);
                                            PrimarySocket.Send(FileHandler.encoding.GetBytes("ACCEPT\n"));
                                        });
                                        GotBase   = true;
                                        recdsofar = 0;
                                        trying    = false;
                                    });
                                }
                                catch (Exception ex)
                                {
                                    TheServer.Schedule.ScheduleSyncTask(() =>
                                    {
                                        if (!Alive)
                                        {
                                            return;
                                        }
                                        PrimarySocket.Close();
                                        Utilities.CheckException(ex);
                                        SysConsole.Output(OutputType.WARNING, "Forcibly disconnected client: " + ex.GetType().Name + ": " + ex.Message);
                                        if (TheServer.CVars.s_debug.ValueB)
                                        {
                                            SysConsole.Output(ex);
                                        }
                                        Alive = false;
                                    });
                                }
                            });
                        }
                    }
                    else if (recd[0] == 'V' && recd[1] == 'O' && recd[2] == 'X' && recd[3] == 'c' && recd[4] == '_')
                    {
                        // VOXALIA chunk connect
                        if (recd[recdsofar - 1] == '\n')
                        {
                            string   data   = FileHandler.encoding.GetString(recd, 6, recdsofar - 7);
                            string[] datums = data.SplitFast('\r');
                            if (datums.Length != 4)
                            {
                                throw new Exception("Invalid VOXc_ connection details!");
                            }
                            string name = datums[0];
                            string key  = datums[1];
                            string host = datums[2];
                            string port = datums[3];
                            if (!Utilities.ValidateUsername(name))
                            {
                                throw new Exception("Invalid connection - unreasonable username!");
                            }
                            TheServer.Schedule.ScheduleSyncTask(() =>
                            {
                                PlayerEntity player = null;
                                for (int i = 0; i < TheServer.PlayersWaiting.Count; i++)
                                {
                                    if (TheServer.PlayersWaiting[i].Name == name && TheServer.PlayersWaiting[i].Host == host &&
                                        TheServer.PlayersWaiting[i].Port == port && TheServer.PlayersWaiting[i].SessionKey == key)
                                    {
                                        player = TheServer.PlayersWaiting[i];
                                        TheServer.PlayersWaiting.RemoveAt(i);
                                        break;
                                    }
                                }

                                PE = player ?? throw new Exception("Can't find player for VOXc_:" + name + ", " + host + ", " + port + ", " + key.Length);
                                player.ChunkNetwork = this;
                                PrimarySocket.Send(FileHandler.encoding.GetBytes("ACCEPT\n"));
                                // TODO: What if the world disappears during connect sequence?
                                player.LastPingByte           = 0;
                                player.LastCPingByte          = 0;
                                PrimarySocket.SendBufferSize *= 10;
                                SendPacket(new PingPacketOut(0));
                                player.Network.SendPacket(new PingPacketOut(0));
                                player.SendStatus();
                                GotBase   = true;
                                recdsofar = 0;
                                player.TheRegion.TheWorld.Schedule.ScheduleSyncTask(() =>
                                {
                                    player.InitPlayer();
                                    player.TheRegion.SpawnEntity(player);
                                });
                            });
                        }
                    }
                    else
                    {
                        throw new Exception("Unknown initial byte set!");
                    }
                }
            }
            catch (Exception ex)
            {
                PrimarySocket.Close();
                try
                {
                    if (PE != null)
                    {
                        PE.Kick("Internal exception.");
                    }
                }
                finally
                {
                    Utilities.CheckException(ex);
                    SysConsole.Output(OutputType.WARNING, "Forcibly disconnected client: " + ex.GetType().Name + ": " + ex.Message);
                    if (TheServer.CVars.s_debug.ValueB)
                    {
                        SysConsole.Output(ex);
                    }
                    Alive = false;
                }
            }
        }