You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ra...@apache.org on 2013/12/31 13:41:10 UTC

git commit: updated refs/heads/4.3 to b55d9ec

Updated Branches:
  refs/heads/4.3 9ec137e75 -> b55d9ecf5


CLOUDSTACK-5344 commit for console proxy rdp for hyperv


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/b55d9ecf
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/b55d9ecf
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/b55d9ecf

Branch: refs/heads/4.3
Commit: b55d9ecf533a5253b0b5cdcd155c692b1d3d7bec
Parents: 9ec137e
Author: Anshul Gangwar <an...@citrix.com>
Authored: Tue Dec 31 00:56:27 2013 +0530
Committer: Rajesh Battala <ra...@citrix.com>
Committed: Tue Dec 31 18:14:53 2013 +0530

----------------------------------------------------------------------
 .../HypervResource/HypervResourceController.cs  |  39 +++
 .../src/com/cloud/server/ManagementServer.java  |   3 +
 .../com/cloud/server/ManagementServerImpl.java  |  26 +-
 .../cloud/servlet/ConsoleProxyClientParam.java  |  35 +-
 .../com/cloud/servlet/ConsoleProxyServlet.java  | 191 ++++++-----
 .../main/java/common/BufferedImageCanvas.java   |   8 +-
 .../java/common/adapter/AwtCanvasAdapter.java   |  20 +-
 .../src/main/java/rdpclient/RdpClient.java      |  17 +-
 services/console-proxy/server/pom.xml           |   5 +
 .../com/cloud/consoleproxy/ConsoleProxy.java    |  40 ++-
 .../consoleproxy/ConsoleProxyAjaxHandler.java   |  45 +--
 .../consoleproxy/ConsoleProxyClientParam.java   |  47 ++-
 .../ConsoleProxyHttpHandlerHelper.java          |  13 +-
 .../consoleproxy/ConsoleProxyRdpClient.java     | 318 +++++++++++++++++++
 .../cloud/consoleproxy/rdp/KeysymToKeycode.java | 115 +++++++
 .../rdp/RdpBufferedImageCanvas.java             | 103 ++++++
 16 files changed, 874 insertions(+), 151 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
index c885598..7948196 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
@@ -1915,6 +1915,45 @@ namespace HypervResource
             }
         }
 
+        // POST api/HypervResource/GetVncPortCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.GetVncPortCommand)]
+        public JContainer GetVncPortCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.GetVncPortCommand + cmd.ToString());
+
+                string details = null;
+                bool result = false;
+                string address = null;
+                int port = -9;
+
+                try
+                {
+                    string vmName = (string)cmd.name;
+                    var sys = wmiCallsV2.GetComputerSystem(vmName);
+                    address = "instanceId=" + sys.Name ;
+                    result = true;
+                }
+                catch (Exception sysEx)
+                {
+                    details = CloudStackTypes.GetVncPortAnswer + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    address = address,
+                    port = port
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVncPortAnswer);
+            }
+        }
+
         public static System.Net.NetworkInformation.NetworkInterface GetNicInfoFromIpAddress(string ipAddress, out string subnet)
         {
             System.Net.NetworkInformation.NetworkInterface[] nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/server/src/com/cloud/server/ManagementServer.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServer.java b/server/src/com/cloud/server/ManagementServer.java
index c5091e9..95835b7 100755
--- a/server/src/com/cloud/server/ManagementServer.java
+++ b/server/src/com/cloud/server/ManagementServer.java
@@ -20,6 +20,7 @@ import java.util.List;
 
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 
+import com.cloud.host.DetailVO;
 import com.cloud.host.HostVO;
 import com.cloud.storage.GuestOSVO;
 import com.cloud.utils.Pair;
@@ -51,6 +52,8 @@ public interface ManagementServer extends ManagementService, PluggableService  {
      */
     HostVO getHostBy(long hostId);
 
+    DetailVO findDetail(long hostId, String name);
+
     String getConsoleAccessUrlRoot(long vmId);
     
     GuestOSVO getGuestOs(Long guestOsId);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index cd8f3fb..e98c97a 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -42,9 +42,6 @@ import javax.crypto.spec.SecretKeySpec;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
-import com.cloud.service.ServiceOfferingVO;
-import com.cloud.service.dao.ServiceOfferingDao;
-import org.apache.cloudstack.api.command.admin.router.UpgradeRouterTemplateCmd;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.log4j.Logger;
 
@@ -148,6 +145,7 @@ import org.apache.cloudstack.api.command.admin.router.RebootRouterCmd;
 import org.apache.cloudstack.api.command.admin.router.StartRouterCmd;
 import org.apache.cloudstack.api.command.admin.router.StopRouterCmd;
 import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd;
+import org.apache.cloudstack.api.command.admin.router.UpgradeRouterTemplateCmd;
 import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd;
 import org.apache.cloudstack.api.command.admin.storage.AddS3Cmd;
 import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd;
@@ -274,6 +272,7 @@ import org.apache.cloudstack.api.command.user.iso.UpdateIsoCmd;
 import org.apache.cloudstack.api.command.user.iso.UpdateIsoPermissionsCmd;
 import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd;
 import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd;
+import org.apache.cloudstack.api.command.user.loadbalancer.AssignCertToLoadBalancerCmd;
 import org.apache.cloudstack.api.command.user.loadbalancer.AssignToLoadBalancerRuleCmd;
 import org.apache.cloudstack.api.command.user.loadbalancer.CreateApplicationLoadBalancerCmd;
 import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBHealthCheckPolicyCmd;
@@ -283,18 +282,17 @@ import org.apache.cloudstack.api.command.user.loadbalancer.DeleteApplicationLoad
 import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLBHealthCheckPolicyCmd;
 import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLBStickinessPolicyCmd;
 import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLoadBalancerRuleCmd;
+import org.apache.cloudstack.api.command.user.loadbalancer.DeleteSslCertCmd;
 import org.apache.cloudstack.api.command.user.loadbalancer.ListApplicationLoadBalancersCmd;
 import org.apache.cloudstack.api.command.user.loadbalancer.ListLBHealthCheckPoliciesCmd;
 import org.apache.cloudstack.api.command.user.loadbalancer.ListLBStickinessPoliciesCmd;
 import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRuleInstancesCmd;
 import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRulesCmd;
+import org.apache.cloudstack.api.command.user.loadbalancer.ListSslCertsCmd;
+import org.apache.cloudstack.api.command.user.loadbalancer.RemoveCertFromLoadBalancerCmd;
 import org.apache.cloudstack.api.command.user.loadbalancer.RemoveFromLoadBalancerRuleCmd;
 import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerRuleCmd;
 import org.apache.cloudstack.api.command.user.loadbalancer.UploadSslCertCmd;
-import org.apache.cloudstack.api.command.user.loadbalancer.DeleteSslCertCmd;
-import org.apache.cloudstack.api.command.user.loadbalancer.ListSslCertsCmd;
-import org.apache.cloudstack.api.command.user.loadbalancer.AssignCertToLoadBalancerCmd;
-import org.apache.cloudstack.api.command.user.loadbalancer.RemoveCertFromLoadBalancerCmd;
 import org.apache.cloudstack.api.command.user.nat.CreateIpForwardingRuleCmd;
 import org.apache.cloudstack.api.command.user.nat.DeleteIpForwardingRuleCmd;
 import org.apache.cloudstack.api.command.user.nat.DisableStaticNatCmd;
@@ -532,6 +530,8 @@ import com.cloud.projects.ProjectManager;
 import com.cloud.resource.ResourceManager;
 import com.cloud.server.ResourceTag.ResourceObjectType;
 import com.cloud.server.auth.UserAuthenticator;
+import com.cloud.service.ServiceOfferingVO;
+import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.storage.DiskOfferingVO;
 import com.cloud.storage.GuestOS;
 import com.cloud.storage.GuestOSCategoryVO;
@@ -577,13 +577,12 @@ import com.cloud.utils.db.DB;
 import com.cloud.utils.db.Filter;
 import com.cloud.utils.db.GlobalLock;
 import com.cloud.utils.db.JoinBuilder;
-import com.cloud.utils.db.TransactionCallback;
-import com.cloud.utils.db.TransactionCallbackNoReturn;
-import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.db.JoinBuilder.JoinType;
 import com.cloud.utils.db.SearchBuilder;
 import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallbackNoReturn;
+import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.net.MacAddress;
 import com.cloud.utils.net.NetUtils;
@@ -856,6 +855,11 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
     }
 
     @Override
+    public DetailVO findDetail(long hostId, String name) {
+        return _detailsDao.findDetail(hostId, name);
+    }
+
+    @Override
     public long getId() {
         return MacAddress.getMacAddress().toLong();
     }
@@ -3931,6 +3935,6 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
     }
 
     public void setLockMasterListener(LockMasterListener lockMasterListener) {
-        this._lockMasterListener = lockMasterListener;
+        _lockMasterListener = lockMasterListener;
     }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/server/src/com/cloud/servlet/ConsoleProxyClientParam.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/servlet/ConsoleProxyClientParam.java b/server/src/com/cloud/servlet/ConsoleProxyClientParam.java
