upnp/upnpstack/dlnawebserver/src/upnptcpsessionwriter.cpp
changeset 0 f5a58ecadc66
--- /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