servicediscoveryandcontrol/pnp/test/upnp/Client/upnpplugin/src/ccontrolchannel.cpp
changeset 0 f5a58ecadc66
--- /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 <es_sock.h>
+#include <e32const.h>
+#include <upnpconstants.h>
+
+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 );
+	}