IpServer
Class UdpServerUplink

source: e:\games\UnrealTournament\IpServer\Classes\UdpServerUplink.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Info
         |
         +--Engine.InternetInfo
            |
            +--IpDrv.InternetLink
               |
               +--IpDrv.UdpLink
                  |
                  +--IpServer.UdpServerUplink
Direct Known Subclasses:None

class UdpServerUplink
extends IpDrv.UdpLink

//============================================================================= // UdpServerUplink // // Version: 1.3 // // This uplink is compliant with the GameSpy Uplink Specification. // The specification is available at http://www.gamespy.com/developer // and might be of use to progammers who want to adapt their own // server uplinks. // // UdpServerUplink sends a heartbeat to the specified master server // every five minutes. The heartbeat is in the form: // \heartbeat\QueryPort\gamename\unreal // // Full documentation on this class is available at http://unreal.epicgames.com/ // //=============================================================================
Variables
 int CurrentQueryNum
           Query ID Number.
 bool DoUplink
           If true, do the uplink
 string HeartbeatMessage
           The message that is sent to the master server.
 string MasterServerAddress
           Address of the master server
 IpAddr MasterServerIpAddr
           Master server's address.
 int MasterServerPort
           Optional port that the master server is listening on
 UdpServerQuery Query
           The query object.
 int Region
           Region of the game server
 name TargetQueryName
           Name of the query server object to use.
 int UpdateMinutes
           Period of update (in minutes)


Function Summary
 void Halt()
     
// Stop the uplink.
 bool ParseNextQuery(string Query, out string, out string, out string, out string)
 string ParseQuery(IpAddr Addr, string QueryStr, int QueryNum, out int)
 void PreBeginPlay()
     
// Initialize.
 void ResolveFailed()
     
// Host resolution failue.
 void Resolved(IpAddr Addr)
     
// When master server address is resolved.
 void Resume()
     
// Resume the uplink.
 bool SendQueryPacket(IpAddr Addr, string SendString, int QueryNum, int PacketNum, string FinalPacket)
     
// SendQueryPacket is a wrapper for SendText that allows for packet numbering.
 void Timer()
     
// Notify the MasterServer we exist.



Source Code


