CLOUDSTACK-5344 commit for console proxy rdp for hyperv

This commit is contained in:
Anshul Gangwar 2013-12-31 00:56:27 +05:30 committed by Rajesh Battala
parent 206c35c620
commit 5941ac46d2
16 changed files with 765 additions and 36 deletions

View File

@ -2000,6 +2000,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();

View File

@ -16,6 +16,7 @@
// under the License.
package com.cloud.server;
import com.cloud.host.DetailVO;
import com.cloud.host.HostVO;
import com.cloud.storage.GuestOSVO;
import com.cloud.utils.Pair;
@ -47,6 +48,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);

View File

@ -854,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();

View File

@ -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;
@ -89,26 +93,51 @@ public class ConsoleProxyClientParam {
this.clientTunnelSession = clientTunnelSession;
}
public String getLocale() {
return this.locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public String getAjaxSessionId() {
return this.ajaxSessionId;
return ajaxSessionId;
}
public void setAjaxSessionId(String ajaxSessionId) {
this.ajaxSessionId = ajaxSessionId;
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public String getClientMapKey() {
if (clientTag != null && !clientTag.isEmpty())
return clientTag;
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;
}
}

View File

@ -328,15 +328,21 @@ 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];
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 = "";
host = hostInfo;
}
} else {
host = hostInfo;
@ -389,28 +395,49 @@ 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())
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());
}

View File

@ -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;
@ -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
}
}

View File

@ -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);
}

View File

@ -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.
*/
@ -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;
}
}

View File

@ -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>

View File

@ -196,8 +196,8 @@ public class ConsoleProxy {
Object result;
try {
result =
authMethod.invoke(ConsoleProxy.context, param.getClientHostAddress(), String.valueOf(param.getClientHostPort()), param.getClientTag(),
param.getClientHostPassword(), param.getTicket(), new Boolean(reauthentication));
authMethod.invoke(ConsoleProxy.context, param.getClientHostAddress(), String.valueOf(param.getClientHostPort()), param.getClientTag(),
param.getClientHostPassword(), param.getTicket(), new Boolean(reauthentication));
} catch (IllegalAccessException e) {
s_logger.error("Unable to invoke authenticateConsoleAccess due to IllegalAccessException" + " for vm: " + param.getClientTag(), e);
authResult.setSuccess(false);
@ -407,7 +407,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);
@ -418,7 +418,7 @@ public class ConsoleProxy {
viewer.initClient(param);
} else if (!param.getClientHostPassword().equals(viewer.getClientHostPassword())) {
s_logger.warn("Bad sid detected(VNC port may be reused). sid in session: " + viewer.getClientHostPassword() + ", sid in request: " +
param.getClientHostPassword());
param.getClientHostPassword());
viewer.initClient(param);
}
}
@ -442,7 +442,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);
@ -457,7 +457,7 @@ public class ConsoleProxy {
}
if (param.getClientHostPassword() == null || param.getClientHostPassword().isEmpty() ||
!param.getClientHostPassword().equals(viewer.getClientHostPassword()))
!param.getClientHostPassword().equals(viewer.getClientHostPassword()))
throw new AuthenticationException("Cannot use the existing viewer " + viewer + ": bad sid");
if (!viewer.isFrontEndAlive()) {
@ -479,6 +479,14 @@ public class ConsoleProxy {
}
}
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()) {

View File

@ -80,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 = "";
@ -128,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) {

View File

@ -33,6 +33,10 @@ public class ConsoleProxyClientParam {
private String locale;
private String ajaxSessionId;
private String hypervHost;
private String username;
private String password;
public ConsoleProxyClientParam() {
clientHostPort = 0;
}
@ -94,7 +98,7 @@ public class ConsoleProxyClientParam {
}
public String getAjaxSessionId() {
return this.ajaxSessionId;
return ajaxSessionId;
}
public void setAjaxSessionId(String ajaxSessionId) {
@ -102,7 +106,7 @@ public class ConsoleProxyClientParam {
}
public String getLocale() {
return this.locale;
return locale;
}
public void setLocale(String locale) {
@ -115,4 +119,28 @@ public class ConsoleProxyClientParam {
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;
}
}

View File

@ -54,14 +54,29 @@ public class ConsoleProxyHttpHandlerHelper {
// make sure we get information from token only
guardUserInput(map);
if (param != null) {
if (param.getClientHostAddress() != null)
if (param.getClientHostAddress() != null) {
s_logger.debug("decode token. host: " + param.getClientHostAddress());
map.put("host", param.getClientHostAddress());
if (param.getClientHostPort() != 0)
} else {
s_logger.error("decode token. host info is not found!");
}
if (param.getClientHostPort() != 0) {
s_logger.debug("decode token. port: " + param.getClientHostPort());
map.put("port", String.valueOf(param.getClientHostPort()));
if (param.getClientTag() != null)
} else {
s_logger.error("decode token. port info is not found!");
}
if (param.getClientTag() != null) {
s_logger.debug("decode token. tag: " + param.getClientTag());
map.put("tag", param.getClientTag());
if (param.getClientHostPassword() != null)
} else {
s_logger.error("decode token. tag info is not found!");
}
if (param.getClientHostPassword() != null) {
map.put("sid", param.getClientHostPassword());
} else {
s_logger.error("decode token. sid info is not found!");
}
if (param.getClientTunnelUrl() != null)
map.put("consoleurl", param.getClientTunnelUrl());
if (param.getClientTunnelSession() != null)
@ -70,6 +85,14 @@ 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 {
s_logger.error("Unable to decode token");
}
} else {
// we no longer accept information from parameter other than token
@ -88,5 +111,8 @@ public class ConsoleProxyHttpHandlerHelper {
map.remove("sessionref");
map.remove("ticket");
map.remove("locale");
map.remove("hypervHost");
map.remove("username");
map.remove("password");
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}