コード例 #1
0
/*
* TV_Upstream_ServerReconnect_f
* 
* The server is changing levels
*/
static void TV_Upstream_ServerReconnect_f( upstream_t *upstream )
{
	if( upstream->demo.playing )
		return;

	if( upstream->state < CA_CONNECTED )
	{
		Com_Printf( "%s: reconnect request while not connected\n", NET_AddressToString( &upstream->serveraddress ) );
		return;
	}

	if( upstream->demo.recording )
		TV_Upstream_StopDemoRecord( upstream, upstream->demo.autorecording, qfalse );

	Com_Printf( "%s: reconnecting...\n", NET_AddressToString( &upstream->serveraddress ) );

	upstream->connect_count = 0;
	upstream->rejected = 0;
#ifdef TCP_ALLOW_CONNECT
	upstream->connect_time = tvs.realtime;
#else
	upstream->connect_time = tvs.realtime - 1500;
#endif
	upstream->state = CA_HANDSHAKE;
	TV_Upstream_AddReliableCommand( upstream, "new" );
}
コード例 #2
0
ファイル: sv_oob.c プロジェクト: codetwister/qfusion
/*
* 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( const socket_t *socket, const netadr_t *address, msg_t *msg )
{
	connectionless_cmd_t *cmd;
	char *s, *c;

	MSG_BeginReading( msg );
	MSG_ReadLong( msg );    // skip the -1 marker

	s = MSG_ReadStringLine( msg );

	Cmd_TokenizeString( s );

	c = Cmd_Argv( 0 );
	Com_DPrintf( "Packet %s : %s\n", NET_AddressToString( address ), c );

	for( cmd = connectionless_cmds; cmd->name; cmd++ )
	{
		if( !strcmp( c, cmd->name ) )
		{
			cmd->func( socket, address );
			return;
		}
	}

	Com_DPrintf( "Bad connectionless packet from %s:\n%s\n", NET_AddressToString( address ), s );
}
コード例 #3
0
ファイル: tv_cmds.c プロジェクト: codetwister/qfusion
/*
* TV_Upstream_Status_f
*/
static void TV_Upstream_Status_f( void )
{
	int i;
	qboolean none;
	client_t *client;
	upstream_t *upstream;

	if( !TV_UpstreamForText( Cmd_Argv( 1 ), &upstream ) )
	{
		Com_Printf( "No such connection\n" );
		return;
	}

	if( upstream )
	{
		Com_Printf( "%s" S_COLOR_WHITE ": %s\n", upstream->name, NET_AddressToString( &upstream->serveraddress ) );
		Com_Printf( "Server name: %s\n", upstream->servername );
		Com_Printf( "Connection: %s\n", TV_ConnstateToString( upstream->state ) );
		Com_Printf( "Relay: %s\n", TV_ConnstateToString( upstream->relay.state ) );
	}
	else
	{
		Com_Printf( "lobby\n" );
	}

	Com_Printf( "Downstream connections:\n" );
	none = qtrue;
	for( i = 0; i < tv_maxclients->integer; i++ )
	{
		client = &tvs.clients[i];

		if( client->state == CS_FREE || client->state == CS_ZOMBIE )
			continue;
		if( !client->relay )
		{
			if( upstream )
				continue;
		}
		else
		{
			if( client->relay->upstream != upstream )
				continue;
		}

		Com_Printf( "%3i: %s" S_COLOR_WHITE " (%s)\n", i, client->name, NET_AddressToString( &client->netchan.remoteAddress ) );
		none = qfalse;
	}
	if( none )
		Com_Printf( "- No downstream connections\n" );
}
コード例 #4
0
ファイル: cl_mm.c プロジェクト: Kaperstone/warsow
qboolean CL_MM_Connect( const netadr_t *address )
{
	/*
	* ch : this here sends a ticket request to MM.
	* upon response we can set the client state to CA_CONNECTING
	* and actually connect to the gameserver
	*/
	stat_query_t *query;

	// Com_Printf("CL_MM_Connect %s\n", NET_AddressToString( address ) );

	cls.mm_ticket = 0;

	// TODO: if not logged in, force login
	if( !cl_mm_enabled )
		return qfalse;

	// TODO: validate the parameters
	query = sq_api->CreateQuery( "ccc", qfalse );
	if( query == NULL )
		return qfalse;

	// TODO: put the session in a cookie
	sq_api->SetField( query, "csession", va( "%d", cls.mm_session ) );
	// we may have ipv4 or ipv6 in here, and MM currently on supports ipv4..
	sq_api->SetField( query, "saddr", NET_AddressToString( address ) );
	sq_api->SetCallback( query, cl_mm_connect_done, NULL );
	sq_api->Send( query );

	return qtrue;
}
コード例 #5
0
ファイル: sv_send.c プロジェクト: Clever-Boy/qfusion
/*
* SV_SendClientsFragments
*/
bool SV_SendClientsFragments( void )
{
	client_t *client;
	int i;
	bool sent = false;

	// send a message to each connected client
	for( i = 0, client = svs.clients; i < sv_maxclients->integer; i++, client++ )
	{
		if( client->state == CS_FREE || client->state == CS_ZOMBIE )
			continue;
		if( client->edict && ( client->edict->r.svflags & SVF_FAKECLIENT ) )
			continue;
		if( !client->netchan.unsentFragments )
			continue;

		if( !Netchan_TransmitNextFragment( &client->netchan ) )
		{
			Com_Printf( "Error sending fragment to %s: %s\n", NET_AddressToString( &client->netchan.remoteAddress ),
				NET_ErrorString() );
			if( client->reliable )
				SV_DropClient( client, DROP_TYPE_GENERAL, "Error sending fragment: %s\n", NET_ErrorString() );
			continue;
		}

		sent = true;
	}

	return sent;
}
コード例 #6
0
ファイル: mm_matches.c プロジェクト: Racenet/racesow
//================
// MM_MatchesList
// Prints the list of matches to console
//================
void MM_MatchList( void )
{
	int i = 0, count = 0;
	mm_match_t *match;

	for( match = mms.matches ; match ; match = match->next )
	{
		Com_Printf( "Match id: %d\n ping type: %s\n gametype: %s\n skill type: %s\n clients:\n",
		            match->id,
		            match->pingtype == TYPE_ANY ? "any" : "dependent",
		            match->gametype,
		            match->skilltype == TYPE_ANY ? "any" : "dependent" );

		for( i = 0; i < match->maxclients; i++ )
		{
			if( match->clients[i] )
				Com_Printf( "  %s %s (%d): %s\n",
				           match->clients[i]->userid < 1 ? "U" : "R", // registered or not
				           match->clients[i]->nickname,
				           match->clients[i]->userid,
				           NET_AddressToString( &match->clients[i]->connection->address ) );
		}

		count++;
	}

	Com_Printf( "%d match(s)\n", count );
}
コード例 #7
0
/*
* TV_Downstream_UpstreamlessPacket
*/
void TV_Downstream_UpstreamlessPacket( const socket_t *socket, const netadr_t *address, msg_t *msg )
{
	upstreamless_cmd_t *cmd;
	char *s, *c;

	MSG_BeginReading( msg );
	MSG_ReadLong( msg );    // skip the -1 marker

	s = MSG_ReadStringLine( msg );

	if( TV_Downstream_SteamServerQuery( s, socket, address, msg ) )
		return;

	Cmd_TokenizeString( s );
	c = Cmd_Argv( 0 );

	for( cmd = upstreamless_cmds; cmd->name; cmd++ )
	{
		if( !strcmp( c, cmd->name ) )
		{
			cmd->func( socket, address );
			return;
		}
	}

	Com_DPrintf( "Bad downstream connectionless packet from %s:\n%s\n", NET_AddressToString( address ), s );
}
コード例 #8
0
ファイル: tv_downstream.c プロジェクト: Kaperstone/warsow
/*
* TV_Downstream_MasterHeartbeat
* Send a message to the master every few minutes to
* let it know we are alive, and log information
*/
void TV_Downstream_MasterHeartbeat( void )
{
	int i;
	const socket_t *socket;

	tvs.lobby.last_heartbeat -= tvs.lobby.snapFrameTime;
	if( tvs.lobby.last_heartbeat > 0 )
		return;

	tvs.lobby.last_heartbeat = HEARTBEAT_SECONDS * 1000;

	if( !tv_public->integer )
		return;

	// send to group master
	for( i = 0; i < MAX_MASTERS; i++ )
	{
		if( tv_master_adr[i].type != NA_NOTRANSMIT )
		{
			Com_Printf( "Sending heartbeat to %s\n", NET_AddressToString( &tv_master_adr[i] ) );

			socket = ( tv_master_adr[i].type == NA_IP6 ? &tvs.socket_udp6 : &tvs.socket_udp );

			// warning: "DarkPlaces" is a protocol name here, not a game name. Do not replace it.
			Netchan_OutOfBandPrint( socket, &tv_master_adr[i], "heartbeat %s\n", "DarkPlaces" );
		}
	}
}
コード例 #9
0
ファイル: sv_oob.c プロジェクト: futurepneu/racemod
/*
* SV_MasterSendQuit
* Notifies Steam master servers that the server is shutting down.
*/
void SV_MasterSendQuit( void )
{
	int i;
	const char quitMessage[] = "b\n";

	if( !sv_public->integer || ( sv_maxclients->integer == 1 ) )
		return;

	// never go public when not acting as a game server
	if( sv.state > ss_game )
		return;

	// send to group master
	for( i = 0; i < MAX_MASTERS; i++ )
	{
		sv_master_t *master = &sv_masters[i];

		if( master->steam && ( master->address.type != NA_NOTRANSMIT ) )
		{
			socket_t *socket = ( master->address.type == NA_IP6 ? &svs.socket_udp6 : &svs.socket_udp );

			if( dedicated && dedicated->integer )
				Com_Printf( "Sending quit to %s\n", NET_AddressToString( &master->address ) );

			NET_SendPacket( socket, ( const uint8_t * )quitMessage, sizeof( quitMessage ), &master->address );
		}
	}
}
コード例 #10
0
ファイル: cl_serverlist.c プロジェクト: codetwister/qfusion
/*
* CL_ParseStatusMessage
* Handle a reply from a ping
*/
void CL_ParseStatusMessage( const socket_t *socket, const netadr_t *address, msg_t *msg )
{
	char *s = MSG_ReadString( msg );
	serverlist_t *pingserver;
	char adrString[64];

	Com_DPrintf( "%s\n", s );

	Q_strncpyz( adrString, NET_AddressToString( address ), sizeof( adrString ) );

	// ping response
	pingserver = CL_ServerFindInList( masterList, adrString );
	if( !pingserver )
		pingserver = CL_ServerFindInList( favoritesList, adrString );

	if( pingserver && pingserver->pingTimeStamp ) // valid ping
	{
		unsigned int ping = Sys_Milliseconds() - pingserver->pingTimeStamp;
		CL_UIModule_AddToServerList( adrString, va( "\\\\ping\\\\%i%s", ping, s ) );
		pingserver->pingTimeStamp = 0;
		pingserver->lastValidPing = Com_DaysSince1900();
		return;
	}

	// assume LAN response
	if( NET_IsLANAddress( address ) && ( localQueryTimeStamp + LAN_SERVER_PINGING_TIMEOUT > Sys_Milliseconds() ) ) {
		unsigned int ping = Sys_Milliseconds() - localQueryTimeStamp;
		CL_UIModule_AddToServerList( adrString, va( "\\\\ping\\\\%i%s", ping, s ) );
		return;
	}

	// add the server info, but ignore the ping, cause it's not valid
	CL_UIModule_AddToServerList( adrString, s );
}
コード例 #11
0
/*
 ==================
 NET_SendPacket
 ==================
*/
void NET_SendPacket (netSrc_t sock, const netAdr_t to, const void *data, int length){

	struct sockaddr	adr;
	int				result, error;

	if (NET_SendLoopPacket(sock, to, data, length))
		return;

	if (to.type != NA_BROADCAST && to.type != NA_IP)
		Com_Error(ERR_FATAL, "NET_SendPacket: bad address type");

	if (net.sockets[sock] == INVALID_SOCKET)
		return;

	NET_NetAdrToSockAdr(&to, &adr);

	result = sendto(net.sockets[sock], (const char *)data, length, 0, &adr, sizeof(adr));

	if (result == SOCKET_ERROR){
		error = WSAGetLastError();

		// WSAEWOULDBLOCK is silent
		if (error == WSAEWOULDBLOCK)
			return;

		// Some PPP links don't allow broadcasts
		if (error == WSAEADDRNOTAVAIL && to.type == NA_BROADCAST)
			return;

		Com_Printf(S_COLOR_RED "NET_SendPacket: %s to %s\n", NET_ErrorString(), NET_AddressToString(to));
	}

	net.packetsSent[sock]++;
	net.bytesSent[sock] += result;
}
コード例 #12
0
ファイル: tv_downstream.c プロジェクト: Kaperstone/warsow
/*
* TV_Downstream_AddMaster_f
* Add a master server to the list
*/
static void TV_Downstream_AddMaster_f( const char *master )
{
	int i;

	if( !master || !master[0] )
		return;

	if( !tv_public->integer )
	{
		Com_Printf( "'TV_Downstream_AddMaster_f' Only public servers use masters.\n" );
		return;
	}

	for( i = 0; i < MAX_MASTERS; i++ )
	{
		if( tv_master_adr[i].type != NA_NOTRANSMIT )
			continue;

		if( !NET_StringToAddress( master, &tv_master_adr[i] ) )
		{
			Com_Printf( "'SV_AddMaster_f' Bad Master server address: %s\n", master );
			return;
		}
		if( NET_GetAddressPort( &tv_master_adr[i] ) == 0 )
			NET_SetAddressPort( &tv_master_adr[i], PORT_MASTER );

		Com_Printf( "Added new master server #%i at %s\n", i, NET_AddressToString( &tv_master_adr[i] ) );
		return;
	}

	Com_Printf( "'TV_Downstream_AddMaster_f' List of master servers is already full\n" );
}
コード例 #13
0
ファイル: sv_oob.c プロジェクト: codetwister/qfusion
/*
* 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.
*/
static void SVC_GetChallenge( const socket_t *socket, const netadr_t *address )
{
	int i;
	int oldest;
	int oldestTime;

	oldest = 0;
	oldestTime = 0x7fffffff;

	if( sv_showChallenge->integer )
		Com_Printf( "Challenge Packet %s\n", NET_AddressToString( address ) );

	// see if we already have a challenge for this ip
	for( i = 0; i < MAX_CHALLENGES; i++ )
	{
		if( NET_CompareBaseAddress( address, &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 = *address;
		svs.challenges[oldest].time = Sys_Milliseconds();
		i = oldest;
	}

	Netchan_OutOfBandPrint( socket, address, "challenge %i", svs.challenges[i].challenge );
}
コード例 #14
0
ファイル: sv_oob.c プロジェクト: codetwister/qfusion
/*
* SV_MasterHeartbeat
* Send a message to the master every few minutes to
* let it know we are alive, and log information
*/
void SV_MasterHeartbeat( void )
{
	int i;

	svc.lastHeartbeat -= svc.snapFrameTime;
	if( svc.lastHeartbeat > 0 )
		return;

	svc.lastHeartbeat = HEARTBEAT_SECONDS * 1000;

	if( !sv_public->integer )
		return;

	// never go public when not acting as a game server
	if( sv.state > ss_game )
		return;

	// send to group master
	for( i = 0; i < MAX_MASTERS; i++ )
	{
		if( master_adr[i].type != NA_NOTRANSMIT )
		{
			socket_t *socket;

			if( dedicated && dedicated->integer )
				Com_Printf( "Sending heartbeat to %s\n", NET_AddressToString( &master_adr[i] ) );

			socket = ( master_adr[i].type == NA_IP6 ? &svs.socket_udp6 : &svs.socket_udp );

			// warning: "DarkPlaces" is a protocol name here, not a game name. Do not replace it.
			Netchan_OutOfBandPrint( socket, &master_adr[i], "heartbeat DarkPlaces\n" );
		}
	}
}
コード例 #15
0
ファイル: cl_sound.c プロジェクト: Kaperstone/warsow
/*
* CL_Mumble_Update
*/
void CL_Mumble_Update( const vec3_t origin, const vec3_t forward, const vec3_t right, const vec3_t up, const char *identity )
{
	vec3_t mp, mf, mt;
	char context[256];

	if( !cl_mumble->integer )
		return;
	if( !identity )
		return;

	VectorScale( origin, cl_mumble_scale->value, mp );
	VectorSet( mf, forward[0], forward[2], forward[1] );
	VectorSet( mt, up[0], up[2], up[1] );

	if( cl_mumble->integer == 2 )
		Com_Printf( "MumbleUpdate:\n%f, %f, %f\n%f, %f, %f\n%f, %f, %f", mp[0], mp[1], mp[2], mf[0], mf[1], mf[2], mt[0], mt[1], mt[2] );

	mumble_update_coordinates( mp, mf, mt );

	// for Mumble 1.2+  http://mumble.sourceforge.net/Link
	mumble_set_identity( identity );

	// TODO: add team to context?
	Q_strncpyz( context, NET_AddressToString( &cls.serveraddress ), sizeof( context ) );
	mumble_set_context( ( const unsigned char * )context, strlen( context ) + 1 );
}
コード例 #16
0
ファイル: sv_oob.c プロジェクト: codetwister/qfusion
/*
* SVC_SendInfoString
*/
static void SVC_SendInfoString( const socket_t *socket, const netadr_t *address, const char *requestType, const char *responseType, qboolean fullStatus )
{
	char *string;

	if( sv_showInfoQueries->integer )
		Com_Printf( "%s Packet %s\n", requestType, NET_AddressToString( address ) );

	// KoFFiE: When not public and coming from a LAN address
	//         assume broadcast and respond anyway, otherwise ignore
	if( ( ( !sv_public->integer ) && ( !NET_IsLANAddress( address ) ) ) ||
		( sv_maxclients->integer == 1 ) )
	{
		return;
	}

	// ignore when in invalid server state
	if( sv.state < ss_loading || sv.state > ss_game )
		return;

	// don't reply when we are locked for mm
	// if( SV_MM_IsLocked() )
	//	return;

	// send the same string that we would give for a status OOB command
	string = SV_LongInfoString( fullStatus );
	if( string )
		Netchan_OutOfBandPrint( socket, address, "%s\n\\challenge\\%s%s", responseType, Cmd_Argv( 1 ), string );
}
コード例 #17
0
ファイル: sv_mm.c プロジェクト: Kaperstone/warsow
int SV_MM_ClientConnect( const netadr_t *address, char *userinfo, unsigned int ticket_id, int session_id )
{
	/*
	* what crizis did.. push a query after checking that ticket id and session id
	* at least aren't null and if server expects login-only clients
	*
	* ahem, figure out how to handle anonymous players. currently this will bug out so that
	* session_id is 0 -> request receives zero id's and freaks out. generate a session_id
	* here and return it.
	*
	* ok done. so this function receives session_id = 0 if we are dealing with 'anonymous'
	* player and this here generates local session-id for the client
	*/
	stat_query_t *query;

	// return of -1 is not an error, it just marks a dummy local session
	if( !sv_mm_initialized || !sv_mm_session )
		return -1;

	// accept only players that are logged in (session_id <= 0 ??)
	if( sv_mm_loginonly->integer && session_id == 0 )
	{
		Com_Printf("SV_MM_ClientConnect: Login-only\n");
		return 0;
	}

	// expect a ticket for logged-in client (rly?) session_id > 0
	// we should force local session in here
	if( ticket_id == 0 && session_id != 0 )
	{
		Com_Printf( "SV_MM_ClientConnect: Logged-in client didnt declare ticket, marking as anonymous\n" );
		session_id = 0;
	}

	if( session_id == 0 )
	{
		// WMM doesnt care about anonymous players
		session_id = SV_MM_GenerateLocalSession();
		Com_Printf("SV_MM_ClientConnect: Generated local session %d\n", session_id );
		return session_id;
	}

	// push a request
	query = sq_api->CreateQuery( "scc", qfalse );
	if( query == NULL )
		return 0;

	// servers own session (TODO: put this to a cookie or smth)
	sq_api->SetField( query, "ssession", va("%d", sv_mm_session ) );

	// clients attributes (nickname here?)
	sq_api->SetField( query, "cticket", va("%u", ticket_id ) );
	sq_api->SetField( query, "csession", va("%d", session_id ) );
	sq_api->SetField( query, "cip", NET_AddressToString( address ) );

	sq_api->SetCallback( query, sv_mm_clientconnect_done, (void*)session_id );
	sq_api->Send( query );

	return session_id;
}
コード例 #18
0
ファイル: sv_oob.c プロジェクト: codetwister/qfusion
/*
* SVC_RemoteCommand
* 
* A client issued an rcon command.
* Shift down the remaining args
* Redirect all printfs
*/
static void SVC_RemoteCommand( const socket_t *socket, const netadr_t *address )
{
	int i;
	char remaining[1024];
	flush_params_t extra;

	i = Rcon_Validate();

	if( i == 0 )
		Com_Printf( "Bad rcon from %s:\n%s\n", NET_AddressToString( address ), Cmd_Args() );
	else
		Com_Printf( "Rcon from %s:\n%s\n", NET_AddressToString( address ), Cmd_Args() );

	extra.socket = socket;
	extra.address = address;
	Com_BeginRedirect( RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect, ( const void * )&extra );

	if( sv_showRcon->integer )
		Com_Printf( "Rcon Packet %s\n", NET_AddressToString( address ) );

	if( !Rcon_Validate() )
	{
		Com_Printf( "Bad rcon_password.\n" );
	}
	else
	{
		remaining[0] = 0;

		for( i = 2; i < Cmd_Argc(); i++ )
		{
			Q_strncatz( remaining, "\"", sizeof( remaining ) );
			Q_strncatz( remaining, Cmd_Argv( i ), sizeof( remaining ) );
			Q_strncatz( remaining, "\" ", sizeof( remaining ) );
		}

		Cmd_ExecuteString( remaining );
	}

	Com_EndRedirect();
}
コード例 #19
0
/*
 ==================
 NET_GetPacket
 ==================
*/
bool NET_GetPacket (netSrc_t sock, netAdr_t *from, msg_t *msg){

	struct sockaddr	adr;
	int				adrLen = sizeof(adr);
	int 			result, error;

	if (NET_GetLoopPacket(sock, from, msg))
		return true;

	if (net.sockets[sock] == INVALID_SOCKET)
		return false;

	result = recvfrom(net.sockets[sock], (char *)msg->data, msg->maxSize, 0, (struct sockaddr *)&adr, &adrLen);

	NET_SockAdrToNetAdr(&adr, from);

	if (result == SOCKET_ERROR){
		error = WSAGetLastError();

		// WSAEWOULDBLOCK and WSAECONNRESET are silent
		if (error == WSAEWOULDBLOCK || error == WSAECONNRESET)
			return false;

		Com_Printf(S_COLOR_RED "NET_GetPacket: %s from %s\n", NET_ErrorString(), NET_AddressToString(*from));
		return false;
	}

	if (result == msg->maxSize){
		Com_Printf(S_COLOR_RED "NET_GetPacket: oversize packet from %s\n", NET_AddressToString(*from));
		return false;
	}

	msg->curSize = result;

	net.packetsReceived[sock]++;
	net.bytesReceived[sock] += result;

	return true;
}
コード例 #20
0
ファイル: sv_oob.c プロジェクト: futurepneu/racemod
/*
* SV_MasterHeartbeat
* Send a message to the master every few minutes to
* let it know we are alive, and log information
*/
void SV_MasterHeartbeat( void )
{
	unsigned int time = Sys_Milliseconds();
	int i;

	if( svc.nextHeartbeat > time )
		return;

	svc.nextHeartbeat = time + HEARTBEAT_SECONDS * 1000;

	if( !sv_public->integer || ( sv_maxclients->integer == 1 ) )
		return;

	// never go public when not acting as a game server
	if( sv.state > ss_game )
		return;

	// send to group master
	for( i = 0; i < MAX_MASTERS; i++ )
	{
		sv_master_t *master = &sv_masters[i];

		if( master->address.type != NA_NOTRANSMIT )
		{
			socket_t *socket;

			if( dedicated && dedicated->integer )
				Com_Printf( "Sending heartbeat to %s\n", NET_AddressToString( &master->address ) );

			socket = ( master->address.type == NA_IP6 ? &svs.socket_udp6 : &svs.socket_udp );

			if( master->steam )
			{
				uint8_t steamHeartbeat = 'q';
				NET_SendPacket( socket, &steamHeartbeat, sizeof( steamHeartbeat ), &master->address );
			}
			else
			{
				// warning: "DarkPlaces" is a protocol name here, not a game name. Do not replace it.
				Netchan_OutOfBandPrint( socket, &master->address, "heartbeat DarkPlaces\n" );
			}
		}
	}
}
コード例 #21
0
ファイル: sv_oob.c プロジェクト: futurepneu/racemod
/*
* SV_AddMaster_f
* Add a master server to the list
*/
static void SV_AddMaster_f( char *address, bool steam )
{
	int i;

	if( !address || !address[0] )
		return;

	if( !sv_public->integer )
	{
		Com_Printf( "'SV_AddMaster_f' Only public servers use masters.\n" );
		return;
	}

	//never go public when not acting as a game server
	if( sv.state > ss_game )
		return;

	for( i = 0; i < MAX_MASTERS; i++ )
	{
		sv_master_t *master = &sv_masters[i];

		if( master->address.type != NA_NOTRANSMIT )
			continue;

		if( !NET_StringToAddress( address, &master->address ) )
		{
			Com_Printf( "'SV_AddMaster_f' Bad Master server address: %s\n", address );
			return;
		}

		if( NET_GetAddressPort( &master->address ) == 0 )
			NET_SetAddressPort( &master->address, steam ? PORT_MASTER_STEAM : PORT_MASTER );

		master->steam = steam;

		Com_Printf( "Added new master server #%i at %s\n", i, NET_AddressToString( &master->address ) );
		return;
	}

	Com_Printf( "'SV_AddMaster_f' List of master servers is already full\n" );
}
コード例 #22
0
ファイル: tv_downstream.c プロジェクト: Kaperstone/warsow
/*
* TV_Downstream_UserinfoChanged
* 
* Pull specific info from a newly changed userinfo string
* into a more C friendly form.
*/
void TV_Downstream_UserinfoChanged( client_t *client )
{
	char *val;

	assert( client );
	assert( Info_Validate( client->userinfo ) );

	// force the IP key/value pair so the game can filter based on ip
	if( !Info_SetValueForKey( client->userinfo, "socket", NET_SocketTypeToString( client->netchan.socket->type ) ) )
	{
		TV_Downstream_DropClient( client, DROP_TYPE_GENERAL, "Error: Couldn't set userinfo (socket)\n" );
		return;
	}
	if( !Info_SetValueForKey( client->userinfo, "ip", NET_AddressToString( &client->netchan.remoteAddress ) ) )
	{
		TV_Downstream_DropClient( client, DROP_TYPE_GENERAL, "Error: Couldn't set userinfo (ip)\n" );
		return;
	}

	// we handle name ourselves here, since tv module doesn't know about all the players
	val = TV_Downstream_FixName( Info_ValueForKey( client->userinfo, "name" ), client );
	Q_strncpyz( client->name, val, sizeof( client->name ) );
	if( !Info_SetValueForKey( client->userinfo, "name", client->name ) )
	{
		TV_Downstream_DropClient( client, DROP_TYPE_GENERAL, "Error: Couldn't set userinfo (name)" );
		return;
	}

	if( client->relay )
		TV_Relay_ClientUserinfoChanged( client->relay, client );

	if( !Info_Validate( client->userinfo ) )
	{
		TV_Downstream_DropClient( client, DROP_TYPE_GENERAL, "Error: Invalid userinfo (after game)" );
		return;
	}
}
コード例 #23
0
ファイル: sv_oob.c プロジェクト: codetwister/qfusion
/*
* SV_AddMaster_f
* Add a master server to the list
*/
static void SV_AddMaster_f( char *master )
{
	int i;

	if( !master || !master[0] )
		return;

	if( !sv_public->integer )
	{
		Com_Printf( "'SV_AddMaster_f' Only public servers use masters.\n" );
		return;
	}

	//never go public when not acting as a game server
	if( sv.state > ss_game )
		return;

	for( i = 0; i < MAX_MASTERS; i++ )
	{
		if( master_adr[i].type != NA_NOTRANSMIT )
			continue;

		if( !NET_StringToAddress( master, &master_adr[i] ) )
		{
			Com_Printf( "'SV_AddMaster_f' Bad Master server address: %s\n", master );
			return;
		}

		if( NET_GetAddressPort( &master_adr[i] ) == 0 )
			NET_SetAddressPort( &master_adr[i], PORT_MASTER );

		Com_Printf( "Added new master server #%i at %s\n", i, NET_AddressToString( &master_adr[i] ) );
		return;
	}

	Com_Printf( "'SV_AddMaster_f' List of master servers is already full\n" );
}
コード例 #24
0
ファイル: tv_cmds.c プロジェクト: codetwister/qfusion
/*
* TV_Status
*/
static void TV_Status( void )
{
	int i;
	qboolean none;
	client_t *client;

	Com_Printf( "Upstream connections:\n" );
	none = qtrue;
	for( i = 0; i < tvs.numupstreams; i++ )
	{
		if( !tvs.upstreams[i] )
			continue;

		Com_Printf( "%3i: %22s: %s\n", i+1, NET_AddressToString( &tvs.upstreams[i]->serveraddress ),
			tvs.upstreams[i]->name );
		none = qfalse;
	}
	if( none )
		Com_Printf( "- No upstream connections\n" );

	Com_Printf( "Downstream connections:\n" );
	none = qtrue;
	for( i = 0; i < tv_maxclients->integer; i++ )
	{
		client = &tvs.clients[i];

		if( client->state == CS_FREE || client->state == CS_ZOMBIE )
			continue;

		Com_Printf( "%3i: %s" S_COLOR_WHITE " (%s): %s" S_COLOR_WHITE " %s\n", i, client->name, NET_AddressToString( &client->netchan.remoteAddress ),
			( client->relay ? client->relay->upstream->name : "lobby" ), client->mv ? "MV" : "" );
		none = qfalse;
	}
	if( none )
		Com_Printf( "- No downstream connections\n" );
}
コード例 #25
0
ファイル: cl_serverlist.c プロジェクト: codetwister/qfusion
/*
* CL_GetServers_f
*/
void CL_GetServers_f( void )
{
	netadr_t adr, *padr;
	char *requeststring;
	int i;
	char *modname, *master;
	trie_error_t err;

	filter_allow_full = qfalse;
	filter_allow_empty = qfalse;
	for( i = 2; i < Cmd_Argc(); i++ )
	{
		if( !Q_stricmp( "full", Cmd_Argv( i ) ) )
			filter_allow_full = qtrue;

		if( !Q_stricmp( "empty", Cmd_Argv( i ) ) )
			filter_allow_empty = qtrue;
	}

	if( !Q_stricmp( Cmd_Argv( 1 ), "local" ) )
	{
		if( localQueryTimeStamp + LAN_SERVER_PINGING_TIMEOUT > Sys_Milliseconds() ) {
			return;
		}

		padr = &adr;
		localQueryTimeStamp = Sys_Milliseconds();

		// send a broadcast packet
		Com_DPrintf( "pinging broadcast...\n" );

		// erm... modname isn't sent in local queries?

		requeststring = va( "info %i %s %s", SERVERBROWSER_PROTOCOL_VERSION,
			filter_allow_full ? "full" : "",
			filter_allow_empty ? "empty" : "" );

		for( i = 0; i < NUM_BROADCAST_PORTS; i++ )
		{
			NET_BroadcastAddress( padr, PORT_SERVER + i );
			Netchan_OutOfBandPrint( &cls.socket_udp, padr, requeststring );
		}
		return;
	}

	//get what master
	master = Cmd_Argv( 2 );
	if( !master || !( *master ) )
		return;

	modname = Cmd_Argv( 3 );
	// never allow anyone to use DEFAULT_BASEGAME as mod name
	if( !modname || !modname[0] || !Q_stricmp( modname, DEFAULT_BASEGAME ) )
		modname = APPLICATION;

	assert( modname[0] );

	// check memory cache
	QMutex_Lock( resolveLock );
	err = Trie_Find( serverlist_masters_trie, master, TRIE_EXACT_MATCH, (void **)&padr );
	QMutex_Unlock( resolveLock );

	if( err == TRIE_OK && ( padr->type == NA_IP || padr->type == NA_IP6 ) )
	{
		const char *cmdname;
		socket_t *socket;

		if ( padr->type == NA_IP )
		{
			cmdname = "getservers";
			socket = &cls.socket_udp;
		}
		else
		{
			cmdname = "getserversExt";
			socket = &cls.socket_udp6;
		}

		// create the message
		requeststring = va( "%s %c%s %i %s %s", cmdname, toupper( modname[0] ), modname+1, SERVERBROWSER_PROTOCOL_VERSION,
			filter_allow_full ? "full" : "",
			filter_allow_empty ? "empty" : "" );

		if( NET_GetAddressPort( padr ) == 0 )
			NET_SetAddressPort( padr, PORT_MASTER );

		Netchan_OutOfBandPrint( socket, padr, requeststring );

		Com_DPrintf( "quering %s...%s: %s\n", master, NET_AddressToString(padr), requeststring );
	}
	else
	{
		Com_Printf( "Bad address: %s\n", master );
	}
}
コード例 #26
0
ファイル: sv_ccmds.c プロジェクト: Racenet/racesow
/*
* SV_Status_f
*/
void SV_Status_f( void )
{
	int i, j, l;
	client_t *cl;
	const char *s;
	int ping;
	if( !svs.clients )
	{
		Com_Printf( "No server running.\n" );
		return;
	}
	Com_Printf( "map              : %s\n", sv.mapname );

	Com_Printf( "num score ping name            lastmsg address               port   rate  \n" );
	Com_Printf( "--- ----- ---- --------------- ------- --------------------- ------ ------\n" );
	for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
	{
		if( !cl->state )
			continue;
		Com_Printf( "%3i ", i );
		Com_Printf( "%5i ", cl->edict->r.client->r.frags );

		if( cl->state == CS_CONNECTED )
			Com_Printf( "CNCT " );
		else if( cl->state == CS_ZOMBIE )
			Com_Printf( "ZMBI " );
		else if( cl->state == CS_CONNECTING )
			Com_Printf( "AWAI " );
		else
		{
			ping = cl->ping < 9999 ? cl->ping : 9999;
			Com_Printf( "%4i ", ping );
		}

		s = COM_RemoveColorTokens( cl->name );
		Com_Printf( "%s", s );
		l = 16 - (int)strlen( s );
		for( j = 0; j < l; j++ )
			Com_Printf( " " );

		Com_Printf( "%7i ", svs.realtime - cl->lastPacketReceivedTime );

		s = NET_AddressToString( &cl->netchan.remoteAddress );
		Com_Printf( "%s", s );
		l = 22 - (int)strlen( s );
		for( j = 0; j < l; j++ )
			Com_Printf( " " );

		Com_Printf( "%5i", cl->netchan.game_port );
#ifndef RATEKILLED
		// wsw : jal : print real rate in use
		Com_Printf( "  " );
		if( cl->edict && ( cl->edict->r.svflags & SVF_FAKECLIENT ) )
			Com_Printf( "BOT" );
		else if( cl->rate == 99999 )
			Com_Printf( "LAN" );
		else
			Com_Printf( "%5i", cl->rate );
#endif
		Com_Printf( " " );
		if( cl->mv )
			Com_Printf( "MV" );
		Com_Printf( "\n" );
	}
	Com_Printf( "\n" );
}
コード例 #27
0
ファイル: net_chan.c プロジェクト: tenght/qfusion
/*
* Netchan_Process
* 
* Returns false if the message should not be processed due to being
* out of order or a fragment.
* 
* Msg must be large enough to hold MAX_MSGLEN, because if this is the
* final fragment of a multi-part message, the entire thing will be
* copied out.
*/
bool Netchan_Process( netchan_t *chan, msg_t *msg )
{
	int sequence, sequence_ack;
	int game_port = -1;
	int fragmentStart, fragmentLength;
	bool fragmented = false;
	int headerlength;
	bool compressed = false;
	bool lastfragment = false;

	// get sequence numbers
	MSG_BeginReading( msg );
	sequence = MSG_ReadLong( msg );
	sequence_ack = MSG_ReadLong( msg ); // wsw : jal : by now our header sends incoming ack too (q3 doesn't)

	// check for fragment information
	if( sequence & FRAGMENT_BIT )
	{
		sequence &= ~FRAGMENT_BIT;
		fragmented = true;

		if( net_showfragments->integer )
			Com_Printf( "Process fragmented packet (%s) (id:%i)\n", NET_SocketToString( chan->socket ), sequence );
	}
	else
	{
		fragmented = false;
	}

	// wsw : jal : check for compressed information
	if( sequence_ack & FRAGMENT_BIT )
	{
		sequence_ack &= ~FRAGMENT_BIT;
		compressed = true;
		if( !fragmented )
			msg->compressed = true;
	}

	// read the game port if we are a server
	if( chan->socket->server )
		game_port = MSG_ReadShort( msg );

	// read the fragment information
	if( fragmented )
	{
		fragmentStart = MSG_ReadShort( msg );
		fragmentLength = MSG_ReadShort( msg );
		if( fragmentLength & FRAGMENT_LAST )
		{
			lastfragment = true;
			fragmentLength &= ~FRAGMENT_LAST;
		}
	}
	else
	{
		fragmentStart = 0; // stop warning message
		fragmentLength = 0;
	}

	if( showpackets->integer )
	{
		if( fragmented )
		{
			Com_Printf( "%s recv %4i : s=%i fragment=%i,%i\n", NET_SocketToString( chan->socket ), msg->cursize,
				sequence, fragmentStart, fragmentLength );
		}
		else
		{
			Com_Printf( "%s recv %4i : s=%i\n", NET_SocketToString( chan->socket ), msg->cursize, sequence );
		}
	}

	//
	// discard out of order or duplicated packets
	//
	if( sequence <= chan->incomingSequence )
	{
		if( showdrop->integer || showpackets->integer )
		{
			Com_Printf( "%s:Out of order packet %i at %i\n", NET_AddressToString( &chan->remoteAddress ), sequence,
				chan->incomingSequence );
		}
		return false;
	}

	//
	// dropped packets don't keep the message from being used
	//
	chan->dropped = sequence - ( chan->incomingSequence+1 );
	if( chan->dropped > 0 )
	{
		if( showdrop->integer || showpackets->integer )
		{
			Com_Printf( "%s:Dropped %i packets at %i\n", NET_AddressToString( &chan->remoteAddress ), chan->dropped,
				sequence );
		}
	}

	//
	// if this is the final framgent of a reliable message,
	// bump incoming_reliable_sequence
	//
	if( fragmented )
	{
		// TTimo
		// make sure we add the fragments in correct order
		// either a packet was dropped, or we received this one too soon
		// we don't reconstruct the fragments. we will wait till this fragment gets to us again
		// (NOTE: we could probably try to rebuild by out of order chunks if needed)
		if( sequence != chan->fragmentSequence )
		{
			chan->fragmentSequence = sequence;
			chan->fragmentLength = 0;
		}

		// if we missed a fragment, dump the message
		if( fragmentStart != (int) chan->fragmentLength )
		{
			if( showdrop->integer || showpackets->integer )
			{
				Com_Printf( "%s:Dropped a message fragment\n", NET_AddressToString( &chan->remoteAddress ), sequence );
			}
			// we can still keep the part that we have so far,
			// so we don't need to clear chan->fragmentLength
			return false;
		}

		// copy the fragment to the fragment buffer
		if( fragmentLength < 0 || msg->readcount + fragmentLength > msg->cursize ||
			chan->fragmentLength + fragmentLength > sizeof( chan->fragmentBuffer ) )
		{
			if( showdrop->integer || showpackets->integer )
			{
				Com_Printf( "%s:illegal fragment length\n", NET_AddressToString( &chan->remoteAddress ) );
			}
			return false;
		}

		memcpy( chan->fragmentBuffer + chan->fragmentLength, msg->data + msg->readcount, fragmentLength );

		chan->fragmentLength += fragmentLength;

		// if this wasn't the last fragment, don't process anything
		if( !lastfragment )
		{
			return false;
		}

		if( chan->fragmentLength > msg->maxsize )
		{
			Com_Printf( "%s:fragmentLength %i > msg->maxsize\n", NET_AddressToString( &chan->remoteAddress ),
				chan->fragmentLength );
			return false;
		}

		// wsw : jal : reconstruct the message

		MSG_Clear( msg );
		MSG_WriteLong( msg, sequence );
		MSG_WriteLong( msg, sequence_ack );
		if( chan->socket->server )
			MSG_WriteShort( msg, game_port );

		msg->compressed = compressed;

		headerlength = msg->cursize;
		MSG_CopyData( msg, chan->fragmentBuffer, chan->fragmentLength );
		msg->readcount = headerlength; // put read pointer after header again
		chan->fragmentLength = 0;

		//let it be finished as standard packets
	}

	// the message can now be read from the current message pointer
	chan->incomingSequence = sequence;

	// wsw : jal[start] :  get the ack from the very first fragment
	chan->incoming_acknowledged = sequence_ack;
	// wsw : jal[end]

	return true;
}
コード例 #28
0
ファイル: sv_oob.c プロジェクト: codetwister/qfusion
/*
* SVC_Ack
*/
static void SVC_Ack( const socket_t *socket, const netadr_t *address )
{
	Com_Printf( "Ping acknowledge from %s\n", NET_AddressToString( address ) );
}
コード例 #29
0
ファイル: sv_oob.c プロジェクト: codetwister/qfusion
/*
* SVC_DirectConnect
* A connection request that did not come from the master
*/
static void SVC_DirectConnect( const socket_t *socket, const netadr_t *address )
{
#ifdef TCP_ALLOW_CONNECT
	int incoming = 0;
#endif
	char userinfo[MAX_INFO_STRING];
	client_t *cl, *newcl;
	int i, version, game_port, challenge;
	int previousclients;
	int session_id;
	char *session_id_str;
	unsigned int ticket_id;
	qboolean tv_client;

	Com_DPrintf( "SVC_DirectConnect (%s)\n", Cmd_Args() );

	version = atoi( Cmd_Argv( 1 ) );
	if( version != APP_PROTOCOL_VERSION )
	{
		if( version <= 6 )
		{            // before reject packet was added
			Netchan_OutOfBandPrint( socket, address, "print\nServer is version %4.2f. Protocol %3i\n",
				APP_VERSION, APP_PROTOCOL_VERSION );
		}
		else
		{
			Netchan_OutOfBandPrint( socket, address,
				"reject\n%i\n%i\nServer and client don't have the same version\n", DROP_TYPE_GENERAL, 0 );
		}
		Com_DPrintf( "    rejected connect from protocol %i\n", version );
		return;
	}

	game_port = atoi( Cmd_Argv( 2 ) );
	challenge = atoi( Cmd_Argv( 3 ) );
	tv_client = ( atoi( Cmd_Argv( 5 ) ) & 1 ? qtrue : qfalse );

	if( !Info_Validate( Cmd_Argv( 4 ) ) )
	{
		Netchan_OutOfBandPrint( socket, address, "reject\n%i\n%i\nInvalid userinfo string\n", DROP_TYPE_GENERAL, 0 );
		Com_DPrintf( "Connection from %s refused: invalid userinfo string\n", NET_AddressToString( address ) );
		return;
	}

	Q_strncpyz( userinfo, Cmd_Argv( 4 ), sizeof( userinfo ) );

	// force the IP key/value pair so the game can filter based on ip
	if( !Info_SetValueForKey( userinfo, "socket", NET_SocketTypeToString( socket->type ) ) )
	{
		Netchan_OutOfBandPrint( socket, address, "reject\n%i\n%i\nError: Couldn't set userinfo (socket)\n",
			DROP_TYPE_GENERAL, 0 );
		Com_DPrintf( "Connection from %s refused: couldn't set userinfo (socket)\n", NET_AddressToString( address ) );
		return;
	}
	if( !Info_SetValueForKey( userinfo, "ip", NET_AddressToString( address ) ) )
	{
		Netchan_OutOfBandPrint( socket, address, "reject\n%i\n%i\nError: Couldn't set userinfo (ip)\n",
			DROP_TYPE_GENERAL, 0 );
		Com_DPrintf( "Connection from %s refused: couldn't set userinfo (ip)\n", NET_AddressToString( address ) );
		return;
	}

	if( Cmd_Argc() >= 7 )
	{
		// we have extended information, ticket-id and session-id
		Com_Printf("Extended information %s\n", Cmd_Argv(6) );
		ticket_id = (unsigned int)atoi( Cmd_Argv(6) );
		session_id_str = Info_ValueForKey( userinfo, "cl_mm_session" );
		if( session_id_str != NULL )
			session_id = atoi( session_id_str );
		else
			session_id = 0;
	}
	else
	{
		ticket_id = 0;
		session_id = 0;
	}

#ifdef TCP_ALLOW_CONNECT
	if( socket->type == SOCKET_TCP )
	{
		// find the connection
		for( i = 0; i < MAX_INCOMING_CONNECTIONS; i++ )
		{
			if( !svs.incoming[i].active )
				continue;

			if( NET_CompareAddress( &svs.incoming[i].address, address ) && socket == &svs.incoming[i].socket )
				break;
		}
		if( i == MAX_INCOMING_CONNECTIONS )
		{
			Com_Error( ERR_FATAL, "Incoming connection not found.\n" );
			return;
		}
		incoming = i;
	}
#endif

	// see if the challenge is valid
	for( i = 0; i < MAX_CHALLENGES; i++ )
	{
		if( NET_CompareBaseAddress( address, &svs.challenges[i].adr ) )
		{
			if( challenge == svs.challenges[i].challenge )
			{
				svs.challenges[i].challenge = 0; // wsw : r1q2 : reset challenge
				svs.challenges[i].time = 0;
				NET_InitAddress( &svs.challenges[i].adr, NA_NOTRANSMIT );
				break; // good
			}
			Netchan_OutOfBandPrint( socket, address, "reject\n%i\n%i\nBad challenge\n",
				DROP_TYPE_GENERAL, DROP_FLAG_AUTORECONNECT );
			return;
		}
	}
	if( i == MAX_CHALLENGES )
	{
		Netchan_OutOfBandPrint( socket, address, "reject\n%i\n%i\nNo challenge for address\n",
			DROP_TYPE_GENERAL, DROP_FLAG_AUTORECONNECT );
		return;
	}

	//r1: limit connections from a single IP
	if( sv_iplimit->integer )
	{
		previousclients = 0;
		for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
		{
			if( cl->state == CS_FREE )
				continue;
			if( NET_CompareBaseAddress( address, &cl->netchan.remoteAddress ) )
			{
				//r1: zombies are less dangerous
				if( cl->state == CS_ZOMBIE )
					previousclients++;
				else
					previousclients += 2;
			}
		}

		if( previousclients >= sv_iplimit->integer * 2 )
		{
			Netchan_OutOfBandPrint( socket, address, "reject\n%i\n%i\nToo many connections from your host\n", DROP_TYPE_GENERAL,
				DROP_FLAG_AUTORECONNECT );
			Com_DPrintf( "%s:connect rejected : too many connections\n", NET_AddressToString( address ) );
			return;
		}
	}

	newcl = NULL;

	// if there is already a slot for this ip, reuse it
	for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
	{
		if( cl->state == CS_FREE )
			continue;
		if( NET_CompareAddress( address, &cl->netchan.remoteAddress ) ||
			( NET_CompareBaseAddress( address, &cl->netchan.remoteAddress ) && cl->netchan.game_port == game_port ) )
		{
			if( !NET_IsLocalAddress( address ) &&
				( svs.realtime - cl->lastconnect ) < (unsigned)( sv_reconnectlimit->integer * 1000 ) )
			{
				Com_DPrintf( "%s:reconnect rejected : too soon\n", NET_AddressToString( address ) );
				return;
			}
			Com_Printf( "%s:reconnect\n", NET_AddressToString( address ) );
			newcl = cl;
			break;
		}
	}

	// find a client slot
	if( !newcl )
	{
		for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
		{
			if( cl->state == CS_FREE )
			{
				newcl = cl;
				break;
			}
			// overwrite fakeclient if no free spots found
			if( cl->state && cl->edict && ( cl->edict->r.svflags & SVF_FAKECLIENT ) )
				newcl = cl;
		}
		if( !newcl )
		{
			Netchan_OutOfBandPrint( socket, address, "reject\n%i\n%i\nServer is full\n", DROP_TYPE_GENERAL,
				DROP_FLAG_AUTORECONNECT );
			Com_DPrintf( "Server is full. Rejected a connection.\n" );
			return;
		}
		if( newcl->state && newcl->edict && ( newcl->edict->r.svflags & SVF_FAKECLIENT ) )
			SV_DropClient( newcl, DROP_TYPE_GENERAL, "Need room for a real player" );
	}

	// get the game a chance to reject this connection or modify the userinfo
	if( !SV_ClientConnect( socket, address, newcl, userinfo, game_port, challenge, qfalse, 
		tv_client, ticket_id, session_id ) )
	{
		char *rejtype, *rejflag, *rejtypeflag, *rejmsg;

		rejtype = Info_ValueForKey( userinfo, "rejtype" );
		if( !rejtype )
			rejtype = "0";
		rejflag = Info_ValueForKey( userinfo, "rejflag" );
		if( !rejflag )
			rejflag = "0";
		// hax because Info_ValueForKey can only be called twice in a row
		rejtypeflag = va( "%s\n%s", rejtype, rejflag );

		rejmsg = Info_ValueForKey( userinfo, "rejmsg" );
		if( !rejmsg )
			rejmsg = "Game module rejected connection";

		Netchan_OutOfBandPrint( socket, address, "reject\n%s\n%s\n", rejtypeflag, rejmsg );

		Com_DPrintf( "Game rejected a connection.\n" );
		return;
	}

	// send the connect packet to the client
	Netchan_OutOfBandPrint( socket, address, "client_connect\n%s", newcl->session );

	// free the incoming entry
#ifdef TCP_ALLOW_CONNECT
	if( socket->type == SOCKET_TCP )
	{
		svs.incoming[incoming].active = qfalse;
		svs.incoming[incoming].socket.open = qfalse;
	}
#endif
}
コード例 #30
0
ファイル: sv_oob.c プロジェクト: codetwister/qfusion
/*
* SVC_InfoResponse
* 
* Responds with short info for broadcast scans
* The second parameter should be the current protocol version number.
*/
static void SVC_InfoResponse( const socket_t *socket, const netadr_t *address )
{
	int i, count;
	char *string;
	qboolean allow_empty = qfalse, allow_full = qfalse;

	if( sv_showInfoQueries->integer )
		Com_Printf( "Info Packet %s\n", NET_AddressToString( address ) );

	// KoFFiE: When not public and coming from a LAN address
	//         assume broadcast and respond anyway, otherwise ignore
	if( ( ( !sv_public->integer ) && ( !NET_IsLANAddress( address ) ) ) ||
		( sv_maxclients->integer == 1 ) )
	{
		return;
	}

	// ignore when in invalid server state
	if( sv.state < ss_loading || sv.state > ss_game )
		return;

	// don't reply when we are locked for mm
	// if( SV_MM_IsLocked() )
	//	return;

	// different protocol version
	if( atoi( Cmd_Argv( 1 ) ) != APP_PROTOCOL_VERSION )
		return;

	// check for full/empty filtered states
	for( i = 0; i < Cmd_Argc(); i++ )
	{
		if( !Q_stricmp( Cmd_Argv( i ), "full" ) )
			allow_full = qtrue;

		if( !Q_stricmp( Cmd_Argv( i ), "empty" ) )
			allow_empty = qtrue;
	}

	count = 0;
	for( i = 0; i < sv_maxclients->integer; i++ )
	{
		if( svs.clients[i].state >= CS_CONNECTED )
		{
			count++;
		}
	}

	if( ( count == sv_maxclients->integer ) && !allow_full )
	{
		return;
	}

	if( ( count == 0 ) && !allow_empty )
	{
		return;
	}

	string = SV_ShortInfoString();
	if( string )
		Netchan_OutOfBandPrint( socket, address, "info\n%s", string );
}