// Copyright (c) 2003-2009 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:
// Name : SdpConnectionField.cpp
// Part of : SDP Codec
// Version : 1.0
//
#include <in_sock.h>
#include <s32strm.h>
#include <stringpool.h>
#include "SdpConnectionField.h"
#include "sdpcodecstringconstants.h"
#include "SdpCodecConstants.h"
#include "SdpCodecStringPool.h"
#include "SdpUtil.h"
#include "SdpCodecErr.h"
#include "SDPCodec.pan"
#include "_sdpdefs.h"
#include "uriutils.h"
// LOCAL CONSTANTS
const TInt KHeaderIndex = 0;
const TInt KNetworkTypeIndex = 1;
const TInt KAddressTypeIndex = 2;
const TInt KAddressIndex = 3;
const TInt KTokenCount = 4;
const TInt KMaxAddressLength = 256;
const TUint KMaxIPDesLength = 39;
_LIT16(KWildAddr, "0.0.0.0");
_LIT16(KWildAddrIPv6, "::");
// ============================ MEMBER FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// CSdpConnectionField::CSdpConnectionField
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CSdpConnectionField::CSdpConnectionField() :
iTTL( KErrNotFound ),
iNumOfAddress( KDefaultNumOfAddress )
{
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSdpConnectionField::ConstructL(
const TDesC8& aText )
{
// aText should be in format
// c=<network type> <address type> <connection address>
iPool = SdpCodecStringPool::StringPoolL();
RArray<TPtrC8> array =
SdpUtil::GetElementsFromLineL( aText, KErrSdpCodecConnectionField );
CleanupClosePushL( array );
if ( array.Count() != KTokenCount )
{
User::Leave( KErrSdpCodecConnectionField );
}
RStringF origHeader = iPool.StringF( SdpCodecStringConstants::EConnection,
SdpCodecStringConstants::Table );
if ( origHeader.DesC().CompareF( array[KHeaderIndex] ) != 0 )
{
// Header didn't match
User::Leave( KErrSdpCodecConnectionField );
}
// <network type>
CopyNetTypeL( array[KNetworkTypeIndex] );
// <address type>
CopyAddressTypeL( array[KAddressTypeIndex] );
// <address>
CopyAddressL( array[KAddressIndex], iPool );
CleanupStack::PopAndDestroy(); // array
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSdpConnectionField::ConstructL(
const TInetAddr& aAddress,
TInt aTTL,
TUint aNumOfAddress )
{
__ASSERT_ALWAYS( IsValidAddress(aAddress, aTTL, aNumOfAddress) == KErrNone,
User::Leave( KErrSdpCodecConnectionField ) );
iPool = SdpCodecStringPool::StringPoolL();
TBuf<KMaxIPDesLength> addr;
//If aAddress is IPv4-Mapped IPv6,the result of Output is IPv4
aAddress.Output( addr );
// Copy address
iAddress = HBufC8::NewL( addr.Length() );
iAddress->Des().Copy( addr );
// TTL
iTTL = aTTL;
// Num of addresses
iNumOfAddress = aNumOfAddress;
// Network type
iNetType = iPool.StringF( SdpCodecStringConstants::ENetType,
SdpCodecStringConstants::Table ).Copy();
// Address type
if ( UriUtils::HostType( addr ) == UriUtils::EIPv4Host )
{
//addresstype for IPv4
iAddressType = iPool.StringF( SdpCodecStringConstants::EAddressTypeIP4,
SdpCodecStringConstants::Table ).Copy();
}
else if ( UriUtils::HostType( addr ) == UriUtils::EIPv6Host )
{
//addresstype IPv6
iAddressType = iPool.StringF( SdpCodecStringConstants::EAddressType,
SdpCodecStringConstants::Table ).Copy();
}
else
{
User::Leave(KErrArgument);
}
__TEST_INVARIANT;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSdpConnectionField::ConstructL(
RStringF aNetType,
RStringF aAddressType,
const TDesC8& aAddress )
{
iPool = SdpCodecStringPool::StringPoolL();
// Network type
CopyNetTypeL( aNetType.DesC() );
// Address type
CopyAddressTypeL( aAddressType.DesC() );
// Address + TTL + numOfAddress
CopyAddressL( aAddress, aNetType.Pool() );
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::DecodeL
// Two-phased constructor
// -----------------------------------------------------------------------------
//
EXPORT_C CSdpConnectionField* CSdpConnectionField::DecodeL(
const TDesC8& aText )
{
CSdpConnectionField* obj = CSdpConnectionField::DecodeLC( aText );
CleanupStack::Pop();
return obj;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::DecodeLC
// Two-phased constructor
// -----------------------------------------------------------------------------
//
EXPORT_C CSdpConnectionField* CSdpConnectionField::DecodeLC(
const TDesC8& aText )
{
CSdpConnectionField* obj = new ( ELeave ) CSdpConnectionField;
CleanupStack::PushL( obj );
obj->ConstructL( aText );
return obj;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::NewL
// Two-phased constructor
// -----------------------------------------------------------------------------
//
EXPORT_C CSdpConnectionField* CSdpConnectionField::NewL(
const TInetAddr& aAddress,
TInt aTTL,
TUint aNumOfAddress )
{
CSdpConnectionField* obj = CSdpConnectionField::NewLC(
aAddress, aTTL, aNumOfAddress );
CleanupStack::Pop();
return obj;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::NewLC
// Two-phased constructor
// -----------------------------------------------------------------------------
//
EXPORT_C CSdpConnectionField* CSdpConnectionField::NewLC(
const TInetAddr& aAddress,
TInt aTTL,
TUint aNumOfAddress )
{
CSdpConnectionField* obj = new ( ELeave ) CSdpConnectionField;
CleanupStack::PushL( obj );
obj->ConstructL( aAddress, aTTL, aNumOfAddress );
return obj;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::NewL
// Two-phased constructor
// -----------------------------------------------------------------------------
//
EXPORT_C CSdpConnectionField* CSdpConnectionField::NewL(
RStringF aNetType,
RStringF aAddressType,
const TDesC8& aAddress )
{
CSdpConnectionField* obj = CSdpConnectionField::NewLC(
aNetType, aAddressType, aAddress );
CleanupStack::Pop();
return obj;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::NewLC
// Two-phased constructor
// -----------------------------------------------------------------------------
//
EXPORT_C CSdpConnectionField* CSdpConnectionField::NewLC(
RStringF aNetType,
RStringF aAddressType,
const TDesC8& aAddress )
{
CSdpConnectionField* obj = new ( ELeave ) CSdpConnectionField;
CleanupStack::PushL( obj );
obj->ConstructL( aNetType, aAddressType, aAddress );
return obj;
}
// Destructor
EXPORT_C CSdpConnectionField::~CSdpConnectionField()
{
delete iAddress;
iNetType.Close();
iAddressType.Close();
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::EncodeL
// Writes attributes in proper format to the stream
// -----------------------------------------------------------------------------
//
EXPORT_C void CSdpConnectionField::EncodeL(
RWriteStream& aStream ) const
{
__TEST_INVARIANT;
TBuf8<20> number; // Is enough for addr as well
// c=<network type> <address type> <connection address>
RStringF header = iPool.StringF( SdpCodecStringConstants::EConnection,
SdpCodecStringConstants::Table );
aStream.WriteL( header.DesC() );
// Network type
aStream.WriteL( iNetType.DesC() );
aStream.WriteL( KSPStr );
// Address type
aStream.WriteL( iAddressType.DesC() );
aStream.WriteL( KSPStr );
// Connection address
aStream.WriteL( *iAddress );
if ( iTTL != KErrNotFound )
{
number.Zero();
number.Append( KSlashStr );
number.AppendFormat( _L8("%d"), iTTL );
aStream.WriteL( number );
}
if ( iNumOfAddress > 1 )
{
number.Zero();
number.Append( KSlashStr );
number.AppendFormat( _L8("%u"), iNumOfAddress );
aStream.WriteL( number );
}
// End-of-Line mark
aStream.WriteL( KCRLFStr );
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::CloneL
// Clones an exact copy of this object
// -----------------------------------------------------------------------------
//
EXPORT_C CSdpConnectionField* CSdpConnectionField::CloneL() const
{
__TEST_INVARIANT;
CSdpConnectionField* obj = NULL;
const TInetAddr* addr = InetAddress();
if ( addr )
{
// Could be anything
obj = CSdpConnectionField::NewL( *addr, iTTL, iNumOfAddress );
}
else
{
// Unicast FQDN address
obj = CSdpConnectionField::NewL( iNetType, iAddressType, *iAddress );
}
__ASSERT_DEBUG( *this == *obj, User::Panic(
KSdpCodecPanicCat, KSdpCodecPanicInternal));
return obj;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::operator==
// Checks if two origin fields are equal
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CSdpConnectionField::operator== (
const CSdpConnectionField& aObj ) const
{
__TEST_INVARIANT;
TBool equal( EFalse );
if ( (*iAddress).CompareF( aObj.Address() ) == 0 &&
NetType() == aObj.NetType() &&
AddressType() == aObj.AddressType() &&
TTLValue() == aObj.TTLValue() &&
NumOfAddress() == aObj.NumOfAddress() )
{
// All attributes match, two fields are equal
equal = ETrue;
}
return equal;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::NetType
// Returns network type
// -----------------------------------------------------------------------------
//
EXPORT_C RStringF CSdpConnectionField::NetType() const
{
__TEST_INVARIANT;
return iNetType;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::AddressType
// Returns address type
// -----------------------------------------------------------------------------
//
EXPORT_C RStringF CSdpConnectionField::AddressType() const
{
__TEST_INVARIANT;
return iAddressType;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::InetAddress
// Returns address in TInetAddr format if possible
// -----------------------------------------------------------------------------
//
EXPORT_C const TInetAddr* CSdpConnectionField::InetAddress() const
{
__TEST_INVARIANT;
TInetAddr* addr = NULL;
TBuf<KMaxAddressLength> addr16;
addr16.Copy( iAddress->Des() );
TInt err = iInetAddress.Input( addr16 );
if ( err == KErrNone )
{
addr = &iInetAddress;
}
return addr;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::Address
// Returns address in TDesC8 format
// -----------------------------------------------------------------------------
//
EXPORT_C const TDesC8& CSdpConnectionField::Address() const
{
return *iAddress;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::SetInetAddressL
// Sets address from TInetAddr
// -----------------------------------------------------------------------------
//
EXPORT_C void CSdpConnectionField::SetInetAddressL(
const TInetAddr& aAddress,
TInt aTTL,
TUint aNumOfAddress )
{
__TEST_INVARIANT;
if ( IsValidAddress( aAddress, aTTL, aNumOfAddress ) == KErrNone )
{
TBuf<KMaxAddressLength> addr16;
//If aAddress IPv4-Mapped IPv6, result of Output IPv4
aAddress.Output( addr16 );
HBufC8* tempBuf = HBufC8::NewL( addr16.Length() );
tempBuf->Des().Copy( addr16 );
SdpUtil::SetDefaultNetTypeAndAddrType(
iPool, aAddress, iNetType, iAddressType );
if(aAddress.Address() && aAddress.IsV4Mapped())
{
iAddressType.Close();
iAddressType = iPool.StringF( SdpCodecStringConstants::EAddressTypeIP4,
SdpCodecStringConstants::Table ).Copy();
}
// Set address
delete iAddress;
iAddress = tempBuf;
// Set attributes for address
iTTL = aTTL;
iNumOfAddress = aNumOfAddress;
}
else
{
User::Leave( KErrSdpCodecConnectionField );
}
__TEST_INVARIANT;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::SetAddressL
// Sets new address and types, leaves on error
// -----------------------------------------------------------------------------
//
EXPORT_C void CSdpConnectionField::SetAddressL(
RStringF aNetType,
RStringF aAddressType,
const TDesC8& aAddress )
{
__TEST_INVARIANT;
TInt err( KErrNone );
RStringF netTypeBackup = iNetType.Copy();
RStringF addressTypeBackup = iAddressType.Copy();
CleanupClosePushL( netTypeBackup );
CleanupClosePushL( addressTypeBackup );
TRAP( err, CopyNetTypeL( aNetType.DesC() ) );
if ( !err )
{
// Netowrk type changed successfully
TRAP( err, CopyAddressTypeL( aAddressType.DesC() ) );
if ( !err )
{
// Address type & network type changed successfully
TRAP( err, CopyAddressL( aAddress, iAddressType.Pool() ) );
if ( err )
{
// Place back old netType & address
iNetType.Close();
iNetType = netTypeBackup.Copy();
iAddressType.Close();
iAddressType = addressTypeBackup.Copy();
User::LeaveIfError( err );
}
// Everything changed succesfully
}
else
{
// Place back old netType
iNetType.Close();
iNetType = netTypeBackup.Copy();
User::LeaveIfError( err );
}
}
else
{
User::LeaveIfError( err );
}
CleanupStack::PopAndDestroy( 2 ); // netTypeBackup, addressTypeBackup
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::TTLValue
// Returns TTL attribute
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CSdpConnectionField::TTLValue() const
{
__TEST_INVARIANT;
return iTTL;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::SetTTLL
// Sets new TTL attribute value, leaves on error
// -----------------------------------------------------------------------------
//
EXPORT_C void CSdpConnectionField::SetTTLL(
TInt aTTL )
{
__TEST_INVARIANT;
const TInetAddr* addr = InetAddress();
// FQDN; Unicast, can be only KErrNotFound
// IP4 Multicast: 0 <= TTL <= 255
// IP4 Unicast, can be only KErrNotFound
// IP6 can be only KErrNotFound
if ( ( !addr && aTTL != KErrNotFound ) ||
( addr && addr->Address() && addr->IsMulticast() &&
( aTTL < 0 || aTTL > 255 ) ) ||
( addr && addr->Address() && !addr->IsMulticast() &&
aTTL != KErrNotFound ) ||
( addr && !addr->Address() && aTTL != KErrNotFound ) )
{
User::Leave( KErrSdpCodecConnectionField );
}
iTTL = aTTL;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::NumOfAddress
// Returns number of continuous addresses for multicast
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CSdpConnectionField::NumOfAddress() const
{
return iNumOfAddress;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::SetNumOfAddressL
// Sets number of addresses
// -----------------------------------------------------------------------------
//
EXPORT_C void CSdpConnectionField::SetNumOfAddressL(
TUint aNumOfAddress )
{
const TInetAddr* addr = InetAddress();
if ( aNumOfAddress < 1 || ( !addr && aNumOfAddress != 1 ) ||
( addr && !addr->IsMulticast() && aNumOfAddress != 1 ) )
{
User::Leave( KErrSdpCodecConnectionField );
}
iNumOfAddress = aNumOfAddress;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::ExternalizeL
// Externalizes the object to stream
// -----------------------------------------------------------------------------
//
void CSdpConnectionField::ExternalizeL(
RWriteStream& aStream ) const
{
__TEST_INVARIANT;
// Address
aStream.WriteUint32L( iAddress->Des().Length() );
aStream.WriteL( iAddress->Des(), iAddress->Des().Length() );
// TTL
aStream.WriteInt32L( iTTL );
// Number of addresses
aStream.WriteInt32L( iNumOfAddress );
// <network type>
aStream.WriteUint32L( iNetType.DesC().Length() );
aStream.WriteL( iNetType.DesC() );
// <address type>
aStream.WriteUint32L( iAddressType.DesC().Length() );
aStream.WriteL( iAddressType.DesC() );
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::InternalizeL
// Internalizes the object from stream
// -----------------------------------------------------------------------------
//
CSdpConnectionField* CSdpConnectionField::InternalizeL(
RReadStream& aStream )
{
TUint32 length;
CSdpConnectionField* obj = NULL;
RStringPool pool = SdpCodecStringPool::StringPoolL();
// address
length = aStream.ReadUint32L();
HBufC8* address = HBufC8::NewLC( length );
TPtr8 ptr( address->Des() );
aStream.ReadL( ptr, length );
// TTL
TInt ttl = aStream.ReadInt32L();
// Number of addresses
TInt numOfAddr = aStream.ReadInt32L();
// Network type
length = aStream.ReadUint32L();
HBufC8* netType = HBufC8::NewLC( length );
ptr.Set( netType->Des() );
aStream.ReadL( ptr, length );
// Address type
length = aStream.ReadUint32L();
HBufC8* addrType = HBufC8::NewLC( length );
ptr.Set( addrType->Des() );
aStream.ReadL( ptr, length );
TInetAddr addr;
HBufC* address16 = HBufC::NewLC( address->Length() ) ;
address16->Des().Copy( *address );
TInt err = addr.Input( *address16 );
if ( !err )
{
// Create connection field based on TInetAddr
obj = CSdpConnectionField::NewL( addr, ttl, numOfAddr );
}
else
{
// Create connection field from buffer, ttl & numOfAddr
// are in this case irrelevant
RStringF netTypeStr = pool.OpenFStringL( *netType );
CleanupClosePushL( netTypeStr );
RStringF addrTypeStr = pool.OpenFStringL( *addrType );
CleanupClosePushL( addrTypeStr );
obj = CSdpConnectionField::NewL( netTypeStr, addrTypeStr, *address );
CleanupStack::PopAndDestroy( 2 ); // netTypeStr, addrTypeStr
}
CleanupStack::PopAndDestroy( 4 ); // address, netType, addrType, address16
return obj;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::IsValidAddress
// Checks if the given address is valid
// -----------------------------------------------------------------------------
//
TInt CSdpConnectionField::IsValidAddress(
TBool aAddressTypeIP4,
const TDesC8& aAddress ) const
{
HBufC8* address = NULL;
TInt ttl( 0 );
TUint num( 0 );
TRAPD( err, address =
ParseAddressFieldL( aAddressTypeIP4, aAddress, ttl, num ) );
delete address;
return err;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::IsValidAddress
// Checks if the given address is valid
// -----------------------------------------------------------------------------
//
TInt CSdpConnectionField::IsValidAddress(
const TInetAddr& aAddress,
TInt aTTL,
TUint aNumOfAddress ) const
{
TInt err( KErrSdpCodecConnectionField );
// 0 <= TTL <= 255 or KErrNotFound if not defined
// Number of addresses > 0
if ( ( aTTL == KErrNotFound || ( aTTL >= 0 && aTTL <= 255 ) ) &&
aNumOfAddress > 0 )
{
TBuf16 <KMaxAddressLength> output;
aAddress.Output(output);
// Address has to be either of type IP4 or IP6
// If IP4 and multicast then it must contain TTL attribute
// If IP4 and unicast then it must NOT contain TTL and must have 1 address
// If IP6 and multicast then it must NOT contain TTL
// If IP6 and unicast then it must NOT contain TTL and must have 1 address
if ( ( aAddress.Address() &&
( ( aAddress.IsMulticast() && aTTL != KErrNotFound ) ||
( aAddress.IsUnicast() && aTTL == KErrNotFound &&
aNumOfAddress == 1 ) ) ) ||
( !aAddress.Address() &&
( ( aAddress.IsMulticast() && aTTL == KErrNotFound ) ||
( aAddress.IsUnicast() && aTTL == KErrNotFound &&
aNumOfAddress == 1 ) ) ||
( aAddress.IsWildAddr() &&
( output.Match(KWildAddr) == 0||
output.Match(KWildAddrIPv6) == 0 )) ) )
{
err = KErrNone;
}
}
return err;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::ParseAddressFieldL
// Format the address field
// -----------------------------------------------------------------------------
//
HBufC8* CSdpConnectionField::ParseAddressFieldL(
TBool aAddressTypeIP4,
const TDesC8& aAddress,
TInt& aTTL,
TUint& aNumberOfAddresses ) const
{
HBufC8* address = NULL;
if ( aAddress.Length() > 0 && aAddress.Length() <= KMaxAddressLength )
{
// IP4 address
TInetAddr addr;
TBuf<KMaxAddressLength> buf16;
// IP address lasts till first separator mark
TInt pos = aAddress.Locate( KSlashChar );
if ( pos == KErrNotFound )
{
pos = aAddress.Length();
}
buf16.Copy( aAddress.Left( pos ) );
// Try to convert the string to TInetAddr
TInt err = addr.Input( buf16 );
//Type and address check
TBuf16 <KMaxAddressLength> output;
addr.Output(output);
if (err == KErrNone)
{
if (addr.Address() )
{
if ( (addr.IsV4Mapped() && aAddressTypeIP4) ||
(!addr.IsV4Mapped() && !aAddressTypeIP4) )
{
User::Leave( KErrSdpCodecConnectionField );
}
else
{
// IP4 address
address = ParseIP4AddressL( pos, addr, aAddress, aTTL,
aNumberOfAddresses );
}
}
else
{
if ( !aAddressTypeIP4)
{
// IP6 address
address = ParseIP6AddressL( pos, addr, aAddress, aTTL,
aNumberOfAddresses );
}
else if ( addr.IsWildAddr() && output.Match(KWildAddr) == 0 )
{
// 0.0.0.0
address = ParseIP4AddressL( pos, addr, aAddress, aTTL,
aNumberOfAddresses );
}
else
{
User::Leave( KErrSdpCodecConnectionField );
}
}
}
else
{
// FQDN
// Clarify that the address contains only valid FQDN chars
// This is always unicast
for ( TInt i( 0 ); i < aAddress.Length(); i++ )
{
if ( KValidFQDNChars().Locate( aAddress[i] ) ==
KErrNotFound )
{
User::Leave( KErrSdpCodecConnectionField );
}
}
address = aAddress.AllocL();
aTTL = KErrNotFound;
aNumberOfAddresses = 1;
}
}
else
{
User::Leave( KErrSdpCodecConnectionField );
}
return address;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::ParseIP4AddressL
// Parses IP4 address and checks that it is valid
// -----------------------------------------------------------------------------
//
HBufC8* CSdpConnectionField::ParseIP4AddressL(
TInt aPos,
TInetAddr& aAddr,
const TDesC8& aAddress,
TInt& aTTL,
TUint& aNumberOfAddresses ) const
{
HBufC8* address = NULL;
if ( aAddr.IsMulticast() )
{
// Multicast address - MUST contain TTL and possibly
// number of addresses
if ( aPos != aAddress.Length() )
{
TInt pos2 = aAddress.Right( aAddress.Length() - aPos - 1 ).Locate(
KSlashChar );
if ( pos2 != KErrNotFound )
{
pos2 += aPos + 1;
// Validity check for number strings
TBool digit = SdpUtil::IsDigit(
aAddress.Mid( aPos + 1, pos2 - aPos - 1 ) );
digit = digit && SdpUtil::IsDigit(
aAddress.Mid( pos2 + 1, aAddress.Length() - pos2 - 1 ) );
if ( !digit )
{
User::Leave( KErrSdpCodecConnectionField );
}
// TTL & number of addresses
User::LeaveIfError(
TLex8( aAddress.Mid( aPos + 1, pos2 - aPos - 1 ) ).Val(
aTTL ) );
User::LeaveIfError(
TLex8( aAddress.Mid(
pos2 + 1, aAddress.Length() - pos2 - 1 ) ).Val(
aNumberOfAddresses, EDecimal ) );
__ASSERT_ALWAYS( aTTL >= 0
&& aTTL <= 255
&& aNumberOfAddresses > 0,
User::Leave( KErrSdpCodecConnectionField ) );
}
else
{
// Validity check for number strings
TBool digit = SdpUtil::IsDigit(
aAddress.Mid( aPos + 1, aAddress.Length() - aPos - 1 ) );
if ( !digit )
{
User::Leave( KErrSdpCodecConnectionField );
}
// Plain TTL
User::LeaveIfError(
TLex8( aAddress.Mid(
aPos + 1, aAddress.Length() - aPos - 1 ) ).Val(
aTTL ) );
aNumberOfAddresses = 1;
__ASSERT_ALWAYS( aTTL >= 0 && aTTL <= 255,
User::Leave( KErrSdpCodecConnectionField ) );
}
address = aAddress.Left( aPos ).AllocL();
}
else
{
User::Leave( KErrSdpCodecConnectionField );
}
}
else
{
// Unicast address - cannot contain any multicast TTLs etc.
if ( aPos == aAddress.Length() )
{
address = aAddress.AllocL();
aTTL = KErrNotFound;
aNumberOfAddresses = 1;
}
else
{
User::Leave( KErrSdpCodecConnectionField );
}
}
return address;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::ParseIP6AddressL
// Parses IP6 address and checks that it is valid
// -----------------------------------------------------------------------------
//
HBufC8* CSdpConnectionField::ParseIP6AddressL(
TInt aPos,
TInetAddr& aAddr,
const TDesC8& aAddress,
TInt& aTTL,
TUint& aNumberOfAddresses ) const
{
HBufC8* address = NULL;
if ( aAddr.IsMulticast() )
{
// Multicast address - CAN contain one extra attribute,
// number of addresses
if ( aPos != aAddress.Length() )
{
// Validity check for number strings
TBool digit = SdpUtil::IsDigit(
aAddress.Mid( aPos + 1, aAddress.Length() - aPos - 1 ) );
if ( !digit )
{
User::Leave( KErrSdpCodecConnectionField );
}
User::LeaveIfError( TLex8( aAddress.Mid(
aPos + 1, aAddress.Length() - aPos - 1 ) ).Val(
aNumberOfAddresses, EDecimal ) );
__ASSERT_ALWAYS( aNumberOfAddresses > 0,
User::Leave( KErrSdpCodecConnectionField ) );
}
else
{
aNumberOfAddresses = 1;
}
aTTL = KErrNotFound; // IP6 does not use TTL
address = aAddress.Left( aPos ).AllocL();
}
else
{
// Unicast address - cannot contain any multicast TTLs etc.
if ( aPos == aAddress.Length() )
{
address = aAddress.AllocL();
aTTL = KErrNotFound;
aNumberOfAddresses = 1;
}
else
{
User::Leave( KErrSdpCodecConnectionField );
}
}
return address;
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::CopyNetTypeL
// Copies network type to object after checking that it is valid
// -----------------------------------------------------------------------------
//
void CSdpConnectionField::CopyNetTypeL(
const TDesC8& aNetType )
{
if ( !SdpUtil::IsToken( aNetType ) )
{
User::Leave( KErrSdpCodecConnectionField );
}
else
{
RStringF netType = iPool.OpenFStringL( aNetType );
iNetType.Close();
iNetType = netType;
}
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::CopyAddressTypeL
// Copies address type after checking that it is valid
// -----------------------------------------------------------------------------
//
void CSdpConnectionField::CopyAddressTypeL(
const TDesC8& aAddrType )
{
if ( !SdpUtil::IsToken( aAddrType ) )
{
User::Leave( KErrSdpCodecConnectionField );
}
else
{
RStringF addrType = iPool.OpenFStringL( aAddrType );
iAddressType.Close();
iAddressType = addrType;
}
}
// -----------------------------------------------------------------------------
// CSdpConnectionField::CopyAddressL
// Copies address after checking that it is valid
// -----------------------------------------------------------------------------
//
void CSdpConnectionField::CopyAddressL(
const TDesC8& aAddress,
RStringPool aPool )
{
RStringF addrTypeIP4 = aPool.StringF(
SdpCodecStringConstants::EAddressTypeIP4,
SdpCodecStringConstants::Table );
RStringF addrTypeIP6 = aPool.StringF(
SdpCodecStringConstants::EAddressType,
SdpCodecStringConstants::Table );
HBufC8* addr = NULL;
if ( iAddressType == addrTypeIP4 || iAddressType == addrTypeIP6 )
{
User::LeaveIfError(
IsValidAddress( iAddressType == addrTypeIP4, aAddress ) );
addr = ParseAddressFieldL( iAddressType == addrTypeIP4, aAddress,
iTTL, iNumOfAddress );
//If address is IPv4-Mapped IPv6 , it is changed to IPv4
TInetAddr inetaddr;
TBuf<KMaxAddressLength> address;
address.Copy(*addr);
TInt err = inetaddr.Input(address);
TBuf16 <KMaxAddressLength> output;
inetaddr.Output(output);
if(!err &&
( ( inetaddr.Address() && inetaddr.IsV4Mapped() ) ||
( inetaddr.IsWildAddr() && output.Match(KWildAddr) != KErrNotFound )
) )
{//IPv4-Mapped IPv6 is changed to IPv4 address
TBuf<KMaxIPDesLength> buf;
inetaddr.Output( buf );
// Copy new address to safe
delete addr;
addr = NULL;
addr = HBufC8::NewL(buf.Length());
addr->Des().Copy(buf);
iAddressType.Close();
iAddressType =
iPool.StringF(SdpCodecStringConstants::EAddressTypeIP4,
SdpCodecStringConstants::Table ).Copy();
}
}
else
{
// Address not IP4 or IP6, must be then non-ws-string
if ( SdpUtil::IsNonWhitespace( aAddress ) )
{
addr = aAddress.AllocL();
}
else
{
User::Leave( KErrSdpCodecConnectionField );
}
}
delete iAddress;
iAddress = addr;
}
// For DEBUG builds
// -----------------------------------------------------------------------------
// CSdpConnectionField::__DbgTestInvariant
// Test invariant
// -----------------------------------------------------------------------------
//
void CSdpConnectionField::__DbgTestInvariant() const
{
TBool validAddr = EFalse;
RStringF addrTypeIP4 = iPool.StringF(
SdpCodecStringConstants::EAddressTypeIP4,
SdpCodecStringConstants::Table );
RStringF addrTypeIP6 = iPool.StringF(
SdpCodecStringConstants::EAddressType,
SdpCodecStringConstants::Table );
if ( iAddress &&
( iAddressType == addrTypeIP4 || iAddressType == addrTypeIP6 ) )
{
TInetAddr addr;
TBuf<KMaxAddressLength> buf16;
buf16.Copy( *iAddress );
TInt err = addr.Input( buf16 );
if ( !err )
{
validAddr = IsValidAddress(addr, iTTL, iNumOfAddress) == KErrNone;
}
else
{
// FQDN unicast
if ( iTTL == KErrNotFound && iNumOfAddress == 1 )
{
validAddr = ETrue;
}
}
}
TBool invariant = ( SdpUtil::IsToken( iNetType.DesC() ) &&
SdpUtil::IsToken( iAddressType.DesC() ) &&
iAddress && SdpUtil::IsNonWhitespace( *iAddress ) &&
validAddr );
if ( !invariant )
{
User::Invariant();
}
}