Esempio n. 1
0
        /**
         * If a packet has not been received from a client for timeout.value
         * seconds, drop the conneciton. Server frames are used instead of realtime
         * to avoid dropping the local client while debugging.
         *
         * When a client is normally dropped, the client_t goes into a zombie state
         * for a few seconds to make sure any final reliable message gets resent if
         * necessary.
         */
        public static void SV_CheckTimeouts()
        {
            int      i;
            client_t cl;
            int      droppoint;
            int      zombiepoint;

            droppoint   = (int)(SV_INIT.svs.realtime - 1000 * SV_MAIN.timeout.value);
            zombiepoint = (int)(SV_INIT.svs.realtime - 1000 * SV_MAIN.zombietime.value);

            for (i = 0; i < SV_MAIN.maxclients.value; i++)
            {
                cl = SV_INIT.svs.clients[i];

                // message times may be wrong across a changelevel
                if (cl.lastmessage > SV_INIT.svs.realtime)
                {
                    cl.lastmessage = SV_INIT.svs.realtime;
                }

                if (cl.state == Defines.cs_zombie && cl.lastmessage < zombiepoint)
                {
                    cl.state = Defines.cs_free;                     // can now be reused

                    continue;
                }

                if ((cl.state == Defines.cs_connected || cl.state == Defines.cs_spawned) && cl.lastmessage < droppoint)
                {
                    SV_SEND.SV_BroadcastPrintf(Defines.PRINT_HIGH, cl.name + " timed out\n");
                    SV_MAIN.SV_DropClient(cl);
                    cl.state = Defines.cs_free;                     // don't bother with zombie state
                }
            }
        }
Esempio n. 2
0
        /**
         * Initializes player structures after successfull connection.
         */
        public static void gotnewcl(int i, int challenge, string userinfo, netadr_t adr, int qport)
        {
            // build a new connection
            // accept the new client
            // this is the only place a client_t is ever initialized

            SV_MAIN.sv_client = SV_INIT.svs.clients[i];

            var edictnum = i + 1;

            var ent = GameBase.g_edicts[edictnum];

            SV_INIT.svs.clients[i].edict = ent;

            // save challenge for checksumming
            SV_INIT.svs.clients[i].challenge = challenge;

            // get the game a chance to reject this connection or modify the
            // userinfo
            if (!PlayerClient.ClientConnect(ent, userinfo))
            {
                if (Info.Info_ValueForKey(userinfo, "rejmsg") != null)
                {
                    Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\n" + Info.Info_ValueForKey(userinfo, "rejmsg") + "\nConnection refused.\n");
                }
                else
                {
                    Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\nConnection refused.\n");
                }

                Com.DPrintf("Game rejected a connection.\n");

                return;
            }

            // parse some info from the info strings
            SV_INIT.svs.clients[i].userinfo = userinfo;
            SV_MAIN.SV_UserinfoChanged(SV_INIT.svs.clients[i]);

            // send the connect packet to the client
            Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "client_connect");

            Netchan.Setup(Defines.NS_SERVER, SV_INIT.svs.clients[i].netchan, adr, qport);

            SV_INIT.svs.clients[i].state = Defines.cs_connected;

            SZ.Init(SV_INIT.svs.clients[i].datagram, SV_INIT.svs.clients[i].datagram_buf, SV_INIT.svs.clients[i].datagram_buf.Length);

            SV_INIT.svs.clients[i].datagram.allowoverflow = true;
            SV_INIT.svs.clients[i].lastmessage            = SV_INIT.svs.realtime;  // don't timeout
            SV_INIT.svs.clients[i].lastconnect            = SV_INIT.svs.realtime;
            Com.DPrintf("new client added.\n");
        }