index 33f124a..5d528c6 100644
--- a/server/src/com/cloud/servlet/ConsoleProxyClientParam.java
+++ b/server/src/com/cloud/servlet/ConsoleProxyClientParam.java
@@ -19,7 +19,7 @@ package com.cloud.servlet;
 // To maintain independency of console proxy project, we duplicate this class from console proxy project
 public class ConsoleProxyClientParam {
 	private String clientHostAddress;
-	private int clientHostPort; 
+	private int clientHostPort;
 	private String clientHostPassword;
 	private String clientTag;
 	private String ticket;
@@ -27,7 +27,11 @@ public class ConsoleProxyClientParam {
 	private String clientTunnelUrl;
 	private String clientTunnelSession;
 	
+    private String hypervHost;
+
 	private String ajaxSessionId;
+    private String username;
+    private String password;
 	
 	public ConsoleProxyClientParam() {
 		clientHostPort = 0;
@@ -90,7 +94,7 @@ public class ConsoleProxyClientParam {
 	}
 	
 	public String getAjaxSessionId() {
-		return this.ajaxSessionId;
+		return ajaxSessionId;
 	}
 	
 	public void setAjaxSessionId(String ajaxSessionId) {
@@ -98,7 +102,7 @@ public class ConsoleProxyClientParam {
 	}
 
 	public String getLocale() {
-		return this.locale;
+		return locale;
 	}
 
 	public void setLocale(String locale) {
@@ -111,4 +115,29 @@ public class ConsoleProxyClientParam {
 		
 		return clientHostAddress + ":" + clientHostPort;
 	}
+
+    public void setHypervHost(String host) {
+        hypervHost = host;
+    }
+
+    public String getHypervHost() {
+        return hypervHost;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getPassword() {
+        return password;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/server/src/com/cloud/servlet/ConsoleProxyServlet.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/servlet/ConsoleProxyServlet.java b/server/src/com/cloud/servlet/ConsoleProxyServlet.java
index aad00a4..e0aaa6d 100644
--- a/server/src/com/cloud/servlet/ConsoleProxyServlet.java
+++ b/server/src/com/cloud/servlet/ConsoleProxyServlet.java
@@ -56,7 +56,6 @@ import com.cloud.uservm.UserVm;
 import com.cloud.utils.Pair;
 import com.cloud.utils.Ternary;
 import com.cloud.utils.db.EntityManager;
-import com.cloud.utils.db.Transaction;
 import com.cloud.utils.db.TransactionLegacy;
 import com.cloud.vm.UserVmDetailVO;
 import com.cloud.vm.VirtualMachine;
@@ -81,6 +80,7 @@ public class ConsoleProxyServlet extends HttpServlet {
     @Inject EntityManager _entityMgr;
     @Inject UserVmDetailsDao _userVmDetailsDao;
 
+
     static ManagementServer s_ms;
 
     private final Gson _gson = new GsonBuilder().create();
@@ -90,8 +90,8 @@ public class ConsoleProxyServlet extends HttpServlet {
 
     @Override
     public void init(ServletConfig config) throws ServletException {
-    	SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
-    	s_ms = _ms;
+        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
+        s_ms = _ms;
     }
 
     @Override
@@ -103,12 +103,12 @@ public class ConsoleProxyServlet extends HttpServlet {
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
 
         try {
-            if(_accountMgr == null || _vmMgr == null || _ms == null) {
+            if (_accountMgr == null || _vmMgr == null || _ms == null) {
                 sendResponse(resp, "Service is not ready");
                 return;
             }
 
-            if(_ms.getHashKey() == null) {
+            if (_ms.getHashKey() == null) {
                 s_logger.debug("Console/thumbnail access denied. Ticket service is not ready yet");
                 sendResponse(resp, "Service is not ready");
                 return;
@@ -122,8 +122,8 @@ public class ConsoleProxyServlet extends HttpServlet {
             params.putAll(req.getParameterMap());
 
             HttpSession session = req.getSession(false);
-            if(session == null) {
-                if(verifyRequest(params)) {
+            if (session == null) {
+                if (verifyRequest(params)) {
                     userId = (String)params.get("userid")[0];
                     account = (String)params.get("account")[0];
                     accountObj = (Account)params.get("accountobj")[0];
@@ -134,12 +134,12 @@ public class ConsoleProxyServlet extends HttpServlet {
                 }
             } else {
                 // adjust to latest API refactoring changes
-                if(session.getAttribute("userid") != null) {
+                if (session.getAttribute("userid") != null) {
                     userId = ((Long)session.getAttribute("userid")).toString();
                 }
 
                 accountObj = (Account)session.getAttribute("accountobj");
-                if(accountObj != null) {
+                if (accountObj != null) {
                     account = "" + accountObj.getId();
                 }
             }
@@ -152,7 +152,7 @@ public class ConsoleProxyServlet extends HttpServlet {
             }
 
             String cmd = req.getParameter("cmd");
-            if(cmd == null || !isValidCmd(cmd)) {
+            if (cmd == null || !isValidCmd(cmd)) {
                 s_logger.debug("invalid console servlet command: " + cmd);
                 sendResponse(resp, "");
                 return;
@@ -160,20 +160,20 @@ public class ConsoleProxyServlet extends HttpServlet {
 
             String vmIdString = req.getParameter("vm");
             Long vmId = _identityService.getIdentityId("vm_instance", vmIdString);
-            if(vmId == null) {
+            if (vmId == null) {
                 s_logger.info("invalid console servlet command parameter: " + vmIdString);
                 sendResponse(resp, "");
                 return;
             }
 
-            if(!checkSessionPermision(req, vmId, accountObj)) {
+            if (!checkSessionPermision(req, vmId, accountObj)) {
                 sendResponse(resp, "Permission denied");
                 return;
             }
 
-            if(cmd.equalsIgnoreCase("thumbnail")) {
+            if (cmd.equalsIgnoreCase("thumbnail")) {
                 handleThumbnailRequest(req, resp, vmId);
-            } else if(cmd.equalsIgnoreCase("access")) {
+            } else if (cmd.equalsIgnoreCase("access")) {
                 handleAccessRequest(req, resp, vmId);
             } else {
                 handleAuthRequest(req, resp, vmId);
@@ -186,27 +186,27 @@ public class ConsoleProxyServlet extends HttpServlet {
 
     private void handleThumbnailRequest(HttpServletRequest req, HttpServletResponse resp, long vmId) {
         VirtualMachine vm = _vmMgr.findById(vmId);
-        if(vm == null) {
+        if (vm == null) {
             s_logger.warn("VM " + vmId + " does not exist, sending blank response for thumbnail request");
             sendResponse(resp, "");
             return;
         }
 
-        if(vm.getHostId() == null) {
+        if (vm.getHostId() == null) {
             s_logger.warn("VM " + vmId + " lost host info, sending blank response for thumbnail request");
             sendResponse(resp, "");
             return;
         }
 
         HostVO host = _ms.getHostBy(vm.getHostId());
-        if(host == null) {
+        if (host == null) {
             s_logger.warn("VM " + vmId + "'s host does not exist, sending blank response for thumbnail request");
             sendResponse(resp, "");
             return;
         }
 
         String rootUrl = _ms.getConsoleAccessUrlRoot(vmId);
-        if(rootUrl == null) {
+        if (rootUrl == null) {
             sendResponse(resp, "");
             return;
         }
@@ -217,19 +217,19 @@ public class ConsoleProxyServlet extends HttpServlet {
         String value = req.getParameter("w");
         try {
             w = Integer.parseInt(value);
-        } catch(NumberFormatException e) {
+        } catch (NumberFormatException e) {
         }
 
         value = req.getParameter("h");
         try {
             h = Integer.parseInt(value);
-        } catch(NumberFormatException e) {
+        } catch (NumberFormatException e) {
         }
 
         try {
             resp.sendRedirect(composeThumbnailUrl(rootUrl, vm, host, w, h));
         } catch (IOException e) {
-            if(s_logger.isInfoEnabled()) {
+            if (s_logger.isInfoEnabled()) {
                 s_logger.info("Client may already close the connection");
             }
         }
@@ -237,36 +237,37 @@ public class ConsoleProxyServlet extends HttpServlet {
 
     private void handleAccessRequest(HttpServletRequest req, HttpServletResponse resp, long vmId) {
         VirtualMachine vm = _vmMgr.findById(vmId);
-        if(vm == null) {
+        if (vm == null) {
             s_logger.warn("VM " + vmId + " does not exist, sending blank response for console access request");
             sendResponse(resp, "");
             return;
         }
 
-        if(vm.getHostId() == null) {
+        if (vm.getHostId() == null) {
             s_logger.warn("VM " + vmId + " lost host info, sending blank response for console access request");
             sendResponse(resp, "");
             return;
         }
 
         HostVO host = _ms.getHostBy(vm.getHostId());
-        if(host == null) {
+
+        if (host == null) {
             s_logger.warn("VM " + vmId + "'s host does not exist, sending blank response for console access request");
             sendResponse(resp, "");
             return;
         }
 
         String rootUrl = _ms.getConsoleAccessUrlRoot(vmId);
-        if(rootUrl == null) {
+        if (rootUrl == null) {
             sendResponse(resp, "<html><body><p>Console access will be ready in a few minutes. Please try it again later.</p></body></html>");
             return;
         }
 
         String vmName = vm.getHostName();
-        if(vm.getType() == VirtualMachine.Type.User) {
+        if (vm.getType() == VirtualMachine.Type.User) {
             UserVm userVm = _entityMgr.findById(UserVm.class, vmId);
             String displayName = userVm.getDisplayName();
-            if(displayName != null && !displayName.isEmpty() && !displayName.equals(vmName)) {
+            if (displayName != null && !displayName.isEmpty() && !displayName.equals(vmName)) {
                 vmName += "(" + displayName + ")";
             }
         }
@@ -283,27 +284,27 @@ public class ConsoleProxyServlet extends HttpServlet {
         // TODO authentication channel between console proxy VM and management server needs to be secured,
         // the data is now being sent through private network, but this is apparently not enough
         VirtualMachine vm = _vmMgr.findById(vmId);
-        if(vm == null) {
+        if (vm == null) {
             s_logger.warn("VM " + vmId + " does not exist, sending failed response for authentication request from console proxy");
             sendResponse(resp, "failed");
             return;
         }
 
-        if(vm.getHostId() == null) {
+        if (vm.getHostId() == null) {
             s_logger.warn("VM " + vmId + " lost host info, failed response for authentication request from console proxy");
             sendResponse(resp, "failed");
             return;
         }
 
         HostVO host = _ms.getHostBy(vm.getHostId());
-        if(host == null) {
+        if (host == null) {
             s_logger.warn("VM " + vmId + "'s host does not exist, sending failed response for authentication request from console proxy");
             sendResponse(resp, "failed");
             return;
         }
 
         String sid = req.getParameter("sid");
-        if(sid == null || !sid.equals(vm.getVncPassword())) {
+        if (sid == null || !sid.equals(vm.getVncPassword())) {
             s_logger.warn("sid " + sid + " in url does not match stored sid " + vm.getVncPassword());
             sendResponse(resp, "failed");
             return;
@@ -320,15 +321,19 @@ public class ConsoleProxyServlet extends HttpServlet {
 
         s_logger.info("Parse host info returned from executing GetVNCPortCommand. host info: " + hostInfo);
 
-        if(hostInfo != null && hostInfo.startsWith("consoleurl")) {
-            String tokens[] = hostInfo.split("&");
+        if (hostInfo != null) {
+            if (hostInfo.startsWith("consoleurl")) {
+                String tokens[] = hostInfo.split("&");
 
-            if(hostInfo.length() > 19 && hostInfo.indexOf('/', 19) > 19) {
-                host = hostInfo.substring(19, hostInfo.indexOf('/', 19)).trim();
-                tunnelUrl = tokens[0].substring("consoleurl=".length());
-                tunnelSession = tokens[1].split("=")[1];
-            } else {
-                host = "";
+                if (hostInfo.length() > 19 && hostInfo.indexOf('/', 19) > 19) {
+                    host = hostInfo.substring(19, hostInfo.indexOf('/', 19)).trim();
+                    tunnelUrl = tokens[0].substring("consoleurl=".length());
+                    tunnelSession = tokens[1].split("=")[1];
+                } else {
+                    host = "";
+                }
+            } else if (hostInfo.startsWith("instanceId")) {
+                host = hostInfo.substring(hostInfo.indexOf('=') + 1);
             }
         } else {
             host = hostInfo;
@@ -338,11 +343,11 @@ public class ConsoleProxyServlet extends HttpServlet {
     }
 
     private String getEncryptorPassword() {
-    	String key = _ms.getEncryptionKey();
-    	String iv = _ms.getEncryptionIV();
+        String key = _ms.getEncryptionKey();
+        String iv = _ms.getEncryptionIV();
 
-    	ConsoleProxyPasswordBasedEncryptor.KeyIVPair keyIvPair = new ConsoleProxyPasswordBasedEncryptor.KeyIVPair(key, iv);
-		return _gson.toJson(keyIvPair);
+        ConsoleProxyPasswordBasedEncryptor.KeyIVPair keyIvPair = new ConsoleProxyPasswordBasedEncryptor.KeyIVPair(key, iv);
+        return _gson.toJson(keyIvPair);
     }
 
     private String composeThumbnailUrl(String rootUrl, VirtualMachine vm, HostVO hostVo, int w, int h) {
@@ -365,7 +370,7 @@ public class ConsoleProxyServlet extends HttpServlet {
         param.setClientHostPassword(sid);
         param.setClientTag(tag);
         param.setTicket(ticket);
-        if(parsedHostInfo.second() != null  && parsedHostInfo.third() != null) {
+        if (parsedHostInfo.second() != null && parsedHostInfo.third() != null) {
             param.setClientTunnelUrl(parsedHostInfo.second());
             param.setClientTunnelSession(parsedHostInfo.third());
         }
@@ -374,7 +379,7 @@ public class ConsoleProxyServlet extends HttpServlet {
                 + encryptor.encryptObject(ConsoleProxyClientParam.class, param));
         sb.append("&w=").append(w).append("&h=").append(h).append("&key=0");
 
-        if(s_logger.isDebugEnabled()) {
+        if (s_logger.isDebugEnabled()) {
             s_logger.debug("Compose thumbnail url: " + sb.toString());
         }
         return sb.toString();
@@ -383,28 +388,48 @@ public class ConsoleProxyServlet extends HttpServlet {
     private String composeConsoleAccessUrl(String rootUrl, VirtualMachine vm, HostVO hostVo) {
         StringBuffer sb = new StringBuffer(rootUrl);
         String host = hostVo.getPrivateIpAddress();
+        String username = _ms.findDetail(hostVo.getId(), "username").getValue();
+        String password = _ms.findDetail(hostVo.getId(), "password").getValue();
 
         Pair<String, Integer> portInfo = _ms.getVncPort(vm);
-        if(s_logger.isDebugEnabled())
+        if (s_logger.isDebugEnabled())
             s_logger.debug("Port info " + portInfo.first());
 
         Ternary<String, String, String> parsedHostInfo = parseHostInfo(portInfo.first());
+        int port = -1;
+        String sid;
+        
+        if (portInfo.second() == -9) {
+            //for hyperv
+            port = 2179;
+        } else {
+            port = portInfo.second();
+        }
 
+        sid = vm.getVncPassword();
         UserVmDetailVO details = _userVmDetailsDao.findDetail(vm.getId(), "keyboard");
-        String sid = vm.getVncPassword();
+
         String tag = vm.getUuid();
-        String ticket = genAccessTicket(host, String.valueOf(portInfo.second()), sid, tag);
+
+        String ticket = genAccessTicket(parsedHostInfo.first(), String.valueOf(port), sid, tag);
         ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(getEncryptorPassword());
         ConsoleProxyClientParam param = new ConsoleProxyClientParam();
         param.setClientHostAddress(parsedHostInfo.first());
-        param.setClientHostPort(portInfo.second());
+        param.setClientHostPort(port);
         param.setClientHostPassword(sid);
         param.setClientTag(tag);
         param.setTicket(ticket);
+
         if (details != null) {
             param.setLocale(details.getValue());
         }
-        if(parsedHostInfo.second() != null  && parsedHostInfo.third() != null) {
+        if (portInfo.second() == -9) {
+            //For Hyperv Clinet Host Address will send Instance id
+            param.setHypervHost(host);
+            param.setUsername(username);
+            param.setPassword(password);
+        }
+        if (parsedHostInfo.second() != null && parsedHostInfo.third() != null) {
             param.setClientTunnelUrl(parsedHostInfo.second());
             param.setClientTunnelSession(parsedHostInfo.third());
         }
@@ -414,10 +439,10 @@ public class ConsoleProxyServlet extends HttpServlet {
         // for console access, we need guest OS type to help implement keyboard
         long guestOs = vm.getGuestOSId();
         GuestOSVO guestOsVo = _ms.getGuestOs(guestOs);
-        if(guestOsVo.getCategoryId() == 6)
+        if (guestOsVo.getCategoryId() == 6)
             sb.append("&guest=windows");
 
-        if(s_logger.isDebugEnabled()) {
+        if (s_logger.isDebugEnabled()) {
             s_logger.debug("Compose console url: " + sb.toString());
         }
         return sb.toString();
@@ -434,7 +459,7 @@ public class ConsoleProxyServlet extends HttpServlet {
             Mac mac = Mac.getInstance("HmacSHA1");
 
             long ts = normalizedHashTime.getTime();
-            ts = ts/60000;		// round up to 1 minute
+            ts = ts / 60000;		// round up to 1 minute
             String secretKey = s_ms.getHashKey();
 
             SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
@@ -445,7 +470,7 @@ public class ConsoleProxyServlet extends HttpServlet {
             byte[] encryptedBytes = mac.doFinal();
 
             return Base64.encodeBase64String(encryptedBytes);
-        } catch(Exception e) {
+        } catch (Exception e) {
             s_logger.error("Unexpected exception ", e);
         }
         return "";
@@ -455,8 +480,8 @@ public class ConsoleProxyServlet extends HttpServlet {
         try {
             resp.setContentType("text/html");
             resp.getWriter().print(content);
-        } catch(IOException e) {
-            if(s_logger.isInfoEnabled()) {
+        } catch (IOException e) {
+            if (s_logger.isInfoEnabled()) {
                 s_logger.info("Client may already close the connection");
             }
         }
@@ -465,18 +490,18 @@ public class ConsoleProxyServlet extends HttpServlet {
     private boolean checkSessionPermision(HttpServletRequest req, long vmId, Account accountObj) {
 
         VirtualMachine vm = _vmMgr.findById(vmId);
-        if(vm == null) {
+        if (vm == null) {
             s_logger.debug("Console/thumbnail access denied. VM " + vmId + " does not exist in system any more");
             return false;
         }
 
         // root admin can access anything
-        if(accountObj.getType() == Account.ACCOUNT_TYPE_ADMIN)
+        if (accountObj.getType() == Account.ACCOUNT_TYPE_ADMIN)
             return true;
 
-        switch(vm.getType())
+        switch (vm.getType())
         {
-        case User :
+        case User:
             try {
                 _accountMgr.checkAccess(accountObj, null, true, vm);
             } catch (PermissionDeniedException ex) {
@@ -485,8 +510,8 @@ public class ConsoleProxyServlet extends HttpServlet {
                         s_logger.debug("VM access is denied. VM owner account " + vm.getAccountId()
                                 + " does not match the account id in session " + accountObj.getId() + " and caller is a normal user");
                     }
-                } else if(accountObj.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || accountObj.getType() == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN) {
-                    if(s_logger.isDebugEnabled()) {
+                } else if (accountObj.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || accountObj.getType() == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN) {
+                    if (s_logger.isDebugEnabled()) {
                         s_logger.debug("VM access is denied. VM owner account " + vm.getAccountId()
                                 + " does not match the account id in session " + accountObj.getId() + " and the domain-admin caller does not manage the target domain");
                     }
@@ -496,11 +521,11 @@ public class ConsoleProxyServlet extends HttpServlet {
             break;
 
         case DomainRouter:
-        case ConsoleProxy :
+        case ConsoleProxy:
         case SecondaryStorageVm:
             return false;
 
-        default :
+        default:
             s_logger.warn("Unrecoginized virtual machine type, deny access by default. type: " + vm.getType());
             return false;
         }
@@ -509,7 +534,7 @@ public class ConsoleProxyServlet extends HttpServlet {
     }
 
     private boolean isValidCmd(String cmd) {
-        if(cmd.equalsIgnoreCase("thumbnail") || cmd.equalsIgnoreCase("access") || cmd.equalsIgnoreCase("auth")) {
+        if (cmd.equalsIgnoreCase("thumbnail") || cmd.equalsIgnoreCase("access") || cmd.equalsIgnoreCase("auth")) {
             return true;
         }
 
@@ -570,7 +595,6 @@ public class ConsoleProxyServlet extends HttpServlet {
                 }
             }
 
-
             // if api/secret key are passed to the parameters
             if ((signature == null) || (apiKey == null)) {
                 if (s_logger.isDebugEnabled()) {
@@ -593,7 +617,8 @@ public class ConsoleProxyServlet extends HttpServlet {
             Account account = userAcctPair.second();
 
             if (!user.getState().equals(Account.State.enabled) || !account.getState().equals(Account.State.enabled)) {
-                s_logger.debug("disabled or locked user accessing the api, userid = " + user.getId() + "; name = " + user.getUsername() + "; state: " + user.getState() + "; accountState: " + account.getState());
+                s_logger.debug("disabled or locked user accessing the api, userid = " + user.getId() + "; name = " + user.getUsername() + "; state: " + user.getState()
+                        + "; accountState: " + account.getState());
                 return false;
             }
 
@@ -617,10 +642,10 @@ public class ConsoleProxyServlet extends HttpServlet {
                 s_logger.debug("User signature: " + signature + " is not equaled to computed signature: " + computedSignature);
             }
 
-            if(equalSig) {
+            if (equalSig) {
                 requestParameters.put("userid", new Object[] {String.valueOf(user.getId())});
                 requestParameters.put("account", new Object[] {account.getAccountName()});
-                requestParameters.put("accountobj", new Object[] { account });
+                requestParameters.put("accountobj", new Object[] {account});
             }
             return equalSig;
         } catch (Exception ex) {
@@ -629,20 +654,32 @@ public class ConsoleProxyServlet extends HttpServlet {
         return false;
     }
 
-    public static final String escapeHTML(String content){
-        if(content == null || content.isEmpty())
+    public static final String escapeHTML(String content) {
+        if (content == null || content.isEmpty())
             return content;
 
         StringBuffer sb = new StringBuffer();
         for (int i = 0; i < content.length(); i++) {
             char c = content.charAt(i);
             switch (c) {
-            case '<': sb.append("&lt;"); break;
-            case '>': sb.append("&gt;"); break;
-            case '&': sb.append("&amp;"); break;
-            case '"': sb.append("&quot;"); break;
-            case ' ': sb.append("&nbsp;");break;
-            default:  sb.append(c); break;
+            case '<':
+                sb.append("&lt;");
+                break;
+            case '>':
+                sb.append("&gt;");
+                break;
+            case '&':
+                sb.append("&amp;");
+                break;
+            case '"':
+                sb.append("&quot;");
+                break;
+            case ' ':
+                sb.append("&nbsp;");
+                break;
+            default:
+                sb.append(c);
+                break;
             }
         }
         return sb.toString();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCanvas.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCanvas.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCanvas.java
index 2418de3..9cb5231 100755
--- a/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCanvas.java
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCanvas.java
@@ -30,7 +30,7 @@ public class BufferedImageCanvas extends Canvas {
     private static final long serialVersionUID = 1L;
 
     // Offline screen buffer
-    private BufferedImage offlineImage;
+    protected BufferedImage offlineImage;
 
     // Cached Graphics2D object for offline screen buffer
     private Graphics2D graphics;
@@ -49,7 +49,7 @@ public class BufferedImageCanvas extends Canvas {
     }
 
     public void setCanvasSize(int width, int height) {
-        this.offlineImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        offlineImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
         graphics = offlineImage.createGraphics();
 
         setSize(offlineImage.getWidth(), offlineImage.getHeight());
@@ -76,4 +76,8 @@ public class BufferedImageCanvas extends Canvas {
         return graphics;
     }
 
+    public void updateFrameBuffer(int x, int y, int w, int h) {
+        //this method will be used to mark the dirty tiles
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtCanvasAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtCanvasAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtCanvasAdapter.java
index 788d370..f3a73d70 100755
--- a/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtCanvasAdapter.java
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtCanvasAdapter.java
@@ -20,13 +20,6 @@ import java.awt.Graphics2D;
 import java.awt.image.BufferedImage;
 import java.awt.image.WritableRaster;
 
-import common.BitmapOrder;
-import common.BitmapRectangle;
-import common.BufferedImageCanvas;
-import common.CopyRectOrder;
-import common.OrderType;
-import common.ScreenDescription;
-
 import rdpclient.rdp.ServerBitmapUpdate;
 import streamer.BaseElement;
 import streamer.ByteBuffer;
@@ -35,6 +28,12 @@ import streamer.Link;
 import streamer.Order;
 import streamer.Pipeline;
 import streamer.PipelineImpl;
+import common.BitmapOrder;
+import common.BitmapRectangle;
+import common.BufferedImageCanvas;
+import common.CopyRectOrder;
+import common.OrderType;
+import common.ScreenDescription;
 
 public class AwtCanvasAdapter extends BaseElement {
 
@@ -48,6 +47,7 @@ public class AwtCanvasAdapter extends BaseElement {
 
     protected BufferedImageCanvas canvas;
 
+    @Override
     public String toString() {
         return "AwtRdpAdapter(" + id + ")";
     }
@@ -57,7 +57,7 @@ public class AwtCanvasAdapter extends BaseElement {
         if (verbose)
             System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
 
-        Order order = (Order)buf.getOrder();
+        Order order = buf.getOrder();
         switch ((OrderType)order.type) {
 
         case BITMAP_UPDATE:
@@ -77,13 +77,14 @@ public class AwtCanvasAdapter extends BaseElement {
     }
 
     private void handleCopyRect(CopyRectOrder order, ByteBuffer buf) {
-        // TODO Auto-generated method stub
         // Copy image
         canvas.getOfflineGraphics().copyArea(order.srcX, order.srcY, order.width, order.height, order.x - order.srcX, order.y - order.srcY);
 
         // Request update of repainted area
+        canvas.updateFrameBuffer(order.x, order.y, order.width, order.height);
         canvas.repaint(order.x, order.y, order.width, order.height);
 
+
     }
 
     private void handleBitmap(BitmapOrder order, ByteBuffer buf) {
@@ -137,6 +138,7 @@ public class AwtCanvasAdapter extends BaseElement {
             g.drawImage(rectImage, x, y, null);
 
             // Request update of repainted area
+            canvas.updateFrameBuffer(x, y, width, height);
             canvas.repaint(x, y, width, height);
         }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/RdpClient.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/RdpClient.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/RdpClient.java
index 969dfc2..1a613cb 100755
--- a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/RdpClient.java
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/RdpClient.java
@@ -63,6 +63,9 @@ import common.adapter.AwtCanvasAdapter;
 
 public class RdpClient extends PipelineImpl {
 
+    AwtMouseEventSource mouseEventSource = null;
+    AwtKeyEventSource keyEventSource = null;
+
     /**
      * Name of last OneTimePacket in handshake sequence.
      */
@@ -211,7 +214,7 @@ public class RdpClient extends PipelineImpl {
                     // Pre Connection Blob
                     "pcb",
 
-                    // Main (will be used after connection seq) or tpkt (to X224) 
+                    // Main (will be used after connection seq) or tpkt (to X224)
                     "server_fastpath >tpkt",
 
                     // SSL
@@ -333,8 +336,8 @@ public class RdpClient extends PipelineImpl {
         // Main network
         //
 
-        AwtMouseEventSource mouseEventSource = new AwtMouseEventSource("mouse");
-        AwtKeyEventSource keyEventSource = new AwtKeyEventSource("keyboard");
+        mouseEventSource = new AwtMouseEventSource("mouse");
+        keyEventSource = new AwtKeyEventSource("keyboard");
 
         // Subscribe packet sender to various events
         canvas.addMouseListener(mouseEventSource);
@@ -390,4 +393,12 @@ public class RdpClient extends PipelineImpl {
         link("client_x224_data_queue", "client_tpkt_queue", "client_tpkt_queue< queue");
 
     }
+
+    public AwtMouseEventSource getMouseEventSource() {
+        return mouseEventSource;
+    }
+
+    public AwtKeyEventSource getKeyEventSource() {
+        return keyEventSource;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/services/console-proxy/server/pom.xml
----------------------------------------------------------------------
diff --git a/services/console-proxy/server/pom.xml b/services/console-proxy/server/pom.xml
index 1149790..32ee590 100644
--- a/services/console-proxy/server/pom.xml
+++ b/services/console-proxy/server/pom.xml
@@ -44,6 +44,11 @@
       <artifactId>cloud-utils</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>rdpclient</groupId>
+      <artifactId>cloudstack-service-console-proxy-rdpclient</artifactId>
+      <version>${project.version}</version>
+    </dependency>
   </dependencies>
   <build>
     <resources>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxy.java
----------------------------------------------------------------------
diff --git a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxy.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxy.java
index 2abce56..68afae1 100644
--- a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxy.java
+++ b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxy.java
@@ -35,11 +35,12 @@ import java.util.concurrent.Executor;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.log4j.xml.DOMConfigurator;
 
-import com.cloud.consoleproxy.util.Logger;
-import com.cloud.utils.PropertiesUtil;
 import com.google.gson.Gson;
 import com.sun.net.httpserver.HttpServer;
 
+import com.cloud.consoleproxy.util.Logger;
+import com.cloud.utils.PropertiesUtil;
+
 /**
  * 
  * ConsoleProxy, singleton class that manages overall activities in console proxy process. To make legacy code work, we still
@@ -72,7 +73,7 @@ public class ConsoleProxy {
     static String factoryClzName;
     static boolean standaloneStart = false;
     
-    static String encryptorPassword = genDefaultEncryptorPassword(); 
+    static String encryptorPassword = genDefaultEncryptorPassword();
     
     private static String genDefaultEncryptorPassword() {
         try {
@@ -193,11 +194,11 @@ public class ConsoleProxy {
         if(authMethod != null) {
             Object result;
             try {
-                result = authMethod.invoke(ConsoleProxy.context, 
-                    param.getClientHostAddress(), 
-                    String.valueOf(param.getClientHostPort()), 
-                    param.getClientTag(), 
-                    param.getClientHostPassword(), 
+                result = authMethod.invoke(ConsoleProxy.context,
+                    param.getClientHostAddress(),
+                    String.valueOf(param.getClientHostPort()),
+                    param.getClientTag(),
+                    param.getClientHostPassword(),
                     param.getTicket(),
                     new Boolean(reauthentication));
             } catch (IllegalAccessException e) {
@@ -294,7 +295,7 @@ public class ConsoleProxy {
                 } catch (FileNotFoundException e) {
                     s_logger.info("Ignoring file not found exception and using defaults");
                 }
-        } 
+        }
         if (confs != null) {
             try {
                 props.load(confs);
@@ -403,7 +404,7 @@ public class ConsoleProxy {
         synchronized (connectionMap) {
             viewer = connectionMap.get(clientKey);
             if (viewer == null) {
-                viewer = new ConsoleProxyVncClient();
+                viewer = getClient(param);
                 viewer.initClient(param);
                 connectionMap.put(clientKey, viewer);
                 s_logger.info("Added viewer object " + viewer);
@@ -438,7 +439,7 @@ public class ConsoleProxy {
             ConsoleProxyClient viewer = connectionMap.get(clientKey);
             if (viewer == null) {
                 authenticationExternally(param);
-                viewer = new ConsoleProxyVncClient();
+                viewer = getClient(param);
                 viewer.initClient(param);
                 
                 connectionMap.put(clientKey, viewer);
@@ -474,7 +475,15 @@ public class ConsoleProxy {
             return viewer;
         }
     }
-    
+
+    private static ConsoleProxyClient getClient(ConsoleProxyClientParam param) {
+        if (param.getHypervHost() != null) {
+            return new ConsoleProxyRdpClient();
+        } else {
+            return new ConsoleProxyVncClient();
+        }
+    }
+
     public static void removeViewer(ConsoleProxyClient viewer) {
         synchronized (connectionMap) {
             for(Map.Entry<String, ConsoleProxyClient> entry : connectionMap.entrySet()) {
@@ -504,8 +513,8 @@ public class ConsoleProxy {
         return authenticateConsoleAccess(param, true);
     }
     
-    public static String getEncryptorPassword() { 
-        return encryptorPassword; 
+    public static String getEncryptorPassword() {
+        return encryptorPassword;
     }
     
     public static void setEncryptorPassword(String password) {
@@ -513,7 +522,8 @@ public class ConsoleProxy {
     }
     
     static class ThreadExecutor implements Executor {
-         public void execute(Runnable r) {
+         @Override
+        public void execute(Runnable r) {
              new Thread(r).start();
          }
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java
----------------------------------------------------------------------
diff --git a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java
index f4d3a17..552471f 100644
--- a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java
+++ b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java
@@ -26,17 +26,19 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import com.cloud.consoleproxy.util.Logger;
 import com.sun.net.httpserver.Headers;
 import com.sun.net.httpserver.HttpExchange;
 import com.sun.net.httpserver.HttpHandler;
 
+import com.cloud.consoleproxy.util.Logger;
+
 public class ConsoleProxyAjaxHandler implements HttpHandler {
     private static final Logger s_logger = Logger.getLogger(ConsoleProxyAjaxHandler.class);
     
     public ConsoleProxyAjaxHandler() {
     }
     
+    @Override
     public void handle(HttpExchange t) throws IOException {
         try {
             if(s_logger.isTraceEnabled())
@@ -65,7 +67,7 @@ public class ConsoleProxyAjaxHandler implements HttpHandler {
         String queries = t.getRequestURI().getQuery();
         if(s_logger.isTraceEnabled())
             s_logger.trace("Handle AJAX request: " + queries);
-        
+
         Map<String, String> queryMap = ConsoleProxyHttpHandlerHelper.getQueryMap(queries);
         
         String host = queryMap.get("host");
@@ -78,6 +80,9 @@ public class ConsoleProxyAjaxHandler implements HttpHandler {
         String console_url = queryMap.get("consoleurl");
         String console_host_session = queryMap.get("sessionref");
         String vm_locale = queryMap.get("locale");
+        String hypervHost = queryMap.get("hypervHost");
+        String username = queryMap.get("username");
+        String password = queryMap.get("password");
 
         if(tag == null)
             tag = "";
@@ -87,7 +92,7 @@ public class ConsoleProxyAjaxHandler implements HttpHandler {
         
         int port;
 
-        if(host == null || portStr == null || sid == null) 
+        if(host == null || portStr == null || sid == null)
             throw new IllegalArgumentException();
         
         try {
@@ -126,6 +131,9 @@ public class ConsoleProxyAjaxHandler implements HttpHandler {
             param.setClientTunnelUrl(console_url);
             param.setClientTunnelSession(console_host_session);
             param.setLocale(vm_locale);
+            param.setHypervHost(hypervHost);
+            param.setUsername(username);
+            param.setPassword(password);
 
             viewer = ConsoleProxy.getAjaxVncViewer(param, ajaxSessionIdStr);
         } catch(Exception e) {
@@ -178,32 +186,31 @@ public class ConsoleProxyAjaxHandler implements HttpHandler {
                 
                 if(s_logger.isTraceEnabled())
                     s_logger.trace("Ajax request indicates client update");
-                
                 handleClientUpdate(t, viewer);
             }
         }
     }
     
-    private static String convertStreamToString(InputStream is, boolean closeStreamAfterRead) { 
-        BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 
-        StringBuilder sb = new StringBuilder(); 
-        String line = null; 
-        try { 
-            while ((line = reader.readLine()) != null) { 
-                sb.append(line + "\n"); 
-            } 
+    private static String convertStreamToString(InputStream is, boolean closeStreamAfterRead) {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+        StringBuilder sb = new StringBuilder();
+        String line = null;
+        try {
+            while ((line = reader.readLine()) != null) {
+                sb.append(line + "\n");
+            }
         } catch (IOException e) {
             s_logger.warn("Exception while reading request body: ", e);
         } finally {
             if(closeStreamAfterRead) {
-                try { 
-                    is.close(); 
-                } catch (IOException e) { 
-                } 
+                try {
+                    is.close();
+                } catch (IOException e) {
+                }
             }
-        } 
-        return sb.toString(); 
-    }   
+        }
+        return sb.toString();
+    }
     
     private void sendResponse(HttpExchange t, String contentType, String response) throws IOException {
         Headers hds = t.getResponseHeaders();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientParam.java
----------------------------------------------------------------------
diff --git a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientParam.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientParam.java
index 7041ff0..76b04c6 100644
--- a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientParam.java
+++ b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientParam.java
@@ -21,18 +21,21 @@ package com.cloud.consoleproxy;
  * Data object to store parameter info needed by client to connect to its host
  */
 public class ConsoleProxyClientParam {
-    
+
     private String clientHostAddress;
-    private int clientHostPort; 
+    private int clientHostPort;
     private String clientHostPassword;
     private String clientTag;
     private String ticket;
-    
+
     private String clientTunnelUrl;
     private String clientTunnelSession;
     private String locale;
     private String ajaxSessionId;
-    
+    private String hypervHost;
+    private String username;
+    private String password;
+
     public ConsoleProxyClientParam() {
         clientHostPort = 0;
     }
@@ -76,7 +79,7 @@ public class ConsoleProxyClientParam {
     public void setTicket(String ticket) {
         this.ticket = ticket;
     }
-    
+
     public String getClientTunnelUrl() {
         return clientTunnelUrl;
     }
@@ -92,9 +95,9 @@ public class ConsoleProxyClientParam {
     public void setClientTunnelSession(String clientTunnelSession) {
         this.clientTunnelSession = clientTunnelSession;
     }
-    
+
     public String getAjaxSessionId() {
-        return this.ajaxSessionId;
+        return ajaxSessionId;
     }
 
     public void setAjaxSessionId(String ajaxSessionId) {
@@ -102,7 +105,7 @@ public class ConsoleProxyClientParam {
     }
 
     public String getLocale() {
-        return this.locale;
+        return locale;
     }
 
     public void setLocale(String locale) {
@@ -110,9 +113,33 @@ public class ConsoleProxyClientParam {
     }
 
     public String getClientMapKey() {
-        if(clientTag != null && !clientTag.isEmpty())
+        if (clientTag != null && !clientTag.isEmpty())
             return clientTag;
-        
+
         return clientHostAddress + ":" + clientHostPort;
     }
+
+    public void setHypervHost(String hypervHost) {
+        this.hypervHost = hypervHost;
+    }
+
+    public String getHypervHost() {
+        return hypervHost;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getPassword() {
+        return password;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java
----------------------------------------------------------------------
diff --git a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java
index 353137c..0facd3f 100644
--- a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java
+++ b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java
@@ -71,10 +71,16 @@ public class ConsoleProxyHttpHandlerHelper {
                     map.put("ticket", param.getTicket());
                 if(param.getLocale() != null)
                     map.put("locale", param.getLocale());
+                if (param.getHypervHost() != null)
+                    map.put("hypervHost", param.getHypervHost());
+                if (param.getUsername() != null)
+                    map.put("username", param.getUsername());
+                if (param.getPassword() != null)
+                    map.put("password", param.getPassword());
             }
         } else {
-               // we no longer accept information from parameter other than token 
-               guardUserInput(map);
+        	// we no longer accept information from parameter other than token
+        	guardUserInput(map);
         }
         return map;
     }
@@ -88,5 +94,8 @@ public class ConsoleProxyHttpHandlerHelper {
         map.remove("sessionref");
         map.remove("ticket");
         map.remove("locale");
+        map.remove("hypervHost");
+        map.remove("username");
+        map.remove("password");
     }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyRdpClient.java
----------------------------------------------------------------------
diff --git a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyRdpClient.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyRdpClient.java
new file mode 100644
index 0000000..73c00be
--- /dev/null
+++ b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyRdpClient.java
@@ -0,0 +1,318 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.consoleproxy;
+
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+import org.apache.log4j.Logger;
+
+import rdpclient.RdpClient;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+import streamer.SocketWrapper;
+import streamer.apr.AprSocketWrapperImpl;
+import streamer.ssl.SSLState;
+
+import com.cloud.consoleproxy.rdp.KeysymToKeycode;
+import com.cloud.consoleproxy.rdp.RdpBufferedImageCanvas;
+import com.cloud.consoleproxy.vnc.FrameBufferCanvas;
+
+import common.AwtKeyEventSource;
+import common.AwtMouseEventSource;
+import common.ScreenDescription;
+import common.SizeChangeListener;
+
+public class ConsoleProxyRdpClient extends ConsoleProxyClientBase {
+
+    private static final Logger s_logger = Logger.getLogger(ConsoleProxyRdpClient.class);
+
+    private static final int SHIFT_KEY_MASK = 64;
+    private static final int CTRL_KEY_MASK = 128;
+    private static final int META_KEY_MASK = 256;
+    private static final int ALT_KEY_MASK = 512;
+
+    private RdpClient _client;
+    private ScreenDescription _screen;
+    private SocketWrapper _socket = null;
+    private RdpBufferedImageCanvas _canvas = null;
+
+    private Thread _worker;
+    private volatile boolean _workerDone = false;
+
+    private int _lastModifierStates = 0;
+
+    private AwtMouseEventSource _mouseEventSource = null;
+    private AwtKeyEventSource _keyEventSource = null;
+
+    public RdpBufferedImageCanvas getCanvas() {
+        return _canvas;
+    }
+
+    public void setCanvas(RdpBufferedImageCanvas canvas) {
+        _canvas = canvas;
+    }
+
+    @Override
+    public void onClientConnected() {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void onClientClose() {
+        s_logger.info("Received client close indication. remove viewer from map.");
+        ConsoleProxy.removeViewer(this);
+    }
+
+    @Override
+    public boolean isHostConnected() {
+        //FIXME
+        return true;
+    }
+
+    @Override
+    public boolean isFrontEndAlive() {
+        if (_socket != null) {
+            if (_workerDone || System.currentTimeMillis() - getClientLastFrontEndActivityTime() > ConsoleProxy.VIEWER_LINGER_SECONDS * 1000) {
+                s_logger.info("Front end has been idle for too long");
+                _socket.shutdown();
+                return false;
+            } else {
+                return true;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public void sendClientRawKeyboardEvent(InputEventType event, int code, int modifiers) {
+        if (_client == null)
+            return;
+
+        updateFrontEndActivityTime();
+
+        KeyEvent keyEvent = map(event, code, modifiers);
+        switch (event) {
+        case KEY_DOWN:
+            _keyEventSource.keyPressed(keyEvent);
+            break;
+
+        case KEY_UP:
+            _keyEventSource.keyReleased(keyEvent);
+            break;
+
+        case KEY_PRESS:
+            break;
+
+        default:
+            assert (false);
+            break;
+        }
+    }
+
+    private KeyEvent map(InputEventType event, int code, int modifiers) {
+        int keycode = KeysymToKeycode.getKeycode(code);
+        char keyChar = (char)keycode;
+
+        KeyEvent keyEvent = null;
+        int modifier = mapModifier(modifiers);
+
+        switch (event) {
+        case KEY_DOWN:
+            keyEvent = new KeyEvent(_canvas, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), modifier, keycode, keyChar);
+            break;
+
+        case KEY_UP:
+            keyEvent = new KeyEvent(_canvas, KeyEvent.KEY_RELEASED, System.currentTimeMillis(), modifier, keycode, keyChar);
+            break;
+
+        case KEY_PRESS:
+            break;
+
+        default:
+            assert (false);
+            break;
+        }
+        return keyEvent;
+    }
+
+    @Override
+    public void sendClientMouseEvent(InputEventType event, int x, int y, int code, int modifiers) {
+        if (_client == null)
+            return;
+        updateFrontEndActivityTime();
+
+        int mousecode = mapMouseButton(code);
+        int modifier = mapMouseModifier(code, modifiers);
+
+        /*if (event == InputEventType.MOUSE_DOWN) {
+            _mouseEventSource.mousePressed(new MouseEvent(_canvas, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(), modifier, x, y, 1, false, mousecode));
+        }
+
+        if (event == InputEventType.MOUSE_UP) {
+            _mouseEventSource.mouseReleased((new MouseEvent(_canvas, MouseEvent.MOUSE_RELEASED, System.currentTimeMillis(), modifier, x, y, 1, false, mousecode)));
+        }
+
+        if (event == InputEventType.MOUSE_DBLCLICK) {
+            _mouseEventSource.mouseReleased((new MouseEvent(_canvas, MouseEvent.MOUSE_RELEASED, System.currentTimeMillis(), modifier, x, y, 2, false, mousecode)));
+        }*/
+    }
+
+    public int mapMouseModifier(int code, int modifiers) {
+        int mod = mapModifier(modifiers);
+        switch (code) {
+        case 0:
+            return mod = mod | MouseEvent.BUTTON1_DOWN_MASK;
+        case 2:
+            return mod = mod | MouseEvent.BUTTON3_DOWN_MASK;
+        default:
+        }
+        return mod;
+    }
+
+    private int mapModifier(int modifiers) {
+        int mod = 0;
+        if ((modifiers & SHIFT_KEY_MASK) != (_lastModifierStates & SHIFT_KEY_MASK)) {
+            if ((modifiers & SHIFT_KEY_MASK) != 0)
+                mod = mod | InputEvent.SHIFT_DOWN_MASK;
+        }
+
+        if ((modifiers & CTRL_KEY_MASK) != (_lastModifierStates & CTRL_KEY_MASK)) {
+            if ((modifiers & CTRL_KEY_MASK) != 0)
+                mod = mod | InputEvent.CTRL_DOWN_MASK;
+        }
+
+        if ((modifiers & META_KEY_MASK) != (_lastModifierStates & META_KEY_MASK)) {
+            if ((modifiers & META_KEY_MASK) != 0)
+                mod = mod | InputEvent.META_DOWN_MASK;
+        }
+
+        if ((modifiers & ALT_KEY_MASK) != (_lastModifierStates & ALT_KEY_MASK)) {
+            if ((modifiers & ALT_KEY_MASK) != 0)
+                mod = mod | InputEvent.ALT_DOWN_MASK;
+        }
+        _lastModifierStates = mod;
+        return mod;
+    }
+
+    public int mapMouseButton(int code) {
+        switch (code) {
+        case 0:
+            return MouseEvent.BUTTON1;
+        case 2:
+            return MouseEvent.BUTTON3;
+        default:
+            return MouseEvent.BUTTON2;
+        }
+
+    }
+
+    @Override
+    public void initClient(final ConsoleProxyClientParam param) {
+        _workerDone = false;
+
+        int canvasWidth = 1024;
+        int canvasHeight = 768;
+        setClientParam(param);
+
+        final String host = param.getHypervHost();
+        final String password = param.getPassword();
+        final String instanceId = param.getClientHostAddress();
+        final int port = param.getClientHostPort();
+
+        _screen = new ScreenDescription();
+        _canvas = new RdpBufferedImageCanvas(this, canvasWidth, canvasHeight);
+        onFramebufferSizeChange(canvasWidth, canvasHeight);
+
+        _screen.addSizeChangeListener(new SizeChangeListener() {
+            @Override
+            public void sizeChanged(int width, int height) {
+                if (_canvas != null) {
+                    _canvas.setCanvasSize(width, height);
+                }
+            }
+        });
+
+        final SSLState sslState = new SSLState();
+
+        final String username = param.getUsername();
+        String name = null;
+        String domain = null;
+        if (username.contains("\\")) {
+            String[] tokens = username.split("\\\\");
+            name = tokens[1];
+            domain = tokens[0];
+        } else {
+            name = username;
+            domain = "Workgroup";
+        }
+
+        _client = new RdpClient("client", host, domain, name, password, instanceId, _screen, _canvas,
+                sslState);
+
+        _mouseEventSource = _client.getMouseEventSource();
+        _keyEventSource = _client.getKeyEventSource();
+
+        _worker = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                _socket = new AprSocketWrapperImpl("socket", sslState);
+                Pipeline pipeline = new PipelineImpl("Client");
+                pipeline.add(_socket, _client);
+                pipeline.link("socket", _client.getId(), "socket");
+                pipeline.validate();
+
+                InetSocketAddress address = new InetSocketAddress(host, port);
+                ConsoleProxy.ensureRoute(host);
+
+                try {
+                    // Connect socket to remote server and run main loop(s)
+                    _socket.connect(address);
+                } catch (IOException e) {
+                    e.printStackTrace();
+                } finally {
+                    shutdown();
+                }
+
+                s_logger.info("Receiver thread stopped.");
+                _workerDone = true;
+            }
+        });
+        _worker.setDaemon(true);
+        _worker.start();
+    }
+
+    @Override
+    public void closeClient() {
+        _workerDone = true;
+        shutdown();
+    }
+
+    @Override
+    protected FrameBufferCanvas getFrameBufferCavas() {
+        return _canvas;
+    }
+
+    protected void shutdown() {
+        if (_socket != null)
+            _socket.shutdown();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/services/console-proxy/server/src/com/cloud/consoleproxy/rdp/KeysymToKeycode.java
----------------------------------------------------------------------
diff --git a/services/console-proxy/server/src/com/cloud/consoleproxy/rdp/KeysymToKeycode.java b/services/console-proxy/server/src/com/cloud/consoleproxy/rdp/KeysymToKeycode.java
new file mode 100644
index 0000000..10282ad
--- /dev/null
+++ b/services/console-proxy/server/src/com/cloud/consoleproxy/rdp/KeysymToKeycode.java
@@ -0,0 +1,115 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.consoleproxy.rdp;
+
+import java.awt.event.KeyEvent;
+
+public class KeysymToKeycode {
+
+    // this keymap is taken from http://openwonderland.googlecode.com/svn/trunk/modules/foundation/xremwin/src/classes/org/jdesktop/wonderland/modules/xremwin/client/KeycodeToKeysym.java
+    private final static int[][] map = {
+            /* XK_BackSpace         */{0xFF08, KeyEvent.VK_BACK_SPACE},
+            /* XK_Tab               */{0xFF09, KeyEvent.VK_TAB},
+            /* XK_Clear             */{0xFF0B, KeyEvent.VK_CLEAR},
+            /* XK_Return            */{0xFF0D, KeyEvent.VK_ENTER},
+            /* XK_Pause             */{0xFF13, KeyEvent.VK_PAUSE},
+            /* XK_Scroll_Lock       */{0xFF14, KeyEvent.VK_SCROLL_LOCK},
+            /* XK_Escape            */{0xFF1B, KeyEvent.VK_ESCAPE},
+            /* XK_Delete            */{0xFFFF, KeyEvent.VK_DELETE},
+            /* XK_Home              */{0xFF50, KeyEvent.VK_HOME},
+            /* XK_Left              */{0xFF51, KeyEvent.VK_LEFT},
+            /* XK_Up                */{0xFF52, KeyEvent.VK_UP},
+            /* XK_Right             */{0xFF53, KeyEvent.VK_RIGHT},
+            /* XK_Down              */{0xFF54, KeyEvent.VK_DOWN},
+            /* XK_Page_Up           */{0xFF55, KeyEvent.VK_PAGE_UP},
+            /* XK_Page_Down         */{0xFF56, KeyEvent.VK_PAGE_DOWN},
+            /* XK_End               */{0xFF57, KeyEvent.VK_END},
+            /* XK_Print             */{0xFF61, KeyEvent.VK_PRINTSCREEN},
+            /* XK_Insert            */{0xFF63, KeyEvent.VK_INSERT},
+            /* XK_Undo              */{0xFF65, KeyEvent.VK_UNDO},
+            /* XK_Find              */{0xFF68, KeyEvent.VK_FIND},
+            /* XK_Cancel            */{0xFF69, KeyEvent.VK_CANCEL},
+            /* XK_Help              */{0xFF6A, KeyEvent.VK_HELP},
+            /* XK_Mode_switch       */{0xFF7E, KeyEvent.VK_MODECHANGE},
+            /* XK_Num_Lock          */{0xFF7F, KeyEvent.VK_NUM_LOCK},
+            /* XK_F1                */{0xFFBE, KeyEvent.VK_F1},
+            /* XK_F2                */{0xFFBF, KeyEvent.VK_F2},
+            /* XK_F3                */{0xFFC0, KeyEvent.VK_F3},
+            /* XK_F4                */{0xFFC1, KeyEvent.VK_F4},
+            /* XK_F5                */{0xFFC2, KeyEvent.VK_F5},
+            /* XK_F6                */{0xFFC3, KeyEvent.VK_F6},
+            /* XK_F7                */{0xFFC4, KeyEvent.VK_F7},
+            /* XK_F8                */{0xFFC5, KeyEvent.VK_F8},
+            /* XK_F9                */{0xFFC6, KeyEvent.VK_F9},
+            /* XK_F10               */{0xFFC7, KeyEvent.VK_F10},
+            /* XK_F11               */{0xFFC8, KeyEvent.VK_F11},
+            /* XK_F12               */{0xFFC9, KeyEvent.VK_F12},
+            /* XK_F13               */{0xFFCA, KeyEvent.VK_F13},
+            /* XK_F14               */{0xFFCB, KeyEvent.VK_F14},
+            /* XK_F15               */{0xFFCC, KeyEvent.VK_F15},
+            /* XK_F16               */{0xFFCD, KeyEvent.VK_F16},
+            /* XK_F17               */{0xFFCE, KeyEvent.VK_F17},
+            /* XK_F18               */{0xFFCF, KeyEvent.VK_F18},
+            /* XK_F19               */{0xFFD0, KeyEvent.VK_F19},
+            /* XK_F20               */{0xFFD1, KeyEvent.VK_F20},
+            /* XK_F21               */{0xFFD2, KeyEvent.VK_F21},
+            /* XK_F22               */{0xFFD3, KeyEvent.VK_F22},
+            /* XK_F23               */{0xFFD4, KeyEvent.VK_F23},
+            /* XK_F24               */{0xFFD5, KeyEvent.VK_F24},
+            /* XK_Shift_L           */{0xFFE1, KeyEvent.VK_SHIFT},
+            /* XK_Control_L         */{0xFFE3, KeyEvent.VK_CONTROL},
+            /* XK_Caps_Lock         */{0xFFE5, KeyEvent.VK_CAPS_LOCK},
+            /* XK_Meta_L            */{0xFFE7, KeyEvent.VK_META},
+            /* XK_Alt_L             */{0xFFE9, KeyEvent.VK_ALT},
+            /* XK_a                 */{0x0061, KeyEvent.VK_A},
+            /* XK_b                 */{0x0062, KeyEvent.VK_B},
+            /* XK_c                 */{0x0063, KeyEvent.VK_C},
+            /* XK_d                 */{0x0064, KeyEvent.VK_D},
+            /* XK_e                 */{0x0065, KeyEvent.VK_E},
+            /* XK_f                 */{0x0066, KeyEvent.VK_F},
+            /* XK_g                 */{0x0067, KeyEvent.VK_G},
+            /* XK_h                 */{0x0068, KeyEvent.VK_H},
+            /* XK_i                 */{0x0069, KeyEvent.VK_I},
+            /* XK_j                 */{0x006a, KeyEvent.VK_J},
+            /* XK_k                 */{0x006b, KeyEvent.VK_K},
+            /* XK_l                 */{0x006c, KeyEvent.VK_L},
+            /* XK_m                 */{0x006d, KeyEvent.VK_M},
+            /* XK_n                 */{0x006e, KeyEvent.VK_N},
+            /* XK_o                 */{0x006f, KeyEvent.VK_O},
+            /* XK_p                 */{0x0070, KeyEvent.VK_P},
+            /* XK_q                 */{0x0071, KeyEvent.VK_Q},
+            /* XK_r                 */{0x0072, KeyEvent.VK_R},
+            /* XK_s                 */{0x0073, KeyEvent.VK_S},
+            /* XK_t                 */{0x0074, KeyEvent.VK_T},
+            /* XK_u                 */{0x0075, KeyEvent.VK_U},
+            /* XK_v                 */{0x0076, KeyEvent.VK_V},
+            /* XK_w                 */{0x0077, KeyEvent.VK_W},
+            /* XK_x                 */{0x0078, KeyEvent.VK_X},
+            /* XK_y                 */{0x0079, KeyEvent.VK_Y},
+            /* XK_z                 */{0x007a, KeyEvent.VK_Z},
+    };
+
+    public static int getKeycode(int keysym) {
+        for (int i = 0; i < (map.length - 1); i++) {
+            if (map[i][0] == keysym) {
+                return map[i][1];
+            }
+        }
+        return keysym;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b55d9ecf/services/console-proxy/server/src/com/cloud/consoleproxy/rdp/RdpBufferedImageCanvas.java
----------------------------------------------------------------------
diff --git a/services/console-proxy/server/src/com/cloud/consoleproxy/rdp/RdpBufferedImageCanvas.java b/services/console-proxy/server/src/com/cloud/consoleproxy/rdp/RdpBufferedImageCanvas.java
new file mode 100644
index 0000000..6dabe05
--- /dev/null
+++ b/services/console-proxy/server/src/com/cloud/consoleproxy/rdp/RdpBufferedImageCanvas.java
@@ -0,0 +1,103 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.consoleproxy.rdp;
+
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.List;
+
+import com.cloud.consoleproxy.ConsoleProxyRdpClient;
+import com.cloud.consoleproxy.util.ImageHelper;
+import com.cloud.consoleproxy.util.TileInfo;
+import com.cloud.consoleproxy.vnc.FrameBufferCanvas;
+
+import common.BufferedImageCanvas;
+
+public class RdpBufferedImageCanvas extends BufferedImageCanvas implements FrameBufferCanvas {
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 1L;
+
+    private final ConsoleProxyRdpClient _rdpClient;
+
+    public RdpBufferedImageCanvas(ConsoleProxyRdpClient client, int width, int height) {
+        super(width, height);
+        _rdpClient = client;
+    }
+
+    @Override
+    public Image getFrameBufferScaledImage(int width, int height) {
+        if (offlineImage != null)
+            return offlineImage.getScaledInstance(width, height, Image.SCALE_DEFAULT);
+        return null;
+    }
+
+    @Override
+    public byte[] getFrameBufferJpeg() {
+        int width = offlineImage.getWidth();
+        int height = offlineImage.getHeight();
+
+        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
+        Graphics2D g = bufferedImage.createGraphics();
+        synchronized (offlineImage) {
+            g.drawImage(offlineImage, 0, 0, width, height, 0, 0, width, height, null);
+            g.dispose();
+        }
+
+        byte[] imgBits = null;
+        try {
+            imgBits = ImageHelper.jpegFromImage(bufferedImage);
+        } catch (IOException e) {
+        }
+
+        return imgBits;
+    }
+
+    @Override
+    public byte[] getTilesMergedJpeg(List<TileInfo> tileList, int tileWidth, int tileHeight) {
+        int width = Math.max(tileWidth, tileWidth * tileList.size());
+
+        BufferedImage bufferedImage = new BufferedImage(width, tileHeight, BufferedImage.TYPE_3BYTE_BGR);
+        Graphics2D g = bufferedImage.createGraphics();
+
+        synchronized (offlineImage) {
+            int i = 0;
+            for (TileInfo tile : tileList) {
+                Rectangle rc = tile.getTileRect();
+                g.drawImage(offlineImage, i * tileWidth, 0, i * tileWidth + rc.width, rc.height, rc.x, rc.y, rc.x + rc.width, rc.y + rc.height, null);
+                i++;
+            }
+        }
+
+        byte[] imgBits = null;
+        try {
+            imgBits = ImageHelper.jpegFromImage(bufferedImage);
+        } catch (IOException e) {
+        }
+        return imgBits;
+    }
+
+    @Override
+    public void updateFrameBuffer(int x, int y, int w, int h) {
+        _rdpClient.onFramebufferUpdate(x, y, w, h);
+    }
+
+}