linklayerprotocols/pppnif/te_ppp/te_incoming_ppp/src/pppendpointimpl.cpp
author William Roberts <williamr@symbian.org>
Wed, 10 Nov 2010 13:36:07 +0000
branchRCL_3
changeset 79 4b172931a477
parent 0 af10295192d8
permissions -rw-r--r--
Make configchange.pl run ceddump.exe with -dtextshell - Bug 3932

// Copyright (c) 2004-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:
// Implementation of CPppEndpointImpl class
// 
//

/**
 @file 
 @internalComponent
*/



#include "pppendpointimpl.h"


#include <in_sock.h>
#include <ss_pman.h>

using namespace te_ppploopback; 

/**
 Constructs the receiver channel.
 
 @param aSocket The socket used by receiver.
 */
CRx::CRx(RSocket* aSocket) : CActive(CActive::EPriorityStandard),iRecvLen(MAX_MSG_LEN), iSocket(aSocket)
	{
	}

/**
 Static construction: Constructs the receiver channel.
 
 @param aSocket The socket used by receiver.
 */
CRx* CRx::NewL(RSocket* aSocket)
	{
	CRx* self = new (ELeave) CRx(aSocket);
	CleanupStack::PushL(self);
	CleanupStack::Pop();
	CActiveScheduler::Add(self);
	return self;
	}


/**
 Destroys the receiver channel.
 
 */
CRx::~CRx()
	{
	Cancel(); // cancel ANY outstanding request at time of destruction
	iObserver = NULL;
	iSocket = NULL;	
	}

/**
 Issues asynchronous read request.
 
 @post Request has been issued.
 */
void CRx::RxL()
	{

	// Issue read request
	iSocket->RecvFrom(iDataBuffer, iRecvAddr, 0, iStatus);
	SetActive();
	}

/**
 Sets the observer for the events on this channel.
 
 @param aObserver The observer.
 @post Observer is set.
 */
void CRx::SetObserver (MSocketObserver* aObserver)
	{
	iObserver = aObserver;
	}

/**
 Retrieves the data received on the channel.
 
 @return data buffer.
 @pre There was data reception notification
 */
HBufC16* CRx::GetDataIn(void)
	{
	return iDataBuffer16.Alloc();
	}

/**
 Retrieves the source address of the data received on the channel.
 
 @return source address
 @pre There was data reception notification
 */	
 TInetAddr CRx::GetSourceInetAddr(void)
 	{
 	return iRecvAddr;
 	}
 

/**
 Notify the channel observer that there was an event.
 
 @param aEvent the event
 @post Observer is Notified.
 */
void CRx::NotifyEvent (TInt aEvent)
	{
	iObserver->HandleSocketEvent(CPppEndpointImpl::ESourceRx, aEvent);
	}


/**
 Service an event on our channel
 Implementation of ActiveObject::RunL()
 
 @pre There was a request issued.
 @post event was serviced.
 */
void CRx::RunL(void)
	{
	if (iStatus==KErrNone) // received some data
		{
		// covert binary received to unicode
		TPtrC16 myPtr (reinterpret_cast<const TUint16*>(iDataBuffer.Ptr()), (iDataBuffer.Size()/2));
		iDataBuffer16 = myPtr;

		NotifyEvent(CRx::ERxReceiveOK);
		}
	else
		{
		// some error condition
		NotifyEvent(CRx::ERxReceiveFailed);
		}
	}
/**
 Cancels receive events.
 
 @post No more events come from this channel.
 */
void CRx::DoCancel (void)
	{
	iSocket->CancelRecv();
	}



/**
 Constructs the Transmitter channel.
 
 @param aSocket the channel's socket
 @param aPeerIpAddr the IP address of the communication peer
 @param aPeerPort UDP port of the peer.
 @post Channel is constructed.
 */
CTx::CTx(RSocket* aSocket, const TPtrC& aPeerIpAddr, TInt aPeerPort) 
	: CActive(CActive::EPriorityStandard),
	iSocket(aSocket)
	{
	iSendAddr.Input(aPeerIpAddr);
	iSendAddr.SetPort(aPeerPort);	
	}
