plugins/consoles/vt100cons/src/tcp/vtc_tcp.cpp
changeset 0 7f656887cf89
child 30 35cb3fe43f60
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/consoles/vt100cons/src/tcp/vtc_tcp.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,440 @@
+// vtc_tcp.cpp
+// 
+// Copyright (c) 2007 - 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "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:
+// Accenture - Initial contribution
+//
+
+#include <e32std.h>
+#include <e32cons.h>
+#include <c32comm.h>
+#include <e32math.h>
+#include <es_sock.h>
+#include <in_sock.h>
+#include <commdbconnpref.h>
+#include <fshell/consoleextensions.h>
+#include <fshell/vtc_base.h>
+#include <fshell/vtc_controller.h>
+
+const TInt KUninitialized = -1;
+
+class TPortConfig
+	{
+public:
+	TPortConfig();
+public:
+	TName iHost;
+	TInt iPort;
+	TInt iIapId;
+	TInt iNetworkId;
+	TInt iProtocolId;
+	TInt iImplicit;
+	};
+
+TPortConfig::TPortConfig()
+	: iPort(8080), iIapId(KUninitialized), iNetworkId(KUninitialized), iProtocolId(KProtocolInetTcp), iImplicit(0)
+	{
+	}
+	
+NONSHARABLE_CLASS(CVtcTcpConsole) : public CVtcConsoleBase
+	{
+public:
+	CVtcTcpConsole();
+	~CVtcTcpConsole();
+private: // From CVtcSerialConsole.
+	virtual void ConstructL(const TDesC& aTitle);
+private: // From MConsoleOutput.
+	virtual TInt Output(const TDesC8& aDes);
+private: // From MConsoleInput.
+	virtual void Input(TDes8& aDes, TRequestStatus& aStatus);
+	virtual void CancelInput(TRequestStatus& aStatus);
+private:
+	TInt ConfigurePort(const TDesC& aConfig);
+	TInt ReadConfig(const TDesC& aConfigDes, TPortConfig& aConfig);
+	TInt Accept(const TPortConfig& aConfig);
+	TInt Connect(const TPortConfig& aConfig);
+	
+	TInt Query(TRequestStatus& stat, TRefByValue<const TDesC> aFmt, ...);
+	void CancelQuery();
+	void CleanupQuery();
+
+private:
+	RSocketServ iSocketServ;
+	RConnection iConnection;
+	RSocket iListeningSocket;
+	RSocket iClientSocket;
+	TSockXfrLength iSockXfrLength;
+	RNotifier iNotifier;
+	TInt iQueryResult;
+	};
+
+
+CVtcTcpConsole::CVtcTcpConsole()
+	{
+	}
+
+CVtcTcpConsole::~CVtcTcpConsole()
+	{
+	iNotifier.Close();
+	
+	iListeningSocket.Close();
+	iClientSocket.Close();
+	iConnection.Close();
+	iSocketServ.Close();
+	}
+
+class TOverflowTruncate : public TDes16Overflow
+	{
+public:
+	virtual void Overflow(TDes16&) {}
+	};
+	
+TInt CVtcTcpConsole::Query(TRequestStatus& stat, TRefByValue<const TDesC> aFmt, ...)
+	{
+	TOverflowTruncate overflow;
+	VA_LIST list;
+	VA_START(list, aFmt);
+	TBuf<0x100> buf;
+	buf.AppendFormatList(aFmt, list, &overflow);
+
+	if (iUnderlyingConsole)
+		{
+		Message(EInformation, buf);
+		// when using a console, the accept can be cancelled by hitting ctrl-c
+		return KErrNotSupported;
+		}
+	else
+		{
+		TInt err = KErrNone;
+		if (iNotifier.Handle() == KNullHandle)
+			{
+			err = iNotifier.Connect();
+			}
+		if (err == KErrNone)
+			{
+			iNotifier.Notify(_L("vt100tcpcons"), buf, _L("OK"), _L("Cancel"), iQueryResult, stat);
+			}
+		return err;
+		}
+	}
+	
+void CVtcTcpConsole::CancelQuery()
+	{
+	if (iNotifier.Handle())
+		{
+		iNotifier.NotifyCancel(); // Annoyingly this doesn't appear to be implemented, so we can't auto-dismiss the dialog.
+		iNotifier.Close();
+		}
+	}
+	
+void CVtcTcpConsole::ConstructL(const TDesC& aTitle)
+	{
+	User::LeaveIfError(ConfigurePort(aTitle));
+	CVtcConsoleBase::ConstructL(aTitle);
+	}
+
+TInt CVtcTcpConsole::ReadConfig(const TDesC& aConfigDes, TPortConfig& aConfig)
+	{
+	_LIT(KKeywordHost, "host");
+	_LIT(KKeywordPort, "port");
+	_LIT(KKeywordIapId, "iap");
+	_LIT(KKeywordNetworkId, "network");
+	_LIT(KKeywordProtocolId, "protocol");
+	_LIT(KKeywordDebug, "debug");
+	_LIT(KKeywordImplicit, "implicit");
+
+	TInt err = KErrNone;
+	TLex lex(aConfigDes);
+	while (!lex.Eos())
+		{
+		TPtrC keyword;
+		TPtrC valueDes;
+		err = ReadKeywordValuePair(lex, keyword, valueDes);
+		if (err != KErrNone)
+			{
+			break;
+			}
+
+		if (keyword == KKeywordHost)
+			{
+			aConfig.iHost = valueDes;
+			}
+		else
+			{
+			TInt valueInt;
+			TLex lex(valueDes);
+			err = lex.Val(valueInt);
+
+			if (keyword == KKeywordPort)
+				{
+				aConfig.iPort = valueInt;
+				}
+			else if (keyword == KKeywordIapId)
+				{
+				aConfig.iIapId = valueInt;
+				}
+			else if (keyword == KKeywordNetworkId)
+				{
+				aConfig.iNetworkId = valueInt;
+				}
+			else if (keyword == KKeywordProtocolId)
+				{
+				aConfig.iProtocolId = valueInt;
+				}
+			else if (keyword == KKeywordDebug)
+				{
+				SetDebug(valueInt);
+				}
+			else if (keyword == KKeywordImplicit)
+				{
+				aConfig.iImplicit = valueInt;
+				}
+			}
+		}
+
+	return err;
+	}
+
+TInt CVtcTcpConsole::ConfigurePort(const TDesC& aConfig)
+	{
+	TPortConfig portConfig;
+	TInt err = ReadConfig(aConfig, portConfig);
+	if (err == KErrNone)
+		{
+		err = iSocketServ.Connect();
+		}
+	if ((err == KErrNone) && !portConfig.iImplicit)
+		{
+		err = iConnection.Open(iSocketServ);
+		if (err == KErrNone)
+			{
+			Message(EDebug, _L("Starting connection..."));
+			TCommDbConnPref prefs;
+			if (portConfig.iIapId == KUninitialized)
+				{
+				prefs.SetDialogPreference(ECommDbDialogPrefPrompt);
+				}
+			else
+				{
+				prefs.SetIapId(portConfig.iIapId);
+				prefs.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
+				}
+			err = iConnection.Start(prefs);
+			if (err)
+				{
+				Message(EError, _L("Connection failed (%d)"), err);
+				}
+			}
+		}
+	if (err == KErrNone)
+		{
+		if (portConfig.iHost.Length() > 0)
+			{
+			err = Connect(portConfig);
+			}
+		else
+			{
+			err = Accept(portConfig);
+			}			
+		}
+
+	if (err == KErrNone)
+		{
+		iClientSocket.SetOpt(KSoTcpNoDelay, KSolInetTcp, ETrue);	// Ignore error (may not be supported).
+		Message(EDebug, _L("Connected."));
+		}
+
+	if (err != KErrNone)
+		{
+		iClientSocket.Close();
+		iListeningSocket.Close();
+		iConnection.Close();
+		iSocketServ.Close();
+		}
+
+	return err;
+	}
+	
+TInt CVtcTcpConsole::Connect(const TPortConfig& aConfig)
+	{
+	Message(EDebug, _L("Connecting to %S:%u"), &aConfig.iHost, aConfig.iPort);
+	TInetAddr addr(aConfig.iPort);
+	TInt err = addr.Input(aConfig.iHost);
+	if (err)
+		{
+		RHostResolver resolver;
+		if (aConfig.iImplicit)
+			{
+			err = (resolver.Open(iSocketServ, KAfInet, aConfig.iProtocolId));
+			}
+		else
+			{
+			err = (resolver.Open(iSocketServ, KAfInet, aConfig.iProtocolId, iConnection));
+			}
+		if (err == KErrNone)
+			{
+			TNameEntry nameEntry;
+			err = resolver.GetByName(aConfig.iHost, nameEntry);
+			if (err == KErrNone)
+				{
+				addr.SetAddress(TInetAddr::Cast(nameEntry().iAddr).Address());
+				}
+			resolver.Close();
+			}
+		}
+	if (err == KErrNone)
+		{
+		if (aConfig.iImplicit)
+			{
+			err = iClientSocket.Open(iSocketServ, KAfInet, KSockStream, aConfig.iProtocolId);
+			}
+		else
+			{
+			err = iClientSocket.Open(iSocketServ, KAfInet, KSockStream, aConfig.iProtocolId, iConnection);
+			}
+		}
+	if (err == KErrNone)
+		{
+		TRequestStatus status;
+		iClientSocket.Connect(addr, status);
+		User::WaitForRequest(status);
+		err = status.Int();
+		}
+	if (err != KErrNone)
+		{
+		Message(EError, _L("Connection to %S:%u failed (%d)"), &aConfig.iHost, aConfig.iPort, err);
+		}
+	return err;
+	}
+	
+TInt CVtcTcpConsole::Accept(const TPortConfig& aConfig)
+	{
+	TInt err = KErrNone;
+	Message(EDebug, _L("Opening listening socket..."));
+	if (aConfig.iImplicit)
+		{
+		err = iListeningSocket.Open(iSocketServ, KAfInet, KSockStream, aConfig.iProtocolId);
+		}
+	else
+		{
+		err = iListeningSocket.Open(iSocketServ, KAfInet, KSockStream, aConfig.iProtocolId, iConnection);
+		}
+	if (err == KErrNone)
+		{
+		TInetAddr addr(aConfig.iPort);
+		Message(EDebug, _L("Binding listening socket..."));
+		err = iListeningSocket.Bind(addr);
+		if (err)
+			{
+			Message(EError, _L("Bind failed (%d)"), err);
+			}
+		}
+	if (err == KErrNone)
+		{
+		err = iListeningSocket.Listen(1);
+		}
+	if (err == KErrNone)
+		{
+		err = iClientSocket.Open(iSocketServ);
+		}
+	if (err == KErrNone)
+		{
+		// Find our local IP address.
+		TInetAddr addr;
+		addr.SetAddress(KInetAddrAny);
+		TPckgBuf<TSoInetIfQuery> query;
+		query().iDstAddr = addr;
+		TInt err2 = iListeningSocket.GetOpt(KSoInetIfQueryByDstAddr, KSolInetIfQuery, query);
+		TInt qerr;
+		
+		TRequestStatus queryStatus;
+		if (err2 == KErrNone)
+			{
+			TBuf<128> addrName;
+			query().iSrcAddr.Output(addrName);
+			qerr = Query(queryStatus, _L("Listening on %S:%d..."), &addrName, aConfig.iPort);
+			}
+		else
+			{
+			qerr = Query(queryStatus, _L("Listening on port %d..."), aConfig.iPort);
+			}
+
+		// Start the accept.
+		TRequestStatus acceptStatus;
+		iListeningSocket.Accept(iClientSocket, acceptStatus);
+
+		if (qerr == KErrNone)
+			{
+			User::WaitForRequest(acceptStatus, queryStatus);
+			if (acceptStatus != KRequestPending)
+				{
+				CancelQuery();
+				User::WaitForRequest(queryStatus);
+				}
+			else
+				{
+				if (iQueryResult == 1)
+					{
+					if (acceptStatus == KRequestPending)
+						{
+						iListeningSocket.CancelAccept();
+						}
+					User::WaitForRequest(acceptStatus);
+					}
+				else
+					{
+					User::WaitForRequest(acceptStatus);
+					}
+				CancelQuery();
+				}
+			}
+		else
+			{
+			User::WaitForRequest(acceptStatus);
+			}
+
+		err = acceptStatus.Int();
+		if (err)
+			{
+			Message(EError, _L("Accept failed (%d)"), err);
+			}
+		else
+			{
+			TInetAddr remote;
+			iClientSocket.RemoteName(remote);
+			TBuf<128> addrName;
+			remote.Output(addrName);
+			Message(EInformation, _L("Remote %S connected."), &addrName);
+			}
+		}
+	return err;
+	}
+	
+TInt CVtcTcpConsole::Output(const TDesC8& aDes)
+	{
+	TRequestStatus status;
+	iClientSocket.Write(aDes, status);
+	User::WaitForRequest(status);
+	return status.Int();
+	}
+
+void CVtcTcpConsole::Input(TDes8& aDes, TRequestStatus& aStatus)
+	{
+	iClientSocket.RecvOneOrMore(aDes, 0, aStatus, iSockXfrLength);
+	}
+
+void CVtcTcpConsole::CancelInput(TRequestStatus&)
+	{
+	iClientSocket.CancelRead();
+	}
+
+EXPORT_C TAny* NewConsole()
+	{
+	return new CVtcTcpConsole;
+	}
+