00001	//=============================================================================
00002	// UdpServerUplink
00003	//
00004	// Version: 1.3
00005	//
00006	// This uplink is compliant with the GameSpy Uplink Specification.
00007	// The specification is available at http://www.gamespy.com/developer
00008	// and might be of use to progammers who want to adapt their own
00009	// server uplinks.
00010	//
00011	// UdpServerUplink sends a heartbeat to the specified master server
00012	// every five minutes.  The heartbeat is in the form:
00013	//    \heartbeat\QueryPort\gamename\unreal
00014	//
00015	// Full documentation on this class is available at http://unreal.epicgames.com/
00016	//
00017	//=============================================================================
00018	class UdpServerUplink extends UdpLink config;
00019	
00020	// Master Uplink Config.
00021	var() config bool		DoUplink;				// If true, do the uplink
00022	var() config int		UpdateMinutes;			// Period of update (in minutes)
00023	var() config string     MasterServerAddress;	// Address of the master server
00024	var() config int		MasterServerPort;		// Optional port that the master server is listening on
00025	var() config int 		Region;					// Region of the game server
00026	var() name				TargetQueryName;		// Name of the query server object to use.
00027	var IpAddr				MasterServerIpAddr;		// Master server's address.
00028	var string		        HeartbeatMessage;		// The message that is sent to the master server.
00029	var UdpServerQuery      Query;					// The query object.
00030	var int				    CurrentQueryNum;		// Query ID Number.
00031	
00032	// Initialize.
00033	function PreBeginPlay()
00034	{
00035		// If master server uplink isn't wanted, exit.
00036		if( !DoUplink )
00037		{
00038			Log("DoUplink is not set.  Not connecting to Master Server.");
00039			return;
00040		}
00041	
00042	/*
00043		if( Level.NetMode == NM_ListenServer )
00044		{
00045			Log("This is a Listen server.  Not connecting to Master Server.");
00046			return;
00047		}
00048	*/
00049	
00050		// Find a the server query handler.
00051		foreach AllActors(class'UdpServerQuery', Query, TargetQueryName)
00052			break;
00053	
00054		if( Query==None )
00055		{
00056			Log("UdpServerUplink: Could not find a UdpServerQuery object, aborting.");
00057			return;
00058		}
00059	
00060		// Set heartbeat message.
00061		if( MasterServerAddress ~= "unreal.epicgames.com" )
00062			HeartbeatMessage = "\\heartbeat\\"$Query.Port$"\\gamename\\"$Query.GameName$"\\gamever\\"$Level.EngineVersion;
00063		else
00064			HeartbeatMessage = "\\heartbeat\\"$Query.Port$"\\gamename\\"$Query.GameName;
00065	
00066		// Set the Port.
00067		MasterServerIpAddr.Port = MasterServerPort;
00068	
00069		// Resolve the Address.
00070		if( MasterServerAddress=="" )
00071			MasterServerAddress = "master"$Region$".gamespy.com";
00072		Resolve( MasterServerAddress );
00073	}
00074	
00075	// When master server address is resolved.
00076	function Resolved( IpAddr Addr )
00077	{
00078		local bool Result;
00079		local int UplinkPort;
00080	
00081		// Set the address
00082		MasterServerIpAddr.Addr = Addr.Addr;
00083	
00084		// Handle failure.
00085		if( MasterServerIpAddr.Addr == 0 )
00086		{
00087			Log("UdpServerUplink: Invalid master server address, aborting.");
00088			return;
00089		}
00090	
00091		// Display success message.
00092		Log("UdpServerUplink: Master Server is "$MasterServerAddress$":"$MasterServerIpAddr.Port);
00093		
00094		// Bind the local port.
00095		UplinkPort = Query.Port + 1;
00096		if( BindPort(UplinkPort, true) == 0 )
00097		{
00098			Log( "UdpServerUplink: Error binding port, aborting." );
00099			return;
00100		}
00101		Log("UdpServerUplink: Port "$UplinkPort$" successfully bound.");
00102	
00103		// Start transmitting.
00104		Resume();
00105	}
00106	
00107	// Host resolution failue.
00108	function ResolveFailed()
00109	{
00110		Log("UdpServerUplink: Failed to resolve master server address, aborting.");
00111	}
00112	
00113	// Notify the MasterServer we exist.
00114	function Timer()
00115	{
00116		local bool Result;
00117	
00118		Result = SendText( MasterServerIpAddr, HeartbeatMessage );
00119		if ( !Result )
00120			Log( "Failed to send heartbeat to master server.");
00121	}
00122	
00123	// Stop the uplink.
00124	function Halt()
00125	{
00126		SetTimer(0.0, false);
00127	}
00128	
00129	// Resume the uplink.
00130	function Resume()
00131	{
00132		SetTimer(UpdateMinutes * 60, true);
00133		Timer();
00134	}
00135	
00136	// Received a query request.
00137	event ReceivedText( IpAddr Addr, string Text )
00138	{
00139		local string Query;
00140		local bool QueryRemaining;
00141		local int  QueryNum, PacketNum;
00142	
00143		// Assign this packet a unique value from 1 to 100
00144		CurrentQueryNum++;
00145		if (CurrentQueryNum > 100)
00146			CurrentQueryNum = 1;
00147		QueryNum = CurrentQueryNum;
00148	
00149		Query = Text;
00150		if (Query == "")		// If the string is empty, don't parse it
00151			QueryRemaining = false;
00152		else
00153			QueryRemaining = true;
00154		
00155		while (QueryRemaining) {
00156			Query = ParseQuery(Addr, Query, QueryNum, PacketNum);
00157			if (Query == "")
00158				QueryRemaining = false;
00159			else
00160				QueryRemaining = true;
00161		}
00162	}
00163	
00164	function bool ParseNextQuery( string Query, out string QueryType, out string QueryValue, out string QueryRest, out string FinalPacket )
00165	{
00166		local string TempQuery;
00167		local int ClosingSlash;
00168	
00169		if (Query == "")
00170			return false;
00171	
00172		// Query should be:
00173		//   \[type]\<value>
00174		if (Left(Query, 1) == "\\")
00175		{
00176			// Check to see if closed.
00177			ClosingSlash = InStr(Right(Query, Len(Query)-1), "\\");
00178			if (ClosingSlash == 0)
00179				return false;
00180	
00181			TempQuery = Query;
00182	
00183			// Query looks like:
00184			//  \[type]\
00185			QueryType = Right(Query, Len(Query)-1);
00186			QueryType = Left(QueryType, ClosingSlash);
00187	
00188			QueryRest = Right(Query, Len(Query) - (Len(QueryType) + 2));
00189	
00190			if ((QueryRest == "") || (Len(QueryRest) == 1))
00191			{
00192				FinalPacket = "final";
00193				return true;
00194			} else if (Left(QueryRest, 1) == "\\")
00195				return true;	// \type\\
00196	
00197			// Query looks like:
00198			//  \type\value
00199			ClosingSlash = InStr(QueryRest, "\\");
00200			if (ClosingSlash >= 0)
00201				QueryValue = Left(QueryRest, ClosingSlash);
00202			else
00203				QueryValue = QueryRest;
00204	
00205			QueryRest = Right(Query, Len(Query) - (Len(QueryType) + Len(QueryValue) + 3));
00206			if (QueryRest == "")
00207			{
00208				FinalPacket = "final";
00209				return true;
00210			} else
00211				return true;
00212		} else {
00213			return false;
00214		}
00215	}
00216	
00217	function string ParseQuery( IpAddr Addr, coerce string QueryStr, int QueryNum, out int PacketNum )
00218	{
00219		local string QueryType, QueryValue, QueryRest, ValidationString;
00220		local bool Result;
00221		local string FinalPacket;
00222		
00223		Result = ParseNextQuery(QueryStr, QueryType, QueryValue, QueryRest, FinalPacket);
00224		if( !Result )
00225			return "";
00226	
00227		if( QueryType=="basic" )
00228		{
00229			// Ignore.
00230			Result = true;
00231		}
00232		else if( QueryType=="secure" )
00233		{
00234			ValidationString = "\\validate\\"$Validate(QueryValue, Query.GameName);
00235			Result = SendQueryPacket(Addr, ValidationString, QueryNum, ++PacketNum, FinalPacket);
00236		}
00237		return QueryRest;
00238	}
00239	
00240	// SendQueryPacket is a wrapper for SendText that allows for packet numbering.
00241	function bool SendQueryPacket(IpAddr Addr, coerce string SendString, int QueryNum, int PacketNum, string FinalPacket)
00242	{
00243		local bool Result;
00244		if (FinalPacket == "final") {
00245			SendString = SendString$"\\final\\";
00246		}
00247		SendString = SendString$"\\queryid\\"$QueryNum$"."$PacketNum;
00248	
00249		Result = SendText(Addr, SendString);
00250	
00251		return Result;
00252	}
00253	
00254	defaultproperties
00255	{
00256	     UpdateMinutes=1
00257	     MasterServerPort=27900
00258	     TargetQueryName=MasterUplink
00259	     RemoteRole=ROLE_None
00260	}

End Source Code