/**
 Static Construction.

 @param aSocket     the channel's socket
 @param aPeerIpAddr the IP address of the communication peer
 @param aPeerPort    UDP port of the peer.
 @post Channel is constructed.
 */
CTx* CTx::NewL(RSocket* aSocket, const TPtrC& aPeerIpAddr, TInt aPeerPort)
	{
	CTx* self = new (ELeave) CTx(aSocket, aPeerIpAddr, aPeerPort);
	CleanupStack::PushL(self);
	CleanupStack::Pop();
	CActiveScheduler::Add(self);
	return self;
	}
	
/**
 Destruction

 @post Channel is destroyed
 */
CTx::~CTx()
	{
	Cancel(); // cancel ANY outstanding request at time of destruction
	iObserver = NULL;
	iSocket = NULL;
	}
/**
 Request to transmit a message, asynchronous.

 @param aData the data to send
 @post Request was issued.
 */
void CTx::TxL (TDesC16& aData)
	{
	if (!IsActive())
		{
		// Take a copy of the unicode data to be sent as binary.
		TPtrC8 myPtr (reinterpret_cast<const TUint8*>(aData.Ptr()), aData.Size());
		iDataBuffer = myPtr;

		iSocket->SendTo(iDataBuffer, iSendAddr, 0, iStatus);
		SetActive();
		}
	}
/**
 Sets the observer for this channel
 
 @param aObserver the channel's observer
 @post Observer is set.
 */
void CTx::SetObserver (MSocketObserver* aObserver)
	{
	iObserver = aObserver;
	}

/**
 Notify the observer about an event on the channel.

 @param aEvent the event
 @post Observer was notified.
 */
void CTx::NotifyEvent (TInt aEvent)
	{
	iObserver->HandleSocketEvent(CPppEndpointImpl::ESourceTx, aEvent);
	}

/**
 Service an event on the channel
 Implementation of ActiveObject::RunL()

 @post Event was serviced.
 */
void CTx::RunL(void)
	{
	if (iStatus==KErrNone) // transmit ok
		{
		NotifyEvent(CTx::ETxTransmitOK);
		}
	else
		{
		NotifyEvent(CTx::ETxTransmitFailed);
		}
	}

/**
 Cancels all outstanding send requests
 
 @post All requests were cancelled.
 */
void CTx::DoCancel (void)
	{
	iSocket->CancelSend();
	}
	
	
//******************************************************************************************
// PPP Endpoint implementation. 

/**
 Construction
  
 @param aIapId Iap Id for this endpoint
 @param aOwnIpAddr IP address to use with this endpoint
 @param aOwnPort  Port to used with this endpoint
 @param aPeerIpAddr the IP address of the communication peer 
 @param aPeerPort UDP port of the peer.
 @post Endpiont is constructed
 */
CPppEndpointImpl::CPppEndpointImpl(TInt aIapId, const TPtrC& aOwnIpAddr, TInt aOwnPort, const TPtrC& aPeerIpAddr, TInt aPeerPort):
	 CActive(CActive::EPriorityStandard),
	 iIapId(aIapId),
	 iOwnIpAddr(aOwnIpAddr),
	 iOwnPort(  aOwnPort),
	 iPeerIpAddr(aPeerIpAddr),	 
	 iPeerPort(  aPeerPort),
	 iPppLink(NULL)
	{
	}

/**
 Static Construction
 
 @param aIapId      Id for this endpoint
 @param aOwnIpAddr  IP address to use with this endpoint
 @param aOwnPort    Port to used with this endpoint
 @param aPeerIpAddr the IP address of the communication peer 
 @param aPeerPort   UDP port of the peer.
 @post Endpoint had been constructed
 */
CPppEndpointImpl* CPppEndpointImpl::NewL(TInt aIapId, const TPtrC& aOwnIpAddr, TInt aOwnPort, const TPtrC& aPeerIpAddr, TInt aPeerPort)
	{
	CPppEndpointImpl* self = new (ELeave) CPppEndpointImpl(aIapId, aOwnIpAddr, aOwnPort, aPeerIpAddr, aPeerPort);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop();
	CActiveScheduler::Add(self);
	return self;
	}

/**
 Second phase of construction
 Creates the simplex channels.

 @post Channels are constructed.
 */
