Beispiel #1
0
void
SV_Status_f (void)
{
	int         i;
	client_t   *cl;
	float       cpu, avg, pak, demo = 0;
	const char *s;


	cpu = (svs.stats.latched_active + svs.stats.latched_idle);
	if (cpu) {
		demo = 100 * svs.stats.latched_demo / cpu;
		cpu = 100 * svs.stats.latched_active / cpu;
	}
	avg = 1000 * svs.stats.latched_active / STATFRAMES;
	pak = (float) svs.stats.latched_packets / STATFRAMES;

	SV_Printf ("net address      : %s\n", NET_AdrToString (net_local_adr));
	SV_Printf ("uptime           : %s\n", nice_time (Sys_DoubleTime ()));
	SV_Printf ("cpu utilization  : %3i%% (%3i%%)\n", (int) cpu, (int)demo);
	SV_Printf ("avg response time: %i ms\n", (int) avg);
	SV_Printf ("packets/frame    : %5.2f\n", pak);

	// min fps lat drp
	if (sv_redirected != RD_NONE && sv_redirected != RD_MOD) {
		// most remote clients are 40 columns
		//          0123456789012345678901234567890123456789
		SV_Printf ("name               userid frags\n");
		SV_Printf ("  address          rate ping drop\n");
		SV_Printf ("  ---------------- ---- ---- -----\n");
		for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) {
			if (!cl->state)
				continue;

			SV_Printf ("%-16.16s  ", cl->name);

			SV_Printf ("%6i %5i", cl->userid, (int) SVfloat (cl->edict, frags));
			if (cl->spectator)
				SV_Printf (" (s)\n");
			else
				SV_Printf ("\n");

			s = NET_BaseAdrToString (cl->netchan.remote_address);
			SV_Printf ("  %-16.16s", s);
			if (cl->state == cs_connected) {
				SV_Printf ("CONNECTING\n");
				continue;
			}
			if (cl->state == cs_zombie) {
				SV_Printf ("ZOMBIE\n");
				continue;
			}
			if (cl->state == cs_server) {
				SV_Printf ("SERVER %d\n", cl->ping);
				continue;
			}
			SV_Printf ("%4i %4i %5.2f\n",
					   (int) (1000 * cl->netchan.frame_rate),
					   (int) SV_CalcPing (cl),
					   100.0 * cl->netchan.drop_count /
							cl->netchan.incoming_sequence);
		}
	} else {
		SV_Printf ("frags userid address         name            rate ping "
				   "drop  qport\n");
		SV_Printf ("----- ------ --------------- --------------- ---- ---- "
				   "----- -----\n");
		for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) {
			if (!cl->state)
				continue;
			SV_Printf ("%5i %6i ", (int) SVfloat (cl->edict, frags),
					   cl->userid);

			s = NET_BaseAdrToString (cl->netchan.remote_address);

			SV_Printf ("%-15.15s ", s);

			SV_Printf ("%-15.15s ", cl->name);

			if (cl->state == cs_connected) {
				SV_Printf ("CONNECTING\n");
				continue;
			}
			if (cl->state == cs_zombie) {
				SV_Printf ("ZOMBIE\n");
				continue;
			}
			if (cl->state == cs_server) {
				SV_Printf ("SERVER %d\n", cl->ping);
				continue;
			}
			SV_Printf ("%4i %4i %3.1f %4i",
						(int) (1000 * cl->netchan.frame_rate),
						(int) SV_CalcPing (cl),
						100.0 * cl->netchan.drop_count /
						cl->netchan.incoming_sequence, cl->netchan.qport);
			if (cl->spectator)
				SV_Printf (" (s)\n");
			else
				SV_Printf ("\n");
		}
	}
	SV_Printf ("\n");
}
Beispiel #2
0
/*
=============
NET_SendPacket
=============
*/
int NET_SendPacket (netsrc_t sock, int length, const void *data, const netadr_t *to)
{
	int		ret, err;
	struct sockaddr	addr;

	switch( to->type ) {
	case NA_LOOPBACK:
		NET_SendLoopPacket (sock, length, data);
		return 1;
	case NA_IP:
	case NA_BROADCAST:
		break;
	default:
		Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
		return 0;
	}

	if (ip_sockets[sock] == INVALID_SOCKET)
		return 0;

	NetadrToSockadr (to, &addr);

	ret = sendto (ip_sockets[sock], data, length, 0, &addr, sizeof(addr) );
	if (ret == SOCKET_ERROR)
	{
#ifdef _WIN32
		err = WSAGetLastError();

		switch( err ) {
		case WSAEWOULDBLOCK:
		case WSAEINTR:
			// wouldblock is silent
			break;
		case WSAECONNRESET:
		case WSAEHOSTUNREACH:
			if( !net_ignore_icmp->integer ) {
				return -1;
			}
			break;
		case WSAEADDRNOTAVAIL:
			// some PPP links dont allow broadcasts
			if (to->type == NA_BROADCAST)
				break;
			// intentional fallthrough
		default:
			Com_Printf ("NET_SendPacket ERROR: %s (%d) to %s\n",
				NET_ErrorString(), err, NET_AdrToString(to));
			break;
		}
#else
		err = errno;

		switch( err ) {
		case EWOULDBLOCK:
			// wouldblock is silent
			break;
		case ECONNRESET:
		case EHOSTUNREACH:
		case ENETUNREACH:
		case ENETDOWN:
			if( !net_ignore_icmp->integer ) {
				return -1;
			}
			break;
		default:
			Com_Printf ("NET_SendPacket ERROR: %s (%d) to %s\n",
				NET_ErrorString(), err, NET_AdrToString( to ) );
			break;
		}
#endif
		return 0;
	}
	return 1;
}
Beispiel #3
0
/*
==================
NET_GetPacket

Receive one packet
==================
*/
qboolean NET_GetPacket(netadr_t *net_from, msg_t *net_message, fd_set *fdr)
{
	int 	ret;
	struct sockaddr_storage from;
	socklen_t	fromlen;
	int		err;
	
	if(ip_socket != INVALID_SOCKET && FD_ISSET(ip_socket, fdr))
	{
		fromlen = sizeof(from);
		ret = recvfrom( ip_socket, (void *)net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen );
		
		if (ret == SOCKET_ERROR)
		{
			err = socketError;

			if( err != EAGAIN && err != ECONNRESET )
				Com_Printf( "NET_GetPacket: %s\n", NET_ErrorString() );
		}
		else
		{

			memset( ((struct sockaddr_in *)&from)->sin_zero, 0, 8 );
		
			if ( usingSocks && memcmp( &from, &socksRelayAddr, fromlen ) == 0 ) {
				if ( ret < 10 || net_message->data[0] != 0 || net_message->data[1] != 0 || net_message->data[2] != 0 || net_message->data[3] != 1 ) {
					return qfalse;
				}
				net_from->type = NA_IP;
				net_from->ip[0] = net_message->data[4];
				net_from->ip[1] = net_message->data[5];
				net_from->ip[2] = net_message->data[6];
				net_from->ip[3] = net_message->data[7];
				net_from->port = *(short *)&net_message->data[8];
				net_message->readcount = 10;
			}
			else {
				SockadrToNetadr( (struct sockaddr *) &from, net_from );
				net_message->readcount = 0;
			}
		
			if( ret >= net_message->maxsize ) {
				Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
				return qfalse;
			}
			
			net_message->cursize = ret;
			return qtrue;
		}
	}
	
	if(ip6_socket != INVALID_SOCKET && FD_ISSET(ip6_socket, fdr))
	{
		fromlen = sizeof(from);
		ret = recvfrom(ip6_socket, (void *)net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen);
		
		if (ret == SOCKET_ERROR)
		{
			err = socketError;

			if( err != EAGAIN && err != ECONNRESET )
				Com_Printf( "NET_GetPacket: %s\n", NET_ErrorString() );
		}
		else
		{
			SockadrToNetadr((struct sockaddr *) &from, net_from);
			net_message->readcount = 0;
		
			if(ret >= net_message->maxsize)
			{
				Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
				return qfalse;
			}
			
			net_message->cursize = ret;
			return qtrue;
		}
	}

	if(multicast6_socket != INVALID_SOCKET && multicast6_socket != ip6_socket && FD_ISSET(multicast6_socket, fdr))
	{
		fromlen = sizeof(from);
		ret = recvfrom(multicast6_socket, (void *)net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen);
		
		if (ret == SOCKET_ERROR)
		{
			err = socketError;

			if( err != EAGAIN && err != ECONNRESET )
				Com_Printf( "NET_GetPacket: %s\n", NET_ErrorString() );
		}
		else
		{
			SockadrToNetadr((struct sockaddr *) &from, net_from);
			net_message->readcount = 0;
		
			if(ret >= net_message->maxsize)
			{
				Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
				return qfalse;
			}
			
			net_message->cursize = ret;
			return qtrue;
		}
	}
	
	
	return qfalse;
}
Beispiel #4
0
void CL_cURL_BeginDownload(const char *localName, const char *remoteURL) {
	clc.curl.used = qtrue;
	Com_Printf("URL: %s\n", remoteURL);
	Com_DPrintf("***** CL_cURL_BeginDownload *****\n"
		"Localname: %s\n"
		"RemoteURL: %s\n"
		"****************************\n", localName, remoteURL);
	CL_cURL_Cleanup();
	Q_strncpyz(clc.curl.downloadURL, remoteURL, sizeof(clc.curl.downloadURL));
	Q_strncpyz(clc.downloadName, localName, sizeof(clc.downloadName));
	Com_sprintf(clc.downloadTempName, sizeof(clc.downloadTempName), "%s.tmp", localName);
	// Set so UI gets access to it
	Cvar_Set("cl_downloadName", localName);
	Cvar_Set("cl_downloadSize", "0");
	Cvar_Set("cl_downloadCount", "0");
	Cvar_SetValue("cl_downloadTime", cls.realtime);
	clc.downloadBlock = 0; // Starting new file
	clc.downloadCount = 0;
	clc.curl.downloadCURL = qcurl_easy_init();
	if(!clc.curl.downloadCURL) {
		Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_easy_init() failed");
		return;
	}
	clc.download = FS_SV_FOpenFileWrite(clc.downloadTempName);
	if(!clc.download) {
		Com_Error(ERR_DROP, "CL_cURL_BeginDownload: failed to open %s for writing", clc.downloadTempName);
		return;
	}
	if(com_developer->integer)
		qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_VERBOSE, 1);
	qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_URL, clc.curl.downloadURL);
	qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_TRANSFERTEXT, 0);
	qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_REFERER, va("jka://%s", NET_AdrToString(clc.serverAddress)));
	qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_USERAGENT, va("%s %s", JK_VERSION, qcurl_version()));
	qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_WRITEFUNCTION, CL_cURL_CallbackWrite);
	qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_WRITEDATA, &clc.download);
	qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_NOPROGRESS, 0);
	qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_PROGRESSFUNCTION, CL_cURL_CallbackProgress);
    qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_SSL_VERIFYPEER, 0);
	qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_PROGRESSDATA, NULL);
	qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_FAILONERROR, 1);
	qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_FOLLOWLOCATION, 1);
	qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_MAXREDIRS, 5);
	clc.curl.downloadCURLM = qcurl_multi_init();	
	if(!clc.curl.downloadCURLM) {
		qcurl_easy_cleanup(clc.curl.downloadCURL);
		clc.curl.downloadCURL = NULL;
		Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_multi_init() failed");
		return;
	}
	qcurl_multi_add_handle(clc.curl.downloadCURLM, clc.curl.downloadCURL);
	if(
//		!(clc.sv_allowDownload & DLF_NO_DISCONNECT) && 
		!clc.curl.disconnected) {

		CL_AddReliableCommand("disconnect", qtrue);
		CL_WritePacket();
		CL_WritePacket();
		CL_WritePacket();
		clc.curl.disconnected = qtrue;
	}
}
Beispiel #5
0
/*
============
Cmd_TokenizeString

Parses the given string into command line tokens.
$Cvars will be expanded unless they are in a quoted token

R1CH: Modified this to avoid use of Z_Alloc/Z_Free. Using
dynamic memory functions for maybe 4-5 bytes at a time is
a waste...
============
*/
void Cmd_TokenizeString (char *text, qboolean macroExpand)
{
	int			cmd_pointer;
	int			i;
	const char	*com_token;

// clear the args from the last string
	for (i=0 ; i<cmd_argc ; i++)
		cmd_argv[i] = NULL;
		//Z_Free (cmd_argv[i]);
		
	cmd_argc = 0;
	cmd_args[0] = 0;
	cmd_pointer = 0;

	// macro expand the text
	if (macroExpand && strchr(text, '$'))
		text = Cmd_MacroExpandString (text);

	if (!text)
		return;

	for (;;)
	{
		// skip whitespace up to a /n
		while (*text && (*text == '\t' || *text == ' ')  && *text != '\n')
		{
			text++;
		}
		
		if (*text == '\n')
		{	// a newline seperates commands in the buffer
			text++;
			break;
		}

		if (!*text)
			return;

		// set cmd_args to everything after the first arg
		if (cmd_argc == 1)
		{
			int		l;

			strncpy (cmd_args, text, sizeof(cmd_args)-1);

			// strip off any trailing whitespace
			l = (int)strlen(cmd_args) - 1;
			if (l == MAX_STRING_CHARS - 1) {
				Com_Printf ("Cmd_TokenizeString: overflowed, possible attack detected.\nargv[0] = %s, remote = %s, len = %d\n", LOG_GENERAL|LOG_EXPLOIT,
					cmd_argv[0], NET_AdrToString(&net_from), net_message.cursize);
				return;
			}
			for ( ; l >= 0 ; l--)
				if (cmd_args[l] <= ' ')
					cmd_args[l] = 0;
				else
					break;
		}
			
		com_token = COM_Parse (&text);
		if (!text)
			return;

		if (cmd_argc < MAX_STRING_TOKENS)
		{
			int len;
			//cmd_argv[cmd_argc] = Z_TagMalloc (strlen(com_token)+1, TAGMALLOC_CMDTOKEN);
			//strcpy (cmd_argv[cmd_argc], com_token);
			len = (int)strlen(com_token);
			if (len+1 + cmd_pointer >= MAX_STRING_CHARS*2)
			{
				Com_Printf ("Cmd_TokenizeString: overflow\n", LOG_GENERAL);
				return;
			}
			strcpy (cmd_buffer + cmd_pointer, com_token);
			cmd_argv[cmd_argc] = cmd_buffer + cmd_pointer;
			cmd_argc++;
			cmd_pointer += len+1;
		}
	}
	
}
Beispiel #6
0
/* <66564> ../engine/net_chan.c:1500 */
int Netchan_CreateFileFragments(qboolean server, netchan_t *chan, const char *filename)
{
	int chunksize;
	int compressedFileTime;
	FileHandle_t hfile;
	signed int filesize;
	int remaining;
	fragbufwaiting_t *p;
	int send;
	fragbuf_t *buf;
	char compressedfilename[MAX_PATH];
	int firstfragment;
	int bufferid;
	int bCompressed;
	int pos;
	fragbufwaiting_t *wait;
	int uncompressed_size;

	bufferid = 1;
	firstfragment = TRUE;
	bCompressed = FALSE;
	chunksize = chan->pfnNetchan_Blocksize(chan->connection_status);

	Q_snprintf(compressedfilename, sizeof compressedfilename, "%s.ztmp", filename);
	compressedFileTime = FS_GetFileTime(compressedfilename);
	if (compressedFileTime >= FS_GetFileTime(filename) && (hfile = FS_Open(compressedfilename, "rb")))
	{
		filesize = FS_Size(hfile);
		FS_Close(hfile);
		bCompressed = 1;
		hfile = FS_Open(filename, "rb");
		if (!hfile)
		{
			Con_Printf("Warning:  Unable to open %s for transfer\n", filename);
			return 0;
		}

		uncompressed_size = FS_Size(hfile);
		if (uncompressed_size > sv_filetransfermaxsize.value)
		{
			FS_Close(hfile);
			Con_Printf("Warning:  File %s is too big to transfer from host %s\n", filename, NET_AdrToString(chan->remote_address));
			return 0;
		}
	}
	else
	{
		hfile = FS_Open(filename, "rb");
		if (!hfile)
		{
			Con_Printf("Warning:  Unable to open %s for transfer\n", filename);
			return 0;
		}
		filesize = FS_Size(hfile);
		if (filesize > sv_filetransfermaxsize.value)
		{
			FS_Close(hfile);
			Con_Printf("Warning:  File %s is too big to transfer from host %s\n", filename, NET_AdrToString(chan->remote_address));
			return 0;
		}

		uncompressed_size = filesize;
		if (sv_filetransfercompression.value != 0.0)
		{
			unsigned char* uncompressed = (unsigned char*)Mem_Malloc(filesize);
			unsigned char* compressed = (unsigned char*)Mem_Malloc(filesize);
			unsigned int compressedSize = filesize;
			FS_Read(uncompressed, filesize, 1, hfile);
			if (BZ_OK == BZ2_bzBuffToBuffCompress((char*)compressed, &compressedSize, (char*)uncompressed, filesize, 9, 0, 30))
			{
				FileHandle_t destFile = FS_Open(compressedfilename, "wb");
				if (destFile)
				{
					Con_DPrintf("Creating compressed version of file %s (%d -> %d)\n", filename, filesize, compressedSize);
					FS_Write(compressed, compressedSize, 1, destFile);
					FS_Close(destFile);
					filesize = compressedSize;
					bCompressed = 1;
				}
			}
			Mem_Free(uncompressed);
			Mem_Free(compressed);
		}
	}
	FS_Close(hfile);

	wait = (fragbufwaiting_t *)Mem_ZeroMalloc(0xCu);
	remaining = filesize;
	pos = 0;

	while (remaining)
	{
		send = min(chunksize, remaining);
		buf = Netchan_AllocFragbuf();
		if (!buf)
		{
			Con_Printf("Couldn't allocate fragbuf_t\n");
			Mem_Free(wait);
			if (server)
			{
				SV_DropClient(host_client, 0, "Malloc problem");
				return 0;
			}
			else
			{
				rehlds_syserror(__FUNCTION__ ": Reverse clientside code");
				return 0;
			}
		}

		buf->bufferid = bufferid++;
		SZ_Clear(&buf->frag_message);
		if (firstfragment)
		{
			firstfragment = FALSE;
			MSG_WriteString(&buf->frag_message, filename);
			MSG_WriteString(&buf->frag_message, bCompressed ? "bz2" : "uncompressed");
			MSG_WriteLong(&buf->frag_message, uncompressed_size);
			send -= buf->frag_message.cursize;
		}
		buf->isfile = TRUE;
		buf->iscompressed = bCompressed;
		buf->size = send;
		buf->foffset = pos;

		Q_strncpy(buf->filename, filename, MAX_PATH - 1);
		buf->filename[MAX_PATH - 1] = 0;

		pos += send;
		remaining -= send;

		Netchan_AddFragbufToTail(wait, buf);
	}

	if (!chan->waitlist[FRAG_FILE_STREAM])
	{
		chan->waitlist[FRAG_FILE_STREAM] = wait;
	}
	else
	{
		p = chan->waitlist[FRAG_FILE_STREAM];
		while (p->next)
			p = p->next;

		p->next = wait;
	}

	return 1;
}
Beispiel #7
0
/* <65fe9> ../engine/net_chan.c:872 */
qboolean Netchan_Process(netchan_t *chan)
{
	//	int i;                                                        //   874
	//	unsigned int sequence;                                        //   875
	//	unsigned int sequence_ack;                                    //   875
	//	unsigned int reliable_ack;                                    //   876
	//	unsigned int reliable_message;                                //   876
	//	unsigned int fragid;                                          //   877
	//	qboolean frag_message;                                        //   878
	//	int frag_offset;                                              //   879
	//	int frag_length;                                              //   880
	//	qboolean message_contains_fragments;                          //   881
	//	Netchan_Validate(netchan_t *chan,
	//		qboolean *frag_message,
	//		unsigned int *fragid,
	//		int *frag_offset,
	//		int *frag_length); /* size=0, low_pc=0 */ //   933
	//	{
	//		char c;                                               //   946
	//		int mask;                                             //   947
	//	}
	//	{
	//		int j;                                                //  1038
	//		unsigned char *src;                                  //  1039
	//		unsigned char *dst;                                  //  1039
	//		int len;                                              //  1040
	//		fragbuf_t *pbuf;                                     //  1041
	//		int inbufferid;                                       //  1042
	//		int intotalbuffers;                                   //  1043
	//		Netchan_FindBufferById(fragbuf_t **pplist,
	//			int id,
	//			qboolean allocate); /* size=0, low_pc=0 */ //  1053
	//		{
	//			int nbytes;                                   //  1056
	//		}
	//	}

	int				i;
	unsigned int	sequence, sequence_ack;
	unsigned int	reliable_ack, reliable_message;
	unsigned int	fragid[MAX_STREAMS] = { 0, 0 };
	qboolean		frag_message[MAX_STREAMS] = { false, false };
	int				frag_offset[MAX_STREAMS] = { 0, 0 };
	int				frag_length[MAX_STREAMS] = { 0, 0 };
	qboolean		message_contains_fragments;


	if (!g_pcls.demoplayback && !g_pcls.passive)
	{
		if (!NET_CompareAdr(net_from, chan->remote_address))
			return FALSE;
	}

	chan->last_received = realtime;

	// get sequence numbers		
	MSG_BeginReading();
	sequence = MSG_ReadLong();
	sequence_ack = MSG_ReadLong();

	if (sequence_ack & 0x40000000)
	{
		if (!g_modfuncs.m_pfnProcessIncomingNet)
			return FALSE;
	}

	if (g_modfuncs.m_pfnProcessIncomingNet)
	{
		if (!g_modfuncs.m_pfnProcessIncomingNet(chan, &net_message))
			return FALSE;
	}

	reliable_message = sequence >> 31;
	reliable_ack = sequence_ack >> 31;
	message_contains_fragments = sequence & (1 << 30) ? true : false;

	COM_UnMunge2(&net_message.data[8], net_message.cursize - 8, sequence & 0xFF);
	if (message_contains_fragments)
	{
		for (i = 0; i < MAX_STREAMS; i++)
		{
			if (MSG_ReadByte())
			{
				frag_message[i] = true;
				fragid[i] = MSG_ReadLong();
				frag_offset[i] = MSG_ReadShort();
				frag_length[i] = MSG_ReadShort();
			}
		}

		if (!Netchan_Validate(chan, frag_message, fragid, frag_offset, frag_offset))
			return FALSE;
	}

	sequence &= ~(1 << 31);
	sequence &= ~(1 << 30);
	sequence_ack &= ~(1 << 31);
	sequence_ack &= ~(1 << 30);

	if (net_showpackets.value != 0.0 && net_showpackets.value != 3.0)
	{
		char c = (chan == &g_pcls.netchan) ? 'c' : 's';

		Con_Printf(
			" %c <-- sz=%i seq=%i ack=%i rel=%i tm=%f\n",
			c,
			net_message.cursize,
			sequence,
			sequence_ack,
			reliable_message,
			(chan == &g_pcls.netchan) ? g_pcl.time : g_psv.time);
	}

	if (sequence <= (unsigned)chan->incoming_sequence)
	{
		if (net_showdrop.value != 0.0) {
			if (sequence == (unsigned)chan->incoming_sequence)
				Con_Printf("%s:duplicate packet %i at %i\n", NET_AdrToString(chan->remote_address), sequence, chan->incoming_sequence);
			else
				Con_Printf("%s:out of order packet %i at %i\n", NET_AdrToString(chan->remote_address), sequence, chan->incoming_sequence);
		}
		return FALSE;
	}

	//
	// dropped packets don't keep the message from being used
	//
	net_drop = sequence - (chan->incoming_sequence + 1);
	if (net_drop > 0 && net_showdrop.value != 0.0)
	{
		Con_Printf("%s:Dropped %i packets at %i\n", NET_AdrToString(chan->remote_address), net_drop, sequence);
	}

	//
	// if the current outgoing reliable message has been acknowledged
	// clear the buffer to make way for the next
	//
	if (reliable_ack == (unsigned)chan->reliable_sequence)
	{
		// Make sure we actually could have ack'd this message
		if (chan->incoming_acknowledged + 1 >= chan->last_reliable_sequence)
		{
			chan->reliable_length = 0;	// it has been received
		}
	}

	//
	// if this message contains a reliable message, bump incoming_reliable_sequence 
	//
	chan->incoming_sequence = sequence;
	chan->incoming_acknowledged = sequence_ack;
	chan->incoming_reliable_acknowledged = reliable_ack;
	if (reliable_message)
	{
		chan->incoming_reliable_sequence ^= 1;
	}

	int statId = chan->flow[FLOW_INCOMING].current & 0x1F;
	chan->flow[FLOW_INCOMING].stats[statId].size = net_message.cursize + UDP_HEADER_SIZE;
	chan->flow[FLOW_INCOMING].stats[statId].time = realtime;
	chan->flow[FLOW_INCOMING].current++;
	Netchan_UpdateFlow(chan);

	if (message_contains_fragments)
	{
		for (i = 0; i < MAX_STREAMS; i++)
		{
			int j;
			fragbuf_t *pbuf;
			int inbufferid;
			int intotalbuffers;

			if (!frag_message[i])
				continue;

			inbufferid = FRAG_GETID(fragid[i]);
			intotalbuffers = FRAG_GETCOUNT(fragid[i]);

			if (fragid[i] != 0)
			{
				pbuf = Netchan_FindBufferById(&chan->incomingbufs[i], fragid[i], true);
				if (pbuf) {
					int len = frag_length[i];
					SZ_Clear(&pbuf->frag_message);
					SZ_Write(&pbuf->frag_message, &net_message.data[msg_readcount + frag_offset[i]], len);
				}
				else {
					Con_Printf("Netchan_Process:  Couldn't allocate or find buffer %i\n", inbufferid);
				}
				// Count # of incoming bufs we've queued? are we done?
				Netchan_CheckForCompletion(chan, i, intotalbuffers);
			}

			// Rearrange incoming data to not have the frag stuff in the middle of it
			int wpos = msg_readcount + frag_offset[i];
			int rpos = wpos + frag_length[i];
			
			Q_memmove(net_message.data + wpos, net_message.data + rpos, net_message.cursize - rpos);
			net_message.cursize -= frag_length[i];

			for (j = i + 1; j < MAX_STREAMS; j++)
			{
				frag_offset[j] -= frag_length[i]; // fragments order already validated
			}
		}

		// Is there anything left to process?
		if (net_message.cursize <= 16)
			return FALSE;
	}

	return TRUE;
}
Beispiel #8
0
static void cAck(int argc, char **argv)
{
	appPrintf("Ping acknowledge from %s\n", NET_AdrToString(&net_from));
}
Beispiel #9
0
/*
==================
cDirectConnect

A connection request that did not come from the master
==================
*/
static void cDirectConnect(int argc, char **argv)
{
	int		i;

	netadr_t adr = net_from;

	Com_DPrintf("SVC_DirectConnect()\n");

	int version = atoi(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 %d\n", version);
		return;
	}

	int port = atoi(argv[2]);
	int challenge = atoi(argv[3]);

	// get userinfo
	char userinfo[MAX_INFO_STRING];
	appStrncpyz(userinfo, argv[4], sizeof(userinfo));
	// force the IP key/value pair to be in userinfo (for game-side IP filters)
	Info_SetValueForKey(userinfo, "ip", NET_AdrToString(&net_from));

	// attractloop servers are ONLY for local clients
	if (sv.attractloop)
	{
		if (!NET_IsLocalAddress(&adr))
		{
			appPrintf("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;
		}
	}

	client_t temp, *cl;
	memset(&temp, 0, sizeof(client_t));
	client_t *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_CompareBaseAdr(&adr, &cl->netchan.remote_address) &&
			(cl->netchan.port == port || adr.port == cl->netchan.remote_address.port))
		{
			if (!NET_IsLocalAddress(&adr) && (svs.realtime - cl->lastconnect) < (sv_reconnect_limit->integer * 1000))
			{
				Com_DPrintf("%s:reconnect rejected : too soon\n", NET_AdrToString(&adr));
				return;
			}
			appPrintf("%s:reconnect\n", NET_AdrToString(&adr));
			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;
			}
	}
	if (!newcl)
	{
		Netchan_OutOfBandPrint(NS_SERVER, adr, "print\nServer is full.\n");
		Com_DPrintf("Rejected a connection.\n");
		return;
	}

	// build a new connection
	// accept the new client
	// this is the only place a client_t is ever initialized
	*newcl = temp;
	sv_client = newcl;
	int edictnum = (newcl-svs.clients)+1;
	edict_t *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
	qboolean result;
	guardGame(ge.ClientConnect);
	result = ge->ClientConnect(ent, userinfo);
	unguardGame;

	if (!result)
	{
		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
	newcl->Userinfo = userinfo;
	SV_UserinfoChanged(newcl);

	// check if client trying to connect with a new protocol
	newcl->newprotocol = !strcmp(argv [5], NEW_PROTOCOL_ID) && sv_extProtocol->integer;
	// send the connect packet to the client
	if (newcl->newprotocol)
	{
		int ver = atoi(argv[6]);
		if (ver != NEW_PROTOCOL_VERSION)
		{
			//?? we may also perform extended protocol checking by adding "[cl_]extprotocol" to userinfo
			Com_DPrintf("Client used extended protocol %d != "STR(NEW_PROTOCOL_VERSION)"\n", ver);
			if (ver < NEW_PROTOCOL_VERSION)
				Netchan_OutOfBandPrint(NS_SERVER, adr, "print\n"
				S_YELLOW"Server provides newer version of extended protocol\nPlease upgrade your client\n" );
			newcl->newprotocol = false;
		}
	}
	if (newcl->newprotocol)
	{
		Com_DPrintf("Connecting client using extended protocol\n");
		Netchan_OutOfBandPrint(NS_SERVER, adr, "client_connect "NEW_PROTOCOL_ID" "STR(NEW_PROTOCOL_VERSION));
	}
	else
		Netchan_OutOfBandPrint(NS_SERVER, adr, "client_connect");

	newcl->netchan.Setup(NS_SERVER, adr, port);
	newcl->maxPacketSize = cl->newprotocol ? MAX_MSGLEN : MAX_MSGLEN_OLD;
	newcl->state         = cs_connected;

	newcl->datagram.Init(newcl->datagram_buf, sizeof(newcl->datagram_buf));
	newcl->datagram.allowoverflow = true;
	newcl->lastmessage   = svs.realtime;	// don't timeout
	newcl->lastconnect   = svs.realtime;
}
Beispiel #10
0
qboolean Sys_GetPacket(netadr_t * net_from, msg_t * net_message)
{
	int             ret;
	struct sockaddr from;
	int             fromlen;
	int             net_socket;
	int             protocol;
	int             err;

	for(protocol = 0; protocol < 2; protocol++)
	{
		if(protocol == 0)
		{
			net_socket = ip_socket;
		}
		else
		{
			net_socket = ipx_socket;
		}

		if(!net_socket)
		{
			continue;
		}

		fromlen = sizeof(from);
		recvfromCount++;		// performance check
		ret = recvfrom(net_socket, net_message->data, net_message->maxsize, 0, (struct sockaddr *)&from, &fromlen);
		if(ret == SOCKET_ERROR)
		{
			err = WSAGetLastError();

			if(err == WSAEWOULDBLOCK || err == WSAECONNRESET)
			{
				continue;
			}
			Com_Printf("NET_GetPacket: %s\n", NET_ErrorString());
			continue;
		}

		if(net_socket == ip_socket)
		{
			memset(((struct sockaddr_in *)&from)->sin_zero, 0, 8);
		}

		if(usingSocks && net_socket == ip_socket && memcmp(&from, &socksRelayAddr, fromlen) == 0)
		{
			if(ret < 10 || net_message->data[0] != 0 || net_message->data[1] != 0 || net_message->data[2] != 0 ||
			   net_message->data[3] != 1)
			{
				continue;
			}
			net_from->type = NA_IP;
			net_from->ip[0] = net_message->data[4];
			net_from->ip[1] = net_message->data[5];
			net_from->ip[2] = net_message->data[6];
			net_from->ip[3] = net_message->data[7];
			net_from->port = *(short *)&net_message->data[8];
			net_message->readcount = 10;
		}
		else
		{
			SockadrToNetadr(&from, net_from);
			net_message->readcount = 0;
		}

		if(ret == net_message->maxsize)
		{
			Com_Printf("Oversize packet from %s\n", NET_AdrToString(*net_from));
			continue;
		}

		net_message->cursize = ret;
		return qtrue;
	}

	return qfalse;
}
Beispiel #11
0
qboolean	NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
{
	int 	ret;
	struct sockaddr_in	from;
	int		fromlen;
	int		net_socket;
	int		protocol;
	int		err;

	if (NET_GetLoopPacket (sock, net_from, net_message))
		return true;

	for (protocol = 0 ; protocol < 2 ; protocol++)
	{
		if (protocol == 0)
			net_socket = ip_sockets[sock];
		else
			net_socket = ipx_sockets[sock];

		if (!net_socket)
			continue;

		fromlen = sizeof(from);
// >>> FIX: For Nintendo Wii using devkitPPC / libogc
// Switching to the equivalent function (and data structures) in the platform:
		//ret = recvfrom (net_socket, net_message->data, net_message->maxsize
		//	, 0, (struct sockaddr *)&from, &fromlen);
		//if (ret == -1)
		ret = net_recvfrom (net_socket, net_message->data, net_message->maxsize > 4096 ? 4096 : net_message->maxsize
			, 0, (struct sockaddr *)&from, &fromlen);
		if (ret < 0)
// <<< FIX
		{
// >>> FIX: For Nintendo Wii using devkitPPC / libogc
// Switching to the equivalent data structures in the platform:
			//err = errno;

			//if (err == EWOULDBLOCK || err == ECONNREFUSED)
			if (ret == -EWOULDBLOCK || ret == -ECONNREFUSED)
// <<< FIX
				continue;
			Com_Printf ("NET_GetPacket: %s from %s\n", NET_ErrorString(),
						NET_AdrToString(*net_from));
			continue;
		}

// >>> FIX: For Nintendo Wii using devkitPPC / libogc
// Adjusting for previous fixes:
		//if (ret == net_message->maxsize)
		if((ret == net_message->maxsize)||(ret >= 4096))
// <<< FIX
		{
			Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
			continue;
		}

		net_message->cursize = ret;
		SockadrToNetadr (&from, net_from);
		return true;
	}

	return false;
}
Beispiel #12
0
/*
====================
LAN_GetServerInfo
====================
*/
static void LAN_GetServerInfo(int source, int n, char *buf, int buflen)
{
	char         info[MAX_STRING_CHARS];
	serverInfo_t *server = NULL;
	info[0] = '\0';

	switch (source)
	{
	case AS_LOCAL:
		if (n >= 0 && n < MAX_OTHER_SERVERS)
		{
			server = &cls.localServers[n];
		}
		break;
	case AS_GLOBAL:
		if (n >= 0 && n < MAX_GLOBAL_SERVERS)
		{
			server = &cls.globalServers[n];
		}
		break;
	case AS_FAVORITES:
		if (n >= 0 && n < MAX_OTHER_SERVERS)
		{
			server = &cls.favoriteServers[n];
		}
		break;
	}
	if (server && buf)
	{
		buf[0] = '\0';
		Info_SetValueForKey(info, "version", server->version);
		Info_SetValueForKey(info, "hostname", server->hostName);
		Info_SetValueForKey(info, "serverload", va("%i", server->load));
		Info_SetValueForKey(info, "mapname", server->mapName);
		Info_SetValueForKey(info, "clients", va("%i", server->clients));
		Info_SetValueForKey(info, "humans", va("%i", server->humans));
		Info_SetValueForKey(info, "sv_maxclients", va("%i", server->maxClients));
		Info_SetValueForKey(info, "ping", va("%i", server->ping));
		Info_SetValueForKey(info, "minping", va("%i", server->minPing));
		Info_SetValueForKey(info, "maxping", va("%i", server->maxPing));
		Info_SetValueForKey(info, "game", server->game);
		Info_SetValueForKey(info, "gametype", va("%i", server->gameType));
		Info_SetValueForKey(info, "nettype", va("%i", server->netType));
		Info_SetValueForKey(info, "addr", NET_AdrToString(server->adr));
		Info_SetValueForKey(info, "friendlyFire", va("%i", server->friendlyFire));
		Info_SetValueForKey(info, "maxlives", va("%i", server->maxlives));
		Info_SetValueForKey(info, "needpass", va("%i", server->needpass));
		Info_SetValueForKey(info, "punkbuster", va("%i", server->punkbuster));
		Info_SetValueForKey(info, "gamename", server->gameName);
		Info_SetValueForKey(info, "g_antilag", va("%i", server->antilag));
		Info_SetValueForKey(info, "weaprestrict", va("%i", server->weaprestrict));
		Info_SetValueForKey(info, "balancedteams", va("%i", server->balancedteams));
		Q_strncpyz(buf, info, buflen);
	}
	else
	{
		if (buf)
		{
			buf[0] = '\0';
		}
	}
}
Beispiel #13
0
/*
=================
SV_GetChallenge

A "getchallenge" OOB command has been received
Returns a challenge number that can be used
in a subsequent connectResponse 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.

If we are authorizing, a challenge request will cause a packet
to be sent to the authorize server.

When an authorizeip is returned, a challenge response will be
sent to that ip.
=================
*/
void SV_GetChallenge(netadr_t from)
{
	int i;
	int oldest;
	int oldestTime;
	challenge_t *challenge;

	// ignore if we are in single player
	if(Cvar_VariableValue("g_gametype") == GT_SINGLE_PLAYER)
	{
		return;
	}

	oldest = 0;
	oldestTime = 0x7fffffff;

	// see if we already have a challenge for this ip
	challenge = &svs.challenges[0];

	for(i = 0 ; i < MAX_CHALLENGES ; i++, challenge++)
	{
		if(NET_CompareAdr(from, challenge->adr))
		{
			break;
		}

		if(challenge->time < oldestTime)
		{
			oldestTime = challenge->time;
			oldest = i;
		}
	}

	if(i == MAX_CHALLENGES)
	{
		// this is the first time this client has asked for a challenge
		challenge = &svs.challenges[oldest];

		challenge->challenge = ((rand() << 16) ^ rand()) ^ svs.time;
		challenge->adr = from;
		challenge->time = svs.time;
		challenge->firstTime = svs.time;
		i = oldest;
	}

	// if they are on a lan address, send the challengeResponse immediately
	if(Sys_IsLANAddress(from))
	{
		challenge->pingTime = svs.time;
		NET_OutOfBandPrint(NS_SERVER, from, "challengeResponse %i", challenge->challenge);
		return;
	}

	// look up the authorize server's IP
	if(!svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD)
	{
		Com_Printf("Resolving %s\n", AUTHORIZE_SERVER_NAME);

		if(!NET_StringToAdr(AUTHORIZE_SERVER_NAME, &svs.authorizeAddress))
		{
			Com_Printf("Couldn't resolve address\n");
			return;
		}

		svs.authorizeAddress.port = BigShort(PORT_AUTHORIZE);
		Com_Printf("%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
		           svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
		           svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
		           BigShort(svs.authorizeAddress.port));
	}

	// if they have been challenging for a long time and we
	// haven't heard anything from the authoirze server, go ahead and
	// let them in, assuming the id server is down
	if(svs.time - challenge->firstTime > AUTHORIZE_TIMEOUT)
	{
		Com_DPrintf("authorize server timed out\n");

		challenge->pingTime = svs.time;
		NET_OutOfBandPrint(NS_SERVER, challenge->adr,
		                   "challengeResponse %i", challenge->challenge);
		return;
	}

	// otherwise send their ip to the authorize server
	if(svs.authorizeAddress.type != NA_BAD)
	{
		cvar_t  *fs;
		char game[1024];

		game[0] = 0;
		fs = Cvar_Get("fs_game", "", CVAR_INIT | CVAR_SYSTEMINFO);

		if(fs && fs->string[0] != 0)
		{
			strcpy(game, fs->string);
		}

		Com_DPrintf("sending getIpAuthorize for %s\n", NET_AdrToString(from));
		fs = Cvar_Get("sv_allowAnonymous", "0", CVAR_SERVERINFO);

		NET_OutOfBandPrint(NS_SERVER, svs.authorizeAddress,
		                   "getIpAuthorize %i %i.%i.%i.%i %s %s",  svs.challenges[i].challenge,
		                   from.ip[0], from.ip[1], from.ip[2], from.ip[3], game, fs->integer);
	}
}
Beispiel #14
0
/*
==================
SV_DirectConnect

A "connect" OOB command has been received
==================
*/
void SV_DirectConnect(netadr_t from)
{
	char userinfo[MAX_INFO_STRING];
	int i;
	client_t    *cl, *newcl;
	MAC_STATIC client_t temp;
	sharedEntity_t *ent;
	int clientNum;
	int version;
	int qport;
	int challenge;
	char        *password;
	int startIndex;
	intptr_t denied;
	int count;

	Com_DPrintf("SVC_DirectConnect ()\n");

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

	version = atoi(Info_ValueForKey(userinfo, "protocol"));

	if(version != PROTOCOL_VERSION)
	{
		NET_OutOfBandPrint(NS_SERVER, from, "print\nServer uses protocol version %i.\n", PROTOCOL_VERSION);
		Com_DPrintf("    rejected connect from version %i\n", version);
		return;
	}

	qport = atoi(Info_ValueForKey(userinfo, "qport"));
	challenge = atoi(Info_ValueForKey(userinfo, "challenge"));

	// quick reject
	for(i = 0, cl = svs.clients ; i < sv_maxclients->integer ; i++, cl++)
	{
		if(cl->state == CS_FREE)
		{
			continue;
		}

		if(NET_CompareBaseAdr(from, cl->netchan.remoteAddress)
		        && (cl->netchan.qport == qport
		            || from.port == cl->netchan.remoteAddress.port))
		{
			if((svs.time - cl->lastConnectTime)
			        < (sv_reconnectlimit->integer * 1000))
			{
				Com_DPrintf("%s:reconnect rejected : too soon\n", NET_AdrToString(from));
				return;
			}

			break;
		}
	}

	// see if the challenge is valid (LAN clients don't need to challenge)
	if(!NET_IsLocalAddress(from))
	{
		int ping;

		for(i = 0 ; i < MAX_CHALLENGES ; i++)
		{
			if(NET_CompareAdr(from, svs.challenges[i].adr))
			{
				if(challenge == svs.challenges[i].challenge)
				{
					break;      // good
				}

				NET_OutOfBandPrint(NS_SERVER, from, "print\nBad challenge.\n");
				return;
			}
		}

		if(i == MAX_CHALLENGES)
		{
			NET_OutOfBandPrint(NS_SERVER, from, "print\nNo challenge for address.\n");
			return;
		}

		// force the IP key/value pair so the game can filter based on ip
		Info_SetValueForKey(userinfo, "ip", NET_AdrToString(from));

		ping = svs.time - svs.challenges[i].pingTime;
		Com_Printf("Client %i connecting with %i challenge ping\n", i, ping);

		// never reject a LAN client based on ping
		if(!Sys_IsLANAddress(from))
		{
			if(sv_minPing->value && ping < sv_minPing->value)
			{
				// don't let them keep trying until they get a big delay
				NET_OutOfBandPrint(NS_SERVER, from, "print\nServer is for high pings only\n");
				Com_DPrintf("Client %i rejected on a too low ping\n", i);
				// reset the address otherwise their ping will keep increasing
				// with each connect message and they'd eventually be able to connect
				svs.challenges[i].adr.port = 0;
				return;
			}

			if(sv_maxPing->value && ping > sv_maxPing->value)
			{
				NET_OutOfBandPrint(NS_SERVER, from, "print\nServer is for low pings only\n");
				Com_DPrintf("Client %i rejected on a too high ping\n", i);
				return;
			}
		}
	}
	else
	{
		// force the "ip" info key to "localhost"
		Info_SetValueForKey(userinfo, "ip", "localhost");
	}

	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 < sv_maxclients->integer ; i++, cl++)
	{
		if(cl->state == CS_FREE)
		{
			continue;
		}

		if(NET_CompareBaseAdr(from, cl->netchan.remoteAddress)
		        && (cl->netchan.qport == qport
		            || from.port == cl->netchan.remoteAddress.port))
		{
			Com_Printf("%s:reconnect\n", NET_AdrToString(from));
			newcl = cl;
			// disconnect the client from the game first so any flags the
			// player might have are dropped
			VM_Call(gvm, GAME_CLIENT_DISCONNECT, newcl - svs.clients);
			//
			goto gotnewcl;
		}
	}

	// find a client slot
	// if "sv_privateClients" is set > 0, then that number
	// of client slots will be reserved for connections that
	// have "password" set to the value of "sv_privatePassword"
	// Info requests will report the maxclients as if the private
	// slots didn't exist, to prevent people from trying to connect
	// to a full server.
	// This is to allow us to reserve a couple slots here on our
	// servers so we can play without having to kick people.

	// check for privateClient password
	password = Info_ValueForKey(userinfo, "password");

	if(!strcmp(password, sv_privatePassword->string))
	{
		startIndex = 0;
	}
	else
	{
		// skip past the reserved slots
		startIndex = sv_privateClients->integer;
	}

	newcl = NULL;

	for(i = startIndex; i < sv_maxclients->integer ; i++)
	{
		cl = &svs.clients[i];

		if(cl->state == CS_FREE)
		{
			newcl = cl;
			break;
		}
	}

	if(!newcl)
	{
		if(NET_IsLocalAddress(from))
		{
			count = 0;

			for(i = startIndex; i < sv_maxclients->integer ; i++)
			{
				cl = &svs.clients[i];

				if(cl->netchan.remoteAddress.type == NA_BOT)
				{
					count++;
				}
			}

			// if they're all bots
			if(count >= sv_maxclients->integer - startIndex)
			{
				SV_DropClient(&svs.clients[sv_maxclients->integer - 1], "only bots on server");
				newcl = &svs.clients[sv_maxclients->integer - 1];
			}
			else
			{
				Com_Error(ERR_FATAL, "server is full on local connect\n");
				return;
			}
		}
		else
		{
			NET_OutOfBandPrint(NS_SERVER, from, "print\nServer is full.\n");
			Com_DPrintf("Rejected a connection.\n");
			return;
		}
	}

	// we got a newcl, so reset the reliableSequence and reliableAcknowledge
	cl->reliableAcknowledge = 0;
	cl->reliableSequence = 0;