Esempio n. 3
0
        /**
         * A connectionless packet has four leading 0xff characters to distinguish
         * it from a game channel. Clients that are in the game can still send
         * connectionless packets. It is used also by rcon commands.
         */
        public static void SV_ConnectionlessPacket()
        {
            string s;
            string c;

            MSG.BeginReading(Globals.net_message);
            MSG.ReadLong(Globals.net_message);             // skip the -1 marker

            s = MSG.ReadStringLine(Globals.net_message);

            Cmd.TokenizeString(s.ToCharArray(), false);

            c = Cmd.Argv(0);

            //for debugging purposes
            //Com.Printf("Packet " + NET.AdrToString(Netchan.net_from) + " : " + c + "\n");
            //Com.Printf(Lib.hexDump(net_message.data, 64, false) + "\n");

            if (0 == Lib.strcmp(c, "ping"))
            {
                SV_MAIN.SVC_Ping();
            }
            else if (0 == Lib.strcmp(c, "ack"))
            {
                SV_MAIN.SVC_Ack();
            }
            else if (0 == Lib.strcmp(c, "status"))
            {
                SV_MAIN.SVC_Status();
            }
            else if (0 == Lib.strcmp(c, "info"))
            {
                SV_MAIN.SVC_Info();
            }
            else if (0 == Lib.strcmp(c, "getchallenge"))
            {
                SV_MAIN.SVC_GetChallenge();
            }
            else if (0 == Lib.strcmp(c, "connect"))
            {
                SV_MAIN.SVC_DirectConnect();
            }
            else if (0 == Lib.strcmp(c, "rcon"))
            {
                SV_MAIN.SVC_RemoteCommand();
            }
            else
            {
                Com.Printf("bad connectionless packet from " + NET.AdrToString(Globals.net_from) + "\n");
                Com.Printf("[" + s + "]\n");
                Com.Printf("" + Lib.hexDump(Globals.net_message.data, 128, false));
            }
        }
Esempio n. 4
0
        /**
         * A client issued an rcon command. Shift down the remaining args Redirect
         * all printfs fromt hte server to the client.
         */
        public static void SVC_RemoteCommand()
        {
            int    i;
            string remaining;

            i = SV_MAIN.Rcon_Validate();

            var msg = Lib.CtoJava(Globals.net_message.data, 4, 1024);

            if (i == 0)
            {
                Com.Printf("Bad rcon from " + NET.AdrToString(Globals.net_from) + ":\n" + msg + "\n");
            }
            else
            {
                Com.Printf("Rcon from " + NET.AdrToString(Globals.net_from) + ":\n" + msg + "\n");
            }

            Com.BeginRedirect(
                Defines.RD_PACKET,
                SV_SEND.sv_outputbuf,
                Defines.SV_OUTPUTBUF_LENGTH,
                (target, buffer) => { SV_SEND.SV_FlushRedirect(target, Lib.stringToBytes(buffer.ToString())); }
                );

            if (0 == SV_MAIN.Rcon_Validate())
            {
                Com.Printf("Bad rcon_password.\n");
            }
            else
            {
                remaining = "";

                for (i = 2; i < Cmd.Argc(); i++)
                {
                    remaining += Cmd.Argv(i);
                    remaining += " ";
                }

                Cmd.ExecuteString(remaining);
            }

            Com.EndRedirect();
        }
Esempio n. 5
0
        /**
         * Called when each game quits, before Sys_Quit or Sys_Error.
         */
        public static void SV_Shutdown(string finalmsg, bool reconnect)
        {
            if (SV_INIT.svs.clients != null)
            {
                SV_MAIN.SV_FinalMessage(finalmsg, reconnect);
            }

            SV_MAIN.Master_Shutdown();

            SV_GAME.SV_ShutdownGameProgs();

            // free current level
            if (SV_INIT.sv.demofile != null)
            {
                try
                {
                    SV_INIT.sv.demofile.Close();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
            }

            SV_INIT.sv = new();

            Globals.server_state = SV_INIT.sv.state;

            if (SV_INIT.svs.demofile != null)
            {
                try
                {
                    SV_INIT.svs.demofile.Close();
                }
                catch (Exception e1)
                {
                    Console.WriteLine(e1);
                }
            }

            SV_INIT.svs = new();
        }
Esempio n. 6
0
        public static void Master_Heartbeat()
        {
            string @string;
            int    i;

            // pgm post3.19 change, cvar pointer not validated before dereferencing
            if (Globals.dedicated == null || 0 == Globals.dedicated.value)
            {
                return;                 // only dedicated servers send heartbeats
            }
            // pgm post3.19 change, cvar pointer not validated before dereferencing
            if (null == SV_MAIN.public_server || 0 == SV_MAIN.public_server.value)
            {
                return;                 // a private dedicated game
            }
            // check for time wraparound
            if (SV_INIT.svs.last_heartbeat > SV_INIT.svs.realtime)
            {
                SV_INIT.svs.last_heartbeat = SV_INIT.svs.realtime;
            }

            if (SV_INIT.svs.realtime - SV_INIT.svs.last_heartbeat < SV_MAIN.HEARTBEAT_SECONDS * 1000)
            {
                return;                 // not time to send yet
            }
            SV_INIT.svs.last_heartbeat = SV_INIT.svs.realtime;

            // send the same string that we would give for a status OOB command
            @string = SV_MAIN.SV_StatusString();

            // send to group master
            for (i = 0; i < Defines.MAX_MASTERS; i++)
            {
                if (SV_MAIN.master_adr[i].port != 0)
                {
                    Com.Printf("Sending heartbeat to " + NET.AdrToString(SV_MAIN.master_adr[i]) + "\n");
                    Netchan.OutOfBandPrint(Defines.NS_SERVER, SV_MAIN.master_adr[i], "heartbeat\n" + @string);
                }
            }
        }
Esempio n. 7
0
        /**
         * SV_Frame.
         */
        public static void SV_Frame(long msec)
        {
            Globals.time_before_game = Globals.time_after_game = 0;

            // if server is not active, do nothing
            if (!SV_INIT.svs.initialized)
            {
                return;
            }

            SV_INIT.svs.realtime += (int)msec;

            // keep the random time dependent
            Lib.rand();

            // check timeouts
            SV_MAIN.SV_CheckTimeouts();

            // get packets from clients
            SV_MAIN.SV_ReadPackets();

            //if (Game.g_edicts[1] !=null)
            //	Com.p("player at:" + Lib.vtofsbeaty(Game.g_edicts[1].s.origin ));

            // move autonomous things around if enough time has passed
            if (0 == SV_MAIN.sv_timedemo.value && SV_INIT.svs.realtime < SV_INIT.sv.time)
            {
                // never let the time get too far off
                if (SV_INIT.sv.time - SV_INIT.svs.realtime > 100)
                {
                    if (SV_MAIN.sv_showclamp.value != 0)
                    {
                        Com.Printf("sv lowclamp\n");
                    }

                    SV_INIT.svs.realtime = SV_INIT.sv.time - 100;
                }

                return;
            }

            // update ping based on the last known frame from all clients
            SV_MAIN.SV_CalcPings();

            // give the clients some timeslices
            SV_MAIN.SV_GiveMsec();

            // let everything in the world think and move
            SV_MAIN.SV_RunGameFrame();

            // send messages back to the clients that had packets read this frame
            SV_SEND.SV_SendClientMessages();

            // save the entire world state if recording a serverdemo
            SV_ENTS.SV_RecordDemoMessage();

            // send a heartbeat to the master if needed
            SV_MAIN.Master_Heartbeat();

            // clear teleport flags, etc for next frame
            SV_MAIN.SV_PrepWorldFrame();
        }
Esempio n. 8
0
        /**
         * Reads packets from the network or loopback.
         */
        public static void SV_ReadPackets()
        {
            int      i;
            client_t cl;
            var      qport = 0;

            while (NET.GetPacket(Defines.NS_SERVER, Globals.net_from, Globals.net_message))
            {
                // check for connectionless packet (0xffffffff) first
                if (Globals.net_message.data[0] == 255 &&
                    Globals.net_message.data[1] == 255 &&
                    Globals.net_message.data[2] == 255 &&
                    Globals.net_message.data[3] == 255)
                {
                    SV_MAIN.SV_ConnectionlessPacket();

                    continue;
                }

                // read the qport out of the message so we can fix up
                // stupid address translating routers
                MSG.BeginReading(Globals.net_message);
                MSG.ReadLong(Globals.net_message);                 // sequence number
                MSG.ReadLong(Globals.net_message);                 // sequence number
                qport = MSG.ReadShort(Globals.net_message) & 0xffff;

                // check for packets from connected clients
                for (i = 0; i < SV_MAIN.maxclients.value; i++)
                {
                    cl = SV_INIT.svs.clients[i];

                    if (cl.state == Defines.cs_free)
                    {
                        continue;
                    }

                    if (!NET.CompareBaseAdr(Globals.net_from, cl.netchan.remote_address))
                    {
                        continue;
                    }

                    if (cl.netchan.qport != qport)
                    {
                        continue;
                    }

                    if (cl.netchan.remote_address.port != Globals.net_from.port)
                    {
                        Com.Printf("SV_ReadPackets: fixing up a translated port\n");
                        cl.netchan.remote_address.port = Globals.net_from.port;
                    }

                    if (Netchan.Process(cl.netchan, Globals.net_message))
                    {
                        // this is a valid, sequenced packet, so process it
                        if (cl.state != Defines.cs_zombie)
                        {
                            cl.lastmessage = SV_INIT.svs.realtime;                             // don't timeout
                            SV_USER.SV_ExecuteClientMessage(cl);
                        }
                    }

                    break;
                }

                if (i != SV_MAIN.maxclients.value)
                {
                    continue;
                }
            }
        }
Esempio n. 9
0
        /**
         * A connection request that did not come from the master.
         */
        public static void SVC_DirectConnect()
        {
            string   userinfo;
            netadr_t adr;
            int      i;
            client_t cl;

            int version;
            int qport;

            adr = Globals.net_from;

            Com.DPrintf("SVC_DirectConnect ()\n");

            version = Lib.atoi(Cmd.Argv(1));

            if (version != Defines.PROTOCOL_VERSION)
            {
                Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\nServer is version " + Globals.VERSION + "\n");
                Com.DPrintf("    rejected connect from version " + version + "\n");

                return;
            }

            qport = Lib.atoi(Cmd.Argv(2));
            var challenge = Lib.atoi(Cmd.Argv(3));

            userinfo = Cmd.Argv(4);

            // force the IP key/value pair so the game can filter based on ip
            userinfo = Info.Info_SetValueForKey(userinfo, "ip", NET.AdrToString(Globals.net_from));

            // attractloop servers are ONLY for local clients
            if (SV_INIT.sv.attractloop)
            {
                if (!NET.IsLocalAddress(adr))
                {
                    Com.Printf("Remote connect in attract loop.  Ignored.\n");
                    Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\nConnection refused.\n");

                    return;
                }
            }

            // see if the challenge is valid
            if (!NET.IsLocalAddress(adr))
            {
                for (i = 0; i < Defines.MAX_CHALLENGES; i++)
                {
                    if (NET.CompareBaseAdr(Globals.net_from, SV_INIT.svs.challenges[i].adr))
                    {
                        if (challenge == SV_INIT.svs.challenges[i].challenge)
                        {
                            break;                             // good
                        }
                        Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\nBad challenge.\n");

                        return;
                    }
                }

                if (i == Defines.MAX_CHALLENGES)
                {
                    Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\nNo challenge for address.\n");

                    return;
                }
            }

            // if there is already a slot for this ip, reuse it
            for (i = 0; i < SV_MAIN.maxclients.value; i++)
            {
                cl = SV_INIT.svs.clients[i];

                if (cl.state == Defines.cs_free)
                {
                    continue;
                }

                if (NET.CompareBaseAdr(adr, cl.netchan.remote_address) && (cl.netchan.qport == qport || adr.port == cl.netchan.remote_address.port))
                {
                    if (!NET.IsLocalAddress(adr) && SV_INIT.svs.realtime - cl.lastconnect < (int)SV_MAIN.sv_reconnect_limit.value * 1000)
                    {
                        Com.DPrintf(NET.AdrToString(adr) + ":reconnect rejected : too soon\n");

                        return;
                    }

                    Com.Printf(NET.AdrToString(adr) + ":reconnect\n");

                    SV_MAIN.gotnewcl(i, challenge, userinfo, adr, qport);

                    return;
                }
            }

            // find a client slot
            //newcl = null;
            var index = -1;

            for (i = 0; i < SV_MAIN.maxclients.value; i++)
            {
                cl = SV_INIT.svs.clients[i];

                if (cl.state == Defines.cs_free)
                {
                    index = i;

                    break;
                }
            }

            if (index == -1)
            {
                Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\nServer is full.\n");
                Com.DPrintf("Rejected a connection.\n");

                return;
            }

            SV_MAIN.gotnewcl(index, challenge, userinfo, adr, qport);
        }
Esempio n. 10
0
 /**
  * Responds with all the info that qplug or qspy can see
  */
 public static void SVC_Status()
 {
     Netchan.OutOfBandPrint(Defines.NS_SERVER, Globals.net_from, "print\n" + SV_MAIN.SV_StatusString());
 }
Esempio n. 11
0
        /**
         * SV_InitGame.
         *
         * A brand new game has been started.
         */
        public static void SV_InitGame()
        {
            int     i;
            edict_t ent;

            //char idmaster[32];
            string idmaster;

            if (SV_INIT.svs.initialized)
            {
                // cause any connected clients to reconnect
                SV_MAIN.SV_Shutdown("Server restarted\n", true);
            }
            else
            {
                // make sure the client is down
                Cl.Drop();
                SCR.BeginLoadingPlaque();
            }

            // get any latched variable changes (maxclients, etc)
            Cvar.GetLatchedVars();

            SV_INIT.svs.initialized = true;

            if (Cvar.VariableValue("coop") != 0 && Cvar.VariableValue("deathmatch") != 0)
            {
                Com.Printf("Deathmatch and Coop both set, disabling Coop\n");
                Cvar.FullSet("coop", "0", Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH);
            }

            // dedicated servers are can't be single player and are usually DM
            // so unless they explicity set coop, force it to deathmatch
            if (Globals.dedicated.value != 0)
            {
                if (0 == Cvar.VariableValue("coop"))
                {
                    Cvar.FullSet("deathmatch", "1", Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH);
                }
            }

            // init clients
            if (Cvar.VariableValue("deathmatch") != 0)
            {
                if (SV_MAIN.maxclients.value <= 1)
                {
                    Cvar.FullSet("maxclients", "8", Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH);
                }
                else if (SV_MAIN.maxclients.value > Defines.MAX_CLIENTS)
                {
                    Cvar.FullSet("maxclients", "" + Defines.MAX_CLIENTS, Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH);
                }
            }
            else if (Cvar.VariableValue("coop") != 0)
            {
                if (SV_MAIN.maxclients.value <= 1 || SV_MAIN.maxclients.value > 4)
                {
                    Cvar.FullSet("maxclients", "4", Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH);
                }
            }
            else             // non-deathmatch, non-coop is one player
            {
                Cvar.FullSet("maxclients", "1", Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH);
            }

            SV_INIT.svs.spawncount = Lib.rand();
            SV_INIT.svs.clients    = new client_t[(int)SV_MAIN.maxclients.value];

            for (var n = 0; n < SV_INIT.svs.clients.Length; n++)
            {
                SV_INIT.svs.clients[n]             = new();
                SV_INIT.svs.clients[n].serverindex = n;
            }

            SV_INIT.svs.num_client_entities = (int)SV_MAIN.maxclients.value * Defines.UPDATE_BACKUP * 64;             //ok.

            SV_INIT.svs.client_entities = new entity_state_t[SV_INIT.svs.num_client_entities];

            for (var n = 0; n < SV_INIT.svs.client_entities.Length; n++)
            {
                SV_INIT.svs.client_entities[n] = new(null);
            }

            // init network stuff
            NET.ConfigServer(SV_MAIN.maxclients.value > 1);

            // heartbeats will always be sent to the id master
            SV_INIT.svs.last_heartbeat = -99999;             // send immediately
            idmaster = "192.246.40.37:" + Defines.PORT_MASTER;
            NET.StringToAdr(idmaster, SV_MAIN.master_adr[0]);

            // init game
            SV_GAME.SV_InitGameProgs();

            for (i = 0; i < SV_MAIN.maxclients.value; i++)
            {
                ent = GameBase.g_edicts[i + 1];
                SV_INIT.svs.clients[i].edict   = ent;
                SV_INIT.svs.clients[i].lastcmd = new();
            }
        }