Exemple #1
0
edict_t *SV_CreateBot ()
{
	int			i, numclients;
	client_t	*cl, *newcl;
	edict_t		*ent;

	numclients = 0;
	newcl = NULL;

	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) {
		if (cl->state == cs_free) {
			if (!newcl)
				newcl = cl;
			continue;
		}
		if (!cl->spectator)
			numclients++;
	}

	if (numclients >= maxclients.value || !newcl)
		return sv.edicts;		// all player spots full, return world

	newcl->clear();
	newcl->state = cs_spawned;
	newcl->bot = true;
	newcl->userid = SV_GenerateUserID();
	newcl->extensions = CLIENT_EXTENSIONS;	// bots always use latest ZQuake :-)

	// init a bogus network connection
	SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf));
	newcl->datagram.allowoverflow = true;
	Netchan_Setup (NS_SERVER, &newcl->netchan, net_null, 0);

	// set up the edict
	ent = EDICT_NUM((newcl - svs.clients) + 1);
	newcl->edict = ent;

//	Com_DPrintf ("Bot %s connected\n", newcl->name.c_str());

	SetUpClientEdict (newcl, ent);

	return ent;
}
Exemple #2
0
/*
==================
SVC_DirectConnect

A connection request that did not come from the master
==================
*/
void SVC_DirectConnect (void)
{
	char		userinfo[1024];
	netadr_t	adr;
	int			i;
	client_t	*cl, *newcl;
	edict_t		*ent;
	int			edictnum;
	char		*s;
	int			clients, spectators;
	qbool		spectator;
	int			qport;
	int			version;
	int			challenge;

	version = atoi(Cmd_Argv(1));
	if (version != PROTOCOL_VERSION)
	{
		Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nServer is version %4.2f.\n", A2C_PRINT, QW_VERSION);
		Com_Printf ("* rejected connect from version %i\n", version);
		return;
	}

	qport = atoi(Cmd_Argv(2));
	challenge = atoi(Cmd_Argv(3));

	// note an extra byte is needed to replace spectator key
	strlcpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-1);

	// see if the challenge is valid
	if (net_from.type != NA_LOOPBACK)
	{
		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, net_from, "%c\nBad challenge.\n", A2C_PRINT);
				return;
			}
		}
		if (i == MAX_CHALLENGES)
		{
			Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nNo challenge for address.\n", A2C_PRINT);
			return;
		}
	}

	// check for password or spectator_password
	s = Info_ValueForKey (userinfo, "spectator");
	if (s[0] && strcmp(s, "0"))
	{
		if (sv_spectatorPassword.string[0] && 
			Q_stricmp(sv_spectatorPassword.string, "none") &&
			strcmp(sv_spectatorPassword.string, s) )
		{	// failed
			Com_Printf ("%s:spectator password failed\n", NET_AdrToString (net_from));
			Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nrequires a spectator password\n\n", A2C_PRINT);
			return;
		}
		Info_RemoveKey (userinfo, "spectator");
		Info_SetValueForStarKey (userinfo, "*spectator", "1", MAX_INFO_STRING);
		spectator = true;
	}
	else
	{
		s = Info_ValueForKey (userinfo, "password");
		if (sv_password.string[0] && 
			Q_stricmp(sv_password.string, "none") &&
			strcmp(sv_password.string, s) )
		{
			Com_Printf ("%s:password failed\n", NET_AdrToString (net_from));
			Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nserver requires a password\n\n", A2C_PRINT);
			return;
		}
		spectator = false;
		Info_RemoveKey (userinfo, "password");
	}