gotnewcl:
	// build a new connection
	// accept the new client
	// this is the only place a client_t is ever initialized
	*newcl = temp;
	clientNum = newcl - svs.clients;
	ent = SV_GentityNum(clientNum);
	newcl->gentity = ent;

	// save the challenge
	newcl->challenge = challenge;

	// save the address
	Netchan_Setup(NS_SERVER, &newcl->netchan, from, qport);

	// save the userinfo
	Q_strncpyz(newcl->userinfo, userinfo, sizeof(newcl->userinfo));

	// get the game a chance to reject this connection or modify the userinfo
	denied = VM_Call(gvm, GAME_CLIENT_CONNECT, clientNum, qtrue, qfalse);   // firstTime = qtrue

	if(denied)
	{
		// we can't just use VM_ArgPtr, because that is only valid inside a VM_Call
		denied = (intptr_t)VM_ExplicitArgPtr(gvm, denied);

		NET_OutOfBandPrint(NS_SERVER, from, "print\n%s\n", denied);
		Com_DPrintf("Game rejected a connection: %s.\n", denied);
		return;
	}

	// RF, create the reliable commands
	if(newcl->netchan.remoteAddress.type != NA_BOT)
	{
		SV_InitReliableCommandsForClient(newcl, MAX_RELIABLE_COMMANDS);
	}
	else
	{
		SV_InitReliableCommandsForClient(newcl, 0);
	}

	SV_UserinfoChanged(newcl);

	// send the connect packet to the client
	NET_OutOfBandPrint(NS_SERVER, from, "connectResponse");

	Com_DPrintf("Going from CS_FREE to CS_CONNECTED for %s\n", newcl->name);

	newcl->state = CS_CONNECTED;
	newcl->nextSnapshotTime = svs.time;
	newcl->lastPacketTime = svs.time;
	newcl->lastConnectTime = svs.time;

	// when we receive the first packet from the client, we will
	// notice that it is from a different serverid and that the
	// gamestate message was not just sent, forcing a retransmit
	newcl->gamestateMessageNum = -1;

	// if this was the first client on the server, or the last client
	// the server can hold, send a heartbeat to the master.
	count = 0;

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

	if(count == 1 || count == sv_maxclients->integer)
	{
		SV_Heartbeat_f();
	}
}
Beispiel #15
0
void Master_SetMaster_f() {

   int AreAdding;
   const char * arg_1, * arg_2;
   int port;
   netadr_t netaddress;
   master_server_t * ptr, * ptr2;

   if(Cmd_Argc() < 2 || Cmd_Argc() > 4) {

      Con_Printf("Setmaster <add | remove | enable | disable> <IP:port>\n");
      Con_Printf(" Current master list:\n");

      for(ptr = masterlist; ptr != NULL; ptr = ptr->next) {

         Con_Printf("  %s\n", NET_AdrToString(ptr->address));
      }

      Con_Printf(" End if list\n");
      return;
   }

   arg_1 = Cmd_Argv(1);
   if(arg_1[0] == '\0') { return; }

   if(Q_strcasecmp(arg_1, "disable") == 0) { gfNoMasterServer = 1; return; }
   if(Q_strcasecmp(arg_1, "enable") == 0) { gfNoMasterServer = 0; return; }

   if(Q_strcasecmp(arg_1, "add") == 0) { AreAdding = 1; }
   else if(Q_strcasecmp(arg_1, "remove") == 0) { AreAdding = 0; }
   else {

      Con_Printf("Setmaster:  Unknown command \"%s\".\n", arg_1);
      return;
   }

   arg_2 = Cmd_Argv(2);

   if(Cmd_Argc() == 4) {
      port = Q_atoi(Cmd_Argv(3));
      if(port < 1 || port > 65535) {
         Con_Printf("Setmaster: Invalid port.  Ports can't be larger than 65535.\n");
         return;
      }
   }
   else {
      port = 27010;
   }

   if(NET_StringToAdr(arg_2, &netaddress) == 0) {
      Con_Printf("Setmaster: Passed address could not be processed by StringToAdr.\n");
      return;
   }
   netaddress.port = port;

   if(AreAdding) {

      Master_Init();
      Master_AddServer(&netaddress);
      gfNoMasterServer = 0;
      Con_Printf("Master server %s:%u added.\n", arg_2, port);
   }
   else {

      //case 1: first node.
      if(NET_CompareAdr(masterlist->address, netaddress) != 0) {
         ptr = masterlist;
         masterlist = masterlist->next;
         Q_Free(ptr);
         return;
      }

      //case 2: some node afterwards
      for(ptr = masterlist; ptr->next != NULL; ptr = ptr->next) {
         if(NET_CompareAdr(ptr->next->address, netaddress) != 0) {

            ptr2 = ptr->next;
            ptr->next = ptr->next->next;
            Q_Free(ptr2);
            return;
         }
      }
      //case 3: not here
      Con_Printf("Master %s:%u couldn't be removed.  Couldn't find it.\n", arg_2, port);
   }
}
Beispiel #16
0
/*
================
SVC_Ack

================
*/
void SVC_Ack (void)
{
    Com_Printf ("Ping acknowledge from %s\n", NET_AdrToString(net_from));
}
Beispiel #17
0
void Master_Init() {

   int i, SkipSection, tempport;
   static int HaveConfigured = 0;
   char * filep;
   const char * curfilep;
   netadr_t tempadr;


   if(HaveConfigured != 0 || gfNoMasterServer != 0) { return; }

   HaveConfigured = 1;

   if(COM_CheckParmCase("-nomaster") != 0 || global_svs.allocated_client_slots <= 1) {

      Con_Printf("%s: Master server comm disabled.\n", __FUNCTION__);
      gfNoMasterServer = 0;
      return; //and don't check again, ever.
   }

   MasterHeartbeatTimeout = 15;

   i = COM_CheckParmCase("-comm");
   if(i != 0 && i+1 < global_com_argc) {

      filep = COM_LoadFileForMe(global_com_argv[i+1], NULL);
   }
   else {

      filep = COM_LoadFileForMe("valvecomm.lst", NULL);
      if(filep == NULL) {
         filep = COM_LoadFileForMe("woncomm.lst", NULL);
      }
   }

   if(filep == NULL) {
      Con_Printf("%s: Couldn't load comm file.  Disabling masters--fix it.\n", __FUNCTION__);
      return;
   }

   curfilep = filep;
   i = 0;
   while(1) {

      curfilep = COM_Parse(curfilep);
      if(global_com_token[0] == '\0') { break; }

      SkipSection = 1;
      if(Q_strcasecmp("master", global_com_token) == 0) {
         SkipSection = 0;
      }

      curfilep = COM_Parse(curfilep);
      if(Q_strcmp("{", global_com_token) != 0) { break; }

      while(1) {

         curfilep = COM_Parse(curfilep);
         if(global_com_token[0] == '\0' || Q_strcmp("}", global_com_token) == 0) { break; }
         if(SkipSection == 0 && NET_StringToAdr(global_com_token, &tempadr) == 0) { break; }

         //We just (maybe) parsed the server name, if you missed it.  Now for the port.
         curfilep = COM_Parse(curfilep);
         if(Q_strcmp(":", global_com_token) != 0) { break; }

         curfilep = COM_Parse(curfilep);
         if(global_com_token[0] == '\0') { break; }

         if(SkipSection == 0) {

            tempport = Q_atoi(global_com_token);
            if(tempport < 1 || tempport > 65535) { tempport = 27010; }
            tempadr.port = tempport;

            Con_Printf("%s: Adding master server %s.\n", __FUNCTION__, NET_AdrToString(tempadr)); //all that work to avoid needless string copying, all gone :)
            Master_AddServer(&tempadr);
            i++;
         }
      }
   }

   COM_FreeFile(filep);

   if(i == 0) {
      Con_Printf("%s: Didn't parse any masters.  Disabling master comm.\n", __FUNCTION__);
      gfNoMasterServer = 0;
   }
}
Beispiel #18
0
/*
==================
SVC_DirectConnect

A connection request that did not come from the master
==================
*/
void SVC_DirectConnect (void)
{
    char		userinfo[MAX_INFO_STRING];
    netadr_t	adr;
    int32_t			i;
    client_t	*cl, *newcl;
    client_t	temp;
    edict_t		*ent;
    int32_t			edictnum;
    int32_t			version;
    int32_t			qport;
    int32_t			challenge;
    int32_t			previousclients;	// rich: connection limit per IP

    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));

    // r1ch: limit connections from a single IP
    previousclients = 0;
    for (i=0,cl=svs.clients; i<(int32_t)maxclients->value; i++,cl++)
    {
        if (cl->state == cs_free)
            continue;
        if (NET_CompareBaseAdr (adr, cl->netchan.remote_address))
        {
            // r1ch: zombies are less dangerous
            if (cl->state == cs_zombie)
                previousclients++;
            else
                previousclients += 2;
        }
    }
    if (previousclients >= (int32_t)sv_iplimit->value * 2)
    {
        Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nToo many connections from your host.\n");
        Com_DPrintf ("    too many connections\n");
        return;
    }
    // end r1ch fix

    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) < ((int32_t)sv_reconnect_limit->value * 1000))
            {
                Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (adr));
                return;
            }
            // r1ch: !! 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");
                // If we legitly get here, spoofed udp isn't possible (passed challenge) and client addr/port combo
                // is exactly the same, so we can assume its really a dropped/crashed client. i hope...
                Com_Printf ("Dropping %s, ghost reconnect\n", cl->name);
                SV_DropClient (cl);
            }
            // end r1ch fix

            Com_Printf ("%s:reconnect\n", NET_AdrToString (adr));

            SV_CleanClient (cl);	// r1ch: clean up last client data

            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;
}
Beispiel #19
0
/* <65b51> ../engine/net_chan.c:412 */
void Netchan_Transmit(netchan_t *chan, int length, byte *data)
{
	byte		send_buf[NET_MAX_MESSAGE];
	qboolean	send_reliable;
	qboolean	send_reliable_fragment;
	qboolean	send_resending = false;
	unsigned	w1, w2;
	int i, j;

	float       fRate;

	sizebuf_t sb_send;
	sb_send.data = send_buf;
	sb_send.buffername = "Netchan_Transmit";
	sb_send.maxsize = sizeof(send_buf);
	sb_send.flags = 0;
	sb_send.cursize = 0;

	// check for message overflow
	if (chan->message.flags & 2) {
		Con_Printf("%s:Outgoing message overflow\n", NET_AdrToString(chan->remote_address));
		return;
	}

	// if the remote side dropped the last reliable message, resend it
	send_reliable = false;

	if (chan->incoming_acknowledged > chan->last_reliable_sequence &&
		chan->incoming_reliable_acknowledged != chan->reliable_sequence)
	{
		send_reliable = true;
		send_resending = true;
	}

	//
	// A packet can have "reliable payload + frag payload + unreliable payload
	// frag payload can be a file chunk, if so, it needs to be parsed on the receiving end and reliable payload + unreliable payload need
	// to be passed on to the message queue.  The processing routine needs to be able to handle the case where a message comes in and a file
	// transfer completes
	//
	//
	// if the reliable transmit buffer is empty, copy the current message out
	if (!chan->reliable_length)
	{
		qboolean send_frag = false;
		fragbuf_t *pbuf;

		// Will be true if we are active and should let chan->message get some bandwidth
		int		 send_from_frag[MAX_STREAMS] = { 0, 0 };
		int		 send_from_regular = 0;

		// If we have data in the waiting list(s) and we have cleared the current queue(s), then 
		//  push the waitlist(s) into the current queue(s)
		Netchan_FragSend(chan);

		// Sending regular payload
		send_from_regular = (chan->message.cursize) ? 1 : 0;

		// Check to see if we are sending a frag payload
		//
		for (i = 0; i < MAX_STREAMS; i++)
		{
			if (chan->fragbufs[i])
			{
				send_from_frag[i] = 1;
			}
		}

		// Stall reliable payloads if sending from frag buffer
		if (send_from_regular && (send_from_frag[FRAG_NORMAL_STREAM]))
		{
			send_from_regular = false;

			// If the reliable buffer has gotten too big, queue it at the end of everything and clear out buffer
			//
			if (chan->message.cursize > MAX_RELIABLE_PAYLOAD)
			{
				Netchan_CreateFragments_(chan == &g_pcls.netchan ? 1 : 0, chan, &chan->message);
				SZ_Clear(&chan->message);
			}
		}

		// Startpos will be zero if there is no regular payload
		for (i = 0; i < MAX_STREAMS; i++)
		{
			chan->frag_startpos[i] = 0;

			// Assume no fragment is being sent
			chan->reliable_fragment[i] = 0;
			chan->reliable_fragid[i] = 0;
			chan->frag_length[i] = 0;

			if (send_from_frag[i])
			{
				send_frag = true;
			}
		}

		if (send_from_regular || send_frag)
		{
			chan->reliable_sequence ^= 1;
			send_reliable = true;
		}

		if (send_from_regular) {
			Q_memcpy(chan->reliable_buf, chan->message_buf, chan->message.cursize);
			chan->reliable_length = chan->message.cursize;
			SZ_Clear(&chan->message);

			// If we send fragments, this is where they'll start
			for (i = 0; i < MAX_STREAMS; i++) {
				chan->frag_startpos[i] = chan->reliable_length;
			}
		}

		for (i = 0; i < MAX_STREAMS; i++) {
			int fragment_size;

			// Is there something in the fragbuf?
			pbuf = chan->fragbufs[i];

			fragment_size = 0; // Compiler warning.
			if (pbuf)	{
				fragment_size = pbuf->frag_message.cursize;

				// Files set size a bit differently.
				if (pbuf->isfile && !pbuf->isbuffer)
				{
					fragment_size = pbuf->size;
				}
			}

			// Make sure we have enought space left
			if (send_from_frag[i] && pbuf && ((chan->reliable_length + fragment_size) < MAX_RELIABLE_PAYLOAD)) {

				chan->reliable_fragid[i] = MAKE_FRAGID(pbuf->bufferid, chan->fragbufcount[i]); // Which buffer are we sending?

				// If it's not in-memory, then we'll need to copy it in frame the file handle.
				if (pbuf->isfile && !pbuf->isbuffer)	{
					char compressedfilename[MAX_PATH];
					FileHandle_t hfile;
					if (pbuf->iscompressed)
					{
						Q_snprintf(compressedfilename, sizeof(compressedfilename), "%s.ztmp", pbuf->filename);
						hfile = FS_Open(compressedfilename, "rb");
					}
					else
					{
						hfile = FS_Open(pbuf->filename, "rb");
					}
					FS_Seek(hfile, pbuf->foffset, FILESYSTEM_SEEK_HEAD);
					FS_Read(&pbuf->frag_message.data[pbuf->frag_message.cursize], pbuf->size, 1, hfile);
					pbuf->frag_message.cursize += pbuf->size;
					FS_Close(hfile);
				}


				Q_memcpy(chan->reliable_buf + chan->reliable_length, pbuf->frag_message.data, pbuf->frag_message.cursize);
				chan->reliable_length += pbuf->frag_message.cursize;
				chan->frag_length[i] = pbuf->frag_message.cursize;


				// Unlink  pbuf
				Netchan_UnlinkFragment(pbuf, &chan->fragbufs[i]);

				chan->reliable_fragment[i] = 1;

				// Offset the rest of the starting positions
				for (j = i + 1; j < MAX_STREAMS; j++)
				{
					chan->frag_startpos[j] += chan->frag_length[i];
				}
			}
		}
	}

	// Prepare the packet header
	w1 = chan->outgoing_sequence | (send_reliable << 31);
	w2 = chan->incoming_sequence | (chan->incoming_reliable_sequence << 31);

	send_reliable_fragment = false;

	for (i = 0; i < MAX_STREAMS; i++)
	{
		if (chan->reliable_fragment[i])
		{
			send_reliable_fragment = true;
			break;
		}
	}

	if (send_reliable && send_reliable_fragment)
	{
		w1 |= (1 << 30);
	}

	chan->outgoing_sequence++;

	MSG_WriteLong(&sb_send, w1);
	MSG_WriteLong(&sb_send, w2);

	if (send_reliable && send_reliable_fragment)
	{
		for (i = 0; i < MAX_STREAMS; i++)
		{
			if (chan->reliable_fragment[i])
			{
				MSG_WriteByte(&sb_send, 1);
				MSG_WriteLong(&sb_send, chan->reliable_fragid[i]);
				MSG_WriteShort(&sb_send, chan->frag_startpos[i]);
				MSG_WriteShort(&sb_send, chan->frag_length[i]);
			}
			else
			{
				MSG_WriteByte(&sb_send, 0);
			}
		}
	}

	// Copy the reliable message to the packet first
	if (send_reliable) {
		SZ_Write(&sb_send, chan->reliable_buf, chan->reliable_length);
		chan->last_reliable_sequence = chan->outgoing_sequence - 1;
	}

	// Is there room for the unreliable payload?
	int max_send_size = MAX_ROUTEABLE_PACKET;
	if (!send_resending)
		max_send_size = sb_send.maxsize;

	if ((max_send_size - sb_send.cursize) >= length) {
		SZ_Write(&sb_send, data, length);
	}
	else {
		Con_DPrintf("Netchan_Transmit:  Unreliable would overfow, ignoring\n");
	}

	// Deal with packets that are too small for some networks
	if (sb_send.cursize < 16)	// Packet too small for some networks
	{
		int i;
		// Go ahead and pad a full 16 extra bytes -- this only happens during authentication / signon
		for (i = sb_send.cursize; i < 16; i++)
		{
			// Note that the server can parse svc_nop, too.
			MSG_WriteByte(&sb_send, svc_nop);
		}
	}

	int statId = chan->flow[FLOW_OUTGOING].current & 0x1F;
	chan->flow[FLOW_OUTGOING].stats[statId].size = sb_send.cursize + UDP_HEADER_SIZE;
	chan->flow[FLOW_OUTGOING].stats[statId].time = realtime;
	chan->flow[FLOW_OUTGOING].current++;
	Netchan_UpdateFlow(chan);

	if (!g_pcls.demoplayback)
	{
		COM_Munge2(sb_send.data + 8, sb_send.cursize - 8, (unsigned char)(chan->outgoing_sequence - 1));

		if (g_modfuncs.m_pfnProcessOutgoingNet)
			g_modfuncs.m_pfnProcessOutgoingNet(chan, &sb_send);

		NET_SendPacket(chan->sock, sb_send.cursize, sb_send.data, chan->remote_address);
	}

	if (g_psv.active && sv_lan.value != 0.0f && sv_lan_rate.value > MIN_RATE)
		fRate = 1.0 / sv_lan_rate.value;
	else
		fRate = 1.0 / chan->rate;

	if (chan->cleartime < realtime) {
		chan->cleartime = realtime;
	}

	chan->cleartime += (sb_send.cursize + UDP_HEADER_SIZE) * fRate;

	if (net_showpackets.value != 0.0f && net_showpackets.value != 2.0f) {
		char c = (chan == &g_pcls.netchan) ? 'c' : 's';

		Con_Printf(" %c --> sz=%i seq=%i ack=%i rel=%i tm=%f\n"
				   , c
				   , sb_send.cursize
				   , chan->outgoing_sequence - 1
				   , chan->incoming_sequence
				   , send_reliable ? 1 : 0
				   , (float)(chan == &g_pcls.netchan ? g_pcl.time : g_psv.time));
	}
}
Beispiel #20
0
/*
=================
Netchan_Process

Returns qfalse 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.
=================
*/
qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) {
	int			sequence;
	int			qport;
	int			fragmentStart, fragmentLength;
	qboolean	fragmented;

	// get sequence numbers		
	MSG_BeginReadingOOB( msg );
	sequence = MSG_ReadLong( msg );

	// check for fragment information
	if ( sequence & FRAGMENT_BIT ) {
		sequence &= ~FRAGMENT_BIT;
		fragmented = qtrue;
	} else {
		fragmented = qfalse;
	}

	// read the qport if we are a server
	if ( chan->sock == NS_SERVER ) {
		qport = MSG_ReadShort( msg );
	}

	// read the fragment information
	if ( fragmented ) {
		fragmentStart  = (unsigned short)MSG_ReadShort( msg );
		fragmentLength = (unsigned short)MSG_ReadShort( msg );
	} else {
		fragmentStart = 0;		// stop warning message
		fragmentLength = 0;
	}

	if ( showpackets->integer ) {
		if ( fragmented ) {
			Com_Printf( "%s recv %4i : s=%i fragment=%i,%i\n"
				, netsrcString[ chan->sock ]
				, msg->cursize
				, sequence
				, fragmentStart, fragmentLength );
		} else {
			Com_Printf( "%s recv %4i : s=%i\n"
				, netsrcString[ chan->sock ]
				, 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_AdrToString( chan->remoteAddress )
				,  sequence
				, chan->incomingSequence );
		}
		return qfalse;
	}

	//
	// 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_AdrToString( chan->remoteAddress )
			, chan->dropped
			, sequence );
		}
	}
	

	//
	// if this is the final framgent of a reliable message,
	// bump incoming_reliable_sequence 
	//
	if ( fragmented ) {
		// make sure we 
		if ( sequence != chan->fragmentSequence ) {
			chan->fragmentSequence = sequence;
			chan->fragmentLength = 0;
		}

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

			//rww - not clearing this will allow us to piece together fragments belonging to other packets
			//that happen to have the same sequence (or so it seems). I am just going to clear it and force
			//the packet to be dropped.

			// hell yeah we have to dump the whole thing -gil
			// but I am scared - mw
			/*
			chan->fragmentLength = 0;
			chan->incomingSequence = sequence;
			chan->fragmentSequence = 0;
			*/
			return qfalse;
		}

		// 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_AdrToString (chan->remoteAddress ) );
			}
			return qfalse;
		}

		Com_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 ( fragmentLength == FRAGMENT_SIZE ) {
			return qfalse;
		}

		if ( chan->fragmentLength+4 > msg->maxsize ) {
			Com_Printf( "%s:fragmentLength %i > msg->maxsize\n"
				, NET_AdrToString (chan->remoteAddress ),
				chan->fragmentLength+4 );
			return qfalse;
		}

		// copy the full message over the partial fragment

		// make sure the sequence number is still there
		*(int *)msg->data = LittleLong( sequence );

		Com_Memcpy( msg->data + 4, chan->fragmentBuffer, chan->fragmentLength );
		msg->cursize = chan->fragmentLength + 4;
		chan->fragmentLength = 0;
		msg->readcount = 4;	// past the sequence number
		msg->bit = 32;	// past the sequence number

		// but I am a wuss -mw 
		// chan->incomingSequence = sequence;   // lets not accept any more with this sequence number -gil
		return qtrue;
	}

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

	return qtrue;
}
Beispiel #21
0
/*
================
SV_Status_f
================
*/
static void SV_Status_f(void)
{
	int           i, j, l;
	client_t      *cl;
	playerState_t *ps;
	const char    *s;
	int           ping;

	// make sure server is running
	if (!com_sv_running->integer)
	{
		Com_Printf("Server is not running.\n");
		return;
	}

	Com_Printf("cpu server utilization: %i %%\n"
	           "avg response time     : %i ms\n"
	           "server time           : %i\n"
	           "internal time         : %i\n"
	           "map                   : %s\n\n"
	           "num score ping name            lastmsg address               qport rate\n"
	           "--- ----- ---- --------------- ------- --------------------- ----- -----\n",
	           ( int ) svs.stats.cpu,
	           ( int ) svs.stats.avg,
	           svs.time,
	           Sys_Milliseconds(),
	           sv_mapname->string);

	// FIXME: extend player name length (>16 chars) ? - they are printed!
	// FIXME: do a Com_Printf per line! ... create the row at first
	for (i = 0, cl = svs.clients ; i < sv_maxclients->integer ; i++, cl++)
	{
		if (!cl->state && !cl->demoClient)
		{
			continue;
		}
		Com_Printf("%3i ", i);
		ps = SV_GameClientNum(i);
		Com_Printf("%5i ", ps->persistant[PERS_SCORE]);

		if (cl->demoClient) // if it's a democlient, we show DEMO instead of the ping (which would be 999 anyway - which is not the case in the scoreboard which show the real ping that had the player because commands are replayed!)
		{
			Com_Printf("DEMO ");
		}
		else if (cl->state == CS_CONNECTED)
		{
			Com_Printf("CNCT ");
		}
		else if (cl->state == CS_ZOMBIE)
		{
			Com_Printf("ZMBI ");
		}
		else
		{
			ping = cl->ping < 9999 ? cl->ping : 9999;
			Com_Printf("%4i ", ping);
		}

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

		Com_Printf("%7i ", svs.time - cl->lastPacketTime);

		s = NET_AdrToString(cl->netchan.remoteAddress);
		Com_Printf("%s", s);

		l = 22 - strlen(s);
		for (j = 0 ; j < l ; j++)
		{
			Com_Printf(" ");
		}

		Com_Printf("%5i", cl->netchan.qport);

		Com_Printf(" %5i\n", cl->rate);
	}

	Com_Printf("\n");
}
Beispiel #22
0
/*
================
SV_Status_f
================
*/
static void SV_Status_f(void) {
	int             i, j, l, ping;
	client_t       *cl;
	playerState_t  *ps;
	const char     *s;

	// Dushan
	float           cpu, avg;

	// make sure server is running
	if(!com_sv_running->integer)
	{
		Com_Printf("Server is not running.\n");
		return;
	}

	// Dushan
	cpu = (svs.stats.latched_active + svs.stats.latched_idle);
	if (cpu) {
		cpu = 100 * svs.stats.latched_active / cpu;
	}
	avg = 1000 * svs.stats.latched_active / STATFRAMES;

	Com_Printf ("cpu utilization  : %3i%%\n",(int)cpu);
	Com_Printf ("avg response time: %i ms\n",(int)avg);

	Com_Printf("map: %s\n", sv_mapname->string);

	Com_Printf("num score ping name            lastmsg address               qport 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);
		ps = SV_GameClientNum(i);
		Com_Printf("%5i ", ps->persistant[PERS_SCORE]);

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

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

		Com_Printf("%7i ", svs.time - cl->lastPacketTime);

		s = NET_AdrToString(cl->netchan.remoteAddress);
		Com_Printf("%s", s);
		l = 22 - strlen(s);
		for(j = 0; j < l; j++) {
			Com_Printf(" ");
		}

		Com_Printf("%5i", cl->netchan.qport);

		Com_Printf(" %5i", cl->rate);

		Com_Printf("\n");
	}
	Com_Printf("\n");
}
Beispiel #23
0
/*
=================
CL_ConnectionlessPacket

Responses to broadcasts, etc
=================
*/
void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
	char	*s;
	const char	*c;
	
	MSG_BeginReading( msg );
	MSG_ReadLong( msg );	// skip the -1

	s = MSG_ReadStringLine( msg );

	Cmd_TokenizeString( s );

	c = Cmd_Argv(0);

	Com_DPrintf ("CL packet %s: %s\n", NET_AdrToString(from), c);

	// challenge from the server we are connecting to
	if ( !strcmp(c, "challengeResponse") ) {
		if ( cls.state != CA_CONNECTING ) {
			Com_Printf( "Unwanted challenge response received.  Ignored.\n" );
		} else {
			// start sending challenge repsonse instead of challenge request packets
			clc.challenge = atoi(Cmd_Argv(1));
			cls.state = CA_CHALLENGING;
			clc.connectPacketCount = 0;
			clc.connectTime = -99999;

			// take this address as the new server address.  This allows
			// a server proxy to hand off connections to multiple servers
			clc.serverAddress = from;
		}
		return;
	}

	// server connection
	if ( !strcmp(c, "connectResponse") ) {
		if ( cls.state >= CA_CONNECTED ) {
			Com_Printf ("Dup connect received.  Ignored.\n");
			return;
		}
		if ( cls.state != CA_CHALLENGING ) {
			Com_Printf ("connectResponse packet while not connecting.  Ignored.\n");
			return;
		}
		if ( !NET_CompareBaseAdr( from, clc.serverAddress ) ) {
			Com_Printf( "connectResponse from a different address.  Ignored.\n" );
			Com_Printf( "%s should have been %s\n", NET_AdrToString( from ), 
				NET_AdrToString( clc.serverAddress ) );
			return;
		}
		Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableIntegerValue( "net_qport" ) );
		cls.state = CA_CONNECTED;
		clc.lastPacketSentTime = -9999;		// send first packet immediately
		return;
	}

	// a disconnect message from the server, which will happen if the server
	// dropped the connection but it is still getting packets from us
	if (!strcmp(c, "disconnect")) {
		CL_DisconnectPacket( from );
		return;
	}

	// echo request from server
	if ( !strcmp(c, "echo") ) {
		NET_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv(1) );
		return;
	}

	// print request from server
	if ( !strcmp(c, "print") ) {
		s = MSG_ReadString( msg );
		UI_UpdateConnectionMessageString( s );
		Com_Printf( "%s", s );
		return;
	}


	Com_DPrintf ("Unknown connectionless packet command.\n");
}
static void SV_AddBanToList(qboolean isexception)
{
	char *banstring;
	char addy2[NET_ADDRSTRMAXLEN];
	netadr_t ip;
	int index, argc, mask;
	serverBan_t *curban;
	
	argc = Cmd_Argc();
	
	if(argc < 2 || argc > 3)
	{
		Com_Printf ("Usage: %s (ip[/subnet] | clientnum [subnet])\n", Cmd_Argv(0));
		return;
	}

	if(serverBansCount > ARRAY_LEN(serverBans))
	{
		Com_Printf ("Error: Maximum number of bans/exceptions exceeded.\n");
		return;
	}

	banstring = Cmd_Argv(1);
	
	if(strchr(banstring, '.') || strchr(banstring, ':'))
	{
		// This is an ip address, not a client num.
		
		if(SV_ParseCIDRNotation(&ip, &mask, banstring))
		{
			Com_Printf("Error: Invalid address %s\n", banstring);
			return;
		}
	}
	else
	{
		client_t *cl;
		
		// client num.
		if(!com_sv_running->integer)
		{
			Com_Printf("Server is not running.\n");
			return;
		}
		
		cl = SV_GetPlayerByNum();

		if(!cl)
		{
			Com_Printf("Error: Playernum %s does not exist.\n", Cmd_Argv(1));
			return;
		}
		
		ip = cl->netchan.remoteAddress;
		
		if(argc == 3)
		{
			mask = atoi(Cmd_Argv(2));
			
			if(ip.type == NA_IP)
			{
				if(mask < 1 || mask > 32)
					mask = 32;
			}
			else
			{
				if(mask < 1 || mask > 128)
					mask = 128;
			}
		}
		else
			mask = (ip.type == NA_IP6) ? 128 : 32;
	}

	if(ip.type != NA_IP && ip.type != NA_IP6)
	{
		Com_Printf("Error: Can ban players connected via the internet only.\n");
		return;
	}

	// first check whether a conflicting ban exists that would supersede the new one.
	for(index = 0; index < serverBansCount; index++)
	{
		curban = &serverBans[index];
		
		if(curban->subnet <= mask)
		{
			if((curban->isexception || !isexception) && NET_CompareBaseAdrMask(curban->ip, ip, curban->subnet))
			{
				Q_strncpyz(addy2, NET_AdrToString(ip), sizeof(addy2));
				
				Com_Printf("Error: %s %s/%d supersedes %s %s/%d\n", curban->isexception ? "Exception" : "Ban",
					   NET_AdrToString(curban->ip), curban->subnet,
					   isexception ? "exception" : "ban", addy2, mask);
				return;
			}
		}
		if(curban->subnet >= mask)
		{
			if(!curban->isexception && isexception && NET_CompareBaseAdrMask(curban->ip, ip, mask))
			{
				Q_strncpyz(addy2, NET_AdrToString(curban->ip), sizeof(addy2));
			
				Com_Printf("Error: %s %s/%d supersedes already existing %s %s/%d\n", isexception ? "Exception" : "Ban",
					   NET_AdrToString(ip), mask,
					   curban->isexception ? "exception" : "ban", addy2, curban->subnet);
				return;
			}
		}
	}

	// now delete bans that are superseded by the new one
	index = 0;
	while(index < serverBansCount)
	{
		curban = &serverBans[index];
		
		if(curban->subnet > mask && (!curban->isexception || isexception) && NET_CompareBaseAdrMask(curban->ip, ip, mask))
			SV_DelBanEntryFromList(index);
		else
			index++;
	}

	serverBans[serverBansCount].ip = ip;
	serverBans[serverBansCount].subnet = mask;
	serverBans[serverBansCount].isexception = isexception;
	
	serverBansCount++;
	
	SV_WriteBans();

	Com_Printf("Added %s: %s/%d\n", isexception ? "ban exception" : "ban",
		   NET_AdrToString(ip), mask);
}
Beispiel #25
0
/*
=============
NET_GetPacket
=============
*/
int NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
{
	int 	ret, err, fromlen;
	struct sockaddr from;

	if (NET_GetLoopPacket (sock, net_from, net_message))
		return 1;

	if (ip_sockets[sock] == INVALID_SOCKET)
		return 0;

	fromlen = sizeof(from);
	ret = recvfrom (ip_sockets[sock], (char *)net_message->data, net_message->maxsize
		, 0, (struct sockaddr *)&from, &fromlen);

	SockadrToNetadr (&from, net_from);

	if (ret == SOCKET_ERROR)
	{
#ifdef _WIN32
		err = WSAGetLastError();

		switch( err ) {
		case WSAEWOULDBLOCK:
			// wouldblock is silent
			break;
		case WSAECONNRESET:
			if( !net_ignore_icmp->integer ) {
				return -1;
			}
			break;
		case WSAEMSGSIZE:
			Com_Printf ("NET_GetPacket: Oversize packet from %s\n", NET_AdrToString(net_from));
			break;
		default:
			Com_Printf ("NET_GetPacket: %s from %s\n", NET_ErrorString(), NET_AdrToString(net_from));
			break;
		}
#else
		err = errno;

		switch( err ) {
		case EWOULDBLOCK:
			// wouldblock is silent
			break;
		case ECONNREFUSED:
			if( !net_ignore_icmp->integer ) {
				return -1;
			}
			break;
		default:
			Com_Printf ("NET_GetPacket: %s from %s\n", NET_ErrorString(), NET_AdrToString(net_from));
			break;
		}
#endif
		return 0;
	}

	if (ret == net_message->maxsize) {
		Com_Printf ("Oversize packet from %s\n", NET_AdrToString (net_from));
		return 0;
	}

	net_message->cursize = ret;
	return 1;
}
Beispiel #26
0
/*
================
SV_Status_f
================
*/
static void SV_Status_f(void)
{
	int           i, j, l;
	client_t      *cl;
	playerState_t *ps;
	const char    *s;
	int           ping;

	// make sure server is running
	if (!com_sv_running->integer)
	{
		Com_Printf("Server is not running.\n");
		return;
	}

	Com_Printf("map: %s\n", sv_mapname->string);

	Com_Printf("num score ping name            lastmsg address               qport 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);
		ps = SV_GameClientNum(i);
		Com_Printf("%5i ", ps->persistant[PERS_SCORE]);

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

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

		Com_Printf("%7i ", svs.time - cl->lastPacketTime);

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

		Com_Printf("%5i", cl->netchan.qport);

		Com_Printf(" %5i", cl->rate);

		Com_Printf("\n");
	}
	Com_Printf("\n");
}
Beispiel #27
0
/*
===============
SVC_RemoteCommand

An rcon packet arrived from the network.
Shift down the remaining args
Redirect all printfs
===============
*/
void SVC_RemoteCommand( netadr_t from, msg_t *msg )
{
	qboolean     valid;
	unsigned int time;
	char         remaining[ 1024 ];

	// show_bug.cgi?id=376
	// if we send an OOB print message this size, 1.31 clients die in a Com_Printf buffer overflow
	// the buffer overflow will be fixed in > 1.31 clients
	// but we want a server side fix
	// we must NEVER send an OOB message that will be > 1.31 MAXPRINTMSG (4096)
#define SV_OUTPUTBUF_LENGTH ( 256 - 16 )
	char                sv_outputbuf[ SV_OUTPUTBUF_LENGTH ];
	static unsigned int lasttime = 0;
	const char          *cmd_aux;

	// TTimo - show_bug.cgi?id=534
	time = Com_Milliseconds();

	if ( time < ( lasttime + 500 ) )
	{
		return;
	}

	lasttime = time;

	if ( !strlen( sv_rconPassword->string ) || strcmp( Cmd_Argv( 1 ), sv_rconPassword->string ) )
	{
		valid = qfalse;
		Com_Printf(_( "Bad rcon from %s:\n%s\n"), NET_AdrToString( from ), Cmd_Argv( 2 ) );
	}
	else
	{
		valid = qtrue;
		Com_Printf(_( "Rcon from %s:\n%s\n"), NET_AdrToString( from ), Cmd_Argv( 2 ) );
	}

	// start redirecting all print outputs to the packet
	svs.redirectAddress = from;
	// FIXME TTimo our rcon redirection could be improved
	//   big rcon commands such as status lead to sending
	//   out of band packets on every single call to Com_Printf
	//   which leads to client overflows
	//   see show_bug.cgi?id=51
	//     (also a Q3 issue)
	Com_BeginRedirect( sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect );

	if ( !strlen( sv_rconPassword->string ) )
	{
		Com_Printf(_( "No rconpassword set on the server.\n" ));
	}
	else if ( !valid )
	{
		Com_Printf(_( "Bad rconpassword.\n" ));
	}
	else
	{
		remaining[ 0 ] = 0;

		// ATVI Wolfenstein Misc #284
		// get the command directly, "rcon <pass> <command>" to avoid quoting issues
		// extract the command by walking
		// since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing
		cmd_aux = Cmd_Cmd();
		cmd_aux += 4;

		while ( cmd_aux[ 0 ] == ' ' )
		{
			cmd_aux++;
		}

		while ( cmd_aux[ 0 ] && cmd_aux[ 0 ] != ' ' ) // password
		{
			cmd_aux++;
		}

		while ( cmd_aux[ 0 ] == ' ' )
		{
			cmd_aux++;
		}

		Q_strcat( remaining, sizeof( remaining ), cmd_aux );

		Cmd_ExecuteString( remaining );
	}

	Com_EndRedirect();
}
Beispiel #28
0
/*
=================
UI_StatusEvent

A server status response has been received, validated and parsed.
=================
*/
void UI_StatusEvent(const serverStatus_t *status)
{
    serverslot_t *slot;
    char *hostname, *host, *mod, *map, *maxclients;
    unsigned timestamp, ping;
    const char *info = status->infostring;
    char key[MAX_INFO_STRING];
    char value[MAX_INFO_STRING];
    int i;

    // ignore unless menu is up
    if (!m_servers.args) {
        return;
    }

    // see if already added
    slot = FindSlot(&net_from, &i);
    if (!slot) {
        // reply to broadcast, create new slot
        if (m_servers.list.numItems >= MAX_STATUS_SERVERS) {
            return;
        }
        m_servers.list.numItems++;
        hostname = UI_CopyString(NET_AdrToString(&net_from));
        timestamp = m_servers.timestamp;
    } else {
        // free previous data
        hostname = slot->hostname;
        timestamp = slot->timestamp;
        FreeSlot(slot);
    }

    host = Info_ValueForKey(info, "hostname");
    if (COM_IsWhite(host)) {
        host = hostname;
    }

    mod = Info_ValueForKey(info, "game");
    if (COM_IsWhite(mod)) {
        mod = "baseq2";
    }

    map = Info_ValueForKey(info, "mapname");
    if (COM_IsWhite(map)) {
        map = "???";
    }

    maxclients = Info_ValueForKey(info, "maxclients");
    if (!COM_IsUint(maxclients)) {
        maxclients = "?";
    }

    if (timestamp > com_eventTime)
        timestamp = com_eventTime;

    ping = com_eventTime - timestamp;
    if (ping > 999)
        ping = 999;

    slot = UI_FormatColumns(SLOT_EXTRASIZE, host, mod, map,
                            va("%d/%s", status->numPlayers, maxclients),
                            va("%u", ping),
                            NULL);
    slot->status = SLOT_VALID;
    slot->address = net_from;
    slot->hostname = hostname;
    slot->color = ColorForStatus(status);

    m_servers.list.items[i] = slot;

    slot->numRules = 0;
    while (slot->numRules < MAX_STATUS_RULES) {
        Info_NextPair(&info, key, value);
        if (!info)
            break;

        if (!key[0])
            strcpy(key, "<MISSING KEY>");

        if (!value[0])
            strcpy(value, "<MISSING VALUE>");

        slot->rules[slot->numRules++] =
            UI_FormatColumns(0, key, value, NULL);
    }

    slot->numPlayers = status->numPlayers;
    for (i = 0; i < status->numPlayers; i++) {
        slot->players[i] =
            UI_FormatColumns(0,
                             va("%d", status->players[i].score),
                             va("%d", status->players[i].ping),
                             status->players[i].name,
                             NULL);
    }

    slot->timestamp = timestamp;

    // don't sort when manually refreshing
    if (m_servers.pingstage)
        m_servers.list.sort(&m_servers.list);

    UpdateStatus();
    UpdateSelection();
}
Beispiel #29
0
static void SV_DelBanFromList(qboolean isexception)
{
	int index, count = 0, todel, mask;
	netadr_t ip;
	char *banstring;
	
	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}
	
	if(Cmd_Argc() != 2)
	{
		Com_Printf ("Usage: %s (ip[/subnet] | num)\n", Cmd_Argv(0));
		return;
	}

	banstring = Cmd_Argv(1);
	
	if(strchr(banstring, '.') || strchr(banstring, ':'))
	{
		serverBan_t *curban;
		
		if(SV_ParseCIDRNotation(&ip, &mask, banstring))
		{
			Com_Printf("Error: Invalid address %s\n", banstring);
			return;
		}
		
		index = 0;
		
		while(index < serverBansCount)
		{
			curban = &serverBans[index];
			
			if(curban->isexception == isexception		&&
			   curban->subnet >= mask 			&&
			   NET_CompareBaseAdrMask(curban->ip, ip, mask))
			{
				Com_Printf("Deleting %s %s/%d\n",
					   isexception ? "exception" : "ban",
					   NET_AdrToString(curban->ip), curban->subnet);
					   
				SV_DelBanEntryFromList(index);
			}
			else
				index++;
		}
	}
	else
	{
		todel = atoi(Cmd_Argv(1));

		if(todel < 1 || todel > serverBansCount)
		{
			Com_Printf("Error: Invalid ban number given\n");
			return;
		}
	
		for(index = 0; index < serverBansCount; index++)
		{
			if(serverBans[index].isexception == isexception)
			{
				count++;
			
				if(count == todel)
				{
					Com_Printf("Deleting %s %s/%d\n",
					   isexception ? "exception" : "ban",
					   NET_AdrToString(serverBans[index].ip), serverBans[index].subnet);

					SV_DelBanEntryFromList(index);

					break;
				}
			}
		}
	}
	
	SV_WriteBans();
}
Beispiel #30
0
/*
=================
Netchan_Process

Returns qfalse 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.
=================
*/
qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) {
	int			sequence;
	int			qport;
	int			fragmentStart, fragmentLength;
	qboolean	fragmented;

	// XOR unscramble all data in the packet after the header
//	Netchan_UnScramblePacket( msg );

	// get sequence numbers		
	MSG_BeginReadingOOB( msg );
	sequence = MSG_ReadLong( msg );

	// check for fragment information
	if ( sequence & FRAGMENT_BIT ) {
		sequence &= ~FRAGMENT_BIT;
		fragmented = qtrue;
	} else {
		fragmented = qfalse;
	}

	// read the qport if we are a server
	if ( chan->sock == NS_SERVER ) {
		qport = MSG_ReadShort( msg );
	}

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

	if ( showpackets->integer ) {
		if ( fragmented ) {
			Com_Printf( "%s recv %4i : s=%i fragment=%i,%i\n"
				, netsrcString[ chan->sock ]
				, msg->cursize
				, sequence
				, fragmentStart, fragmentLength );
		} else {
			Com_Printf( "%s recv %4i : s=%i\n"
				, netsrcString[ chan->sock ]
				, 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_AdrToString( chan->remoteAddress )
				,  sequence
				, chan->incomingSequence );
		}
		return qfalse;
	}

	//
	// 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_AdrToString( 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 != chan->fragmentLength ) {
			if ( showdrop->integer || showpackets->integer ) {
				Com_Printf( "%s:Dropped a message fragment\n"
				, NET_AdrToString( chan->remoteAddress ));
			}
			// we can still keep the part that we have so far,
			// so we don't need to clear chan->fragmentLength
			return qfalse;
		}

		// 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_AdrToString (chan->remoteAddress ) );
			}
			return qfalse;
		}

		Com_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 ( fragmentLength == FRAGMENT_SIZE ) {
			return qfalse;
		}

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

		// copy the full message over the partial fragment

		// make sure the sequence number is still there
		*(int *)msg->data = LittleLong( sequence );

		Com_Memcpy( msg->data + 4, chan->fragmentBuffer, chan->fragmentLength );
		msg->cursize = chan->fragmentLength + 4;
		chan->fragmentLength = 0;
		msg->readcount = 4;	// past the sequence number
		msg->bit = 32;	// past the sequence number

		// TTimo
		// clients were not acking fragmented messages
		chan->incomingSequence = sequence;
		
		return qtrue;
	}

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

	return qtrue;
}