⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rgcp.cpp

📁 Symbian C++ scmp.zip
💻 CPP
字号:
// rgcp.cpp
//
// Copyright (c) 2003 Symbian Ltd.  All rights reserved
//

#include "rgcp.h"

#include <s32mem.h>

enum TPanic
	{
	EInitiateNotBlank,
	EListenNotBlank,
	ESendResponseNotResponding,
	EResponseTooLong,
	ESendResponseBadOpcode,
	ESendRequestNotRequesting,
	ERequestTooLong,
	ESendRequestBadOpcode,
	EResendNothingSent,
	EBadIncomingPacket,
	EReceiveNotWaiting,
	EHandleInitNotInitiating,
	ENoHandler,
	};

static void Panic(TInt aPanic)
	{
	_LIT(KPanicCategory,"RGCP");
	User::Panic(KPanicCategory, aPanic);
	}

// construct/destruct

EXPORT_C CRgcpSession::CRgcpSession()
	{
	}

EXPORT_C void CRgcpSession::ConstructL(TUint32 aGameProtocol)
	{
	iGsdp.ConnectL(*this);
	iGsdp.SetGameProtocol(aGameProtocol);
	}

EXPORT_C void CRgcpSession::SetHandler(MRgcpHandler* aHandler)
	{
	// set handler for events driven (mostly) by incoming data
	iHandler=aHandler;
	// activate or deactive listening as necessary
	if (!iHandler)
		iGsdp.StopListening();
	else if (!IsBlank())
		iGsdp.Listen();
	}

EXPORT_C CRgcpSession::~CRgcpSession()
	{
	iGsdp.Close();
	}

// initialization

EXPORT_C void CRgcpSession::SetGdpProtocolL(TUid aGdpProtocol)
	{
	iGsdp.SetGdpProtocol(aGdpProtocol);
	}

// state transitioning functions

EXPORT_C void CRgcpSession::Initiate(const TDesC8& aOtherAddress)
	{
	__ASSERT_ALWAYS(IsBlank(), Panic(EInitiateNotBlank));
	__ASSERT_ALWAYS(iHandler, Panic(ENoHandler));
	// basic GSDP setup
	iGsdp.SetOtherAddress(aOtherAddress);
	iGsdp.AllocMyNextPort();
	iGsdp.SetOtherPort(0);
	iGsdp.ReceiveAll();
	iGsdp.Listen();
	// reset sequence numbers
	iNextSendSequenceNo=0;
	iLastReceivedSequenceNo=0;
	// sent initiate request
	DoSendResponse(EReserved,TPtrC8(0,0));
	DoSendRequest(EInitiate,TPtrC8(0,0));
	// state transition
	iState=EInitiating;
	}

EXPORT_C void CRgcpSession::Listen()
	{
	__ASSERT_ALWAYS(IsBlank(), Panic(EListenNotBlank));
	__ASSERT_ALWAYS(iHandler, Panic(ENoHandler));
	// basic GSDP setup
	iGsdp.SetOtherAddress(_L8(""));
	iGsdp.SetMyPort(0);
	iGsdp.SetOtherPort(0);
	iGsdp.ReceiveAll();
	iGsdp.Listen();
	// reset sequence numbers
	iNextSendSequenceNo=1;
	iLastReceivedSequenceNo=0;
	// state transition
	iState=EListening;
	}

EXPORT_C void CRgcpSession::Terminate()
	{
	DoTerminate(ETrue); // client-initiated terminate
	}

void CRgcpSession::DoTerminate(TBool aClientInitiated)
	{
	if (IsBlank())
		return;
	// send terminate request if needed
	if (IsBound() && aClientInitiated)
		{
		iNextSendSequenceNo=0;
		DoSendResponse(EReserved, TPtrC8(0,0));
		DoSendRequest(ETerminate, TPtrC8(0,0));
		}
	// GSDP stuff
	iGsdp.StopListening();
	// call handler function
	iHandler->RgcpHandleTerminated(aClientInitiated);
	// state transition
	iState=EBlank;
	}

EXPORT_C void CRgcpSession::SendResponse(TInt aOpcode, const TDesC8& aData)
	{
	// validity check state, opcode and data length
	__ASSERT_ALWAYS(IsResponding(), Panic(ESendResponseNotResponding));
	__ASSERT_ALWAYS(aOpcode!=ETerminate && aOpcode!=EInitiate,
			Panic(ESendResponseBadOpcode));
	__ASSERT_ALWAYS(aData.Size()<=126, Panic(EResponseTooLong));
	__ASSERT_ALWAYS(iHandler, Panic(ENoHandler));
	// send the response
	DoSendResponse(aOpcode, aData);
	// change state
	iState=ERequesting;
	}

