upnp/upnpstack/ssdpserver/src/upnpudpserver.cpp
changeset 0 f5a58ecadc66
child 31 b51a6f4f15ba
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/upnp/upnpstack/ssdpserver/src/upnpudpserver.cpp	Tue Feb 02 01:12:20 2010 +0200
@@ -0,0 +1,936 @@
+/** @file
+* Copyright (c) 2005-2008 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:  CUpnpUdpServer
+*
+*/
+
+
+// INCLUDE FILES
+#include <in_iface.h>
+#include <e32math.h>
+#include <commdb.h>
+
+#include "upnpcons.h"
+#include "upnpudpsendrequest.h"
+#include "upnpudpserver.h"
+#define KLogFile _L("upnpudpserver.txt")
+#include "upnpcustomlog.h"
+#include "upnpstring.h"
+#include "upnplist.h"
+#include "upnpconnectionmanagerproxy.h"
+
+
+// CONSTANTS
+const TUint32 KUdpMessageSize = 2048;
+const TInt KTTLValue = 4;
+const TInt KMicrosecond = 1000000;
+const TInt KMXMaxValue = 120;
+const TInt KInetAddrPrefixMatchLen = 16;
+
+// ============================= LOCAL FUNCTIONS ===============================
+// -----------------------------------------------------------------------------
+// CleanupArray
+// Used by TCleanupItem to clean a RPointerArray<TPtrC>
+// -----------------------------------------------------------------------------
+//
+void CleanupArray( TAny* aArray )
+    {
+    ( reinterpret_cast<RPointerArray<TPtrC8>*>( aArray ) )->ResetAndDestroy();
+    }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::CUpnpUdpServer
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CUpnpUdpServer::CUpnpUdpServer( RSocketServ* aSocketServ,
+                        MUpnpUdpServerObserver* aObserver,
+                        TInt aListeningPort )
+    : CActive( EPriorityHigh ),
+      iMulticastFlags( 0 ),
+      iMessagePtr( NULL, 0,0 ),
+      iIsStarted( EFalse )
+    {
+    LOGS( "SSDP *** CUpnpUdpServer::CUpnpUdpServer");
+
+    CActiveScheduler::Add( this );
+    iSocketServ = aSocketServ;
+    iObserver = aObserver;
+    iServerPort = aListeningPort;
+
+    iRandomSeed = KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::UdpConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::UdpConstructL()
+    {
+    iSendMessage = NULL;
+
+    iPendingTimerMessages = new (ELeave) CArrayPtrSeg<CUpnpSsdpMessage>( 1 );
+
+    // Create local timer
+    User::LeaveIfError( iSendTimer.CreateLocal() );
+
+    iConnectionManagerProxy = CUpnpConnectionManagerProxy::NewL( *iSocketServ );
+    TInt error = iConnectionManagerProxy->EnsureStart();
+
+    if ( error )
+        {
+        LOGS1( "CUpnpTcpServer::ListenL *** Error in attaching RConnection: error: %d",
+            error );
+        // Nothing else to do but leave, connection is not possible and
+        // can't access network
+        User::LeaveIfError( error );
+        }
+
+    iActiveIap = iConnectionManagerProxy->ActiveIap();
+    iLocalInterfaceAddress = iConnectionManagerProxy->LocalAddress();
+
+    RefreshLocalAddressInfo();
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::~CUpnpUdpServer()
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CUpnpUdpServer::~CUpnpUdpServer()
+    {
+    LOGS( "SSDP *** CUpnpUdpServer::~CUpnpUdpServer");
+    Cancel();
+    Close();
+
+    iSendTimer.Close();
+
+    iSendRequestList.ResetAndDestroy();
+    iSendRequestList.Close();
+
+    delete iSendMessage;
+
+    delete iMessage;
+
+    if( iPendingTimerMessages )
+        {
+        // Go through the messages and cancel timers
+        for(TInt i=0; i< iPendingTimerMessages->Count(); i++)
+            {
+            CUpnpSsdpMessage* arrayMsg = iPendingTimerMessages->At( i );
+            if( arrayMsg )
+                {
+                // Cancel the timer in the message
+                arrayMsg->CancelMessageTimeout();
+                }
+            }
+        // Destroy the whole message array
+        iPendingTimerMessages->ResetAndDestroy();
+        delete iPendingTimerMessages;
+        iPendingTimerMessages = NULL;
+        }
+
+    // close network connection
+    delete iConnectionManagerProxy;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::JoinMulticastGroupL
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::JoinMulticastGroupL()
+    {
+    TIp6Mreq mreq;
+    // the ipv4 multicast address that should use
+    TInetAddr addr;
+    addr.SetAddress( KDefaultMulticastAddress );
+    addr.SetFamily( KAfInet );
+    addr.ConvertToV4Mapped();
+
+    mreq.iAddr = addr.Ip6Address();
+    mreq.iInterface = 0;
+    TPckgBuf< TIp6Mreq > opt( mreq );
+
+    LOGS( "SSDP CUpnpUdpServer::JoinMulticastGroupL" );
+    User::LeaveIfError( iSocket.SetOpt( KSoIp6JoinGroup, KSolInetIp, opt ) );
+
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::ApplyMulticastSocketSettingsL
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::ApplyMulticastSocketSettingsL()
+    {
+    LOGS( "SSDP CUpnpUdpServer::ApplyMulticastSocketSettingsL" );
+
+    User::LeaveIfError( iSocket.SetOpt( KSoIp6MulticastLoop, KProtocolInetIp, 0 ) );
+    User::LeaveIfError( iSocket.SetOpt( KSoReuseAddr, KProtocolInetIp, 1 ) );
+
+    JoinMulticastGroupL();
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::ApplyCommonSocketSettingsL
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::ApplyCommonSocketSettingsL()
+    {
+    LOGS( "SSDP CUpnpUdpServer::ApplyCommonSocketSettingsL Socket TTL" );
+
+    User::LeaveIfError( iSocket.SetOpt( KSoIpTTL, KSolInetIp, KTTLValue ) );
+    User::LeaveIfError( iSocket.SetOpt( KSoIp6MulticastHops, KSolInetIp,
+                                        KTTLValue ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::OpenL
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::OpenL( )
+    {
+    if ( !IsStarted() )
+        {
+        TRAPD( error, OpenSocketAndStartReceiveL() )
+        if ( error )
+            {
+            LOGS1( "SSDP CUpnpUdpServer::OpenL error: %d", error );
+            Close();
+            User::Leave( error );
+            }
+        else
+            {
+            iIsStarted = ETrue;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::OpenSocketAndStartReceiveL
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::OpenSocketAndStartReceiveL( )
+    {
+    LOGS( "SSDP CUpnpUdpServer::OpenSocketAndStartReceiveL");
+    TInt error = iSocket.Open( *iSocketServ, KAfInet,
+        KSockDatagram, KProtocolInetUdp, iConnectionManagerProxy->ConnectionL() );
+    User::LeaveIfError( error );
+
+    User::LeaveIfError( iSocket.SetLocalPort( iServerPort ) );
+    // for multicast start
+    if ( KDefaultMulticastPort == iServerPort )
+        {
+        ApplyMulticastSocketSettingsL();
+        }
+
+    ApplyCommonSocketSettingsL();
+
+    TInetAddr bindAddr;
+    error = iSocket.Bind( bindAddr ) ;
+    if( KErrNone != error && KErrAlreadyExists != error )
+        {
+        LOGS( "SSDP CUpnpUdpServer::OpenSocketAnd.. bind error: %d");
+        User::Leave( error );
+        }
+
+    ReceiveL();
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::IsStarted
+// -----------------------------------------------------------------------------
+//
+TBool CUpnpUdpServer::IsStarted()
+    {
+    return iIsStarted;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::SendL
+// Send a message.
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::SendL( TDesC8& aBuffer, TInetAddr& anAddr )
+    {
+    LOGS( "SSDP *** CUpnpUdpServer::SendL");
+
+    if ( !IsStarted() )
+        {
+        return;
+        }
+
+    if ( IsActive() && ( iState == ESendingTimer || iState == ESendDone ) )
+        {
+        CUpnpUdpSendRequest* req = CUpnpUdpSendRequest::NewL( aBuffer, anAddr );
+        CleanupStack::PushL( req );
+        iSendRequestList.AppendL( req );
+        CleanupStack::Pop( req );
+        }
+    else
+        {
+        Cancel();
+
+        delete iSendMessage;
+        iSendMessage = NULL;
+        iSendMessage = aBuffer.AllocL();
+
+        iSenderAddress = anAddr;
+        iSenderAddress.SetFamily( KAfInet );
+
+        iSenderAddress.ConvertToV4Mapped();
+
+        iSocket.SendTo( *iSendMessage,
+                        iSenderAddress,
+                        iMulticastFlags,
+                        iStatus );
+
+        iState = ESendingTimer; // in this state when RunL will be called after sending
+                                // message successfuly, the delay timer will start
+        SetActive();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::SendDoneL
+// Sending is done.
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::SendDoneL()
+    {
+    LOGS( "SSDP *** CUpnpUdpServer::SendDoneL");
+
+    delete iSendMessage;
+    iSendMessage = NULL;
+
+    if ( iSendRequestList.Count() > 0 )
+        {
+        CUpnpUdpSendRequest* request = iSendRequestList[0];
+        iSendRequestList.Remove(0);
+        iSendRequestList.Compress();
+        CleanupStack::PushL( request );
+        SendL( *(request->iBuffer), request->iAddr );
+        CleanupStack::PopAndDestroy( request );
+        }
+    else
+        {
+        ReceiveL();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::ReceiveL
+// Receive message.
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::ReceiveL()
+    {
+    LOGS( "SSDP *** CUpnpUdpServer::ReceiveL");
+
+    if ( !IsActive() )
+        {
+        // If iMessage is not yet created, do it now.
+        // This pointer will be used until SSDP server is closed down.
+        if ( !iMessage )
+            {
+            iMessage = HBufC8::NewL( KUdpMessageSize );
+            }
+
+        // Set data length to zero for the next RecvFrom
+        iMessage->Des().SetLength( 0 );
+
+        iMessagePtr.Set( (unsigned char*) iMessage->Ptr(), 0, KUdpMessageSize );
+
+        iClientAddr.SetPort( iServerPort );
+
+        iSocket.RecvFrom( iMessagePtr, iClientAddr, iMulticastFlags, iStatus );
+
+        SetActive();
+        iState = EReceiving;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::RunL
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::RunL()
+    {
+
+    if ( iStatus.Int() != KErrNone )
+        {
+        LOGS1( "SSDP *** CUpnpUdpServer::RunL - UDPServer error, error code: %d",
+            iStatus.Int() );
+
+        if ( iStatus.Int() != KErrCancel )
+            {
+            ReceiveL();
+            }
+        else
+            {
+            RestartOrContinueSendProcessingL();
+            }
+        }
+    else
+        {
+        switch ( iState )
+            {
+            case ESendingTimer:                                // Introduce delay between sending messages to prevent from
+                // Introduce delay between sending messages to prevent from
+                iSendTimer.Cancel();               
+                iSendTimer.After( iStatus, KSendingDelay ); // SSDP notification storm.
+                iState = ESendDone;
+                SetActive();
+                break;
+            case EReceiving:
+                {
+                TUint temp = iClientAddr.Address();
+
+                TUint port = iClientAddr.Port();
+
+                TInetAddr addr = TInetAddr( temp, port );
+
+                addr.SetFamily( KAfInet );
+#ifdef _DEBUG
+                TBuf8<KAddressLength> address;
+                CUpnpHttpMessage::AddrOutput(addr, address);
+
+                TBuf<KMaxName> logBuf;
+                    logBuf.Copy( address.Left( logBuf.MaxLength() ) );
+                LOGS1( "SSDP *** CUpnpUdpServer::RunL - Received buffer from: %S",
+                    &logBuf );
+#endif //_DEBUG
+
+                CUpnpSsdpMessage* msg = NULL;
+
+                TRAPD( err, msg = CUpnpSsdpMessage::NewL(
+                    (TDesC8&) iMessagePtr, addr ) );
+                if ( err )
+                    {
+                    delete msg;
+                    msg = NULL;
+                    LOGS( "SSDP *** CUpnpUdpServer::RunL - Ssdp message parse failed. Ingoring message.");
+                    RestartOrContinueProcessingL();
+                    return;
+                    }
+                CleanupStack::PushL(msg);
+                // check that given message is valid.
+                TInt error = ValidateSsdpMessageL( msg );
+                if( error == KErrNone )
+                    {
+
+                    // no error, message is put to receive queue, and it gets
+                    // handled when the timer expires.
+                    // KErrNone used for constant, because it always remains
+                    // the same.
+                    if( msg->IsSsdpMSearch() )
+                        {
+                        CleanupStack::Pop( msg );
+
+                        AddPendingTimerMessageL( msg );
+
+                        // no delete, message in array
+                        msg = NULL;
+                        }
+                    else
+                        {
+                        //checks wether the Source IP is in same network i.e. auto-IP(169.254.X.X) or non-auto-IP range
+
+                        TInetAddr autoIPAddr = TInetAddr( KDefaultAutoIPAddress,
+                                                          KDefaultMulticastPort );
+                        autoIPAddr.SetFamily( KAfInet );
+
+                        if ( iAutoIP && autoIPAddr.Match( addr, KInetAddrPrefixMatchLen ) )
+                            {
+                            LOGS( "SSDP *** MESSAGE_FROM_AUTO_VERIFIED_NETWORK");
+                            iObserver->UdpMessageReceivedL( msg );
+                            }
+                        else if ( !autoIPAddr.Match( addr, KInetAddrPrefixMatchLen ) )
+                            {
+                            LOGS( "SSDP *** MESSAGE_FROM_NON_AUTO_VERIFIED_NETWORK");
+                            iObserver->UdpMessageReceivedL( msg );
+                            }
+
+                        CleanupStack::PopAndDestroy(msg);
+                        }
+                    }
+                else
+                    {
+                    // message not valid, delete it.
+                    LOGS( "SSDP *** CUpnpUdpServer::RunL - Invalid SSDP message. Ingoring message.");
+                    CleanupStack::PopAndDestroy(msg);
+                    }
+
+                RestartOrContinueProcessingL();
+
+                }
+                break;
+            case ESending:
+                delete iSendMessage;
+                iSendMessage = NULL;
+                RestartOrContinueProcessingL();
+                break;
+
+            case ESendDone:
+                SendDoneL();
+                break;
+
+            default:
+                // message not valid, delete it.
+                LOGS( "SSDP *** CUpnpUdpServer::RunL - DEFAULT CASE, NOTHING TO DO!");
+                break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpSsdpServer::RunError
+// Active Object RunError called when RunL leaves.
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpUdpServer::RunError( TInt aError )
+    {
+LOGS1( "SSDP *** CUpnpUdpServer::RunError: %d", aError );
+    TRAP_IGNORE( RestartOrContinueProcessingL() );
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::DoCancel
+// Active object DoCancel cancels active request.
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::DoCancel()
+    {
+    iSocket.CancelAll();
+    iSendTimer.Cancel();    
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::CloseL
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::Close()
+    {
+    LOGS( "SSDP *** CUpnpUdpServer::Close");
+
+    if ( IsStarted() ) // socket can be not open correctly
+        {
+        Cancel();
+        // for multicast start
+        if(iServerPort == KDefaultMulticastPort)
+            {
+            TIp6Mreq mreq;
+
+            TInetAddr addr;
+            addr.SetAddress( KDefaultMulticastAddress );
+            addr.SetPort(KDefaultMulticastPort);
+            addr.SetFamily(KAfInet);
+            addr.ConvertToV4Mapped();
+            mreq.iAddr = addr.Ip6Address();
+
+            mreq.iInterface = 0;
+            TPckgBuf< TIp6Mreq > opt(mreq);
+            iSocket.SetOpt(KSoIp6LeaveGroup, KSolInetIp, opt);
+            }
+        // for multicast end.
+        }
+    iSocket.Close();
+    iIsStarted = EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::ValidateSsdpMessageL
+// Function validates SSDP messages. It checks that correct headers are
+// found etc.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CUpnpUdpServer::TSsdpValidity CUpnpUdpServer::ValidateSsdpMessageL( CUpnpSsdpMessage* aMsg )
+    {
+    CUpnpUdpServer::TSsdpValidity validity = CUpnpUdpServer::EMessageOk;
+
+    // Message is search message
+    if( aMsg->IsSsdpMSearch() )
+        {
+        // checking first line of message
+        CUpnpHttpHeaderList* list=aMsg->HeaderList();
+        CUpnpHttpHeader* header = list->First();
+        if( header )
+            {
+            if(!CompareLinesL(header->Name(),UpnpSSDP::KMethodMSearch()))
+                {
+                // First line of message not "M-SEARCH * HTTP/1.1".
+                // Invalid message.
+               validity = CUpnpUdpServer::EHeaderNotMSearch;
+                }
+            }
+        else
+            {
+            // no headers. Invalid message. no further handling.
+            validity = CUpnpUdpServer::EHeadersMissing;
+            return validity;
+            }
+
+        // no delete, owned by message.
+        header=NULL;
+        // no delete, owned by message.
+        list=NULL;
+
+        TDesC8& mxString = aMsg->GetHeaderValue( UpnpSSDP::KHdrMx() );
+
+        // if no MX header found, not valid message.
+        if( mxString != KNullDesC8() )
+            {
+            // try to parse value to TInt. If possible, then message is valid for MX check.
+            TInt mxValue = 0;
+            TInt errorInConversion = 0;
+            TLex8 lex( mxString );
+            errorInConversion = lex.Val(mxValue);
+            // check that there are no errors in conversion. If error in conversion,
+            // not valid SSDP MX header.
+            if( errorInConversion != KErrNone || lex.Remainder().Length() > 0)
+                {
+                validity = CUpnpUdpServer::EErrorInMxConversion;
+                }
+            else if( mxValue < 0 )
+                {
+                // check that MX value is positive. Negative value not valid.
+                validity = CUpnpUdpServer::EInvalidMXValue;
+                }
+
+            // Checking if MAN header is found.
+            TDesC8& manString = aMsg->GetHeaderValue( UpnpSSDP::KHdrMan() );
+            if( manString != KNullDesC8() )
+                {
+                // MAN header found. Checking that is has valid value.
+                if( manString != UpnpSSDP::KNotificationDiscover() )
+                    {
+                    // MAN header value not "ssdp:discover". Invalid header.
+                    validity = CUpnpUdpServer::EInvalidManHeader;
+                    }
+                }
+            else
+                {
+                // MAN header not found. Invalid message.
+                validity = CUpnpUdpServer::EInvalidManHeader;
+                }
+
+            // Check that ST header is found.
+            TDesC8& stString = aMsg->GetHeaderValue( UpnpSSDP::KHdrSt() );
+            if( stString == KNullDesC8() )
+                {
+                // no ST header found. invalid SSDP search.
+                validity = CUpnpUdpServer::EInvalidStHeader;
+                }
+
+            TDesC8& hostString = aMsg->GetHeaderValue( UpnpSSDP::KHdrHost() );
+            if( hostString != UpnpSSDP::KDefaultHost() )
+                {
+                // HOST header not "239.255.255.250:1900". Invalid message.
+                validity = CUpnpUdpServer::EInvalidHostHeader;
+                }
+            }
+        else
+            {
+            // no MX header.
+            validity = CUpnpUdpServer::EInvalidMXValue;
+            }
+        }
+
+
+    // Message is SSDP response
+    else if( aMsg->IsSsdpResponse() )
+        {
+        // if message is SSDP response, header should
+        // be "HTTP/1.1 200 OK".
+        CUpnpHttpHeaderList* list=aMsg->HeaderList();
+        CUpnpHttpHeader* header = list->First();
+        if( header )
+            {
+            if (!CompareLinesL(header->Name(),UpnpHTTP::KHTTPOk()))
+                {
+                // First line of message not "HTTP/1.1 200 OK".
+                // Invalid message.
+                LOGS( "SSDP *** CUpnpUdpServer::EBadSsdpResponse");
+                validity = CUpnpUdpServer::EBadSsdpResponse;
+                }
+            }
+        else
+            {
+            // no headers. Invalid message. no further handling.
+            LOGS( "SSDP *** CUpnpUdpServer::EHeadersMissing");
+            validity = CUpnpUdpServer::EHeadersMissing;
+            return validity;
+            }
+
+        // no delete, owned by message.
+        header=NULL;
+        // no delete, owned by message.
+        list=NULL;
+
+        TDesC8& cache = aMsg->GetHeaderValue( UpnpSSDP::KHdrCacheControl() );
+        if( cache != KNullDesC8() )
+            {
+            TPtrC8 cachePtr;
+            cachePtr.Set( cache );
+
+            TInt posOfMaxAge = cachePtr.FindC( UpnpSSDP::KSsdpMaxAge() );
+            TInt posOfEqual = cachePtr.FindC( UpnpString::KEqual() );
+            if (posOfMaxAge != KErrNotFound && posOfEqual!= KErrNotFound
+                                            && posOfMaxAge < posOfEqual)
+                {
+                cachePtr.Set( cachePtr.Right((cachePtr.Length()
+                    - UpnpString::KEqual().Length()) - posOfEqual) );
+                }
+
+            TInt cacheValue = 0;
+            TInt errorInConversion = 0;
+            TLex8 lex( cachePtr );
+            lex.SkipSpace();
+            errorInConversion = lex.Val(cacheValue);
+            // check that there are no errors in conversion.
+            // If error in conversion, not valid
+            // SSDP CACHE-CONTROL header.
+            if( errorInConversion < KErrNone )
+                {
+                LOGS( "SSDP *** CUpnpUdpServer::EInvalidCacheControlHeader");
+                validity = CUpnpUdpServer::EInvalidCacheControlHeader;
+                }
+            else if ( cacheValue < 0 )
+                {
+                // check that CACHE-CONTROL value is positive.
+                // Negative value not valid.
+                LOGS( "SSDP *** CUpnpUdpServer::EInvalidCacheControlHeader");
+                validity = CUpnpUdpServer::EInvalidCacheControlHeader;
+                }
+            }
+        else
+            {
+            // no CACHE-CONTROL header. Invalid message.
+            LOGS( "SSDP *** CUpnpUdpServer::EInvalidCacheControlHeader");
+            validity = CUpnpUdpServer::EInvalidCacheControlHeader;
+            }
+
+        }
+
+    return validity;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::CompareLines
+// Compare two line ignoring number of space between elements
+// -----------------------------------------------------------------------------
+//
+TBool CUpnpUdpServer::CompareLinesL(const TDesC8& aValue, const TDesC8& aPattern)
+    {
+    TBool result = EFalse;
+    TPtrC8 value(aValue);
+    TPtrC8 pattern(aPattern);
+    RPointerArray<TPtrC8> values;
+    RPointerArray<TPtrC8> patterns;
+    CleanupStack::PushL( TCleanupItem( CleanupArray, &values ) );
+    CleanupStack::PushL( TCleanupItem( CleanupArray, &patterns ) );
+
+    UpnpString::CutToPiecesL(value,UpnpString::KSpace()[0], values);
+    UpnpString::CutToPiecesL(pattern,UpnpString::KSpace()[0], patterns);
+
+    if (values.Count() == patterns.Count())
+        {
+        result = ETrue;
+        for (TInt i = 0; i < values.Count(); i++)
+            {
+            if (patterns[i]->Compare(*(values[i])) != 0)
+                {
+                result = EFalse;
+                break;
+                }
+            }
+        }
+
+    CleanupStack::PopAndDestroy( &patterns );
+    CleanupStack::PopAndDestroy( &values );
+    return result;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::RestartOrContinueSendProcessingL()
+// -----------------------------------------------------------------------------
+//
+TBool CUpnpUdpServer::RestartOrContinueSendProcessingL()
+    {
+    if ( iSendRequestList.Count() > 0 )
+        {
+        CUpnpUdpSendRequest* request = iSendRequestList[0];
+        CleanupStack::PushL( request );
+        iSendRequestList.Remove( 0 );
+        iSendRequestList.Compress();
+        SendL( *( request->iBuffer ), request->iAddr );
+        CleanupStack::PopAndDestroy( request );
+        return ETrue;
+        }
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::RestartOrContinueProcessing
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::RestartOrContinueProcessingL()
+    {
+    if ( !RestartOrContinueSendProcessingL() )
+        {
+        ReceiveL();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::MessageExpiredL
+// Function gets called when message's timer expires. This means that this
+// message should be sent.
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::MessageExpiredL( CUpnpHttpMessage* aMessage )
+    {
+    LOGS( "SSDP *** CUpnpUdpServer::MessageExpiredL" );
+
+    CUpnpSsdpMessage* msg = static_cast<CUpnpSsdpMessage*>( aMessage );
+
+    // going thru array and removing current message from it.
+    for ( TInt i = 0; i < iPendingTimerMessages->Count(); i++ )
+        {
+        CUpnpSsdpMessage* arrayMsg = iPendingTimerMessages->At( i );
+        if ( arrayMsg == msg )
+            {
+            // Remove message from array and compress array.
+            iPendingTimerMessages->Delete( i );
+            iPendingTimerMessages->Compress();
+            break;
+            }
+        }
+    // Prevents WLan lost MessageHandler panic 
+    // don't remove because if this function leaves msg is destroyed. 
+    // Msg has CActive responsible for RunError as member so it will be destroyed and therefore
+    // CActiveSheduler will cause unhandled exception which is seen as messagehandler panic
+    TRAP_IGNORE( iObserver->UdpMessageReceivedL( msg ) );
+    delete msg; 
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::AddressChangedL()
+// Function gets called when the IP address of server is changed
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpUdpServer::AddressChangedL( TInetAddr& aAddr )
+    {
+    Close();
+    iLocalInterfaceAddress = aAddr;
+    RefreshLocalAddressInfo();
+    OpenL();
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::UpdateLocalAddressInfoL()
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::RefreshLocalAddressInfo()
+    {
+#ifdef _DEBUG
+    TBuf<KAddressLength> buf;
+    iLocalInterfaceAddress.Output( buf );
+    LOGS1( "SSDP AddressChangedL IP: %S", &buf );
+#endif //_DEBUG
+
+    TInetAddr addr = TInetAddr( KDefaultAutoIPAddress, KDefaultMulticastPort );
+    addr.SetFamily( KAfInet );
+
+    if ( iLocalInterfaceAddress.Match( addr, KInetAddrPrefixMatchLen ) )
+        {
+        iAutoIP = ETrue;
+        LOGS( "SSDP AddressChangedL AUTO_IP" );
+        }
+    else
+        {
+        iAutoIP = EFalse;
+        LOGS( "SSDP AddressChangedL NO_AUTO_IP" );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::CalculateMxValue()
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpUdpServer::CalculateMxValue( const TDesC8& aMxString )
+    {
+    TReal rand = Math::FRand( iRandomSeed );
+
+    TLex8 lex( aMxString );
+    TInt mxValue( 0 );
+
+    TInt lexError = lex.Val( mxValue );
+    if (( lexError != KErrNone ) || ( mxValue > KMXMaxValue )) // if delay in responsing more than 120 sec then it should be decreased until 120 sec
+        {
+        mxValue = KMXMaxValue;
+        }
+
+    // divide by two to ensure that the responses
+    // come before the time expires
+    TReal mx = rand * KMicrosecond * mxValue / 2;
+    return mx;
+    }
+
+// -----------------------------------------------------------------------------
+// CUpnpUdpServer::AddPendingTimerMessageL()
+// -----------------------------------------------------------------------------
+//
+void CUpnpUdpServer::AddPendingTimerMessageL( CUpnpSsdpMessage* aMessage )
+    {
+    // only 20 messages allowed from one IP
+    const TInt KMaxMessageNumberFromOneIP = 20;
+    
+    TInt cnt = 0;
+    for ( TInt i = 0; i < iPendingTimerMessages->Count(); i++ )
+        {
+        CUpnpSsdpMessage* msg = iPendingTimerMessages->At( i );
+        if ( msg->Sender().Address() == aMessage->Sender().Address() )
+            {
+            if ( ++cnt > KMaxMessageNumberFromOneIP )
+                {
+                delete aMessage;
+                return;
+                }
+            }
+        }
+
+    CleanupStack::PushL( aMessage );
+
+    // parsing value for wait timer
+    TInt mxUse = CalculateMxValue(
+                        aMessage->GetHeaderValue( UpnpSSDP::KHdrMx() ) );
+
+    // set message timeout so when timout occurs, message
+    // get's handled.
+    aMessage->SetMessageTimeoutL( this, mxUse );
+
+    // appending message to array
+    iPendingTimerMessages->AppendL( aMessage );
+
+    CleanupStack::Pop( aMessage );
+    }
+
+//  End of File
+