IpServer
Class UdpServerUplink

source: c:\runehov\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 ServerRegion
           Region of the game server (changed from Region to avoid collision with actor region)
 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 		ServerRegion;			// Region of the game server (changed from Region to avoid collision with actor region)
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		HeartbeatMessage = "\\heartbeat\\"$Query.Port$"\\gamename\\"$Query.GameName;
00062	
00063		// Set the Port.
00064		MasterServerIpAddr.Port = MasterServerPort;
00065	
00066		// Resolve the Address.
00067		if( MasterServerAddress=="" )
00068			MasterServerAddress = "master"$ServerRegion$".gamespy.com";
00069		Resolve( MasterServerAddress );
00070	}
00071	
00072	// When master server address is resolved.
00073	function Resolved( IpAddr Addr )
00074	{
00075		local bool Result;
00076		local int UplinkPort;
00077	
00078		// Set the address
00079		MasterServerIpAddr.Addr = Addr.Addr;
00080	
00081		// Handle failure.
00082		if( MasterServerIpAddr.Addr == 0 )
00083		{
00084			Log("UdpServerUplink: Invalid master server address, aborting.");
00085			return;
00086		}
00087	
00088		// Display success message.
00089		Log("UdpServerUplink: Master Server is "$MasterServerAddress$":"$MasterServerIpAddr.Port);
00090		
00091		// Bind the local port.
00092		UplinkPort = Query.Port + 1;
00093		if( BindPort(UplinkPort, true) == 0 )
00094		{
00095			Log( "UdpServerUplink: Error binding port, aborting." );
00096			return;
00097		}
00098		Log("UdpServerUplink: Port "$UplinkPort$" successfully bound.");
00099	
00100		// Start transmitting.
00101		Resume();
00102	}
00103	
00104	// Host resolution failue.
00105	function ResolveFailed()
00106	{
00107		Log("UdpServerUplink: Failed to resolve master server address, aborting.");
00108	}
00109	
00110	// Notify the MasterServer we exist.
00111	function Timer()
00112	{
00113		local bool Result;
00114	
00115		Result = SendText( MasterServerIpAddr, HeartbeatMessage );
00116		if ( !Result )
00117			Log( "Failed to send heartbeat to master server.");
00118	}
00119	
00120	// Stop the uplink.
00121	function Halt()
00122	{
00123		SetTimer(0.0, false);
00124	}
00125	
00126	// Resume the uplink.
00127	function Resume()
00128	{
00129		SetTimer(UpdateMinutes * 60, true);
00130		Timer();
00131	}
00132	
00133	// Received a query request.
00134	event ReceivedText( IpAddr Addr, string Text )
00135	{
00136		local string Query;
00137		local bool QueryRemaining;
00138		local int  QueryNum, PacketNum;
00139	
00140		// Assign this packet a unique value from 1 to 100
00141		CurrentQueryNum++;
00142		if (CurrentQueryNum > 100)
00143			CurrentQueryNum = 1;
00144		QueryNum = CurrentQueryNum;
00145	
00146		Query = Text;
00147		if (Query == "")		// If the string is empty, don't parse it
00148			QueryRemaining = false;
00149		else
00150			QueryRemaining = true;
00151		
00152		while (QueryRemaining) {
00153			Query = ParseQuery(Addr, Query, QueryNum, PacketNum);
00154			if (Query == "")
00155				QueryRemaining = false;
00156			else
00157				QueryRemaining = true;
00158		}
00159	}
00160	
00161	function bool ParseNextQuery( string Query, out string QueryType, out string QueryValue, out string QueryRest, out string FinalPacket )
00162	{
00163		local string TempQuery;
00164		local int ClosingSlash;
00165	
00166		if (Query == "")
00167			return false;
00168	
00169		// Query should be:
00170		//   \[type]\<value>
00171		if (Left(Query, 1) == "\\")
00172		{
00173			// Check to see if closed.
00174			ClosingSlash = InStr(Right(Query, Len(Query)-1), "\\");
00175			if (ClosingSlash == 0)
00176				return false;
00177	
00178			TempQuery = Query;
00179	
00180			// Query looks like:
00181			//  \[type]\
00182			QueryType = Right(Query, Len(Query)-1);
00183			QueryType = Left(QueryType, ClosingSlash);
00184	
00185			QueryRest = Right(Query, Len(Query) - (Len(QueryType) + 2));
00186	
00187			if ((QueryRest == "") || (Len(QueryRest) == 1))
00188			{
00189				FinalPacket = "final";
00190				return true;
00191			} else if (Left(QueryRest, 1) == "\\")
00192				return true;	// \type\\
00193	
00194			// Query looks like:
00195			//  \type\value
00196			ClosingSlash = InStr(QueryRest, "\\");
00197			if (ClosingSlash >= 0)
00198				QueryValue = Left(QueryRest, ClosingSlash);
00199			else
00200				QueryValue = QueryRest;
00201	
00202			QueryRest = Right(Query, Len(Query) - (Len(QueryType) + Len(QueryValue) + 3));
00203			if (QueryRest == "")
00204			{
00205				FinalPacket = "final";
00206				return true;
00207			} else
00208				return true;
00209		} else {
00210			return false;
00211		}
00212	}
00213	
00214	function string ParseQuery( IpAddr Addr, coerce string QueryStr, int QueryNum, out int PacketNum )
00215	{
00216		local string QueryType, QueryValue, QueryRest, ValidationString;
00217		local bool Result;
00218		local string FinalPacket;
00219		
00220		Result = ParseNextQuery(QueryStr, QueryType, QueryValue, QueryRest, FinalPacket);
00221		if( !Result )
00222			return "";
00223	
00224		if( QueryType=="basic" )
00225		{
00226			// Ignore.
00227			Result = true;
00228		}
00229		else if( QueryType=="secure" )
00230		{
00231			ValidationString = "\\validate\\"$Validate(QueryValue, Query.GameName);
00232			Result = SendQueryPacket(Addr, ValidationString, QueryNum, ++PacketNum, FinalPacket);
00233		}
00234		else
00235		{
00236			Log("UdpServerQuery: Unknown query: "$QueryType);
00237		}
00238		if( !Result )
00239			Log("UdpServerQuery: Error responding to query.");
00240		return QueryRest;
00241	}
00242	
00243	// SendQueryPacket is a wrapper for SendText that allows for packet numbering.
00244	function bool SendQueryPacket(IpAddr Addr, coerce string SendString, int QueryNum, int PacketNum, string FinalPacket)
00245	{
00246		local bool Result;
00247		if (FinalPacket == "final") {
00248			SendString = SendString$"\\final\\";
00249		}
00250		SendString = SendString$"\\queryid\\"$QueryNum$"."$PacketNum;
00251	
00252		Result = SendText(Addr, SendString);
00253	
00254		return Result;
00255	}
00256	
00257	defaultproperties
00258	{
00259	     UpdateMinutes=5
00260	     MasterServerAddress="master.gamespy.com"
00261	     MasterServerPort=27900
00262	     TargetQueryName=MasterUplink
00263	     RemoteRole=ROLE_None
00264	}

End Source Code