--- /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