plugins/consoles/rcons/client/src/remote_console.cpp
changeset 0 7f656887cf89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/consoles/rcons/client/src/remote_console.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,482 @@
+// remote_console.cpp
+// 
+// Copyright (c) 2005 - 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 <e32uid.h>
+#include <in_sock.h>
+#ifdef USE_RCONNECTION
+#include <es_enum.h>
+#include <commdbconnpref.h>
+#endif
+#include <fshell/consoleextensions.h>
+#include "remote_console.h"
+
+const TInt KMajorVersion = 1;
+const TInt KMinorVersion = 0;
+
+#define DEBUG_LOG(x) if (iUnderlyingConsole && iConfig.Debug()) iUnderlyingConsole->Write(_L(x))
+#define DEBUG_LOG_1(x, a) if (iUnderlyingConsole && iConfig.Debug()) iUnderlyingConsole->Printf(_L(x), a)
+#define DEBUG_LOG_2(x, a, b) if (iUnderlyingConsole && iConfig.Debug()) iUnderlyingConsole->Printf(_L(x), a, b)
+#define DEBUG_LOG_3(x, a, b, c) if (iUnderlyingConsole && iConfig.Debug()) iUnderlyingConsole->Printf(_L(x), a, b, c)
+#define CLEANUP_AND_RETURN_IF_ERROR(x) { TInt __err = x; if (__err < 0) { CleanupConnection(); return __err; } }
+
+enum TPacketType
+	{
+	ECommandCreateConsoleWindow,
+	ECommandAttachKeyEventSocket,
+	ECommandWrite,
+	ECommandGetCursorPos,
+	ECommandSetAbsCursorPos,
+	ECommandSetRelCursorPos,
+	ECommandSetCursorHeight,
+	ECommandGetScreenSize,
+	ECommandSetTitle,
+	ECommandClearScreen,
+	ECommandClearToEndOfLine
+	};
+
+
+class THeaderBase
+	{
+public:
+	THeaderBase(TPacketType aCommand, TInt aPacketSize);
+private:
+	const TInt iPacketType;
+	const TInt iPacketSize;
+	};
+
+THeaderBase::THeaderBase(TPacketType aCommand, TInt aPacketSize)
+	: iPacketType(aCommand), iPacketSize(aPacketSize - sizeof(THeaderBase))
+	{
+	}
+
+class TCreateConsoleWindowHeader : public THeaderBase
+	{
+public:
+	TCreateConsoleWindowHeader(const TDesC& aTitle, TSize aSize);
+private:
+	const TInt iMajorVersion;
+	const TInt iMinorVersion;
+	TInt iWidth;
+	TInt iHeight;
+	TInt iTitleLength;
+	};
+
+TCreateConsoleWindowHeader::TCreateConsoleWindowHeader(const TDesC& aTitle, TSize aSize)
+	: THeaderBase(ECommandCreateConsoleWindow, sizeof(TCreateConsoleWindowHeader) + aTitle.Size()), iMajorVersion(KMajorVersion), iMinorVersion(KMinorVersion), iWidth(aSize.iWidth), iHeight(aSize.iHeight), iTitleLength(aTitle.Length())
+	{
+	}
+
+class TAttachKeyEventSocketHeader : public THeaderBase
+	{
+public:
+	TAttachKeyEventSocketHeader(TInt aWindowId);
+private:
+	TInt iWindowId;
+	};
+
+TAttachKeyEventSocketHeader::TAttachKeyEventSocketHeader(TInt aWindowId)
+	: THeaderBase(ECommandAttachKeyEventSocket, sizeof(TAttachKeyEventSocketHeader)), iWindowId(aWindowId)
+	{
+	}
+
+class TWriteHeader : public THeaderBase
+	{
+public:
+	TWriteHeader(const TDesC& aDes);
+private:
+	TInt iDesLength;
+	};
+
+TWriteHeader::TWriteHeader(const TDesC& aDes)
+	: THeaderBase(ECommandWrite, sizeof(TWriteHeader) + aDes.Size()), iDesLength(aDes.Length())
+	{
+	}
+
+class TWriteOneHeader : public THeaderBase
+	{
+public:
+	TWriteOneHeader(const TDesC& aDes);
+private:
+	TInt iDesLength;
+	TUint16 iChar;
+	};
+
+TWriteOneHeader::TWriteOneHeader(const TDesC& aDes)
+	: THeaderBase(ECommandWrite, sizeof(TWriteOneHeader)), iDesLength(1), iChar(aDes[0])
+	{
+	}
+
+
+class TSetCursorPosHeader : public THeaderBase
+	{
+public:
+	TSetCursorPosHeader(TPacketType aCommand, const TPoint& aPos);
+private:
+	TInt iX;
+	TInt iY;
+	};
+
+TSetCursorPosHeader::TSetCursorPosHeader(TPacketType aCommand, const TPoint& aPos)
+	: THeaderBase(aCommand, sizeof(TSetCursorPosHeader)), iX(aPos.iX), iY(aPos.iY)
+	{
+	ASSERT((aCommand == ECommandSetAbsCursorPos) || (aCommand == ECommandSetRelCursorPos));
+	}
+
+class TSetCursorHeightHeader : public THeaderBase
+	{
+public:
+	TSetCursorHeightHeader(TInt aHeight);
+private:
+	TInt iHeight;
+	};
+
+TSetCursorHeightHeader::TSetCursorHeightHeader(TInt aHeight)
+	: THeaderBase(ECommandSetCursorHeight, sizeof(TSetCursorHeightHeader)), iHeight(aHeight)
+	{
+	}
+
+class TSetTitleHeader : public THeaderBase
+	{
+public:
+	TSetTitleHeader(const TDesC& aTitle);
+	};
+
+TSetTitleHeader::TSetTitleHeader(const TDesC& aTitle)
+	: THeaderBase(ECommandSetTitle, sizeof(TSetTitleHeader) + aTitle.Size())
+	{
+	}
+
+
+CRemoteConsole::CRemoteConsole()
+	: iKeyEventPckg(iKeyEvent)
+	{
+	}
+
+CRemoteConsole::~CRemoteConsole()
+	{
+	CleanupConnection();
+	delete iUnderlyingConsole;
+	}
+
+TInt CRemoteConsole::Create(const TDesC& aTitle, TSize aSize)
+	{
+	TInt ret = iConfig.Init();
+	if (ret == KErrNone)
+		{
+		ret = Connect(aTitle, aSize);
+		}
+	if (ret && iUnderlyingConsole)
+		{
+		iUnderlyingConsole->Printf(_L("Remote connection failed: %d\r\n"), ret);
+#ifdef __WINS__
+		// Give the user the chance to read the error message.
+		User::After(10000000);
+#endif
+		}
+	return ret;
+	}
+
+TInt CRemoteConsole::Connect(const TDesC& aTitle, TSize aSize)
+	{
+	// Connect to Socket Server.
+	DEBUG_LOG("Connecting to ESock\r\n");
+	TInt err = iSocketSession.Connect();
+	CLEANUP_AND_RETURN_IF_ERROR(err);
+
+#ifdef USE_RCONNECTION
+	switch (iConfig.ConnectionType())
+		{
+		default:
+		case TRemoteConsoleConfig::EImplicit:
+			{
+			DEBUG_LOG("Opening command socket\r\n");
+			CLEANUP_AND_RETURN_IF_ERROR(iCommandSocket.Open(iSocketSession, KAfInet, KSockStream, iConfig.Protocol()));
+			DEBUG_LOG("Opening event\r\n");
+			CLEANUP_AND_RETURN_IF_ERROR(iKeyEventSocket.Open(iSocketSession, KAfInet, KSockStream, iConfig.Protocol()));
+			break;
+			}
+		case TRemoteConsoleConfig::EExplicit:
+			{
+			DEBUG_LOG("Opening connection\r\n");
+			CLEANUP_AND_RETURN_IF_ERROR(iConnection.Open(iSocketSession));
+			TUint numConnections;
+			DEBUG_LOG("Enumerating existing connections\r\n");
+			err = iConnection.EnumerateConnections(numConnections);
+			CLEANUP_AND_RETURN_IF_ERROR(err);
+			DEBUG_LOG_2("Looking for IapId: %d NetId: %d\r\n", iConfig.IapId(), iConfig.NetworkId());
+
+			TBool connectionAttached(EFalse);
+			for (TInt i = 1; i <= (TInt)numConnections; ++i)
+				{
+				DEBUG_LOG_1("Getting info for connection %d\r\n", i);
+				TConnectionInfoBuf connectionInfoBuf;
+				CLEANUP_AND_RETURN_IF_ERROR(iConnection.GetConnectionInfo(i, connectionInfoBuf));
+				const TConnectionInfo& info = connectionInfoBuf();
+				DEBUG_LOG_2("Found IapId: %d NetId: %d\r\n", info.iIapId, info.iNetId);
+				if ((info.iIapId == iConfig.IapId()) && (info.iNetId == iConfig.NetworkId()))
+					{
+					DEBUG_LOG("Matching IAP and Network IDs found, attaching...\r\n");
+					CLEANUP_AND_RETURN_IF_ERROR(iConnection.Attach(connectionInfoBuf, RConnection::EAttachTypeNormal));
+					DEBUG_LOG("Opening command socket on connection\r\n");
+					CLEANUP_AND_RETURN_IF_ERROR(iCommandSocket.Open(iSocketSession, KAfInet, KSockStream, iConfig.Protocol(), iConnection));
+					DEBUG_LOG("Opening event socket on connection\r\n");
+					CLEANUP_AND_RETURN_IF_ERROR(iKeyEventSocket.Open(iSocketSession, KAfInet, KSockStream, iConfig.Protocol(), iConnection));
+					connectionAttached = ETrue;
+					}
+				}
+			if (!connectionAttached)
+				{
+				CLEANUP_AND_RETURN_IF_ERROR(KErrCouldNotConnect);
+				}
+			break;
+			}
+		}
+#else	// USE_RCONNECTION
+	DEBUG_LOG("Opening command socket\r\n");
+	CLEANUP_AND_RETURN_IF_ERROR(iCommandSocket.Open(iSocketSession, KAfInet, KSockStream, iConfig.Protocol()));
+	DEBUG_LOG("Opening event\r\n");
+	CLEANUP_AND_RETURN_IF_ERROR(iKeyEventSocket.Open(iSocketSession, KAfInet, KSockStream, iConfig.Protocol()));
+#endif
+
+	iCommandSocket.SetOpt(KSoTcpNoDelay, KSolInetTcp, ETrue);	// Ignore error (may not be supported).
+	iKeyEventSocket.SetOpt(KSoTcpNoDelay, KSolInetTcp, ETrue);	// Ignore error (may not be supported).
+
+	// Resolve IP address (if need be).
+	const TDesC& remoteHostName = iConfig.RemoteHostName();
+	TInetAddr remoteAddress(iConfig.RemotePort());
+	err = remoteAddress.Input(remoteHostName);
+	if (err)
+		{
+		RHostResolver resolver;
+#ifdef USE_RCONNECTION
+		if (iConnection.SubSessionHandle())
+			{
+			CLEANUP_AND_RETURN_IF_ERROR(resolver.Open(iSocketSession, KAfInet, iConfig.Protocol(), iConnection));
+			}
+		else
+			{
+			CLEANUP_AND_RETURN_IF_ERROR(resolver.Open(iSocketSession, KAfInet, iConfig.Protocol()));
+			}
+#else
+		CLEANUP_AND_RETURN_IF_ERROR(resolver.Open(iSocketSession, KAfInet, iConfig.Protocol()));
+#endif
+		TNameEntry nameEntry;
+		err = resolver.GetByName(remoteHostName, nameEntry);
+		if (err)
+			{
+			resolver.Close();
+			CLEANUP_AND_RETURN_IF_ERROR(err);
+			}
+		remoteAddress.SetAddress(TInetAddr::Cast(nameEntry().iAddr).Address());
+		resolver.Close();
+		}
+
+	// Connect command socket.
+	DEBUG_LOG_2("Connecting command socket to %S : %d\r\n", &remoteHostName, iConfig.RemotePort());
+	TRequestStatus status;
+	iCommandSocket.Connect(remoteAddress, status);
+	User::WaitForRequest(status);
+	CLEANUP_AND_RETURN_IF_ERROR(status.Int());
+
+	// Request a new console window in the remote host.
+	DEBUG_LOG("Requesting new console window\r\n");
+	TCreateConsoleWindowHeader createConsoleWindowHeader(aTitle, aSize);
+	TPckgC<TCreateConsoleWindowHeader> createConsoleWindowHeaderPckg(createConsoleWindowHeader);
+	iCommandSocket.Write(createConsoleWindowHeaderPckg, status);
+	User::WaitForRequest(status);
+	CLEANUP_AND_RETURN_IF_ERROR(status.Int());
+	DEBUG_LOG("Sending title\r\n");
+	TPtrC8 narrowTitlePtr((TUint8*)aTitle.Ptr(), aTitle.Size());
+	iCommandSocket.Write(narrowTitlePtr, status);
+	User::WaitForRequest(status);
+	CLEANUP_AND_RETURN_IF_ERROR(status.Int());
+
+	// Read response (window identifier if successful).
+	DEBUG_LOG("Reading window identifier\r\n");
+	TInt response;
+	TPckg<TInt> responsePckg(response);
+	iCommandSocket.Read(responsePckg, status);
+	User::WaitForRequest(status);
+	CLEANUP_AND_RETURN_IF_ERROR(status.Int());
+	CLEANUP_AND_RETURN_IF_ERROR(response);
+
+	// Connect key event socket.
+	DEBUG_LOG_2("Connecting event socket to %S : %d\r\n", &remoteHostName, iConfig.RemotePort());
+	iKeyEventSocket.Connect(remoteAddress, status);
+	User::WaitForRequest(status);
+	CLEANUP_AND_RETURN_IF_ERROR(status.Int());
+
+	// Attach key event socket to the new console window.
+	DEBUG_LOG("Attaching event socket to console window\r\n");
+	TAttachKeyEventSocketHeader attachKeyEventSocketHeader(response);
+	TPckgC<TAttachKeyEventSocketHeader> attachKeyEventSocketHeaderPckg(attachKeyEventSocketHeader);
+	iKeyEventSocket.Write(attachKeyEventSocketHeaderPckg, status);
+	User::WaitForRequest(status);
+	CLEANUP_AND_RETURN_IF_ERROR(status.Int());
+
+	return KErrNone;
+	}
+
+void CRemoteConsole::Read(TRequestStatus& aStatus)
+	{
+	iKeyEventSocket.Read(iKeyEventPckg, aStatus);
+	}
+
+void CRemoteConsole::ReadCancel()
+	{
+	iKeyEventSocket.CancelRead();
+	}
+
+void CRemoteConsole::Write(const TDesC& aDes)
+	{
+	if (aDes.Length() == 1)
+		{
+		// Only do a single ESock write for the case where there's only 1 character.
+		TWriteOneHeader writeHeader(aDes);
+		TPckgC<TWriteOneHeader> writeHeaderPckg(writeHeader);
+		WriteCommand(writeHeaderPckg);
+		}
+	else
+		{
+		TWriteHeader writeHeader(aDes);
+		TPckgC<TWriteHeader> writeHeaderPckg(writeHeader);
+		WriteCommand(writeHeaderPckg);
+		TPtrC8 narrowPtr((TUint8*)aDes.Ptr(), aDes.Size());
+		WriteCommand(narrowPtr);
+		}
+	}
+
+TPoint CRemoteConsole::CursorPos() const
+	{
+	THeaderBase header(ECommandGetCursorPos, sizeof(THeaderBase));
+	TPckgC<THeaderBase> headerPckg(header);
+	WriteCommand(headerPckg);
+	TPoint response;
+	TPckg<TPoint> responsePckg(response);
+	ReadCommandResponse(responsePckg);
+	return response;
+	}
+
+void CRemoteConsole::SetCursorPosAbs(const TPoint& aPoint)
+	{
+	TSetCursorPosHeader header(ECommandSetAbsCursorPos, aPoint);
+	TPckgC<TSetCursorPosHeader> headerPckg(header);
+	WriteCommand(headerPckg);
+	}
+
+void CRemoteConsole::SetCursorPosRel(const TPoint& aPoint)
+	{
+	TSetCursorPosHeader header(ECommandSetRelCursorPos, aPoint);
+	TPckgC<TSetCursorPosHeader> headerPckg(header);
+	WriteCommand(headerPckg);
+	}
+
+void CRemoteConsole::SetCursorHeight(TInt aPercentage)
+	{
+	TSetCursorHeightHeader header(aPercentage);
+	TPckgC<TSetCursorHeightHeader> headerPckg(header);
+	WriteCommand(headerPckg);
+	}
+
+void CRemoteConsole::SetTitle(const TDesC& aTitle)
+	{
+	TSetTitleHeader header(aTitle);
+	TPckgC<TSetTitleHeader> headerPckg(header);
+	WriteCommand(headerPckg);
+	TPtrC8 narrowTitlePtr((TUint8*)aTitle.Ptr(), aTitle.Size());
+	WriteCommand(narrowTitlePtr);
+	}
+
+void CRemoteConsole::ClearScreen()
+	{
+	THeaderBase header(ECommandClearScreen, sizeof(THeaderBase));
+	TPckgC<THeaderBase> headerPckg(header);
+	WriteCommand(headerPckg);
+	}
+
+void CRemoteConsole::ClearToEndOfLine()
+	{
+	THeaderBase header(ECommandClearToEndOfLine, sizeof(THeaderBase));
+	TPckgC<THeaderBase> headerPckg(header);
+	WriteCommand(headerPckg);
+	}
+
+TSize CRemoteConsole::ScreenSize() const
+	{
+	THeaderBase header(ECommandGetScreenSize, sizeof(THeaderBase));
+	TPckgC<THeaderBase> headerPckg(header);
+	WriteCommand(headerPckg);
+	TSize response;
+	TPckg<TSize> responsePckg(response);
+	ReadCommandResponse(responsePckg);
+	return response;
+	}
+
+TKeyCode CRemoteConsole::KeyCode() const
+	{
+	return (TKeyCode)(iKeyEvent.iChar);
+	}
+
+TUint CRemoteConsole::KeyModifiers() const
+	{
+	return iKeyEvent.iModifiers;
+	}
+
+TInt CRemoteConsole::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
+	{
+	if (aExtensionId == UnderlyingConsole::KSetUnderlyingConsoleExtension)
+		{
+		iUnderlyingConsole = (CConsoleBase*)a1;
+		return KErrNone;
+		}
+	else
+		{
+		return CConsoleBase::Extension_(aExtensionId, a0, a1);
+		}
+	}
+
+void CRemoteConsole::CleanupConnection()
+	{
+	iKeyEventSocket.Close();
+	iCommandSocket.Close();
+#ifdef USE_RCONNECTION
+	iConnection.Close();
+#endif
+	iSocketSession.Close();
+	}
+
+void CRemoteConsole::WriteCommand(const TDesC8& aDes) const
+	{
+	TRequestStatus status;
+	iCommandSocket.Write(aDes, status);
+	User::WaitForRequest(status);
+	}
+
+void CRemoteConsole::ReadCommandResponse(TDes8& aDes) const
+	{
+	TRequestStatus status;
+	iCommandSocket.Read(aDes, status);
+	User::WaitForRequest(status);
+	}
+
+
+EXPORT_C TAny* NewConsole()
+	{
+	return new CRemoteConsole;
+	}
+
+#ifndef EKA2
+GLDEF_C TInt E32Dll(TDllReason)
+	{
+	return(KErrNone);
+	}
+#endif