EXPORT_C void CRgcpSession::SendResponse(TInt aOpcode)
	{
	SendResponse(aOpcode, TPtrC8(0,0));
	}

EXPORT_C void CRgcpSession::SendResponse()
	{
	SendResponse(EReserved);
	}

EXPORT_C void CRgcpSession::SendRequest(TInt aOpcode, const TDesC8& aData)
	{
	// validity check state, opcode and data length
	__ASSERT_ALWAYS(IsRequesting(), Panic(ESendRequestNotRequesting));
	__ASSERT_ALWAYS(aOpcode!=EReserved && aOpcode!=ETerminate && aOpcode!=EInitiate,
			Panic(ESendRequestBadOpcode));
	__ASSERT_ALWAYS(aData.Size()<=126, Panic(ERequestTooLong));
	__ASSERT_ALWAYS(iHandler, Panic(ENoHandler));
	// send the request
	DoSendRequest(aOpcode, aData);
	// change state
	iState=EWaiting;
	}

EXPORT_C void CRgcpSession::SendRequest(TInt aOpcode)
	{
	SendRequest(aOpcode, TPtrC8(0,0));
	}

void CRgcpSession::DoSendResponse(TInt aOpcode, const TDesC8& aData)
	{
	// initialize writer to write buffer from scratch
	iSendWriter.Open(iSendBuffer);
	// write and increment the sequence number
	iSendWriter.WriteInt32L(iNextSendSequenceNo++);
	// check for null case - no opcode, no data
	if (aOpcode==EReserved && aData.Size()==0)
		{
		iSendWriter.WriteUint8L(0); // zero-length datagram
		return;
		}
	// write length, opcode, data
	iSendWriter.WriteUint8L(1+aData.Size());
	iSendWriter.WriteUint8L(aOpcode);
	iSendWriter.WriteL(aData);
	}

void CRgcpSession::DoSendRequest(TInt aOpcode, const TDesC8& aData)
	{
	// write length, opcode, data
	iSendWriter.WriteUint8L(1+aData.Size());
	iSendWriter.WriteUint8L(aOpcode);
	iSendWriter.WriteL(aData);
	// commit to send buffer
	iSendWriter.CommitL();
	// send buffer
	iGsdp.Send(iSendBuffer);
	}

EXPORT_C void CRgcpSession::Resend()
	{
	__ASSERT_ALWAYS(IsInitiating() || IsWaiting(), Panic(EResendNothingSent));
	__ASSERT_ALWAYS(iHandler, Panic(ENoHandler));
	iGsdp.Send(iSendBuffer);
	}

// persistence

EXPORT_C void CRgcpSession::ExternalizeL(RWriteStream& aStream) const
	{
	// protocol and state
	aStream.WriteInt32L(iGsdp.GetGameProtocol());
	aStream.WriteInt32L(iGsdp.GetGdpProtocol().iUid);
	aStream.WriteUint8L(iState);
	// my port
	aStream.WriteInt32L(iGsdp.GetMyPort());
	// other address and port
	TBuf8<KMaxGsdpAddress> address;
	iGsdp.GetOtherAddress(address);
	aStream.WriteUint8L(address.Length());
	aStream.WriteL(address);
	aStream.WriteInt32L(iGsdp.GetOtherPort());
	// send information
	aStream.WriteInt32L(iNextSendSequenceNo);
	if (IsBlank() || IsListening())
		{
		aStream.WriteUint8L(0); // empty send buffer
		}
	else
		{
		const_cast<CRgcpSession*>(this)->iSendWriter.CommitL();
		aStream.WriteUint8L(iSendBuffer.Size());
		aStream.WriteL(iSendBuffer);
		}
	// receive information
	aStream.WriteInt32L(iLastReceivedSequenceNo);
	aStream.WriteUint8L(iReceiveBuffer.Size());
	aStream.WriteL(iReceiveBuffer);
	}

EXPORT_C void CRgcpSession::InternalizeL(RReadStream& aStream)
	{
	// reset
	iGsdp.StopListening();
	// protocol and state
	iGsdp.SetGameProtocol(aStream.ReadInt32L());
	iGsdp.SetGdpProtocol(TUid::Uid(aStream.ReadInt32L()));
	iState=(TState) aStream.ReadUint8L();
	// my port
	iGsdp.SetMyPort(aStream.ReadInt32L());
	// other address and port
	TBuf8<KMaxGsdpAddress> address;
	aStream.ReadL(address, aStream.ReadUint8L());
	iGsdp.SetOtherAddress(address);
	iGsdp.SetOtherPort(aStream.ReadInt32L());
	// send information
	iNextSendSequenceNo=aStream.ReadInt32L();
	TInt sendLength=aStream.ReadUint8L();
	iSendWriter.Open(iSendBuffer);
	iSendWriter.WriteL(aStream, sendLength);
	iSendWriter.CommitL();
	// receive information
	iLastReceivedSequenceNo=aStream.ReadInt32L();
	aStream.ReadL(iReceiveBuffer, aStream.ReadUint8L());
	// start listening if we can
	if (iHandler && !IsBlank())
		iGsdp.Listen();
	}

