realtimenetprots/sipfw/SIP/ConnectionMgr/src/CIcmpV6Receiver.cpp
changeset 0 307788aac0a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/ConnectionMgr/src/CIcmpV6Receiver.cpp	Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,208 @@
+// Copyright (c) 2002-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          : CIcmpV6Receiver.cpp
+// Part of       : ConnectionMgr
+// Version       : SIP/4.0
+// Destination Unreachable Message:
+// 0                   1                   2                   3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// |     Type      |     Code      |          Checksum             |
+// |                             Unused                            |
+// |                    As much of invoking packet                 |
+// +                as will fit without the ICMPv6 packet          +
+// |                exceeding the minimum IPv6 MTU [IPv6]          |
+// IPv6 Header Format:
+// 0                   1                   2                   3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// |Version| Traffic Class |           Flow Label                  |
+// |         Payload Length        |  Next Header  |   Hop Limit   |
+// +                         Source Address                        +
+// +                      Destination Address                      +
+// Extension Header Format:
+// |  Next Header  |  Hdr Ext Len  |                               |
+// .             type-specific data (variable length)              .
+// User datagram:
+// 0      7 8     15 16    23 24    31
+// |     Source      |   Destination   |
+// |      Port       |      Port       |
+// |     Length      |    Checksum     |
+// |          data octets ...
+// In the code the data is located in 8-bit pieces.
+//
+
+
+
+
+#include <ip6_hdr.h>
+#include <icmp6_hdr.h>
+#include <udp_hdr.h>
+#include <ext_hdr.h>
+#include <in_sock.h>
+#include "CIcmpV6Receiver.h"
+#include "MIcmpReceiver.h"
+#include "CSipConnection.h"
+#include "CommonConsts.h"
+#include "SipLogs.h"
+
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::NewL
+// -----------------------------------------------------------------------------
+//
+CIcmpV6Receiver* CIcmpV6Receiver::NewL(MIcmpErrorObserver& aObserver,
+									   RSocketServ& aServer)
+	{
+	CIcmpV6Receiver* self = new (ELeave) CIcmpV6Receiver();
+	CleanupStack::PushL(self);
+	self->ConstructL(aObserver, aServer);
+	CleanupStack::Pop();
+	return self;
+	}
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::CIcmpV6Receiver
+// -----------------------------------------------------------------------------
+//
+CIcmpV6Receiver::CIcmpV6Receiver() : CActive( CActive::EPriorityStandard )
+	{
+	}
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CIcmpV6Receiver::ConstructL(MIcmpErrorObserver& aObserver,
+								 RSocketServ& aServer)
+	{
+	CActiveScheduler::Add(this);
+	iObserver = &aObserver;
+	iServer = &aServer;
+
+	// Start
+	User::LeaveIfError(iSocket.Open(*iServer, KAfInet, KSockDatagram,
+									KProtocolInet6Icmp));
+	Receive();
+	}
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::~CIcmpV6Receiver
+// -----------------------------------------------------------------------------
+//
+CIcmpV6Receiver::~CIcmpV6Receiver()
+	{
+	Cancel();
+	iSocket.Close();
+	}
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::RunL
+// -----------------------------------------------------------------------------
+//
+void CIcmpV6Receiver::RunL()
+	{
+	if(iStatus == KErrNone)
+		{
+		CheckError();
+		Receive();
+		}
+	}
+
+// Disabled PC-Lint warning for "Suspicious pointer-to-pointer conversion
+// (area too small))". It was caused by TUin8* to TInet6xxx typecasts and could
+// not be avoided otherwise.
+/*lint -e826 */
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::CheckError
+// -----------------------------------------------------------------------------
+//
+void CIcmpV6Receiver::CheckError()
+	{
+	const TUint KDestinationUnreachable = 1;
+	
+	// Pointer to ICMP header
+	TInet6HeaderICMP* icmpPtr = ( TInet6HeaderICMP* ) iData.Ptr();
+
+	// Pointer to IPv6 header
+	TInet6HeaderIP* ipv6Ptr = ( TInet6HeaderIP* )( iData.Ptr() + 8 );
+	// Get the whole length of the header in bytes
+	TUint32 payloadLength = ipv6Ptr->PayloadLength();
+	TUint32 offset = 0;
+
+	// Pointer to IPv6 extension header
+	TInet6HeaderExtension* extPtr =
+		( TInet6HeaderExtension* )( iData.Ptr() + 14 );
+	// Get the extension header length in bytes
+	TUint32 extHdrLength = extPtr->HeaderLength();
+
+	// Pointer to UDP data
+	TInet6HeaderUDP* udpPtr = ( TInet6HeaderUDP* )( ipv6Ptr->EndPtr() );
+				
+	// Error message type
+	TUint32 error = icmpPtr->Type();
+	if( error == KDestinationUnreachable )
+		{
+		TUint32 nextHeader = 0;
+		do  // Search the correct header, if there are extension headers
+			{
+			nextHeader = extPtr->NextHeader();
+			if( nextHeader == KProtocolInetUdp )
+				{
+				// Get the destination port number
+				iAddress.SetPort( udpPtr->DstPort() );
+
+				// Set the destination address
+				iAddress.SetAddress( ipv6Ptr->DstAddr() );
+
+			    __SIP_INT_LOG1( "ICMP error", error )
+                __SIP_ADDR_LOG( "ICMP error address", iAddress )
+
+				iObserver->IcmpError( iAddress );
+				}
+			else
+				{
+				// Step to next header
+				if( offset < payloadLength )
+					{
+					extPtr = extPtr + extHdrLength;
+					offset = offset + extHdrLength;
+					}
+				}
+			// Loop until UDP datagram is found. If it is not found,
+			// get out of here and do nothing.
+			} while ((nextHeader != KProtocolInetUdp) && (offset < payloadLength));
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::DoCancel
+// -----------------------------------------------------------------------------
+//
+void CIcmpV6Receiver::DoCancel()
+	{
+	iSocket.CancelRecv();
+	}
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::Receive
+// -----------------------------------------------------------------------------
+//
+void CIcmpV6Receiver::Receive()
+	{
+	if(!IsActive())
+		{
+		iSocket.Recv( iData, 0, iStatus );
+		SetActive();
+		}
+	}