mirror of https://github.com/apache/cloudstack.git
CLOUDSTACK-5344 commit for console proxy rdp for hyperv
This commit is contained in:
parent
9ec137e75b
commit
b55d9ecf53
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -855,6 +854,11 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||
return _hostDao.findById(hostId);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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("<"); break;
|
||||
case '>': sb.append(">"); break;
|
||||
case '&': sb.append("&"); break;
|
||||
case '"': sb.append("""); break;
|
||||
case ' ': sb.append(" ");break;
|
||||
default: sb.append(c); break;
|
||||
case '<':
|
||||
sb.append("<");
|
||||
break;
|
||||
case '>':
|
||||
sb.append(">");
|
||||
break;
|
||||
case '&':
|
||||
sb.append("&");
|
||||
break;
|
||||
case '"':
|
||||
sb.append(""");
|
||||
break;
|
||||
case ' ':
|
||||
sb.append(" ");
|
||||
break;
|
||||
default:
|
||||
sb.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue