diff -r 000000000000 -r f5a58ecadc66 upnp/upnpstack/dlnawebserver/src/upnptcpsessionwriter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/upnp/upnpstack/dlnawebserver/src/upnptcpsessionwriter.cpp Tue Feb 02 01:12:20 2010 +0200 @@ -0,0 +1,383 @@ +/** @file +* Copyright (c) 2005-2006 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: CUpnpTcpSessionWriter is a class responsible for +* asynchronous writing to a socket owned by CUpnpTcpSession. +* +*/ + + + +#include "upnptcpsession.h" +#include "upnptcpsessionwriter.h" +#define KLogFile _L("DLNAWebServer.txt") +#include "upnpcustomlog.h" + + +class CUpnpTcpWriteRequest : public CBase + { +public: + static CUpnpTcpWriteRequest* NewL( const TDesC8& aBuffer ) + { + CUpnpTcpWriteRequest* self = new (ELeave) CUpnpTcpWriteRequest(); + CleanupStack::PushL( self ); + self->ConstructL( aBuffer ); + CleanupStack::Pop(); + + return self; + } + +private: + CUpnpTcpWriteRequest() {} + void ConstructL( const TDesC8& aBuffer ) + { + iBuffer.CreateL( aBuffer ); + } + +public: + TDesC8& Buffer() + { + return iBuffer; + } + + ~CUpnpTcpWriteRequest() + { + iBuffer.Close(); + } + +private: + RBuf8 iBuffer; + }; + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionWriter::NewL +// Factory method. +// --------------------------------------------------------------------------- +// +CUpnpTcpSessionWriter* CUpnpTcpSessionWriter::NewL( CUpnpTcpSession& aSession, + RSocket& aSocket, + TThreadPriority aPriority ) + { + CUpnpTcpSessionWriter* self = new ( ELeave ) + CUpnpTcpSessionWriter( aSession, aSocket, aPriority ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionWriter::CUpnpTcpSessionWriter +// C++ constructor. +// --------------------------------------------------------------------------- +// +CUpnpTcpSessionWriter::CUpnpTcpSessionWriter( CUpnpTcpSession& aSession, + RSocket& aSocket, + TThreadPriority aPriority ) + :CActive( aPriority ), + iSocket( aSocket ), + iSession( aSession ), + iInitialPriority( aPriority ) + { + LOGS1( "%i, CUpnpTcpSessionWriter::CUpnpTcpSessionWriter", iSession.Id() ); + } + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionReader::TcpConstructL +// Two-phased constructor +// constructor that can leave. Used from derived classes. +// --------------------------------------------------------------------------- +// +void CUpnpTcpSessionWriter::ConstructL() + { + CActiveScheduler::Add( this ); + iState = ENotConnected; + iRetryWrite = CUpnpRetryWrite::NewL( iSession, iSocket, this, (TThreadPriority)Priority() ); + } + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionReader::~CUpnpTcpSessionReader +// Destructor. +// --------------------------------------------------------------------------- +// +CUpnpTcpSessionWriter::~CUpnpTcpSessionWriter() + { + LOGS1( "%i, CUpnpTcpSessionWriter::~CUpnpTcpSessionWriter", iSession.Id() ); + + Cancel(); + iState = EDisconnected; + + iWriteRequestList.ResetAndDestroy(); + iWriteRequestList.Close(); + + iSendBuffer.Close(); + + delete iRetryWrite; + } + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionWriter::IssueWriteL +// Issues writing request if session is connected and the socket is not +// already sending. If metioned conditions are not met then it queues the request. +// --------------------------------------------------------------------------- +// +void CUpnpTcpSessionWriter::IssueWriteL( const TDesC8& aBuffer ) + { + LOGS1( "%i, CUpnpTcpSessionWriter::IssueWriteL(TDesC8&)", iSession.Id() ); + + // Don't do anything because socket is already closed or we are writing already. + if( iState == EDisconnected || (iSession.DownloadOngoing() ) + || (iSession.ShuttingDown() && iState != ENotConnected) ) + return; + + // If session not connected yet or is already sending then queue the write request + if ( iState == ENotConnected || iState == EWriting ) + { + CUpnpTcpWriteRequest* req = CUpnpTcpWriteRequest::NewL( aBuffer ); + CleanupStack::PushL(req); + User::LeaveIfError(iWriteRequestList.Append( req )); + CleanupStack::Pop(); + + LOGS2( "%i, CUpnpTcpSessionWriter::IssueWriteL - queue size=%i," + , iSession.Id(), iWriteRequestList.Count() ); + return; + } + + LOGS2( "%i, CUpnpTcpSessionWriter::IssueWriteL queue size=%i" + , iSession.Id() , iWriteRequestList.Count() ); + + // If session already connected then just prepare sending buffer and request + // send from socket + + iSendBuffer.Close(); + iSendBuffer.CreateL( aBuffer ); + + /*if (Priority() == iInitialPriority) + SetPriority( iInitialPriority - 5); + else + SetPriority( iInitialPriority); */ + + Deque(); + CActiveScheduler::Add(this); + + iSocket.Write( iSendBuffer, iStatus ); + iState = EWriting; + + SetActive(); + } + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionWriter::SessionConnected +// Informs writer if session is connected. If it is then writer checks if there +// are queued write requests. If there are any then it issues writing. +// --------------------------------------------------------------------------- +// +void CUpnpTcpSessionWriter::SessionConnected( TBool aConnected ) + { + LOGS2( "%i, CUpnpTcpSessionWriter::SessionConnected(),aConnected %i" + , iSession.Id() , aConnected ); + if( aConnected && iState == ENotConnected ) + { + iState = EWaiting; + TRAP_IGNORE( SendNextWriteRequestL() ); + } + else if( !aConnected && iState != ENotConnected ) + { + Cancel(); + iState = EDisconnected; + } + } + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionWriter::HasWriteRequestsToSend +// Returns true if there are any write requests queued. +// --------------------------------------------------------------------------- +// +TBool CUpnpTcpSessionWriter::HasWriteRequestsToSend() + { + return ( iWriteRequestList.Count() > 0 ); + } + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionWriter::IsWriting +// Returns true if writer is writing data to the socket at the moment. +// --------------------------------------------------------------------------- +// +TBool CUpnpTcpSessionWriter::IsWriting() + { + return iState == EWriting; + } + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionWriter::DoCancel +// From class CActive +// Cancels issued writing request. +// --------------------------------------------------------------------------- +// +void CUpnpTcpSessionWriter::DoCancel() + { + LOGS1( "%i, CUpnpTcpSessionWriter::DoCancel", iSession.Id() ); + + // Cancel asychronous write request + iState = EWaiting; + } + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionWriter::RunL +// From class CActive +// Function called when issued writing is completed. Function checks if there +// are any write requests left to send and if there are then it issues writing. +// If queue is empty then function informs upper layer that writing is completed. +// --------------------------------------------------------------------------- +// +void CUpnpTcpSessionWriter::RunL() + { + LOGS2( "%i, CUpnpTcpSessionWriter::RunL(), iStatus %i", + iSession.Id() , iStatus.Int() ); + + // Active object request complete handler + if ( iStatus == KErrNone ) + { + switch( iState ) + { + // Character has been written to socket + case EWriting: + + if (Priority() == iInitialPriority) + SetPriority( iInitialPriority + 5); + else + SetPriority( iInitialPriority); + + // Change state because write request is finished already + iState = EWaiting; + if( HasWriteRequestsToSend() ) + SendNextWriteRequestL(); + else + iSession.WritingCompletedL(); + break; + + default: + LOGS2( "%i, PANIC: CUpnpTcpSessionWriter::RunL, %i", + iSession.Id() , iState ); + User::Panic( _L("Writer::RunL"), iState ); + break; + }; + } + else + { + if( iState == EWriting && (iStatus.Int() == KErrNoMemory || iStatus.Int() == KErrNotReady ) ) + { + iRetryWrite->IssueWriteRetry(); + } + else + { + + // Error: pass it up to session + iState = EWaiting; + iSession.HandleErrorL( iStatus.Int() ); + } + } + } +// ----------------------------------------------------------------------------- +// CUpnpTcpSessionWriter::RunError +// RunError is called when RunL leaves. +// ----------------------------------------------------------------------------- +// +TInt CUpnpTcpSessionWriter::RunError( TInt aError ) + { + LOGS2( "%i, CUpnpTcpSessionWriter::RunError %d" + , iSession.Id() , aError); + return KErrNone; + } + + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionWriter::SendNextWriteRequestL +// Function checks if there are any write requests left and if there are then +// issues writing and removes this request from queue. +// --------------------------------------------------------------------------- +// +void CUpnpTcpSessionWriter::SendNextWriteRequestL() + { + LOGS2( "%i, CUpnpTcpSessionWriter::SendNextWriteRequest(), iState %i", + iSession.Id() , iState ); + switch( iState ) + { + case EWaiting: + // Write queued request + if ( iWriteRequestList.Count() > 0 ) + { + CUpnpTcpWriteRequest* req = iWriteRequestList[0]; + if ( req ) + { + iWriteRequestList.Remove(0); + iWriteRequestList.Compress(); + CleanupStack::PushL( req ); + IssueWriteL( req->Buffer() ); + CleanupStack::PopAndDestroy( req ); + } + } + break; + + case ENotConnected: + case EDisconnected: + LOGS2( "%i, PANIC: CUpnpTcpSessionWriter::SendNextWriteRequest, %i", + iSession.Id() , iState ); + User::Panic( _L("SendNext::ENotConnected or EDisconnected"), iState ); + break; + } + } + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionWriter::RetryWriteFailL +// +// --------------------------------------------------------------------------- +// +void CUpnpTcpSessionWriter::RetryWriteFailL( TInt aError ) + { + // Error: pass it up to session + iSession.HandleErrorL( aError ); + iState = EWaiting; + } + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionWriter::RetryWriteSucceed +// +// --------------------------------------------------------------------------- +// +void CUpnpTcpSessionWriter::RetryWriteSucceed() + { + if ( iSendBuffer.Length() == 0 ) return; + + Deque(); + CActiveScheduler::Add(this); + + iSocket.Write( iSendBuffer, iStatus ); + iState = EWriting; + + SetActive(); + } + +// --------------------------------------------------------------------------- +// CUpnpTcpSessionWriter::IsRetrying +// +// --------------------------------------------------------------------------- +// +TBool CUpnpTcpSessionWriter::IsRetrying() + { + return (iRetryWrite->IsStarted()); + } + +// End of File