mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-22 20:51:31 +00:00
Connectionless server commands in eine eigene Datei
This commit is contained in:
parent
5973a3c8e9
commit
cb0159014d
3 changed files with 436 additions and 395 deletions
8
Makefile
8
Makefile
|
@ -241,6 +241,7 @@ GAME_ABI_OBJS = \
|
|||
# Server objects
|
||||
SERVER_OBJS = \
|
||||
build/server/sv_cmd.o \
|
||||
build/server/sv_conless.o \
|
||||
build/server/sv_entities.o \
|
||||
build/server/sv_game.o \
|
||||
build/server/sv_init.o \
|
||||
|
@ -273,6 +274,7 @@ SDL_OBJS= \
|
|||
# Dedicated server object
|
||||
DEDICATED_SERVER_OBJS = \
|
||||
build/dedicated_server/sv_cmd.o \
|
||||
build/dedicated_server/sv_conless.o \
|
||||
build/dedicated_server/sv_entities.o \
|
||||
build/dedicated_server/sv_game.o \
|
||||
build/dedicated_server/sv_init.o \
|
||||
|
@ -607,6 +609,9 @@ build/gameabi/q_shared.o : src/game/baseq2/q_shared.c
|
|||
build/server/sv_cmd.o : src/server/sv_cmd.c
|
||||
$(CC) $(CFLAGS_CLIENT) -o $@ -c $<
|
||||
|
||||
build/server/sv_conless.o : src/server/sv_conless.c
|
||||
$(CC) $(CFLAGS_CLIENT) -o $@ -c $<
|
||||
|
||||
build/server/sv_entities.o : src/server/sv_entities.c
|
||||
$(CC) $(CFLAGS_CLIENT) -o $@ -c $<
|
||||
|
||||
|
@ -666,6 +671,9 @@ build/sdl/sound.o : src/sdl/sound.c
|
|||
build/dedicated_server/sv_cmd.o : src/server/sv_cmd.c
|
||||
$(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $<
|
||||
|
||||
build/dedicated_server/sv_conless.o : src/server/sv_conless.c
|
||||
$(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $<
|
||||
|
||||
build/dedicated_server/sv_entities.o : src/server/sv_entities.c
|
||||
$(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $<
|
||||
|
||||
|
|
427
src/server/sv_conless.c
Normal file
427
src/server/sv_conless.c
Normal file
|
@ -0,0 +1,427 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Connectionless server commands.
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "header/server.h"
|
||||
|
||||
extern cvar_t *hostname;
|
||||
extern cvar_t *rcon_password;
|
||||
|
||||
cvar_t *sv_reconnect_limit; /* minimum seconds between connect messages */
|
||||
|
||||
char * SV_StatusString ( void );
|
||||
|
||||
/*
|
||||
* 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() );
|
||||
}
|
||||
|
||||
void
|
||||
SVC_Ack ( void )
|
||||
{
|
||||
Com_Printf( "Ping acknowledge from %s\n", NET_AdrToString( net_from ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
count = 0;
|
||||
|
||||
for ( i = 0; i < maxclients->value; i++ )
|
||||
{
|
||||
if ( svs.clients [ i ].state >= cs_connected )
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
void
|
||||
SVC_Ping ( void )
|
||||
{
|
||||
Netchan_OutOfBandPrint( NS_SERVER, net_from, "ack" );
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 );
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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 ) );
|
||||
|
||||
strncpy( userinfo, Cmd_Argv( 4 ), sizeof ( userinfo ) - 1 );
|
||||
userinfo [ sizeof ( userinfo ) - 1 ] = 0;
|
||||
|
||||
/* 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_connected )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( NET_CompareBaseAdr( adr, cl->netchan.remote_address ) &&
|
||||
( ( cl->netchan.qport == qport ) ||
|
||||
( adr.port == cl->netchan.remote_address.port ) ) )
|
||||
{
|
||||
if ( !NET_IsLocalAddress( adr ) && ( ( svs.realtime - cl->lastconnect ) < ( (int) sv_reconnect_limit->value * 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 */
|
||||
newcl = NULL;
|
||||
|
||||
for ( i = 0, cl = svs.clients; i < maxclients->value; 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" );
|
||||
|
||||
Netchan_Setup( NS_SERVER, &newcl->netchan, adr, qport );
|
||||
|
||||
newcl->state = cs_connected;
|
||||
|
||||
SZ_Init( &newcl->datagram, newcl->datagram_buf, sizeof ( newcl->datagram_buf ) );
|
||||
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 );
|
||||
}
|
||||
|
||||
/*
|
||||
* 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++ )
|
||||
{
|
||||
strcat( remaining, Cmd_Argv( i ) );
|
||||
strcat( remaining, " " );
|
||||
}
|
||||
|
||||
Cmd_ExecuteString( remaining );
|
||||
}
|
||||
|
||||
Com_EndRedirect();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
|
@ -49,9 +49,9 @@ 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 */
|
||||
|
||||
void Master_Shutdown ( void );
|
||||
void SV_ConnectionlessPacket ( void );
|
||||
|
||||
/*
|
||||
* Called when the player is totally leaving the server, either willingly
|
||||
|
@ -121,400 +121,6 @@ SV_StatusString ( void )
|
|||
return ( 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() );
|
||||
}
|
||||
|
||||
void
|
||||
SVC_Ack ( void )
|
||||
{
|
||||
Com_Printf( "Ping acknowledge from %s\n", NET_AdrToString( net_from ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
count = 0;
|
||||
|
||||
for ( i = 0; i < maxclients->value; i++ )
|
||||
{
|
||||
if ( svs.clients [ i ].state >= cs_connected )
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
void
|
||||
SVC_Ping ( void )
|
||||
{
|
||||
Netchan_OutOfBandPrint( NS_SERVER, net_from, "ack" );
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 );
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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 ) );
|
||||
|
||||
strncpy( userinfo, Cmd_Argv( 4 ), sizeof ( userinfo ) - 1 );
|
||||
userinfo [ sizeof ( userinfo ) - 1 ] = 0;
|
||||
|
||||
/* 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_connected )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( NET_CompareBaseAdr( adr, cl->netchan.remote_address ) &&
|
||||
( ( cl->netchan.qport == qport ) ||
|
||||
( adr.port == cl->netchan.remote_address.port ) ) )
|
||||
{
|
||||
if ( !NET_IsLocalAddress( adr ) && ( ( svs.realtime - cl->lastconnect ) < ( (int) sv_reconnect_limit->value * 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 */
|
||||
newcl = NULL;
|
||||
|
||||
for ( i = 0, cl = svs.clients; i < maxclients->value; 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" );
|
||||
|
||||
Netchan_Setup( NS_SERVER, &newcl->netchan, adr, qport );
|
||||
|
||||
newcl->state = cs_connected;
|
||||
|
||||
SZ_Init( &newcl->datagram, newcl->datagram_buf, sizeof ( newcl->datagram_buf ) );
|
||||
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 );
|
||||
}
|
||||
|
||||
/*
|
||||
* 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++ )
|
||||
{
|
||||
strcat( remaining, Cmd_Argv( i ) );
|
||||
strcat( remaining, " " );
|
||||
}
|
||||
|
||||
Cmd_ExecuteString( remaining );
|
||||
}
|
||||
|
||||
Com_EndRedirect();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================ */
|
||||
|
||||
/*
|
||||
* Updates the cl->ping variables
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue