diff -r 000000000000 -r f5a58ecadc66 servicediscoveryandcontrol/pnp/test/upnp/Client/upnpplugin/src/ccontrolchannel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servicediscoveryandcontrol/pnp/test/upnp/Client/upnpplugin/src/ccontrolchannel.cpp Tue Feb 02 01:12:20 2010 +0200 @@ -0,0 +1,258 @@ +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "ccontrolchannel.h" +#include +#include +#include + +CControlChannelHandler::CControlChannelHandler ( RSocket &aSocket, TBool aChannelType ) +:CActive ( EPriorityNormal ), iSocket ( aSocket ), iChannelType ( aChannelType ) + { + CActiveScheduler::Add(this); + } + +TInt CControlChannelHandler::RunError ( TInt aError ) + { + User::RequestComplete ( iChannelStatus, aError ); + return KErrNone; + } +// ------------------------------------------------------------- +CControlChannelReader* CControlChannelReader::NewL ( RSocket& aSocket, TBool aChannelType ) + { + return new ( ELeave ) CControlChannelReader ( aSocket, aChannelType ); + } + +CControlChannelReader::CControlChannelReader ( RSocket& aSocket, TBool aChannelType ) + : CControlChannelHandler ( aSocket, aChannelType ) + { + } + +CControlChannelReader::~CControlChannelReader () + { + Cancel (); + } + +void CControlChannelReader::Read ( TControlMessage& aMessage, TRequestStatus& aStatus ) + { + if ( iChannelType == EFalse ) + { + __ASSERT_DEBUG ( !aMessage.IsDirty (), User::Panic ( KUPnPControlChannel, KErrInUse ) ); + } + + iMessage = &aMessage; + iChannelStatus = &aStatus; + *iChannelStatus = KRequestPending; + + iSocket.RecvOneOrMore ( iMessage->MessagePtr(), 0, iStatus, iBytesReceived ); + SetActive (); + } + +void CControlChannelReader::RunL () + { + User::LeaveIfError ( iStatus.Int() ); + TPtrC8 buffer ( iMessage->MessagePtr() ); + TInt lenToSkip = 0; + if ( iDataLength == 0 ) // ie; first message + { + // We should have more than 4 bytes ( ie; the identifier, which is of TUint, + // size. here, sizeof (TUint) ) + __ASSERT_DEBUG ( buffer.Length () > sizeof(TUint), User::Invariant() ); + + // Extract the first 4 bytes. we will have our identifier with it. + TLex8 parser ( buffer ); + TUint id = 0; + User::LeaveIfError ( parser.Val ( id, EDecimal ) ); + iMessage->SetId( id ); + lenToSkip = sizeof (TUint); + + // Check how we are going to end with the message. checking the TControlMessage::MaxLength + // or by explicitly specifying it. + + // Get the Maxlength and set it to the iMessage + TInt maxLen = 0; + User::LeaveIfError ( iSocket.GetOpt ( KCHMaxRecvLength, KCHOptionLevel, maxLen ) ); + iMessage->SetMaxLength ( maxLen ); + } + TPtrC8 bufferToCopy ( buffer.Ptr() + lenToSkip, buffer.Length() - lenToSkip ); + iMessage->MessagePtr().Copy ( bufferToCopy ); + iDataLength += bufferToCopy.Length (); + TInt maxLen = iMessage->MaxLength (); + if ( maxLen == KErrUnknown ) + { + // We have to issue a GetOpt to see whether we complete with the message. + TBool last = EFalse; + User::LeaveIfError ( iSocket.GetOpt ( KCHLastMessage, KCHOptionLevel, last ) ); + if ( last ) + iMessage->SetLast (); + } + else + { + if ( iDataLength == maxLen ) + { + // We completed with the message. Set the message end flag as ETrue + // and reset the iRecvLength + iDataLength = 0; + iMessage->SetLast (); + } + } + + if ( iMessage->IsLast () && iChannelType == EFalse ) + { + // client usage is done with the current control message + // We have to set a dirty bit as well for not reusing this message again + iMessage->SetDirty (); + } + + User::RequestComplete ( iChannelStatus, KErrNone ); + } + +void CControlChannelReader::DoCancel () + { + iSocket.CancelRecv (); + User::RequestComplete ( iChannelStatus, KErrCancel ); + } + +// --------------------------------------------------------------- + +CControlChannelWriter* CControlChannelWriter::NewL ( RSocket& aSocket, TBool aChannelType ) + { + return new ( ELeave ) CControlChannelWriter ( aSocket, aChannelType ); + } + +CControlChannelWriter::CControlChannelWriter ( RSocket& aSocket, TBool aChannelType ) + : CControlChannelHandler ( aSocket, aChannelType) + { + } + +CControlChannelWriter::~CControlChannelWriter () + { + Cancel (); + } + +void CControlChannelWriter::Write ( TControlMessage& aMessage, TRequestStatus& aStatus ) + { + if ( iChannelType ) + { + __ASSERT_DEBUG ( !aMessage.IsDirty (), User::Panic ( KUPnPControlChannel, KErrInUse ) ); + } + + iMessage = &aMessage; + iChannelStatus = &aStatus; + *iChannelStatus = KRequestPending; + + if ( iMessage->Id () == 0 ) + { + // Message ID is not set. Typically when we do the first send after connect + // ie; Client side RControlChannel operation. + iMessage->SetId ( iSocket.SubSessionHandle () ); + } + + if ( iMessage->MaxLength() != KErrUnknown ) + { + TCHMessageOption option ( iMessage->Id (), iMessage->MaxLength () ); + TPckg < TCHMessageOption > optionBuf ( option ); + // Set the total size if set in the TControlMessage + iSocket.SetOpt ( KCHMaxRecvLength, KCHOptionLevel, optionBuf ); + } + + if ( iMessage->IsLast () && iChannelType ) + { + // server usage is done with the current control message + // We have to set a dirty bit as well for not reusing this message again + iMessage->SetDirty (); + } + + iSocket.Send ( iMessage->MessageDes(), iMessage->Id(), iStatus ); + SetActive (); + } + +void CControlChannelWriter::RunL () + { + User::LeaveIfError ( iStatus.Int() ); + if ( iMessage->MaxLength() == KErrUnknown && iMessage->IsLast () ) + { + TCHMessageOption option ( iMessage->Id (), iMessage->IsLast () ); + TPckg < TCHMessageOption > optionBuf ( option ); + + // SetOpt to know whether we are sending the last message + User::LeaveIfError ( iSocket.SetOpt( KCHLastMessage, KCHOptionLevel, optionBuf ) ); + } + + User::RequestComplete ( iChannelStatus, KErrNone ); + } + +void CControlChannelWriter::DoCancel () + { + iSocket.CancelSend (); + User::RequestComplete ( iChannelStatus, KErrCancel ); + } + +// ---------------------------------------------------------------- + +CControlChannel* CControlChannel::NewL ( RSocketServ& aSocketServ, RSubConnection& aSubConnection, TUint aAddrFamily, TBool aChannelType, TUint aProtocol, const TConnectionDetails& aConnInfo ) + { + CControlChannel* self = new (ELeave) CControlChannel ( ); + CleanupStack::PushL ( self ); + self->ConstructL ( aSocketServ, aSubConnection, aAddrFamily, aChannelType, aProtocol, aConnInfo ); + CleanupStack::Pop (); // self + return self; + } + +CControlChannel::~CControlChannel () + { + delete iReader; + delete iWriter; + iSocket.Close (); + } + +void CControlChannel::Recv ( TControlMessage& aMessage, TRequestStatus& aStatus ) + { + iReader->Read ( aMessage, aStatus ); + } + +void CControlChannel::Send ( TControlMessage& aMessage, TRequestStatus& aStatus ) + { + iWriter->Write ( aMessage, aStatus ); + } + + +CControlChannel::CControlChannel ( ) + { + } + +void CControlChannel::ConstructL ( RSocketServ& aSocketServ, RSubConnection& aSubConnection, TUint aAddrFamily, TBool aChannelType, TUint aProtocol, const TConnectionDetails& aConnInfo ) + { + User::LeaveIfError ( iSocket.Open( aSocketServ, aAddrFamily, KSockStream, aProtocol, aSubConnection ) ); + + if ( aConnInfo.iAddr ) + { + TRequestStatus connectStatus; + iSocket.Connect ( *(aConnInfo.iAddr), connectStatus ); + User::WaitForRequest ( connectStatus ); // This is Ok to do... as in the esock server ( actually flow )will just store the + // connect address internally and not attempting to do an actual connect. As good as + // setopt but we need the socket to know that this is a connected socket. + User::LeaveIfError ( connectStatus.Int() ); + } + + if ( aConnInfo.iUri.Length() != 0 ) + { + // Do a setopt to inform the esock about our URI + User::LeaveIfError ( iSocket.SetOpt ( KCHAbsoluteUri, KCHOptionLevel, aConnInfo.iUri ) ); + } + + iReader = CControlChannelReader::NewL ( iSocket, aChannelType ); + iWriter = CControlChannelWriter::NewL ( iSocket, aChannelType ); + }