Source/ThunderBeast/QuakeToon/server/sv_main.c
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_free)
			continue;
		if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
			&& ( cl->netchan.qport == qport 
			|| adr.port == cl->netchan.remote_address.port ) )
		{
			if (!NET_IsLocalAddress (adr) && (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;
}
/*
==================
SVC_DirectConnect

A connection request that did not come from the master
==================
*/
SVC_DirectConnect
A connection request that did not come from the master
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;
	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;
	Info_SetValueForKey (userinfo, "ip", NET_AdrToString(net_from));
	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;
		}
	}
	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;		
				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));
	for (i=0,cl=svs.clients ; i<maxclients->value ; 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 (!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;
		}
	}
	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:	
	*newcl = temp;
	sv_client = newcl;
	edictnum = (newcl-svs.clients)+1;
	ent = EDICT_NUM(edictnum);
	newcl->edict = ent;
	newcl->challenge = challenge; 
	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;
	}
	strncpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)-1);
	SV_UserinfoChanged (newcl);
	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;	
	newcl->lastconnect = svs.realtime;
}
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 ( " \n " ) ; version = atoi ( Cmd_Argv ( 1 ) ) ; if ( version != PROTOCOL_VERSION ) { Netchan_OutOfBandPrint ( NS_SERVER , adr , " \n \n " , VERSION ) ; Com_DPrintf ( " \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 ; Info_SetValueForKey ( userinfo , " " , NET_AdrToString ( net_from ) ) ; if ( sv . attractloop ) { if ( ! NET_IsLocalAddress ( adr ) ) { Com_Printf ( " \n " ) ; Netchan_OutOfBandPrint ( NS_SERVER , adr , " \n \n " ) ; return ; } } 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 ; Netchan_OutOfBandPrint ( NS_SERVER , adr , " \n \n " ) ; return ; } } if ( i == MAX_CHALLENGES ) { Netchan_OutOfBandPrint ( NS_SERVER , adr , " \n \n " ) ; return ; } } newcl = & temp ; memset ( newcl , 0 , sizeof ( client_t ) ) ; for ( i = 0 , cl = svs . clients ; i < maxclients -> value ; 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 ( ! NET_IsLocalAddress ( adr ) && ( svs . realtime - cl -> lastconnect ) < ( ( int ) sv_reconnect_limit -> value * 1000 ) ) { Com_DPrintf ( " \n " , NET_AdrToString ( adr ) ) ; return ; } Com_Printf ( " \n " , NET_AdrToString ( adr ) ) ; newcl = cl ; goto gotnewcl ; } } 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 , " \n \n " ) ; Com_DPrintf ( " \n " ) ; return ; } gotnewcl : * newcl = temp ; sv_client = newcl ; edictnum = ( newcl - svs . clients ) + 1 ; ent = EDICT_NUM ( edictnum ) ; newcl -> edict = ent ; newcl -> challenge = challenge ; if ( ! ( ge -> ClientConnect ( ent , userinfo ) ) ) { if ( * Info_ValueForKey ( userinfo , " " ) ) Netchan_OutOfBandPrint ( NS_SERVER , adr , " \n \n \n " , Info_ValueForKey ( userinfo , " " ) ) ; else Netchan_OutOfBandPrint ( NS_SERVER , adr , " \n \n " ) ; Com_DPrintf ( " \n " ) ; return ; } strncpy ( newcl -> userinfo , userinfo , sizeof ( newcl -> userinfo ) - 1 ) ; SV_UserinfoChanged ( newcl ) ; Netchan_OutOfBandPrint ( NS_SERVER , adr , " " ) ; 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 ; newcl -> lastconnect = svs . realtime ; }
SVC_DirectConnect
A connection request that did not come from the master
SVC_DirectConnect A connection request that did not come from the master
// force the IP key/value pair so the game can filter based on ip // attractloop servers are ONLY for local clients // see if the challenge is valid // good // if there is already a slot for this ip, reuse it // find a client slot // build a new connection // accept the new client // this is the only place a client_t is ever initialized // save challenge for checksumming // get the game a chance to reject this connection or modify the userinfo // parse some info from the info strings // send the connect packet to the client // don't timeout