void CPppEndpointImpl::ConstructL (void)
	{	
	iPppLink = new (ELeave) CPppLinkImpl(this, &iRConn); // PPP link
	
	iRxAO = CRx::NewL(&iSocket); // Receiver channel
	iRxAO->SetObserver(this);
	
	iTxAO = CTx::NewL(&iSocket, iPeerIpAddr, iPeerPort); // Transmitter channel	
	iTxAO->SetObserver(this);	
	}


/**
 Destruction
 Cancels all requests.

 @post Endpoint had been destroyed.
 */
CPppEndpointImpl::~CPppEndpointImpl()
	{
	// Cancel ANY outstanding request - including these requests owned by the channels
	Cancel();
	
	iListener = NULL;
	delete iRxAO;
	delete iTxAO;
	delete iPppLink;
	}
	
	
void CPppEndpointImpl::NotifyLinkUp(TInt aError)
	{
	iListener->OnEvent(iOurId, MPppEndpointListener::ELinkUp, aError);
	}
	
void CPppEndpointImpl::NotifyLinkDown(TInt aError)
	{
	iListener->OnEvent(iOurId, MPppEndpointListener::ELinkDown, aError);
	}




/**
 Handles an event on a channel

 @param aSource event source
 @param aReason event cause
 @post Event was handled.
 */
void CPppEndpointImpl::HandleSocketEvent (TInt aSource, TInt aReason)
	{
	// Translate and dispatch to our own listener.
	switch(aSource) // Determine who caused the event
		{
		case ESourceRx:
			if(aReason == CRx::ERxReceiveOK)
				{
				iListener->OnEvent(iOurId, MPppEndpointListener::ERecv, KErrNone);
				}
			else if(aReason == CRx::ERxReceiveFailed)
				{
				iListener->OnEvent(iOurId, MPppEndpointListener::ERecv, KErrGeneral);
				}
			else
				{
				ASSERT(EFalse);
				}
			break; 
		
		case ESourceTx :
			if(aReason == CTx::ETxTransmitOK)
				{
				iListener->OnEvent(iOurId, MPppEndpointListener::ESend, KErrNone);
				}
			else if(aReason == CTx::ETxTransmitFailed)
				{
				iListener->OnEvent(iOurId, MPppEndpointListener::ESend, KErrGeneral);
				}
			else
				{
				ASSERT(EFalse);
				}
			break;		
			
		
		default:
			ASSERT(EFalse); 
		}
	}


/**
 Requests a Connection to the PPP Peer asynchronously

 @post Request was issued.
 */
void CPppEndpointImpl::ConnectToPeerL()
	{	
	TInt err = KErrNone;;
	
	err = iSession.Connect(); // Connect to the socket server
	User::LeaveIfError(err);		
	
	err = iRConn.Open(iSession); 
	User::LeaveIfError(err);
	
	// Set connection preferences to use PPP
	iConnPref.SetIapId(iIapId);
	
	// NOTE: There is an issue with PhoneBook synchronizer as of March 3, 2004.
	// It may cause the tests to fail, if "ECommDbDialogPrefDoNotPrompt" is specified.
	// If this is the case, use "ECommDbDialogPrefPromptIfWrongMode" instead.
	iConnPref.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
	
	
	// Issue asynchronous request to initialize PPP. This returns immediately.
	iPppLink->OpenPppLinkL(&iConnPref);
	}
	

/**
 Disconnects from the peer.

 @post Disconnected from the peer.
 */
void CPppEndpointImpl::DisconnectFromPeerL()
	{
	iPppLink->ClosePppLinkL();
	iRConn.Close();
	iSession.Close();		
	}
	
TBool CPppEndpointImpl::IsConnectedToPeer()
	{
	return (iRConn.SubSessionHandle() != 0);
	}

/**
 Opens a communication channel for this endpoint.
 Does not affect PPP operation.
 Used for allow a complete separation of PPP connection / disconnection and data exchange.
 
 @pre Successfully connected to PPP Peer.
 @post Communication channel is open
 */
void CPppEndpointImpl::OpenCommChannelL()
	{	
	TInt err = iSocket.Open(iSession, KAfInet, KSockDatagram, KProtocolInetUdp, iRConn);
	User::LeaveIfError(err);

	// Bind the socket
	TInetAddr ownAddrOnPort;
	ownAddrOnPort.Input(iOwnIpAddr);
	ownAddrOnPort.SetPort(iOwnPort);	
	User::LeaveIfError(iSocket.Bind(ownAddrOnPort));	
	}
	
/**
 Closes the communication channel for this endpoint.
 Does not affect PPP operation.
 Used for allow a complete separation of PPP connection / disconnection and data exchange.
 
 @post Communication channel is closed
 */
void CPppEndpointImpl::CloseCommChannel()
	{
	iRxAO->Cancel();
	iTxAO->Cancel();	
	iSocket.CancelAll();
	iSocket.Close();
	} 	
	

/**
 Request to send a message on the channel, asynchronous

 @param aMsg The message
 @pre Communication channel opened successfully.
 @post The request was issued
 */
void CPppEndpointImpl::SendMessageL (TDesC& aMsg)
	{
	iTxAO->TxL(aMsg);
	}

/**
 Sets a listener for this PPP endpoint.
 
 @param aListener The listener
 @param aId the ID for this endpoint
 @post Listener was set.
 */
void CPppEndpointImpl::SetObserver (MPppEndpointListener* aListener, MPppEndpointListener::EEndpointId aId)
	{
	iListener = aListener;
	iOurId = aId;
	}

/**
 Request to receive a message on the channel, asynchronous
 
 @pre Communication channel opened successfully.
 @post The request was issued
 */
void CPppEndpointImpl::RequestMessageL (void)
	{
	iRxAO->RxL();
	}


/**
 Retrieves the data received on this channel.
 
 @return the data buffer
 @pre Communication channel opened successfully.
 */

HBufC16* CPppEndpointImpl::GetDataIn(void)
	{
	return iRxAO->GetDataIn();
	}
 
	
/**
 Retrieves the source address of the data received on this channel.
 
 @return the source address
 @pre Receive event notification was received. 
 */
TInetAddr CPppEndpointImpl::GetSourceInetAddr(void)	
	{
	return iRxAO->GetSourceInetAddr();
	}




/**
Retrieves the primary and secondary IPv4 DNS addresses of this endpoint

@param aDns1 Set to the primary DNS address on return, if any (should be cleared on entry)
@param aDns2 Set to the secondary DNS address on return, if any (should be cleared on entry)

@pre must be connected to peer (Because we may need to obtain our DNS address from peer.
*/
void CPppEndpointImpl::GetDnsAddrsL(TUint32& aDns1, TUint32& aDns2)
	{
	TPckgBuf<TSoInetInterfaceInfo> infoBuf;		// IPv4 stack only
	TSoInetInterfaceInfo info;					// IPv4 stack only
	
	// Open a socket to get the interfaces.
	RSocket sock;
	User::LeaveIfError(
		sock.Open(iSession, KAfInet, KSockStream, KProtocolInetTcp, iRConn));

	// Iterate through all interfaces, looking for DNS servers
	for (;;)
		{
		TInt retc = sock.GetOpt(KSoInetNextInterface,KSolInetIfCtrl,infoBuf);
		if (retc == KErrNotFound)
			break;
		else if (retc != KErrNone)
			{
			break;
			}
			
		info = infoBuf();
		TBool gotAddrs = EFalse;
		
		
		if (info.iState == EIfUp)
			{
			if (info.iNameSer1.Address())
				{
				aDns1 = info.iNameSer1.Address();
				gotAddrs = ETrue;
				}
			
			if (info.iNameSer2.Address() && (info.iNameSer2.Address() != info.iNameSer1.Address()))
				{
				aDns2 = info.iNameSer2.Address();
				gotAddrs = ETrue;
				}
			}

		if (gotAddrs)
			break;
		}
		
		sock.Close();
	}





// ActiveObject Implementation.

/**
 Called by ActiveObject::Cancel()
 
 @post communication channel was closed.
 */
void CPppEndpointImpl::DoCancel (void)
	{
	CloseCommChannel();	// cancels everything and closes the socket.
	iPppLink->Cancel();
	}
	

/**
 ActiveObject::RunL() 
 Never gets called in this implementation
 
*/	
void CPppEndpointImpl::RunL(void)
	{
	}