EXPORT_C TStreamId CRgcpSession::StoreL(CStreamStore& aStore) const
	{
	RStoreWriteStream stream;
	TStreamId id = stream.CreateLC(aStore);
	ExternalizeL(stream);
	stream.CommitL();
	CleanupStack::PopAndDestroy(); // stream
	return id;
	}

EXPORT_C void CRgcpSession::RestoreL(const CStreamStore& aStore, TStreamId aStreamId)
	{
	RStoreReadStream stream;
	stream.OpenLC(aStore,aStreamId);
	InternalizeL(stream);
	CleanupStack::PopAndDestroy(); // stream
	}

// handling received packets

void CRgcpSession::GsdpHandleL(const TDesC8& aData)
	{
	TInt seqno, responseOpcode, requestOpcode;
	TRAPD(err, CrackPacketL(aData, seqno, responseOpcode, requestOpcode));
	__ASSERT_ALWAYS(!err, Panic(EBadIncomingPacket));
	HandlePacket(seqno, responseOpcode, requestOpcode);
	}

void CRgcpSession::CrackPacketL(const TDesC8& aData, TInt& aSeqNo, TInt& aResponseOpcode, TInt& aRequestOpcode)
	{
	// prepare to read the incoming data
	iReceiveBuffer=aData;
	RDesReadStream stream;
	stream.PushL();
	// read the data
	stream.Open(iReceiveBuffer);
	aSeqNo=stream.ReadInt32L();
	// response
	TInt responseLength=stream.ReadUint8L();
	aResponseOpcode=EReserved;
	iResponse.Zero();
	if (responseLength>0)
		{
		aResponseOpcode=stream.ReadUint8L();
		stream.ReadL(iResponse, responseLength-1);
		}
	// request
	TInt requestLength=stream.ReadUint8L();
	aRequestOpcode=stream.ReadUint8L();
	stream.ReadL(iRequest, requestLength-1);
	// finished reading
	CleanupStack::PopAndDestroy(); // stream
	}

void CRgcpSession::HandlePacket(TInt aSeqNo, TInt aResponseOpcode, TInt aRequestOpcode)
	{
	// test initiate or terminate requests
	if (aSeqNo==0 && aRequestOpcode==ETerminate)
		{
		HandleTerminateRequest();
		return;
		}
	if (aSeqNo==0 && aRequestOpcode==EInitiate && IsListening())
		{
		HandleInitiateRequest();
		return;
		}
	// test against sequence number
	if (aSeqNo!=iLastReceivedSequenceNo+1)
		return; // drop packet
	iLastReceivedSequenceNo++; // bump sequence number
	// handle response
	if (aResponseOpcode==EInitiate && iLastReceivedSequenceNo==1)
		{
		__ASSERT_ALWAYS(IsInitiating(), Panic(EHandleInitNotInitiating)); // check we were expacting it
		iHandler->RgcpHandleBound();
		}
	else
		{
		__ASSERT_ALWAYS(IsWaiting(), Panic(EReceiveNotWaiting)); // check we were expacting it
		iHandler->RgcpHandleResponse(aResponseOpcode, iResponse);
		}
	if (IsBlank()) // we were terminated
		return;
	// handle request
	iState=EResponding;
	iHandler->RgcpHandleRequest(aRequestOpcode, iRequest);
	if (IsBlank()) // we were terminated
		return;
	if (IsResponding()) // request-handling didn't generate a response
		SendResponse(); // write null response, and change state to requesting
	iHandler->RgcpStartRequesting(); // indicate app can request now
	}

void CRgcpSession::HandleTerminateRequest()
	{
	DoTerminate(EFalse); // non-client-initiated terminate
	}

void CRgcpSession::HandleInitiateRequest()
	{
	iGsdp.AllocMyNextPort();
	DoSendResponse(EInitiate, TPtrC8(0,0));
	iState=ERequesting;
	iHandler->RgcpHandleBound();
	if (IsBlank())
		return;
	iHandler->RgcpStartRequesting();
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -