📄 rgcp.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 + -