r10673 - packages/trunk/alien-arena/debian/patches
Michael Gilbert
gilbert-guest at alioth.debian.org
Fri Jan 8 02:18:43 UTC 2010
Author: gilbert-guest
Date: 2010-01-08 02:18:43 +0000 (Fri, 08 Jan 2010)
New Revision: 10673
Added:
packages/trunk/alien-arena/debian/patches/debian-changes-7.33-1
Log:
include changes file
Added: packages/trunk/alien-arena/debian/patches/debian-changes-7.33-1
===================================================================
--- packages/trunk/alien-arena/debian/patches/debian-changes-7.33-1 (rev 0)
+++ packages/trunk/alien-arena/debian/patches/debian-changes-7.33-1 2010-01-08 02:18:43 UTC (rev 10673)
@@ -0,0 +1,1485 @@
+Description: Upstream changes introduced in version 7.33-1
+ This patch has been created by dpkg-source during the package build.
+ Here's the last changelog entry, hopefully it gives details on why
+ those changes were made:
+ .
+ alien-arena (7.33-1) unstable; urgency=high
+ .
+ * New upstream release with many feature enhancments
+ (closes: #592770, #467387, #437461).
+ * Fixes CVE-2009-3637 remote arbitrary code execution (closes: #552038).
+ * Eliminated bashisms from launcher scripts (closes: #530040).
+ * Add support for new upstream file naming scheme to watch file
+ (closes: #513659).
+ * Server browser is now in-game.
+ * Updated to use source format version 3.0.
+ * Config directory has been moved to '~/.config/alien-arena' to adhere
+ to the latest freedesktop standards.
+ * Updated to standards version 3.8.3.
+ .
+ The person named in the Author field signed this changelog entry.
+Author: Michael Gilbert <michael.s.gilbert at gmail.com>
+Bug-Debian: http://bugs.debian.org/437461
+Bug-Debian: http://bugs.debian.org/467387
+Bug-Debian: http://bugs.debian.org/513659
+Bug-Debian: http://bugs.debian.org/530040
+Bug-Debian: http://bugs.debian.org/552038
+Bug-Debian: http://bugs.debian.org/592770
+
+---
+The information above should follow the Patch Tagging Guidelines, please
+checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
+are templates for supplementary fields that you might want to add:
+
+Origin: <vendor|upstream|other>, <url of original patch>
+Bug: <url in upstream bugtracker>
+Bug-Debian: http://bugs.debian.org/<bugnumber>
+Forwarded: <no|not-needed|url proving that it has been forwarded>
+Reviewed-By: <name and email of someone who approved the patch>
+Last-Update: <YYYY-MM-DD>
+
+--- /dev/null
++++ alien-arena-7.33/out
+@@ -0,0 +1,11 @@
++--- source/server/sv_main.c.bak 2010-01-07 20:53:47.000000000 -0500
+++++ source/server/sv_main.c 2010-01-07 20:54:07.000000000 -0500
++@@ -166,7 +166,7 @@
++ #endif
++ //s = NET_AdrToString ( cl->netchan.remote_address); //fuck you Luigi
++ Com_sprintf (player, sizeof(player), "%i %i \"%s\" \"127.0.0.1\"\n",
++- cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, nametxt);
+++ cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, nametxt, "suppressed");
++ playerLength = strlen(player);
++ if (statusLength + playerLength >= sizeof(status) )
++ break; // can't hold any more
+--- /dev/null
++++ alien-arena-7.33/sv_main.c.new
+@@ -0,0 +1,1428 @@
++/*
++Copyright (C) 1997-2001 Id Software, Inc.
++
++This program is free software; you can redistribute it and/or
++modify it under the terms of the GNU General Public License
++as published by the Free Software Foundation; either version 2
++of the License, or (at your option) any later version.
++
++This program is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++
++See the GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with this program; if not, write to the Free Software
++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++
++*/
++
++#include "server.h"
++
++master_sv_t master_status[MAX_MASTERS]; // status of master servers
++
++client_t *sv_client; // current client
++
++cvar_t *sv_paused;
++cvar_t *sv_timedemo;
++
++cvar_t *sv_enforcetime;
++
++cvar_t *timeout; // seconds without any message
++cvar_t *zombietime; // seconds to sink messages after disconnect
++
++cvar_t *rcon_password; // password for remote server commands
++
++cvar_t *allow_download;
++cvar_t *allow_download_players;
++cvar_t *allow_download_models;
++cvar_t *allow_download_sounds;
++cvar_t *allow_download_maps;
++
++cvar_t *sv_airaccelerate;
++
++cvar_t *sv_joustmode;
++
++cvar_t *sv_noreload; // don't reload level state when reentering
++
++cvar_t *maxclients; // FIXME: rename sv_maxclients
++cvar_t *sv_showclamp;
++
++cvar_t *hostname;
++cvar_t *public_server; // should heartbeats be sent
++
++cvar_t *sv_reconnect_limit; // minimum seconds between connect messages
++
++cvar_t *sv_ratelimit_status; //new security measures
++cvar_t *sv_iplimit;
++
++cvar_t *sv_downloadurl;
++
++int sv_numbots;
++
++void Master_Shutdown (void);
++
++short ShortSwap (short l);
++
++//============================================================================
++
++
++/*
++=====================
++SV_DropClient
++
++Called when the player is totally leaving the server, either willingly
++or unwillingly. This is NOT called if the entire server is quiting
++or crashing.
++=====================
++*/
++void SV_DropClient (client_t *drop)
++{
++ // add the disconnect
++
++ MSG_WriteByte (&drop->netchan.message, svc_disconnect);
++
++ if (drop->state == cs_spawned)
++ {
++ // call the prog function for removing a client
++ // this will remove the body, among other things
++ ge->ClientDisconnect (drop->edict);
++ }
++
++ if (drop->download)
++ {
++ FS_FreeFile (drop->download);
++ drop->download = NULL;
++ }
++
++ drop->state = cs_zombie; // become free in a few seconds
++ drop->name[0] = 0;
++}
++
++
++
++/*
++==============================================================================
++
++CONNECTIONLESS COMMANDS
++
++==============================================================================
++*/
++
++/*
++===============
++SV_StatusString
++
++Builds the string that is sent as heartbeats and status replies
++===============
++*/
++char *SV_StatusString (void)
++{
++ char player[1024];
++ static char status[MAX_MSGLEN - 16];
++ int i;
++#ifdef NOTUSED
++ int j, k;
++#endif
++ client_t *cl;
++ int statusLength;
++ int playerLength;
++ char *name;
++ //char *s;
++ char nametxt[MAX_INFO_STRING];
++
++ strcpy (status, Cvar_Serverinfo());
++ strcat (status, "\n");
++ statusLength = strlen(status);
++
++ for (i=0 ; i<maxclients->value ; i++)
++ {
++ cl = &svs.clients[i];
++ if (cl->state == cs_connected || cl->state == cs_spawned )
++ {
++ name = cl->name;
++#ifdef NOTUSED
++ //handle color chars
++ nametxt[0] = 0;
++ k = 0;
++ while(j = *name) {
++ if ( Q_IsColorString( name ) ) {
++ name +=2;
++ continue;
++ }
++ nametxt[k] = j;
++ name++;
++ k++;
++ //failsafe - break at 32 chars
++ if(k>30)
++ break;
++ }
++ nametxt[k]=0;
++#else
++ //allow color chars to be sent
++ strcpy(nametxt, name);
++ nametxt[31] = '\0'; //failsafe
++#endif
++ //s = NET_AdrToString ( cl->netchan.remote_address); //fuck you Luigi
++ Com_sprintf (player, sizeof(player), "%i %i \"%s\" \"127.0.0.1\"\n",
++ cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, nametxt, "suppressed");
++ playerLength = strlen(player);
++ if (statusLength + playerLength >= sizeof(status) )
++ break; // can't hold any more
++ strcpy (status + statusLength, player);
++ statusLength += playerLength;
++
++ }
++ }
++ //bot score info
++ cl = &svs.clients[0]; //get the bots info from the first client
++ if(cl->edict->client->ps.botnum) {
++ for(i = 0; i < cl->edict->client->ps.botnum; i++) {
++
++ name = cl->edict->client->ps.bots[i].name;
++#ifdef NOTUSED
++ //handle color chars
++ nametxt[0] = 0;
++ k = 0;
++ while(j = *name) {
++ if ( Q_IsColorString( name ) ) {
++ name +=2;
++ continue;
++ }
++ nametxt[k] = j;
++ name++;
++ k++;
++ //failsafe - break at 32 chars
++ if(k>30)
++ break;
++ }
++ nametxt[k]=0;
++#else
++ //allow color chars to be sent
++ strcpy(nametxt, name);
++ nametxt[31] = '\0'; //failsafe
++#endif
++
++ Com_sprintf (player, sizeof(player), "%i %i \"%s\" \"127.0.0.1\"\n",
++ cl->edict->client->ps.bots[i].score, 0, nametxt);
++ playerLength = strlen(player);
++ if (statusLength + playerLength >= sizeof(status) )
++ break; // can't hold any more
++ strcpy (status + statusLength, player);
++ statusLength += playerLength;
++ }
++ }
++ //end bot score info
++ return status;
++}
++
++/*
++================
++SVC_Status
++
++Responds with all the info that qplug or qspy can see
++================
++*/
++/*void SVC_Status (void)
++{
++ Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", SV_StatusString());
++#if 0
++ Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
++ Com_Printf (SV_StatusString());
++ Com_EndRedirect ();
++#endif
++}*/
++static qboolean RateLimited (ratelimit_t *limit, int maxCount)
++{
++ int diff;
++
++ diff = sv.time - limit->time;
++
++ //a new sampling period
++ if (diff > limit->period || diff < 0)
++ {
++ limit->time = sv.time;
++ limit->count = 0;
++ }
++ else
++ {
++ if (limit->count >= maxCount)
++ return true;
++ }
++
++ return false;
++}
++
++static void RateSample (ratelimit_t *limit)
++{
++ int diff;
++
++ diff = sv.time - limit->time;
++
++ //a new sampling period
++ if (diff > limit->period || diff < 0)
++ {
++ limit->time = sv.time;
++ limit->count = 1;
++ }
++ else
++ {
++ limit->count++;
++ }
++}
++
++static void SVC_Status (void)
++{
++
++ RateSample (&svs.ratelimit_status);
++
++ if (RateLimited (&svs.ratelimit_status, sv_ratelimit_status->integer))
++ {
++ Com_DPrintf ("SVC_Status: Dropped status request from %s\n", NET_AdrToString (net_from));
++ return;
++ }
++
++ Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", SV_StatusString());
++}
++
++/*
++================
++SVC_Ack
++
++================
++*/
++void SVC_Ack (void)
++{
++ int i;
++ Com_Printf ("Ping acknowledge from %s\n", NET_AdrToString(net_from));
++ for ( i = 0 ; i < MAX_MASTERS ; i ++ ) {
++ if ( master_status[i].name[0] == 0 )
++ break;
++
++ if ( master_status[i].addr.port == 0 )
++ continue;
++
++ if ( NET_CompareAdr (master_status[i].addr, net_from) )
++ master_status[i].last_ping_ack = 2;
++ }
++}
++
++/*
++================
++SVC_Info
++
++Responds with short info for broadcast scans
++The second parameter should be the current protocol version number.
++================
++*/
++void SVC_Info (void)
++{
++ char string[64];
++ int i, count;
++ int version;
++ client_t *cl;
++
++ if (maxclients->value == 1)
++ return; // ignore in single player
++
++ version = atoi (Cmd_Argv(1));
++
++ if (version != PROTOCOL_VERSION) {
++ Com_sprintf (string, sizeof(string), "%s: wrong version\n", hostname->string, sizeof(string));
++ //r1: return instead of sending another packet. prevents spoofed udp packet
++ // causing server <-> server info loops.
++ return;
++ }
++ else
++ {
++ count = 0;
++ for (i=0 ; i<maxclients->value ; i++)
++ if (svs.clients[i].state >= cs_connected)
++ count++;
++ //bot score info
++ cl = &svs.clients[0];
++ if(cl->edict->client->ps.botnum > 0)
++ count += cl->edict->client->ps.botnum; //add the bots
++ //end bot score info
++
++ Com_sprintf (string, sizeof(string), "%16s %8s %2i/%2i\n", hostname->string, sv.name, count, (int)maxclients->value);
++ }
++
++ Netchan_OutOfBandPrint (NS_SERVER, net_from, "info\n%s", string);
++}
++
++/*
++================
++SVC_Ping
++
++Just responds with an acknowledgement
++================
++*/
++void SVC_Ping (void)
++{
++ Netchan_OutOfBandPrint (NS_SERVER, net_from, "ack");
++}
++
++void SV_KickClient (client_t *cl, const char /*@null@*/*reason, const char /*@null@*/*cprintf)
++{
++ if (reason && cl->state == cs_spawned && cl->name[0])
++ SV_BroadcastPrintf (PRINT_HIGH, "%s was dropped: %s\n", cl->name, reason);
++ if (cprintf)
++ SV_ClientPrintf (cl, PRINT_HIGH, "%s", cprintf);
++ Com_Printf ("Dropping %s, %s.\n", cl->name, reason ? reason : "SV_KickClient");
++ SV_DropClient (cl);
++}
++
++/*
++=================
++SVC_GetChallenge
++
++Returns a challenge number that can be used
++in a subsequent client_connect command.
++We do this to prevent denial of service attacks that
++flood the server with invalid connection IPs. With a
++challenge, they must give a valid IP address.
++=================
++*/
++void SVC_GetChallenge (void)
++{
++ int i;
++ int oldest;
++ int oldestTime;
++
++ oldest = 0;
++ oldestTime = 0x7fffffff;
++
++ // see if we already have a challenge for this ip
++ for (i = 0 ; i < MAX_CHALLENGES ; i++)
++ {
++ if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
++ break;
++ if (svs.challenges[i].time < oldestTime)
++ {
++ oldestTime = svs.challenges[i].time;
++ oldest = i;
++ }
++ }
++
++ if (i == MAX_CHALLENGES)
++ {
++ // overwrite the oldest
++ svs.challenges[oldest].challenge = rand() & 0x7fff;
++ svs.challenges[oldest].adr = net_from;
++ svs.challenges[oldest].time = curtime;
++ i = oldest;
++ }
++
++ // send it back
++ Netchan_OutOfBandPrint (NS_SERVER, net_from, "challenge %i", svs.challenges[i].challenge);
++}
++
++/*
++==================
++SVC_DirectConnect
++
++A connection request that did not come from the master
++==================
++*/
++void SVC_DirectConnect (void)
++{
++ char userinfo[MAX_INFO_STRING];
++ netadr_t adr;
++ int i;
++ client_t *cl, *newcl;
++ client_t temp;
++ edict_t *ent;
++ int edictnum;
++ int version;
++ int qport;
++ int challenge;
++ int previousclients;
++ int botnum, botkick;
++
++ adr = net_from;
++
++ Com_DPrintf ("SVC_DirectConnect ()\n");
++
++ version = atoi(Cmd_Argv(1));
++ if (version != PROTOCOL_VERSION)
++ {
++ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is version %4.2f.\n", VERSION);
++ Com_DPrintf (" rejected connect from version %i\n", version);
++ return;
++ }
++
++ qport = atoi(Cmd_Argv(2));
++
++ challenge = atoi(Cmd_Argv(3));
++
++ //security, overflow fixes
++
++ //limit connections from a single IP
++ previousclients = 0;
++ for (i=0,cl=svs.clients ; i<maxclients->integer ; i++,cl++)
++ {
++ if (cl->state == cs_free)
++ continue;
++ if (NET_CompareBaseAdr (adr, cl->netchan.remote_address))
++ {
++ //zombies are less dangerous
++ if (cl->state == cs_zombie)
++ previousclients++;
++ else
++ previousclients += 2;
++ }
++ }
++
++ if (previousclients >= sv_iplimit->integer * 2)
++ {
++ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nToo many connections from your host.\n");
++ Com_DPrintf (" too many connections\n");
++ return;
++ }
++
++ // sku - reserve 32 bytes for the IP address
++ strncpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-32);
++ userinfo[sizeof(userinfo) - 32] = 0;
++
++ //check it is not overflowed, save enough bytes for /ip/111.222.333.444:55555
++ if (strlen(userinfo) + 25 >= sizeof(userinfo)-1)
++ {
++ Com_DPrintf (" userinfo length exceeded\n");
++ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nUserinfo string length exceeded.\n");
++ return;
++ }
++ else if (!userinfo[0])
++ {
++ Com_DPrintf (" empty userinfo string\n");
++ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nBad userinfo string.\n");
++ return;
++ }
++
++ //block anyone trying to use the end-of-message-in-string exploit
++ if (strchr(userinfo, '\xFF'))
++ {
++ char *ptr;
++ ptr = strchr (userinfo, '\xFF');
++ ptr -= 8;
++ if (ptr < userinfo)
++ ptr = userinfo;
++ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused due to attempted exploit!\n");
++ return;
++ }
++ if (Info_KeyExists (userinfo, "ip"))
++ {
++ char *p;
++ p = Info_ValueForKey(userinfo, "ip");
++ Com_Printf ("EXPLOIT: Client %s attempted to spoof IP address: %s\n", Info_ValueForKey (userinfo, "name"), NET_AdrToString(adr));
++ return;
++ }
++
++ // force the IP key/value pair so the game can filter based on ip
++ Info_SetValueForKey (userinfo, "ip", NET_AdrToString(net_from));
++
++ // attractloop servers are ONLY for local clients
++ if (sv.attractloop)
++ {
++ if (!NET_IsLocalAddress (adr))
++ {
++ Com_Printf ("Remote connect in attract loop. Ignored.\n");
++ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n");
++ return;
++ }
++ }
++
++ // see if the challenge is valid
++ if (!NET_IsLocalAddress (adr))
++ {
++ for (i=0 ; i<MAX_CHALLENGES ; i++)
++ {
++ if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
++ {
++ if (challenge == svs.challenges[i].challenge)
++ break; // good
++ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nBad challenge.\n");
++ return;
++ }
++ }
++ if (i == MAX_CHALLENGES)
++ {
++ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nNo challenge for address.\n");
++ return;
++ }
++ }
++
++ newcl = &temp;
++ memset (newcl, 0, sizeof(client_t));
++
++ // if there is already a slot for this ip, reuse it
++ for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
++ {
++ if (cl->state == cs_free)
++ continue;
++
++ if (NET_CompareAdr (adr, cl->netchan.remote_address))
++ {
++
++ //r1: !! fix nasty bug where non-disconnected clients (from dropped disconnect
++ //packets) could be overwritten!
++ if (cl->state != cs_zombie)
++ {
++ Com_DPrintf (" client already found\n");
++ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nPlayer '%s' is already connected from %s.\n", cl->name, NET_AdrToString(adr));
++ return;
++ }
++
++ if (!NET_IsLocalAddress (adr) && (svs.realtime - cl->lastconnect) < ((int)sv_reconnect_limit->integer * 1000))
++ {
++ Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (adr));
++ return;
++ }
++ Com_Printf ("%s:reconnect\n", NET_AdrToString (adr));
++
++ newcl = cl;
++ goto gotnewcl;
++ }
++ }
++
++ // find a client slot
++ cl = &svs.clients[0]; //get the active bots info from the first client
++ botnum = cl->edict->client->ps.botnum;
++ //still need to reserve one slot
++ newcl = NULL;
++
++ //are we using botkickthreshold?
++ botkick = Cvar_VariableValue("sv_botkickthreshold");
++
++ //prevent client slot overwrites with bots rejoining after map change
++ if(botkick) {
++
++ if(botkick < sv_numbots)
++ botnum = botkick;
++ else
++ botnum = sv_numbots;
++ }
++
++ for (i=0,cl=svs.clients ; i<maxclients->value-botnum; i++,cl++)
++ {
++ if (cl->state == cs_free)
++ {
++ newcl = cl;
++ break;
++ }
++ }
++ if (!newcl)
++ {
++ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is full.\n");
++ Com_DPrintf ("Rejected a connection.\n");
++ return;
++ }
++
++gotnewcl:
++ // build a new connection
++ // accept the new client
++ // this is the only place a client_t is ever initialized
++ *newcl = temp;
++ sv_client = newcl;
++ edictnum = (newcl-svs.clients)+1;
++ ent = EDICT_NUM(edictnum);
++ newcl->edict = ent;
++ newcl->challenge = challenge; // save challenge for checksumming
++
++ // get the game a chance to reject this connection or modify the userinfo
++
++ if (!(ge->ClientConnect (ent, userinfo)))
++ {
++
++ if (*Info_ValueForKey (userinfo, "rejmsg"))
++ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\n%s\nConnection refused.\n",
++ Info_ValueForKey (userinfo, "rejmsg"));
++ else
++ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n" );
++ Com_DPrintf ("Game rejected a connection.\n");
++ return;
++ }
++
++ // parse some info from the info strings
++ strncpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)-1);
++ SV_UserinfoChanged (newcl);
++
++ // send the connect packet to the client
++ Netchan_OutOfBandPrint(NS_SERVER, adr, "client_connect %s", sv_downloadurl->string);
++
++ Netchan_Setup (NS_SERVER, &newcl->netchan , adr, qport);
++
++ newcl->state = cs_connected;
++
++ SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf) );
++ SZ_SetName (&newcl->datagram, va("Datagram buffer %s", NET_AdrToString(adr)), true);
++
++ newcl->datagram.allowoverflow = true;
++ newcl->lastmessage = svs.realtime; // don't timeout
++ newcl->lastconnect = svs.realtime;
++}
++
++int Rcon_Validate (void)
++{
++ if (!strlen (rcon_password->string))
++ return 0;
++
++ if (strcmp (Cmd_Argv(1), rcon_password->string) )
++ return 0;
++
++ return 1;
++}
++
++/*
++===============
++SVC_RemoteCommand
++
++A client issued an rcon command.
++Shift down the remaining args
++Redirect all printfs
++===============
++*/
++void SVC_RemoteCommand (void)
++{
++ int i;
++ char remaining[1024];
++
++ i = Rcon_Validate ();
++
++ if (i == 0)
++ Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
++ else
++ Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
++
++ Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
++
++ if (!Rcon_Validate ())
++ {
++ Com_Printf ("Bad rcon_password.\n");
++ }
++ else
++ {
++ remaining[0] = 0;
++
++ for (i=2 ; i<Cmd_Argc() ; i++)
++ {
++ /* If spaces present in args, quote them in the remaining string */
++ if(strchr(Cmd_Argv(i), ' '))
++ {
++ strcat (remaining, "\"");
++ strcat (remaining, Cmd_Argv(i) );
++ strcat (remaining, "\"");
++ }
++ else
++ {
++ strcat (remaining, Cmd_Argv(i) );
++ }
++ strcat (remaining, " ");
++ }
++
++ Cmd_ExecuteString (remaining);
++ }
++
++ Com_EndRedirect ();
++}
++
++/*
++=================
++SV_ConnectionlessPacket
++
++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.
++=================
++*/
++void SV_ConnectionlessPacket (void)
++{
++ char *s;
++ char *c;
++
++ //r1: make sure we never talk to ourselves
++ if (NET_IsLocalAddress (net_from) && !NET_IsLocalHost(&net_from) && ShortSwap(net_from.port) == server_port)
++ {
++ Com_DPrintf ("dropped %d byte connectionless packet from self! (spoofing attack?)\n", net_message.cursize);
++ return;
++ }
++
++
++ MSG_BeginReading (&net_message);
++ MSG_ReadLong (&net_message); // skip the -1 marker
++
++ s = MSG_ReadStringLine (&net_message);
++
++ Cmd_TokenizeString (s, false);
++
++ c = Cmd_Argv(0);
++ Com_DPrintf ("Packet %s : %s\n", NET_AdrToString(net_from), c);
++
++ if (!strcmp(c, "ping"))
++ SVC_Ping ();
++ else if (!strcmp(c, "ack"))
++ SVC_Ack ();
++ else if (!strcmp(c,"status"))
++ SVC_Status ();
++ else if (!strcmp(c,"info"))
++ SVC_Info ();
++ else if (!strcmp(c,"getchallenge"))
++ SVC_GetChallenge ();
++ else if (!strcmp(c,"connect"))
++ SVC_DirectConnect ();
++ else if (!strcmp(c, "rcon"))
++ SVC_RemoteCommand ();
++ else
++ Com_Printf ("bad connectionless packet from %s:\n%s\n"
++ , NET_AdrToString (net_from), s);
++}
++
++
++//============================================================================
++
++/*
++===================
++SV_CalcPings
++
++Updates the cl->ping variables
++===================
++*/
++void SV_CalcPings (void)
++{
++ int i, j;
++ client_t *cl;
++ int total, count;
++
++ for (i=0 ; i<maxclients->value ; i++)
++ {
++ cl = &svs.clients[i];
++ if (cl->state != cs_spawned )
++ continue;
++
++#if 0
++ if (cl->lastframe > 0)
++ cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = sv.framenum - cl->lastframe + 1;
++ else
++ cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = 0;
++#endif
++
++ total = 0;
++ count = 0;
++ for (j=0 ; j<LATENCY_COUNTS ; j++)
++ {
++ if (cl->frame_latency[j] > 0)
++ {
++ count++;
++ total += cl->frame_latency[j];
++ }
++ }
++ if (!count)
++ cl->ping = 0;
++ else
++#if 0
++ cl->ping = total*100/count - 100;
++#else
++ cl->ping = total / count;
++#endif
++
++ // let the game dll know about the ping
++ cl->edict->client->ping = cl->ping;
++ }
++}
++
++
++/*
++===================
++SV_GiveMsec
++
++Every few frames, gives all clients an allotment of milliseconds
++for their command moves. If they exceed it, assume cheating.
++===================
++*/
++void SV_GiveMsec (void)
++{
++ int i;
++ client_t *cl;
++
++ if (sv.framenum & 15)
++ return;
++
++ for (i=0 ; i<maxclients->value ; i++)
++ {
++ cl = &svs.clients[i];
++ if (cl->state == cs_free )
++ continue;
++
++ cl->commandMsec = 1800; // 1600 + some slop
++ }
++}
++
++
++/*
++=================
++SV_ReadPackets
++=================
++*/
++void SV_ReadPackets (void)
++{
++ int i;
++ client_t *cl;
++ int qport;
++
++ while (NET_GetPacket (NS_SERVER, &net_from, &net_message))
++ {
++ // check for connectionless packet (0xffffffff) first
++ if (*(int *)net_message.data == -1)
++ {
++ SV_ConnectionlessPacket ();
++ continue;
++ }
++
++ // read the qport out of the message so we can fix up
++ // stupid address translating routers
++ MSG_BeginReading (&net_message);
++ MSG_ReadLong (&net_message); // sequence number
++ MSG_ReadLong (&net_message); // sequence number
++ qport = MSG_ReadShort (&net_message) & 0xffff;
++
++ // check for packets from connected clients
++ for (i=0, cl=svs.clients ; i<maxclients->value ; i++,cl++)
++ {
++ if (cl->state == cs_free)
++ continue;
++
++ if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address))
++ continue;
++ if (cl->netchan.qport != qport)
++ continue;
++ if (cl->netchan.remote_address.port != net_from.port)
++ {
++ Com_Printf ("SV_ReadPackets: fixing up a translated port\n");
++ cl->netchan.remote_address.port = net_from.port;
++ }
++
++ if (Netchan_Process(&cl->netchan, &net_message))
++ { // this is a valid, sequenced packet, so process it
++ if (cl->state != cs_zombie)
++ {
++ cl->lastmessage = svs.realtime; // don't timeout
++ SV_ExecuteClientMessage (cl);
++ }
++ }
++ break;
++ }
++
++ if (i != maxclients->value)
++ continue;
++ }
++}
++
++/*
++==================
++SV_CheckTimeouts
++
++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
++==================
++*/
++void SV_CheckTimeouts (void)
++{
++ int i;
++ client_t *cl;
++ int droppoint;
++ int zombiepoint;
++
++ droppoint = svs.realtime - 1000*timeout->value;
++ zombiepoint = svs.realtime - 1000*zombietime->value;
++
++ for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
++ {
++
++
++ // message times may be wrong across a changelevel
++ if (cl->lastmessage > svs.realtime)
++ cl->lastmessage = svs.realtime;
++
++ if (cl->state == cs_zombie
++ && cl->lastmessage < zombiepoint)
++ {
++ cl->state = cs_free; // can now be reused
++ continue;
++ }
++ if ( (cl->state == cs_connected || cl->state == cs_spawned)
++ && cl->lastmessage < droppoint)
++ {
++ SV_BroadcastPrintf (PRINT_HIGH, "%s timed out\n", cl->name);
++ SV_DropClient (cl);
++ cl->state = cs_free; // don't bother with zombie state
++ }
++ }
++}
++
++/*
++================
++SV_PrepWorldFrame
++
++This has to be done before the world logic, because
++player processing happens outside RunWorldFrame
++================
++*/
++void SV_PrepWorldFrame (void)
++{
++ edict_t *ent;
++ int i;
++
++ for (i=0 ; i<ge->num_edicts ; i++, ent++)
++ {
++ ent = EDICT_NUM(i);
++ // events only last for a single message
++ ent->s.event = 0;
++ }
++
++}
++
++
++/*
++=================
++SV_RunGameFrame
++=================
++*/
++void SV_RunGameFrame (void)
++{
++ if (host_speeds->value)
++ time_before_game = Sys_Milliseconds ();
++
++ // we always need to bump framenum, even if we
++ // don't run the world, otherwise the delta
++ // compression can get confused when a client
++ // has the "current" frame
++ sv.framenum++;
++ sv.time = sv.framenum*100;
++
++ // don't run if paused
++ if (!sv_paused->value || maxclients->value > 1)
++ {
++ ge->RunFrame ();
++
++ // never get more than one tic behind
++ if (sv.time < svs.realtime)
++ {
++ if (sv_showclamp->value)
++ Com_Printf ("sv highclamp\n");
++ svs.realtime = sv.time;
++ }
++ }
++
++ if (host_speeds->value)
++ time_after_game = Sys_Milliseconds ();
++
++}
++
++/*
++==================
++SV_Frame
++
++==================
++*/
++void SV_Frame (int msec)
++{
++ time_before_game = time_after_game = 0;
++
++ // if server is not active, do nothing
++ if (!svs.initialized)
++ return;
++
++ svs.realtime += msec;
++
++ // keep the random time dependent
++ rand ();
++
++ // check timeouts
++ SV_CheckTimeouts ();
++
++ // get packets from clients
++ SV_ReadPackets ();
++
++ // move autonomous things around if enough time has passed
++ if (!sv_timedemo->value && svs.realtime < sv.time)
++ {
++ // never let the time get too far off
++ if (sv.time - svs.realtime > 100)
++ {
++ if (sv_showclamp->value)
++ Com_Printf ("sv lowclamp\n");
++ svs.realtime = sv.time - 100;
++ }
++ NET_Sleep(sv.time - svs.realtime);
++ return;
++ }
++
++ // update ping based on the last known frame from all clients
++ SV_CalcPings ();
++
++ // give the clients some timeslices
++ SV_GiveMsec ();
++
++ // let everything in the world think and move
++ SV_RunGameFrame ();
++
++ // send messages back to the clients that had packets read this frame
++ SV_SendClientMessages ();
++
++ // save the entire world state if recording a serverdemo
++ SV_RecordDemoMessage ();
++
++ // send a heartbeat to the master if needed
++ Master_Heartbeat ();
++
++ // clear teleport flags, etc for next frame
++ SV_PrepWorldFrame ();
++
++}
++
++//============================================================================
++
++/*
++================
++Master_Heartbeat
++
++Send a message to the master every few minutes to
++let it know we are alive, and log information
++================
++*/
++#define HEARTBEAT_SECONDS 300
++void Master_Heartbeat (void)
++{
++ char string[MAX_MSGLEN];
++
++ // pgm post3.19 change, cvar pointer not validated before dereferencing
++
++ if(!public_server || !public_server->value)
++ return;
++
++ // check for time wraparound
++ if (svs.last_heartbeat > svs.realtime)
++ svs.last_heartbeat = svs.realtime;
++
++ if (svs.realtime - svs.last_heartbeat < HEARTBEAT_SECONDS*1000)
++ return; // not time to send yet
++
++ svs.last_heartbeat = svs.realtime;
++
++ // send the same string that we would give for a status OOB command
++ Com_sprintf (string, MAX_MSGLEN, "heartbeat\n%s", SV_StatusString ());
++ SV_HandleMasters (string, "heartbeat");
++}
++
++/*
++=================
++Master_Shutdown
++
++Informs all masters that this server is going down
++=================
++*/
++void Master_Shutdown (void)
++{
++
++ // pgm post3.19 change, cvar pointer not validated before dereferencing
++ if (!public_server || !public_server->value)
++ return; // a private dedicated game
++
++ SV_HandleMasters ("shutdown", "shutdown");
++}
++
++
++/*
++=================
++SV_HandleMasters
++
++Sends a message to all master servers, looking up the
++master servers' addresses if appropriate.
++=================
++*/
++void SV_HandleMasters (const char *message, const char *console_message)
++{
++ int i;
++ qboolean updated_master;
++
++ // if the server is not dedicated, we need to check cl_master
++ if ( !( dedicated && dedicated->value ) )
++ {
++ if ( !sv_master )
++ {
++ sv_master = Cvar_Get ("cl_master", "master.corservers.com", CVAR_ARCHIVE);
++ updated_master = true;
++ }
++ else if ( sv_master->modified )
++ {
++ sv_master->modified = false;
++ updated_master = true;
++ }
++ else
++ {
++ updated_master = false;
++ }
++
++ if ( updated_master )
++ {
++ memset (&master_status[0], 0, sizeof(master_sv_t));
++ strncpy (master_status[0].name, sv_master->string, MAX_MASTER_LEN);
++ }
++ }
++
++ // first we need to loop through the master servers
++ // in order to find the ones that need (re-)resolving
++ for ( i = 0; i < MAX_MASTERS ; i ++ )
++ {
++ if ( master_status[i].name[0] == 0 )
++ break;
++
++ // if we already sent a ping and didn't get
++ // any acknowledgement packet, we need to try
++ // re-resolving
++ if ( master_status[i].resolved && master_status[i].last_ping_sent > master_status[i].last_ping_ack )
++ {
++ Com_Printf ("No acknowledgement from %s - re-resolving\n", master_status[i].name);
++ master_status[i].resolved = false;
++ }
++
++ if ( master_status[i].resolved )
++ continue;
++
++ if (!NET_StringToAdr (master_status[i].name, &master_status[i].addr))
++ {
++ // resolution failed, did we say so already?
++ if ( !master_status[i].failed )
++ {
++ Com_Printf ("Bad master address: %s\n", master_status[i].name);
++ master_status[i].failed = true;
++ }
++ master_status[i].addr.port = 0;
++ }
++ else
++ {
++ master_status[i].failed = false;
++ master_status[i].resolved = true;
++
++ if (master_status[i].addr.port == 0)
++ master_status[i].addr.port = BigShort (PORT_MASTER);
++
++ Com_Printf ("Master server at %s\n", NET_AdrToString (master_status[i].addr));
++ }
++ }
++
++ // send the message we needed to send
++ for ( i = 0 ; i < MAX_MASTERS ; i ++ )
++ {
++ if ( master_status[i].name[0] == 0 )
++ break;
++
++ if ( master_status[i].addr.port == 0 )
++ continue;
++
++ Com_Printf ("Sending %s to %s\n", console_message, NET_AdrToString (master_status[i].addr));
++ Netchan_OutOfBandPrint (NS_SERVER, master_status[i].addr, "%s", message);
++ master_status[i].last_ping_sent = 1;
++ master_status[i].last_ping_ack = 0;
++ }
++}
++
++
++//============================================================================
++
++
++/*
++=================
++SV_UserinfoChanged
++
++Pull specific info from a newly changed userinfo string
++into a more C freindly form.
++=================
++*/
++void SV_UserinfoChanged (client_t *cl)
++{
++ char *val;
++ int i;
++
++ // call prog code to allow overrides
++ ge->ClientUserinfoChanged (cl->edict, cl->userinfo, 0);
++
++ // name for C code
++ strncpy (cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name)-1);
++ // mask off high bit
++ for (i=0 ; i<sizeof(cl->name) ; i++)
++ cl->name[i] &= 127;
++
++ // rate command
++ val = Info_ValueForKey (cl->userinfo, "rate");
++ if (strlen(val))
++ {
++ i = atoi(val);
++ cl->rate = i;
++ if (cl->rate < 100)
++ cl->rate = 100;
++ if (cl->rate > 15000)
++ cl->rate = 15000;
++ }
++ else
++ cl->rate = 5000;
++
++ // msg command
++ val = Info_ValueForKey (cl->userinfo, "msg");
++ if (strlen(val))
++ {
++ cl->messagelevel = atoi(val);
++ }
++
++}
++
++
++//============================================================================
++
++/*
++===============
++SV_Init
++
++Only called at quake2.exe startup, not for each game
++===============
++*/
++void SV_Init (void)
++{
++ SV_InitOperatorCommands ();
++
++ rcon_password = Cvar_Get ("rcon_password", "", 0);
++ Cvar_Get ("skill", "1", 0);
++ Cvar_Get ("deathmatch", "1", CVAR_LATCH); //Alien Arena is *always* deathmatch
++ Cvar_Get ("ctf", "0", CVAR_LATCH);
++ Cvar_Get ("dmflags", va("%i", DF_INSTANT_ITEMS), CVAR_SERVERINFO);
++ Cvar_Get ("fraglimit", "0", CVAR_SERVERINFO);
++ Cvar_Get ("timelimit", "0", CVAR_SERVERINFO);
++ Cvar_Get ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
++ Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO|CVAR_NOSET);;
++ maxclients = Cvar_Get ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
++ hostname = Cvar_Get ("hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE);
++ timeout = Cvar_Get ("timeout", "125", 0);
++ zombietime = Cvar_Get ("zombietime", "2", 0);
++ sv_showclamp = Cvar_Get ("showclamp", "0", 0);
++ sv_paused = Cvar_Get ("paused", "0", 0);
++ sv_timedemo = Cvar_Get ("timedemo", "0", 0);
++ sv_enforcetime = Cvar_Get ("sv_enforcetime", "0", 0);
++ allow_download = Cvar_Get ("allow_download", "1", CVAR_ARCHIVE);
++ allow_download_players = Cvar_Get ("allow_download_players", "0", CVAR_ARCHIVE);
++ allow_download_models = Cvar_Get ("allow_download_models", "1", CVAR_ARCHIVE);
++ allow_download_sounds = Cvar_Get ("allow_download_sounds", "1", CVAR_ARCHIVE);
++ allow_download_maps = Cvar_Get ("allow_download_maps", "1", CVAR_ARCHIVE);
++ sv_downloadurl = Cvar_Get("sv_downloadurl", "http://icculus.org/alienarena/sv_downloadurl", CVAR_SERVERINFO);
++
++ sv_noreload = Cvar_Get ("sv_noreload", "0", 0);
++
++ sv_airaccelerate = Cvar_Get("sv_airaccelerate", "0", CVAR_LATCH);
++
++ sv_joustmode = Cvar_Get("sv_joustmode", "0", CVAR_SERVERINFO);
++
++ public_server = Cvar_Get ("sv_public", "1", 0);
++
++ sv_reconnect_limit = Cvar_Get ("sv_reconnect_limit", "3", CVAR_ARCHIVE);
++
++ sv_ratelimit_status = Cvar_Get ("sv_ratelimit_status", "15", 0);
++
++ sv_iplimit = Cvar_Get ("sv_iplimit", "3", 0);
++
++ SZ_Init (&net_message, net_message_buffer, sizeof(net_message_buffer));
++ SZ_SetName (&net_message, "Net message buffer", true);
++}
++
++/*
++==================
++SV_FinalMessage
++
++Used by SV_Shutdown to send a final message to all
++connected clients before the server goes down. The messages are sent immediately,
++not just stuck on the outgoing message list, because the server is going
++to totally exit after returning from this function.
++==================
++*/
++void SV_FinalMessage (char *message, qboolean reconnect)
++{
++ int i;
++ client_t *cl;
++
++ SZ_Clear (&net_message);
++ MSG_WriteByte (&net_message, svc_print);
++ MSG_WriteByte (&net_message, PRINT_HIGH);
++ MSG_WriteString (&net_message, message);
++
++ if (reconnect)
++ MSG_WriteByte (&net_message, svc_reconnect);
++ else
++ MSG_WriteByte (&net_message, svc_disconnect);
++
++ // send it twice
++ // stagger the packets to crutch operating system limited buffers
++
++ for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
++
++ if (cl->state >= cs_connected)
++ Netchan_Transmit (&cl->netchan, net_message.cursize
++ , net_message.data);
++
++ for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
++
++ if (cl->state >= cs_connected)
++ Netchan_Transmit (&cl->netchan, net_message.cursize
++ , net_message.data);
++}
++
++
++
++/*
++================
++SV_Shutdown
++
++Called when each game quits,
++before Sys_Quit or Sys_Error
++================
++*/
++void SV_Shutdown (char *finalmsg, qboolean reconnect)
++{
++ extern void Con_Clear_f (void);
++
++ if (svs.clients)
++ SV_FinalMessage (finalmsg, reconnect);
++
++ Master_Shutdown ();
++ SV_ShutdownGameProgs ();
++
++ // free current level
++ if (sv.demofile)
++ fclose (sv.demofile);
++ memset (&sv, 0, sizeof(sv));
++ Com_SetServerState (sv.state);
++
++ // free server static data
++ if (svs.clients)
++ Z_Free (svs.clients);
++ if (svs.client_entities)
++ Z_Free (svs.client_entities);
++ if (svs.demofile)
++ fclose (svs.demofile);
++ memset (&svs, 0, sizeof(svs));
++}
++
++qboolean IsVisible(vec3_t org1,vec3_t org2)
++{
++ trace_t trace;
++
++ trace = SV_Trace2 (org1, NULL, NULL, org2, NULL, MASK_VISIBILILITY);
++
++ if (trace.fraction != 1)
++ return false;
++ return true;
++}
More information about the Pkg-games-commits
mailing list