applayerprotocols/telnetengine/SRC/TELRESOL.CPP
changeset 0 b16258d2340f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerprotocols/telnetengine/SRC/TELRESOL.CPP	Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,344 @@
+// 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:
+// Telnet Protocol API
+// CTelnetResolver implementation
+// 
+//
+
+/**
+ @file 
+*/
+
+
+#include "TELRESOL.H"
+#include "IOBUFFER.H"
+#include "TELCTRL.H"
+#include "ACTIVEIO.H"
+#include "TELDEBUG.H"
+
+
+CTelnetResolver::CTelnetResolver() : CActive(EPriorityStandard)
+/**
+Constructor
+*/
+    {
+    CActiveScheduler::Add(this);
+    }
+
+CTelnetResolver::~CTelnetResolver()
+/**
+Destructor
+*/
+    {
+	__FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetResolver::D'Tor"));
+	iSocket.Close();
+	iResolver.Close();
+    iSocketServ.Close();
+	Cancel();
+    }
+
+CTelnetResolver* CTelnetResolver::NewL(MTelnetResolver* aNotifier)
+    {
+    CTelnetResolver* self = new(ELeave) CTelnetResolver;
+    CleanupStack::PushL(self);
+    self->ConstructL(aNotifier);
+    CleanupStack::Pop();
+    return self;
+    }
+
+void CTelnetResolver::ConstructL(MTelnetResolver* aNotifier)
+    {
+    iState = EDisconnected;
+	iEvent = ENone;
+
+    User::LeaveIfError(iSocketServ.Connect());
+
+    iNotify = aNotifier;
+    }
+
+void CTelnetResolver::TriggerActive(const TEvent aEvent)
+/**
+Helper method that triggers our active object RunL() and sets the cause
+iEvent member which is interrogated in RunL() in the appropriate state
+Currently NOT called from RunL() it'self
+*/
+	{
+	iEvent = aEvent;
+	SetActive();
+	TRequestStatus *pS=&iStatus;
+	User::RequestComplete(pS,KErrNone);
+	}
+
+TInt CTelnetResolver::IssueConnect(const TDesC& aServerName, TUint aPort)
+/**
+Called as a result of an API Connect.
+Needs to use name resolution
+*/
+
+	{
+	// Check for valid state
+	if(iState != EDisconnected)
+		return(KErrInUse);
+	// Set member variable for the host name and the port
+    TInt err;
+	if((err = iResolver.Open(iSocketServ, KAfInet, KProtocolInetTcp)) != KErrNone)
+		return(err);
+	
+	// Copy host name and port into our object
+	iHostAddr.SetPort(aPort);
+	iServerName = aServerName;
+	// Make the async call to the resolver
+	iResolver.GetByName(iServerName,iNameEntry,iStatus);
+	// EDisconnected is the top of the state machine so set the state for Event() completion
+	iState = ELookingUp;
+	
+	SetActive();
+	return(KErrNone);
+	}
+
+TInt CTelnetResolver::IssueConnect(const TInetAddr& aInetAddr, TUint aPort)
+/**
+Called as a result of an API Connect.
+IP address supplied
+*/
+	{
+	if(iState != EDisconnected)
+		return(KErrInUse);
+
+	// copy IP and port to our object
+	iHostAddr.SetPort(aPort);
+	if (aInetAddr.Family() == KAfInet)
+		iHostAddr.SetAddress(aInetAddr.Address());
+	else
+		iHostAddr.SetAddress(aInetAddr.Ip6Address());
+
+	// Synchronous Open followed by Asynchronous Connect
+	TInt err;
+	if((err = iSocket.Open(iSocketServ, KAfInet, KSockStream, KProtocolInetTcp)) == KErrNone)
+		{
+		iSocket.Connect(iHostAddr, iStatus);
+		// EDisconnected is top of the state machine so set the state for Event() completion
+		iState = EConnecting;
+		SetActive();
+		}
+	else
+		{
+		return(err);
+		}
+
+	return(KErrNone);
+	}
+
+TInt CTelnetResolver::IssueDisconnect()
+/**
+Called as a result of API Disconnect
+*/
+	{
+	TInt ret;
+	if(iState == EConnected)
+		{
+		// Requires action in the state machine so trigger RunL with the appropriate event
+		// providing the we are connected.
+		TriggerActive(EDoDisconnect);
+		ret = KErrNone;
+		}
+	else if(iState == ELookingUp)
+		{
+		// Still looking up, cancel and reset states
+		iResolver.Cancel();
+		iResolver.Close();
+		iState = EDisconnected;
+		iEvent = ENone;
+		ret = KErrServerBusy;
+		__FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetResolver::IssueDisconnect() Cancel ELookingUp"));
+		}
+	else if(iState == EConnecting)
+		{
+		// Opening the socket, cancel and reset states
+		iState = EDisconnected;
+		iEvent = ENone;
+		iSocket.Close();
+		ret = KErrServerBusy;
+		__FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetResolver::IssueDisconnect() Cancel EConnecting"));
+		}
+	else
+		// Already Disconnecting
+		ret = KErrDisconnected;
+
+	return(ret);
+	}
+
+void CTelnetResolver::HandleEof()
+/**
+Called from FSM when it reads Eof
+*/
+	{
+	// Requires action in the state machine so trigger RunL with the appropriate event
+	TriggerActive(EEofDetected);
+	}
+
+
+void CTelnetResolver::DoCancel()
+    {
+    }
+
+void CTelnetResolver::RunL()
+    {
+	// ONLY called from here
+	Event();
+    }
+
+void CTelnetResolver::Event()
+/**
+State machine for the Telnet Resolver class.
+Called ONLY from CTelnetResolver::RunL()
+Main switch on the current state with checks for iEvent and/or iStatus depending on the state.
+EDisconnected state is not in the machine as iState is ALWAYS set to ELookingUp or EConnecting
+as a result of a client app connect request.
+TODO Need to implement client app EDoDisconnect event in the EConnecting and ELookingUp states 
+*/
+	{
+	// Switch on the state. Only certain events are legal in certain states
+	switch(iState)
+		{
+	case	ELookingUp	:		
+		__FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetResolver::Event() ELookingUp"));
+		// COMPLETION from host lookup (transitory state)
+		// Finished with the resolver
+		iResolver.Close();		
+		// Completion of GetByName()
+		if(iStatus == KErrNone)
+			{
+			// Get the first IP address from the list returned and copy it to our object
+			iNameRecord = iNameEntry();
+			if (TInetAddr::Cast(iNameRecord.iAddr).Family() == KAfInet)
+				iHostAddr.SetAddress(TInetAddr::Cast(iNameRecord.iAddr).Address());
+			else
+				iHostAddr.SetAddress(TInetAddr::Cast(iNameRecord.iAddr).Ip6Address());
+
+			// Get a socket and make async connection call
+			if(iSocket.Open(iSocketServ, KAfInet, KSockStream, KProtocolInetTcp) == KErrNone)
+				{
+				iSocket.Connect(iHostAddr, iStatus);
+				iState = EConnecting;
+				SetActive();
+				}				
+			else
+				{
+				// ERROR
+				__FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetResolver::Event() ELookingUp ERROR 1"));
+				iState = EDisconnected;
+				iEvent = ENone;
+				iNotify->ResolverDisconnected();
+				}
+			}
+		else
+			{
+			__FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetResolver::Event() ELookingUp ERROR 2"));
+			iState = EDisconnected;
+			iEvent = ENone;
+			iNotify->ResolverDisconnected();
+			}
+		break;
+								
+	case	EConnecting	:
+		__FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetResolver::Event() EConnecting"));
+		// COMPLETION from Connect (Transitory state)
+		// TODO :- check iEvent for client EDoDisconnect
+		// Just check the iStatus, the event code is not relevant
+		if(iStatus == KErrNone)
+			{
+			// set the state and notify client we have connected
+			iState = EConnected;
+			TRAPD(err, iNotify->ResolverConnectedL());
+			if(err!=KErrNone)
+				{
+				__FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetResolver::Event() EConnecting, ResolverConnectedL left with error = %d"),err);	
+				iState = EDisconnected;
+				iEvent = ENone;
+				iSocket.Close();
+				iNotify->ResolverDisconnected();
+				break;
+				}
+			}
+		else
+			{
+			// ERROR
+			__FLOG_STATIC1(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetResolver::Event() EConnecting ERROR = %d"),iStatus.Int());
+			iState = EDisconnected;
+			iEvent = ENone;
+			iSocket.Close();
+			iNotify->ResolverDisconnected();
+			}
+		break;
+				
+	case	EConnected	:
+		// ONLY NON transitory state
+		// from the client app
+		if(iEvent == EEofDetected)
+			{
+			// EOF from the line as a result of a Read (TCP connection being closed by remote end)
+			// Reset the state, close the socket and notify the client app
+			iState = EDisconnected;
+			iEvent = ENone;
+			iSocket.Close();
+			iNotify->ResolverDisconnected();
+			}
+		else if(iEvent == EDoDisconnect)
+			{
+			// Client requested Disconnect
+			// Shutdown output (Sends TCP FIN) , set the state
+			// Asynchronous call
+			iEvent = ENone;
+			iSocket.Shutdown(RSocket::EStopOutput,iStatus);
+			iState = EShuttingDown;
+			SetActive();
+			}
+		else
+			{
+			// ERROR
+			// BUG only transition here is on the above 2 events
+			__FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CTelnetResolver::Event() EConnected ERROR"));
+
+			}
+
+		break;
+
+	case	EShuttingDown	:
+		if(iStatus != KErrNone)
+			{
+			}
+		iState = EDisconnecting;
+		break;
+
+	case	EDisconnecting	:
+		// COMPLETION from client DoDisconnect shuddown()
+		// EOF from the line is all we can expect here
+		if(iEvent == EEofDetected)
+			{
+			iState = EDisconnected;
+			iEvent = ENone;
+			iSocket.Close();
+			iNotify->ResolverDisconnected();
+			}
+		else
+			{
+			}
+		break;
+		
+	default	:
+		// ERROR
+		break;
+		}
+	}