diff -r 000000000000 -r f5a58ecadc66 upnp/upnpstack/ssdpserver/src/upnpudpserver.cpp --- /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 +#include +#include + +#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 +// ----------------------------------------------------------------------------- +// +void CleanupArray( TAny* aArray ) + { + ( reinterpret_cast*>( 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( 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 address; + CUpnpHttpMessage::AddrOutput(addr, address); + + TBuf 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 values; + RPointerArray 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( 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 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 +