#ifdef MAUTH
    // Check that the client is allowed to connect...
	if( net_from.type != NA_LOOPBACK && !COM_CheckParm("-nomauth") )
    {
        authclient_t *authclient;
    
        // Try the auth token queue first...
        authclient = SV_AuthListFind(&authtokq, Info_ValueForKey(userinfo, "name"));
        if( authclient == NULL )
        {
            // Fall back to checking if they had already connected and are in the
            // client queue already (i.e. were on here before a map change)...
            authclient = SV_AuthListFind(&authclientq, Info_ValueForKey(userinfo, "name"));
            if( authclient == NULL )
            {
                // FIXME drop with reason
                Com_Printf ("MAUTH: Client %s not in a queue; connect refused.\n", Info_ValueForKey(userinfo, "name"));
                return;
            }
        }
        else
        {
            // They're valid, so move them to the main client queue from the
            // auth cache queue...
            SV_AuthListMove(&authtokq, &authclientq, authclient);
        }

        // Move to auth'd clients queue if they're valid...
        if( !authclient->valid )
        {
            // FIXME drop with reason
            Com_Printf ("MAUTH: Client %s not validated yet; connect refused.\n", Info_ValueForKey(userinfo, "name"));
            return;
        }
        
        //SV_AuthListPrint(&authtokq);
        //SV_AuthListPrint(&authclientq);
        
        Com_Printf ("MAUTH: Client %s connection allowed.\n", Info_ValueForKey(userinfo, "name"));
    }
    else
    {
        Com_Printf("MAUTH: loopback or disabled; allowing client connection.\n");
    }
#endif

	adr = net_from;

	// if there is already a slot for this ip, reuse it
	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
	{
		if (cl->state == cs_free)
			continue;
		if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
			&& ( cl->netchan.qport == qport 
			|| adr.port == cl->netchan.remote_address.port ))
		{
			if (cl->state == cs_connected) {
				Com_Printf ("%s:dup connect\n", NET_AdrToString (adr));
				return;
			}

			Com_Printf ("%s:reconnect\n", NET_AdrToString (adr));
			if (cl->state == cs_spawned)
			{
				SV_DropClient (cl);
				SV_ClearReliable (cl);	// don't send the disconnect
			}
			cl->state = cs_free;
			break;
		}
	}

	// count up the clients and spectators and find an empty client slot
	clients = spectators = 0;
	newcl = NULL;
	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++,cl++)
	{
		if (cl->state == cs_free) {
			if (!newcl)
				newcl = cl;		// grab first available slot
			continue;
		}
		if (cl->spectator)
			spectators++;
		else
			clients++;
	}

	// if at server limits, refuse connection
	if ( (spectator && spectators >= (int)maxspectators.value)
		|| (!spectator && clients >= (int)maxclients.value)
		|| !newcl)
	{
		Com_Printf ("%s:full connect\n", NET_AdrToString (adr));
		Netchan_OutOfBandPrint (NS_SERVER, adr, "%c\nserver is full\n\n", A2C_PRINT);
		return;
	}

	// build a new connection
	// accept the new client
	// this is the only place a client_t is ever initialized
	memset (newcl, 0, sizeof(*newcl));
	newcl->userid = SV_GenerateUserID();

	strlcpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo));

	Netchan_OutOfBandPrint (NS_SERVER, adr, "%c", S2C_CONNECTION );

	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;

	// spectator mode can ONLY be set at join time
	newcl->spectator = spectator;

	// extract extensions bits
	newcl->extensions = atoi(Info_ValueForKey(newcl->userinfo, "*z_ext"));
	Info_RemoveKey (newcl->userinfo, "*z_ext");

#ifdef VWEP_TEST
	newcl->extensions |= atoi(Info_ValueForKey(newcl->userinfo, "*vwtest")) ? Z_EXT_VWEP : 0;
	Info_RemoveKey (newcl->userinfo, "*vwtest");
#endif

	// See if the client is using a proxy. The best test I can come up with for now...
	newcl->uses_proxy = *Info_ValueForKey(newcl->userinfo, "Qizmo") ? true : false;

	edictnum = (newcl - svs.clients) + 1;
	ent = EDICT_NUM(edictnum);	
	ent->inuse = true;
	newcl->edict = ent;
	
	// parse some info from the info strings
	SV_ExtractFromUserinfo (newcl);

	// JACK: Init the floodprot stuff.
	for (i=0; i<10; i++)
		newcl->whensaid[i] = 0.0;
	newcl->whensaidhead = 0;
	newcl->lockedtill = 0;

	// call the progs to get default spawn parms for the new client
	PR_ExecuteProgram (pr_global_struct->SetNewParms);
	for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
		newcl->spawn_parms[i] = (&pr_global_struct->parm1)[i];

	if (newcl->spectator)
		Com_Printf ("Spectator %s connected\n", newcl->name);
	else
		Com_DPrintf ("Client %s connected\n", newcl->name);

	newcl->sendinfo = true;
}