mirror of https://github.com/apache/cloudstack.git
Console proxy refactoring - new VNC engine is plugged in
This commit is contained in:
parent
bed3f7f7e2
commit
27c77133d4
File diff suppressed because it is too large
Load Diff
|
|
@ -114,22 +114,11 @@ public class ConsoleProxyAjaxHandler implements HttpHandler {
|
|||
}
|
||||
}
|
||||
|
||||
ConsoleProxyViewer viewer = null;
|
||||
ConsoleProxyClient viewer = null;
|
||||
try {
|
||||
viewer = ConsoleProxy.getAjaxVncViewer(host, port, sid, tag, ticket, ajaxSessionIdStr);
|
||||
} catch(Exception e) {
|
||||
|
||||
/*
|
||||
StringWriter writer = new StringWriter();
|
||||
try {
|
||||
ConsoleProxy.processTemplate("viewer-bad-sid.ftl", null, writer);
|
||||
} catch (IOException ex) {
|
||||
s_logger.warn("Unexpected exception in processing template.", e);
|
||||
} catch (TemplateException ex) {
|
||||
s_logger.warn("Unexpected exception in processing template.", e);
|
||||
}
|
||||
StringBuffer sb = writer.getBuffer();
|
||||
*/
|
||||
s_logger.warn("Failed to create viwer due to " + e.getMessage(), e);
|
||||
|
||||
String[] content = new String[] {
|
||||
|
|
@ -236,7 +225,8 @@ public class ConsoleProxyAjaxHandler implements HttpHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private void handleClientEventBag(ConsoleProxyViewer viewer, String requestData) {
|
||||
@SuppressWarnings("deprecation")
|
||||
private void handleClientEventBag(ConsoleProxyClient viewer, String requestData) {
|
||||
if(s_logger.isTraceEnabled())
|
||||
s_logger.trace("Handle event bag, event bag: " + requestData);
|
||||
|
||||
|
|
@ -294,7 +284,7 @@ public class ConsoleProxyAjaxHandler implements HttpHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private void handleClientEvent(ConsoleProxyViewer viewer, int event, Map<String, String> queryMap) {
|
||||
private void handleClientEvent(ConsoleProxyClient viewer, int event, Map<String, String> queryMap) {
|
||||
int code = 0;
|
||||
int x = 0, y = 0;
|
||||
int modifiers = 0;
|
||||
|
|
@ -347,7 +337,7 @@ public class ConsoleProxyAjaxHandler implements HttpHandler {
|
|||
if(s_logger.isTraceEnabled())
|
||||
s_logger.trace("Handle client mouse move event. x: " + x + ", y: " + y);
|
||||
}
|
||||
viewer.sendClientMouseEvent(event, x, y, code, modifiers);
|
||||
viewer.sendClientMouseEvent(InputEventType.fromEventCode(event), x, y, code, modifiers);
|
||||
break;
|
||||
|
||||
case 4: // key press
|
||||
|
|
@ -371,7 +361,7 @@ public class ConsoleProxyAjaxHandler implements HttpHandler {
|
|||
|
||||
if(s_logger.isDebugEnabled())
|
||||
s_logger.debug("Handle client keyboard event. event: " + event + ", code: " + code + ", modifier: " + modifiers);
|
||||
viewer.sendClientRawKeyboardEvent(event, code, modifiers);
|
||||
viewer.sendClientRawKeyboardEvent(InputEventType.fromEventCode(event), code, modifiers);
|
||||
break;
|
||||
|
||||
default :
|
||||
|
|
@ -379,7 +369,7 @@ public class ConsoleProxyAjaxHandler implements HttpHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private void handleClientKickoff(HttpExchange t, ConsoleProxyViewer viewer) throws IOException {
|
||||
private void handleClientKickoff(HttpExchange t, ConsoleProxyClient viewer) throws IOException {
|
||||
String response = viewer.onAjaxClientKickoff();
|
||||
t.sendResponseHeaders(200, response.length());
|
||||
OutputStream os = t.getResponseBody();
|
||||
|
|
@ -390,7 +380,7 @@ public class ConsoleProxyAjaxHandler implements HttpHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private void handleClientStart(HttpExchange t, ConsoleProxyViewer viewer, String title, String guest) throws IOException {
|
||||
private void handleClientStart(HttpExchange t, ConsoleProxyClient viewer, String title, String guest) throws IOException {
|
||||
List<String> languages = t.getRequestHeaders().get("Accept-Language");
|
||||
String response = viewer.onAjaxClientStart(title, languages, guest);
|
||||
|
||||
|
|
@ -408,7 +398,7 @@ public class ConsoleProxyAjaxHandler implements HttpHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private void handleClientUpdate(HttpExchange t, ConsoleProxyViewer viewer) throws IOException {
|
||||
private void handleClientUpdate(HttpExchange t, ConsoleProxyClient viewer) throws IOException {
|
||||
String response = viewer.onAjaxClientUpdate();
|
||||
|
||||
Headers hds = t.getResponseHeaders();
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ public class ConsoleProxyAjaxImageHandler implements HttpHandler {
|
|||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
|
||||
ConsoleProxyViewer viewer = ConsoleProxy.getVncViewer(host, port, sid, tag, ticket);
|
||||
ConsoleProxyClient viewer = ConsoleProxy.getVncViewer(host, port, sid, tag, ticket);
|
||||
byte[] img = viewer.getAjaxImageCache().getImage(key);
|
||||
if(img != null) {
|
||||
Headers hds = t.getResponseHeaders();
|
||||
|
|
|
|||
|
|
@ -1,25 +1,56 @@
|
|||
package com.cloud.consoleproxy;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Kelven Yang
|
||||
* ConsoleProxyClient defines an standard interface that a console client should implement,
|
||||
* example of such console clients could be a VNC client or a RDP client
|
||||
*
|
||||
* ConsoleProxyClient maintains a session towards the target host, it glues the session
|
||||
* to a AJAX frontend viewer
|
||||
* to a AJAX front-end viewer
|
||||
*/
|
||||
public interface ConsoleProxyClient {
|
||||
int getClientId();
|
||||
|
||||
//
|
||||
// Quick status
|
||||
//
|
||||
boolean isHostConnected();
|
||||
boolean isFrontEndAlive();
|
||||
|
||||
//
|
||||
// AJAX viewer
|
||||
//
|
||||
long getAjaxSessionId();
|
||||
AjaxFIFOImageCache getAjaxImageCache();
|
||||
Image getClientScaledImage(int width, int height); // client thumbnail support
|
||||
|
||||
String onAjaxClientStart(String title, List<String> languages, String guest);
|
||||
String onAjaxClientUpdate();
|
||||
String onAjaxClientKickoff();
|
||||
|
||||
//
|
||||
// Input handling
|
||||
//
|
||||
void sendClientRawKeyboardEvent(InputEventType event, int code, int modifiers);
|
||||
void sendClientMouseEvent(InputEventType event, int x, int y, int code, int modifiers);
|
||||
|
||||
//
|
||||
// Info/Stats
|
||||
//
|
||||
long getClientCreateTime();
|
||||
long getClientLastFrontEndActivityTime();
|
||||
|
||||
String getClientHostAddress();
|
||||
int getClientHostPort();
|
||||
String getClientHostPassword();
|
||||
String getClientTag();
|
||||
|
||||
//
|
||||
// Setup/house-keeping
|
||||
//
|
||||
void initClient(String clientHostAddress, int clientHostPort,
|
||||
String clientHostPassword, String clientTag);
|
||||
String clientHostPassword, String clientTag, String ticket);
|
||||
void closeClient();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.cloud.consoleproxy;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -8,7 +9,6 @@ import org.apache.log4j.Logger;
|
|||
import com.cloud.console.TileInfo;
|
||||
import com.cloud.console.TileTracker;
|
||||
import com.cloud.consoleproxy.vnc.FrameBufferCanvas;
|
||||
import com.cloud.consoleproxy.vnc.FrameBufferEventListener;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -20,7 +20,7 @@ import com.cloud.consoleproxy.vnc.FrameBufferEventListener;
|
|||
* It mainly implements the features needed by front-end AJAX viewer
|
||||
*
|
||||
*/
|
||||
public abstract class ConsoleProxyClientBase implements ConsoleProxyClient, FrameBufferEventListener {
|
||||
public abstract class ConsoleProxyClientBase implements ConsoleProxyClient, ConsoleProxyClientListener {
|
||||
private static final Logger s_logger = Logger.getLogger(ConsoleProxyClientBase.class);
|
||||
|
||||
private static int s_nextClientId = 0;
|
||||
|
|
@ -37,6 +37,7 @@ public abstract class ConsoleProxyClientBase implements ConsoleProxyClient, Fram
|
|||
protected int port;
|
||||
protected String passwordParam;
|
||||
protected String tag = "";
|
||||
protected String ticket = "";
|
||||
protected long createTime = System.currentTimeMillis();
|
||||
protected long lastFrontEndActivityTime = System.currentTimeMillis();
|
||||
|
||||
|
|
@ -45,6 +46,8 @@ public abstract class ConsoleProxyClientBase implements ConsoleProxyClient, Fram
|
|||
protected int resizedFramebufferHeight;
|
||||
|
||||
public ConsoleProxyClientBase() {
|
||||
tracker = new TileTracker();
|
||||
tracker.initTracking(64, 64, 800, 600);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -55,6 +58,30 @@ public abstract class ConsoleProxyClientBase implements ConsoleProxyClient, Fram
|
|||
return clientId;
|
||||
}
|
||||
|
||||
public abstract boolean isHostConnected();
|
||||
public abstract boolean isFrontEndAlive();
|
||||
|
||||
@Override
|
||||
public long getAjaxSessionId() {
|
||||
return this.ajaxSessionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AjaxFIFOImageCache getAjaxImageCache() {
|
||||
return ajaxImageCache;
|
||||
}
|
||||
|
||||
public Image getClientScaledImage(int width, int height) {
|
||||
FrameBufferCanvas canvas = getFrameBufferCavas();
|
||||
if(canvas != null)
|
||||
return canvas.getFrameBufferScaledImage(width, height);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract void sendClientRawKeyboardEvent(InputEventType event, int code, int modifiers);
|
||||
public abstract void sendClientMouseEvent(InputEventType event, int x, int y, int code, int modifiers);
|
||||
|
||||
@Override
|
||||
public long getClientCreateTime() {
|
||||
return createTime;
|
||||
|
|
@ -87,8 +114,8 @@ public abstract class ConsoleProxyClientBase implements ConsoleProxyClient, Fram
|
|||
|
||||
@Override
|
||||
public abstract void initClient(String clientHostAddress, int clientHostPort,
|
||||
String clientHostPassword, String clientTag);
|
||||
|
||||
String clientHostPassword, String clientTag, String ticket);
|
||||
|
||||
@Override
|
||||
public abstract void closeClient();
|
||||
|
||||
|
|
@ -170,6 +197,7 @@ public abstract class ConsoleProxyClientBase implements ConsoleProxyClient, Fram
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String onAjaxClientKickoff() {
|
||||
return "onKickoff();";
|
||||
}
|
||||
|
|
@ -193,8 +221,11 @@ public abstract class ConsoleProxyClientBase implements ConsoleProxyClient, Fram
|
|||
"Unable to start console session as connection is refused by the machine you are accessing" +
|
||||
"</p></div></body></html>";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String onAjaxClientStart(String title, List<String> languages, String guest) {
|
||||
updateFrontEndActivityTime();
|
||||
|
||||
if(!waitForViewerReady())
|
||||
return onAjaxClientConnectFailed();
|
||||
|
||||
|
|
@ -317,8 +348,10 @@ public abstract class ConsoleProxyClientBase implements ConsoleProxyClient, Fram
|
|||
public String onAjaxClientDisconnected() {
|
||||
return "onDisconnect();";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String onAjaxClientUpdate() {
|
||||
updateFrontEndActivityTime();
|
||||
if(!waitForViewerReady())
|
||||
return onAjaxClientDisconnected();
|
||||
|
||||
|
|
@ -386,14 +419,6 @@ public abstract class ConsoleProxyClientBase implements ConsoleProxyClient, Fram
|
|||
return ++s_nextClientId;
|
||||
}
|
||||
|
||||
public long getAjaxSessionId() {
|
||||
return this.ajaxSessionId;
|
||||
}
|
||||
|
||||
public AjaxFIFOImageCache getAjaxImageCache() {
|
||||
return ajaxImageCache;
|
||||
}
|
||||
|
||||
private void signalTileDirtyEvent() {
|
||||
synchronized(tileDirtyEvent) {
|
||||
dirtyFlag = true;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ import java.util.StringTokenizer;
|
|||
import com.cloud.console.Logger;
|
||||
import com.cloud.console.RfbProto;
|
||||
|
||||
public class ConsoleProxyClientHandler extends Thread {
|
||||
public class ConsoleProxyClientHandler extends Thread {
|
||||
/*
|
||||
private static final Logger s_logger = Logger.getLogger(ConsoleProxyClientHandler.class);
|
||||
|
||||
Socket clientSocket = null;
|
||||
|
|
@ -274,5 +275,6 @@ public class ConsoleProxyClientHandler extends Thread {
|
|||
} finally {
|
||||
viewer.lastUsedTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package com.cloud.consoleproxy;
|
||||
|
||||
public interface ConsoleProxyClientListener {
|
||||
void onFramebufferSizeChange(int w, int h);
|
||||
void onFramebufferUpdate(int x, int y, int w, int h);
|
||||
|
||||
void onClientConnected();
|
||||
void onClientClose();
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.cloud.consoleproxy;
|
||||
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
|
|
@ -28,6 +29,11 @@ public class ConsoleProxyClientStatsCollector {
|
|||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
return gson.toJson(this);
|
||||
}
|
||||
|
||||
public void getStatsReport(OutputStreamWriter os) {
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
gson.toJson(this, os);
|
||||
}
|
||||
|
||||
private void setConnections(Hashtable<String, ConsoleProxyClient> connMap) {
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@ import java.io.OutputStream;
|
|||
import java.io.OutputStreamWriter;
|
||||
|
||||
import com.cloud.console.Logger;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.sun.net.httpserver.Headers;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
|
|
@ -60,15 +58,14 @@ public class ConsoleProxyCmdHandler implements HttpHandler {
|
|||
int i = path.indexOf("/", 1);
|
||||
String cmd = path.substring(i + 1);
|
||||
s_logger.info("Get CMD request for " + cmd);
|
||||
if (cmd.equals("getstatus")) {
|
||||
ConsoleProxyStatus status = new ConsoleProxyStatus();
|
||||
status.setConnections(ConsoleProxy.connectionMap);
|
||||
if (cmd.equals("getstatus")) {
|
||||
ConsoleProxyClientStatsCollector statsCollector = ConsoleProxy.getStatsCollector();
|
||||
|
||||
Headers hds = t.getResponseHeaders();
|
||||
hds.set("Content-Type", "text/plain");
|
||||
t.sendResponseHeaders(200, 0);
|
||||
OutputStreamWriter os = new OutputStreamWriter(t.getResponseBody());
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
gson.toJson(status, os);
|
||||
OutputStreamWriter os = new OutputStreamWriter(t.getResponseBody());
|
||||
statsCollector.getStatsReport(os);
|
||||
os.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ public class ConsoleProxyGCThread extends Thread {
|
|||
s_logger.debug("Report load change : " + loadInfo);
|
||||
}
|
||||
|
||||
try { Thread.sleep(30000); } catch (InterruptedException ex) {}
|
||||
try { Thread.sleep(1000); } catch (InterruptedException ex) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,10 +123,10 @@ public class ConsoleProxyMonitor {
|
|||
private static void configLog4j() {
|
||||
URL configUrl = System.class.getResource("/conf/log4j-cloud.xml");
|
||||
if(configUrl == null)
|
||||
configUrl = System.class.getClassLoader().getSystemResource("log4j-cloud.xml");
|
||||
configUrl = ClassLoader.getSystemResource("log4j-cloud.xml");
|
||||
|
||||
if(configUrl == null)
|
||||
configUrl = System.class.getClassLoader().getSystemResource("conf/log4j-cloud.xml");
|
||||
configUrl = ClassLoader.getSystemResource("conf/log4j-cloud.xml");
|
||||
|
||||
if(configUrl != null) {
|
||||
try {
|
||||
|
|
@ -150,7 +150,6 @@ public class ConsoleProxyMonitor {
|
|||
|
||||
public static void main(String[] argv) {
|
||||
configLog4j();
|
||||
|
||||
(new ConsoleProxyMonitor(argv)).run();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.util.ArrayList;
|
|||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/*
|
||||
public class ConsoleProxyStatus {
|
||||
ArrayList<ConsoleProxyConnection> connections;
|
||||
public ConsoleProxyStatus() {
|
||||
|
|
@ -59,3 +60,4 @@ public class ConsoleProxyStatus {
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
@ -93,32 +93,6 @@ public class ConsoleProxyThumbnailHandler implements HttpHandler {
|
|||
OutputStream os = t.getResponseBody();
|
||||
os.write(bs);
|
||||
os.close();
|
||||
|
||||
/*
|
||||
// Send back a dummy image
|
||||
File f = new File ("./images/cannotconnect.jpg");
|
||||
long length = f.length();
|
||||
FileInputStream fis = new FileInputStream(f);
|
||||
Headers hds = t.getResponseHeaders();
|
||||
hds.set("Content-Type", "image/jpeg");
|
||||
hds.set("Cache-Control", "no-cache");
|
||||
hds.set("Cache-Control", "no-store");
|
||||
t.sendResponseHeaders(200, length);
|
||||
OutputStream os = t.getResponseBody();
|
||||
try {
|
||||
while (true) {
|
||||
byte[] b = new byte[8192];
|
||||
int n = fis.read(b);
|
||||
if (n < 0) {
|
||||
break;
|
||||
}
|
||||
os.write(b, 0, n);
|
||||
}
|
||||
} finally {
|
||||
os.close();
|
||||
fis.close();
|
||||
}
|
||||
*/
|
||||
s_logger.error("Cannot get console, sent error JPG response for " + t.getRequestURI());
|
||||
return;
|
||||
} finally {
|
||||
|
|
@ -126,8 +100,7 @@ public class ConsoleProxyThumbnailHandler implements HttpHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private void doHandle(HttpExchange t) throws Exception,
|
||||
IllegalArgumentException {
|
||||
private void doHandle(HttpExchange t) throws Exception, IllegalArgumentException {
|
||||
String queries = t.getRequestURI().getQuery();
|
||||
Map<String, String> queryMap = getQueryMap(queries);
|
||||
int width = 0;
|
||||
|
|
@ -154,9 +127,9 @@ public class ConsoleProxyThumbnailHandler implements HttpHandler {
|
|||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
|
||||
ConsoleProxyViewer viewer = ConsoleProxy.getVncViewer(host, port, sid, tag, ticket);
|
||||
ConsoleProxyClient viewer = ConsoleProxy.getVncViewer(host, port, sid, tag, ticket);
|
||||
|
||||
if (viewer.status != ConsoleProxyViewer.STATUS_NORMAL_OPERATION) {
|
||||
if (!viewer.isHostConnected()) {
|
||||
// use generated image instead of static
|
||||
BufferedImage img = generateTextImage(width, height, "Connecting");
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(8196);
|
||||
|
|
@ -171,54 +144,13 @@ public class ConsoleProxyThumbnailHandler implements HttpHandler {
|
|||
os.write(bs);
|
||||
os.close();
|
||||
|
||||
/*
|
||||
// Send back a dummy image
|
||||
File f = new File ("./images/notready.jpg");
|
||||
long length = f.length();
|
||||
FileInputStream fis = new FileInputStream(f);
|
||||
Headers hds = t.getResponseHeaders();
|
||||
hds.set("Content-Type", "image/jpeg");
|
||||
hds.set("Cache-Control", "no-cache");
|
||||
hds.set("Cache-Control", "no-store");
|
||||
t.sendResponseHeaders(200, length);
|
||||
|
||||
OutputStream os = t.getResponseBody();
|
||||
try {
|
||||
while (true) {
|
||||
byte[] b = new byte[8192];
|
||||
int n = fis.read(b);
|
||||
if (n < 0) {
|
||||
break;
|
||||
}
|
||||
os.write(b, 0, n);
|
||||
}
|
||||
} finally {
|
||||
os.close();
|
||||
fis.close();
|
||||
}
|
||||
*/
|
||||
if(s_logger.isInfoEnabled())
|
||||
s_logger.info("Console not ready, sent dummy JPG response, viewer status : " + viewer.status);
|
||||
s_logger.info("Console not ready, sent dummy JPG response");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
if (viewer.status == ConsoleViewer.STATUS_AUTHENTICATION_FAILURE) {
|
||||
String response = "Authentication failed";
|
||||
t.sendResponseHeaders(200, response.length());
|
||||
OutputStream os = t.getResponseBody();
|
||||
os.write(response.getBytes());
|
||||
os.close();
|
||||
} else if (viewer.vc == null || viewer.vc.memImage == null) {
|
||||
String response = "Server not ready";
|
||||
t.sendResponseHeaders(200, response.length());
|
||||
OutputStream os = t.getResponseBody();
|
||||
os.write(response.getBytes());
|
||||
os.close();
|
||||
} else
|
||||
*/
|
||||
}
|
||||
|
||||
{
|
||||
Image scaledImage = viewer.vc.memImage.getScaledInstance(width,
|
||||
height, Image.SCALE_DEFAULT);
|
||||
Image scaledImage = viewer.getClientScaledImage(width, height);
|
||||
BufferedImage bufferedImage = new BufferedImage(width, height,
|
||||
BufferedImage.TYPE_3BYTE_BGR);
|
||||
Graphics2D bufImageGraphics = bufferedImage.createGraphics();
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ import com.cloud.console.RfbProtoAdapter;
|
|||
import com.cloud.console.RfbViewer;
|
||||
import com.cloud.console.TileInfo;
|
||||
import com.cloud.console.TileTracker;
|
||||
|
||||
|
||||
/*
|
||||
public class ConsoleProxyViewer implements java.lang.Runnable, RfbViewer, RfbProtoAdapter, ITileScanListener {
|
||||
private static final Logger s_logger = Logger.getLogger(ConsoleProxyViewer.class);
|
||||
|
||||
|
|
@ -317,42 +318,6 @@ public class ConsoleProxyViewer implements java.lang.Runnable, RfbViewer, RfbPro
|
|||
}
|
||||
|
||||
static void authenticationExternally(String host, String port, String tag, String sid, String ticket) throws AuthenticationException {
|
||||
/*
|
||||
if(ConsoleProxy.management_host != null) {
|
||||
try {
|
||||
boolean success = false;
|
||||
URL url = new URL(ConsoleProxy.management_host + "/console?cmd=auth&vm=" + getTag() + "&sid=" + passwordParam);
|
||||
|
||||
URLConnection conn = url.openConnection();
|
||||
|
||||
// setting TIMEOUTs to avoid possible waiting until death situations
|
||||
conn.setConnectTimeout(5000);
|
||||
conn.setReadTimeout(5000);
|
||||
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
String inputLine;
|
||||
if ((inputLine = in.readLine()) != null) {
|
||||
if(inputLine.equals("success"))
|
||||
success = true;
|
||||
}
|
||||
in.close();
|
||||
|
||||
if(!success) {
|
||||
if(s_logger.isInfoEnabled())
|
||||
s_logger.info("External authenticator failed authencation request for vm " + getTag() + " with sid " + passwordParam);
|
||||
|
||||
throw new AuthenticationException("Unable to contact external authentication source " + ConsoleProxy.management_host);
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
s_logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
} catch(IOException e) {
|
||||
s_logger.error("Unable to contact external authentication source due to " + e.getMessage(), e);
|
||||
throw new AuthenticationException("Unable to contact external authentication source " + ConsoleProxy.management_host);
|
||||
}
|
||||
} else {
|
||||
s_logger.warn("No external authentication source being setup.");
|
||||
}
|
||||
*/
|
||||
if(!ConsoleProxy.authenticateConsoleAccess(host, port, tag, sid, ticket)) {
|
||||
s_logger.warn("External authenticator failed authencation request for vm " + tag + " with sid " + sid);
|
||||
|
||||
|
|
@ -978,31 +943,6 @@ public class ConsoleProxyViewer implements java.lang.Runnable, RfbViewer, RfbPro
|
|||
i++;
|
||||
}
|
||||
|
||||
/*
|
||||
SimpleHash model = new SimpleHash();
|
||||
model.put("tileSequence", sbTileSequence.toString());
|
||||
model.put("imgUrl", imgUrl);
|
||||
model.put("updateUrl", updateUrl);
|
||||
model.put("width", String.valueOf(width));
|
||||
model.put("height", String.valueOf(height));
|
||||
model.put("tileWidth", String.valueOf(tileWidth));
|
||||
model.put("tileHeight", String.valueOf(tileHeight));
|
||||
model.put("title", title);
|
||||
model.put("rawKeyboard", ConsoleProxy.keyboardType == ConsoleProxy.KEYBOARD_RAW ? "true" : "false");
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
try {
|
||||
ConsoleProxy.processTemplate("viewer.ftl", model, writer);
|
||||
} catch (IOException e) {
|
||||
s_logger.warn("Unexpected exception in processing template.", e);
|
||||
} catch (TemplateException e) {
|
||||
s_logger.warn("Unexpected exception in processing template.", e);
|
||||
}
|
||||
StringBuffer sb = writer.getBuffer();
|
||||
if(s_logger.isTraceEnabled())
|
||||
s_logger.trace("onAjaxClientStart response: " + sb.toString());
|
||||
return sb.toString();
|
||||
*/
|
||||
return getAjaxViewerPageContent(sbTileSequence.toString(), imgUrl,
|
||||
updateUrl, width, height, tileWidth, tileHeight, title,
|
||||
ConsoleProxy.keyboardType == ConsoleProxy.KEYBOARD_RAW, languages, guest);
|
||||
|
|
@ -1129,31 +1069,6 @@ public class ConsoleProxyViewer implements java.lang.Runnable, RfbViewer, RfbPro
|
|||
i++;
|
||||
}
|
||||
|
||||
/*
|
||||
SimpleHash model = new SimpleHash();
|
||||
model.put("tileSequence", sbTileSequence.toString());
|
||||
model.put("resized", doResize);
|
||||
model.put("imgUrl", imgUrl);
|
||||
model.put("width", String.valueOf(resizedFramebufferWidth));
|
||||
model.put("height", String.valueOf(resizedFramebufferHeight));
|
||||
model.put("tileWidth", String.valueOf(tracker.getTileWidth()));
|
||||
model.put("tileHeight", String.valueOf(tracker.getTileHeight()));
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
try {
|
||||
ConsoleProxy.processTemplate("viewer-update.ftl", model, writer);
|
||||
} catch (IOException e) {
|
||||
s_logger.warn("Unexpected exception in processing template.", e);
|
||||
} catch (TemplateException e) {
|
||||
s_logger.warn("Unexpected exception in processing template.", e);
|
||||
}
|
||||
StringBuffer sb = writer.getBuffer();
|
||||
|
||||
if(s_logger.isTraceEnabled())
|
||||
s_logger.trace("onAjaxClientUpdate response: " + sb.toString());
|
||||
|
||||
return sb.toString();
|
||||
*/
|
||||
return getAjaxViewerUpdatePageContent(sbTileSequence.toString(), imgUrl, doResize, resizedFramebufferWidth,
|
||||
resizedFramebufferHeight, tracker.getTileWidth(), tracker.getTileHeight());
|
||||
}
|
||||
|
|
@ -1304,5 +1219,7 @@ public class ConsoleProxyViewer implements java.lang.Runnable, RfbViewer, RfbPro
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
package com.cloud.consoleproxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.consoleproxy.vnc.FrameBufferCanvas;
|
||||
import com.cloud.consoleproxy.vnc.RfbConstants;
|
||||
import com.cloud.consoleproxy.vnc.VncClient;
|
||||
|
||||
/**
|
||||
|
|
@ -15,19 +19,124 @@ public class ConsoleProxyVncClient extends ConsoleProxyClientBase {
|
|||
private static final Logger s_logger = Logger.getLogger(ConsoleProxyVncClient.class);
|
||||
|
||||
private VncClient client;
|
||||
|
||||
private Thread worker;
|
||||
private boolean workerDone = false;
|
||||
|
||||
public ConsoleProxyVncClient() {
|
||||
}
|
||||
|
||||
public boolean isHostConnected() {
|
||||
if(client != null)
|
||||
return client.isHostConnected();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFrontEndAlive() {
|
||||
if(workerDone || System.currentTimeMillis() - getClientLastFrontEndActivityTime() > ConsoleProxy.VIEWER_LINGER_SECONDS*1000)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void initClient(String clientHostAddress, int clientHostPort,
|
||||
String clientHostPassword, String clientTag) {
|
||||
// TODO
|
||||
@Override
|
||||
public void initClient(final String clientHostAddress, final int clientHostPort,
|
||||
final String clientHostPassword, final String clientTag, final String ticket) {
|
||||
this.host = clientHostAddress;
|
||||
this.port = clientHostPort;
|
||||
this.passwordParam = clientHostPassword;
|
||||
this.tag = clientTag;
|
||||
this.ticket = ticket;
|
||||
|
||||
client = new VncClient(this);
|
||||
worker = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
long startTick = System.currentTimeMillis();
|
||||
while(System.currentTimeMillis() - startTick < 7000) {
|
||||
try {
|
||||
client.connectTo(clientHostAddress, clientHostPort, clientHostPassword);
|
||||
} catch (UnknownHostException e) {
|
||||
s_logger.error("Unexpected exception: ", e);
|
||||
} catch (IOException e) {
|
||||
s_logger.error("Unexpected exception: ", e);
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
workerDone = true;
|
||||
}
|
||||
});
|
||||
|
||||
worker.setDaemon(true);
|
||||
worker.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeClient() {
|
||||
// TODO
|
||||
if(client != null)
|
||||
client.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientConnected() {
|
||||
}
|
||||
|
||||
public void onClientClose() {
|
||||
ConsoleProxy.removeViewer(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFramebufferUpdate(int x, int y, int w, int h) {
|
||||
super.onFramebufferUpdate(x, y, w, h);
|
||||
client.requestUpdate(false);
|
||||
}
|
||||
|
||||
public void sendClientRawKeyboardEvent(InputEventType event, int code, int modifiers) {
|
||||
if(client == null)
|
||||
return;
|
||||
|
||||
updateFrontEndActivityTime();
|
||||
|
||||
switch(event) {
|
||||
case KEY_DOWN :
|
||||
client.sendClientKeyboardEvent(RfbConstants.KEY_DOWN, code, 0);
|
||||
break;
|
||||
|
||||
case KEY_UP :
|
||||
client.sendClientKeyboardEvent(RfbConstants.KEY_UP, code, 0);
|
||||
break;
|
||||
|
||||
case KEY_PRESS :
|
||||
break;
|
||||
|
||||
default :
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void sendClientMouseEvent(InputEventType event, int x, int y, int code, int modifiers) {
|
||||
if(client == null)
|
||||
return;
|
||||
|
||||
updateFrontEndActivityTime();
|
||||
|
||||
int pointerMask = 0;
|
||||
int mask = 1;
|
||||
if(code == 2)
|
||||
mask = 4;
|
||||
if(event == InputEventType.MOUSE_DOWN) {
|
||||
pointerMask = mask;
|
||||
}
|
||||
|
||||
client.sendClientMouseEvent(pointerMask, x, y, code, modifiers);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FrameBufferCanvas getFrameBufferCavas() {
|
||||
if(client != null)
|
||||
return client.getFrameBufferCanvas();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,680 @@
|
|||
/**
|
||||
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the GNU General Public License v3 or later.
|
||||
*
|
||||
* It is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or any later version.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.cloud.consoleproxy;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.net.ssl.SSLServerSocket;
|
||||
|
||||
import org.apache.log4j.xml.DOMConfigurator;
|
||||
|
||||
import com.cloud.console.AuthenticationException;
|
||||
import com.cloud.console.Logger;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
|
||||
/*
|
||||
public class ConsoleProxy_obsolete {
|
||||
private static final Logger s_logger = Logger.getLogger(ConsoleProxy_obsolete.class);
|
||||
|
||||
public static final int KEYBOARD_RAW = 0;
|
||||
public static final int KEYBOARD_COOKED = 1;
|
||||
|
||||
public static Object context;
|
||||
|
||||
// this has become more ugly, to store keystore info passed from management server (we now use management server managed keystore to support
|
||||
// dynamically changing to customer supplied certificate)
|
||||
public static byte[] ksBits;
|
||||
public static String ksPassword;
|
||||
|
||||
public static Method authMethod;
|
||||
public static Method reportMethod;
|
||||
public static Method ensureRouteMethod;
|
||||
|
||||
static Hashtable<String, ConsoleProxyViewer> connectionMap = new Hashtable<String, ConsoleProxyViewer>();
|
||||
static int tcpListenPort = 5999;
|
||||
static int httpListenPort = 80;
|
||||
static int httpCmdListenPort = 8001;
|
||||
static String jarDir = "./applet/";
|
||||
static boolean compressServerMessage = true;
|
||||
static int viewerLinger = 180;
|
||||
static int reconnectMaxRetry = 5;
|
||||
static int readTimeoutSeconds = 90;
|
||||
static int keyboardType = KEYBOARD_RAW;
|
||||
static String factoryClzName;
|
||||
static boolean standaloneStart = false;
|
||||
|
||||
private static void configLog4j() {
|
||||
URL configUrl = System.class.getResource("/conf/log4j-cloud.xml");
|
||||
if(configUrl == null)
|
||||
configUrl = System.class.getClassLoader().getSystemResource("log4j-cloud.xml");
|
||||
|
||||
if(configUrl == null)
|
||||
configUrl = System.class.getClassLoader().getSystemResource("conf/log4j-cloud.xml");
|
||||
|
||||
if(configUrl != null) {
|
||||
try {
|
||||
System.out.println("Configure log4j using " + configUrl.toURI().toString());
|
||||
} catch (URISyntaxException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
File file = new File(configUrl.toURI());
|
||||
|
||||
System.out.println("Log4j configuration from : " + file.getAbsolutePath());
|
||||
DOMConfigurator.configureAndWatch(file.getAbsolutePath(), 10000);
|
||||
} catch (URISyntaxException e) {
|
||||
System.out.println("Unable to convert log4j configuration Url to URI");
|
||||
}
|
||||
// DOMConfigurator.configure(configUrl);
|
||||
} else {
|
||||
System.out.println("Configure log4j with default properties");
|
||||
}
|
||||
}
|
||||
|
||||
private static void configProxy(Properties conf) {
|
||||
s_logger.info("Configure console proxy...");
|
||||
for(Object key : conf.keySet()) {
|
||||
s_logger.info("Property " + (String)key + ": " + conf.getProperty((String)key));
|
||||
}
|
||||
|
||||
String s = conf.getProperty("consoleproxy.tcpListenPort");
|
||||
if (s!=null) {
|
||||
tcpListenPort = Integer.parseInt(s);
|
||||
s_logger.info("Setting tcpListenPort=" + s);
|
||||
}
|
||||
|
||||
s = conf.getProperty("consoleproxy.httpListenPort");
|
||||
if (s!=null) {
|
||||
httpListenPort = Integer.parseInt(s);
|
||||
s_logger.info("Setting httpListenPort=" + s);
|
||||
}
|
||||
|
||||
s = conf.getProperty("premium");
|
||||
if(s != null && s.equalsIgnoreCase("true")) {
|
||||
s_logger.info("Premium setting will override settings from consoleproxy.properties, listen at port 443");
|
||||
httpListenPort = 443;
|
||||
factoryClzName = "com.cloud.consoleproxy.ConsoleProxySecureServerFactoryImpl";
|
||||
} else {
|
||||
factoryClzName = ConsoleProxyBaseServerFactoryImpl.class.getName();
|
||||
}
|
||||
|
||||
s = conf.getProperty("consoleproxy.httpCmdListenPort");
|
||||
if (s!=null) {
|
||||
httpCmdListenPort = Integer.parseInt(s);
|
||||
s_logger.info("Setting httpCmdListenPort=" + s);
|
||||
}
|
||||
s = conf.getProperty("consoleproxy.jarDir");
|
||||
if (s!=null) {
|
||||
jarDir = s;
|
||||
s_logger.info("Setting jarDir=" + s);
|
||||
}
|
||||
s = conf.getProperty("consoleproxy.viewerLinger");
|
||||
if (s!=null) {
|
||||
viewerLinger = Integer.parseInt(s);
|
||||
s_logger.info("Setting viewerLinger=" + s);
|
||||
}
|
||||
s = conf.getProperty("consoleproxy.compressServerMessage");
|
||||
if (s!=null) {
|
||||
compressServerMessage = Boolean.parseBoolean(s);
|
||||
s_logger.info("Setting compressServerMessage=" + s);
|
||||
}
|
||||
|
||||
s = conf.getProperty("consoleproxy.reconnectMaxRetry");
|
||||
if (s!=null) {
|
||||
reconnectMaxRetry = Integer.parseInt(s);
|
||||
s_logger.info("Setting reconnectMaxRetry=" + reconnectMaxRetry);
|
||||
}
|
||||
|
||||
s = conf.getProperty("consoleproxy.readTimeoutSeconds");
|
||||
if (s!=null) {
|
||||
readTimeoutSeconds = Integer.parseInt(s);
|
||||
s_logger.info("Setting readTimeoutSeconds=" + readTimeoutSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
public static ConsoleProxyServerFactory getHttpServerFactory() {
|
||||
try {
|
||||
Class<?> clz = Class.forName(factoryClzName);
|
||||
try {
|
||||
ConsoleProxyServerFactory factory = (ConsoleProxyServerFactory)clz.newInstance();
|
||||
factory.init(ConsoleProxy_obsolete.ksBits, ConsoleProxy_obsolete.ksPassword);
|
||||
return factory;
|
||||
} catch (InstantiationException e) {
|
||||
s_logger.error(e.getMessage(), e);
|
||||
return null;
|
||||
} catch (IllegalAccessException e) {
|
||||
s_logger.error(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
s_logger.warn("Unable to find http server factory class: " + factoryClzName);
|
||||
return new ConsoleProxyBaseServerFactoryImpl();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean authenticateConsoleAccess(String host, String port, String vmId, String sid, String ticket) {
|
||||
if(standaloneStart)
|
||||
return true;
|
||||
|
||||
if(authMethod != null) {
|
||||
Object result;
|
||||
try {
|
||||
result = authMethod.invoke(ConsoleProxy_obsolete.context, host, port, vmId, sid, ticket);
|
||||
} catch (IllegalAccessException e) {
|
||||
s_logger.error("Unable to invoke authenticateConsoleAccess due to IllegalAccessException" + " for vm: " + vmId, e);
|
||||
return false;
|
||||
} catch (InvocationTargetException e) {
|
||||
s_logger.error("Unable to invoke authenticateConsoleAccess due to InvocationTargetException " + " for vm: " + vmId, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(result != null && result instanceof Boolean) {
|
||||
return ((Boolean)result).booleanValue();
|
||||
} else {
|
||||
s_logger.error("Invalid authentication return object " + result + " for vm: " + vmId + ", decline the access");
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
s_logger.warn("Private channel towards management server is not setup. Switch to offline mode and allow access to vm: " + vmId);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void reportLoadInfo(String gsonLoadInfo) {
|
||||
if(reportMethod != null) {
|
||||
try {
|
||||
reportMethod.invoke(ConsoleProxy_obsolete.context, gsonLoadInfo);
|
||||
} catch (IllegalAccessException e) {
|
||||
s_logger.error("Unable to invoke reportLoadInfo due to " + e.getMessage());
|
||||
} catch (InvocationTargetException e) {
|
||||
s_logger.error("Unable to invoke reportLoadInfo due to " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
s_logger.warn("Private channel towards management server is not setup. Switch to offline mode and ignore load report");
|
||||
}
|
||||
}
|
||||
|
||||
public static void ensureRoute(String address) {
|
||||
if(ensureRouteMethod != null) {
|
||||
try {
|
||||
ensureRouteMethod.invoke(ConsoleProxy_obsolete.context, address);
|
||||
} catch (IllegalAccessException e) {
|
||||
s_logger.error("Unable to invoke ensureRoute due to " + e.getMessage());
|
||||
} catch (InvocationTargetException e) {
|
||||
s_logger.error("Unable to invoke ensureRoute due to " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
s_logger.warn("Unable to find ensureRoute method, console proxy agent is not up to date");
|
||||
}
|
||||
}
|
||||
|
||||
public static void startWithContext(Properties conf, Object context, byte[] ksBits, String ksPassword) {
|
||||
s_logger.info("Start console proxy with context");
|
||||
if(conf != null) {
|
||||
for(Object key : conf.keySet()) {
|
||||
s_logger.info("Context property " + (String)key + ": " + conf.getProperty((String)key));
|
||||
}
|
||||
}
|
||||
|
||||
configLog4j();
|
||||
Logger.setFactory(new ConsoleProxyLoggerFactory());
|
||||
|
||||
// Using reflection to setup private/secure communication channel towards management server
|
||||
ConsoleProxy_obsolete.context = context;
|
||||
ConsoleProxy_obsolete.ksBits = ksBits;
|
||||
ConsoleProxy_obsolete.ksPassword = ksPassword;
|
||||
try {
|
||||
Class<?> contextClazz = Class.forName("com.cloud.agent.resource.consoleproxy.ConsoleProxyResource");
|
||||
authMethod = contextClazz.getDeclaredMethod("authenticateConsoleAccess", String.class, String.class, String.class, String.class, String.class);
|
||||
reportMethod = contextClazz.getDeclaredMethod("reportLoadInfo", String.class);
|
||||
ensureRouteMethod = contextClazz.getDeclaredMethod("ensureRoute", String.class);
|
||||
} catch (SecurityException e) {
|
||||
s_logger.error("Unable to setup private channel due to SecurityException", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
s_logger.error("Unable to setup private channel due to NoSuchMethodException", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
s_logger.error("Unable to setup private channel due to IllegalArgumentException", e);
|
||||
} catch(ClassNotFoundException e) {
|
||||
s_logger.error("Unable to setup private channel due to ClassNotFoundException", e);
|
||||
}
|
||||
|
||||
// merge properties from conf file
|
||||
InputStream confs = ConsoleProxy_obsolete.class.getResourceAsStream("/conf/consoleproxy.properties");
|
||||
Properties props = new Properties();
|
||||
if (confs == null) {
|
||||
s_logger.info("Can't load consoleproxy.properties from classpath, will use default configuration");
|
||||
} else {
|
||||
try {
|
||||
props.load(confs);
|
||||
|
||||
for(Object key : props.keySet()) {
|
||||
// give properties passed via context high priority, treat properties from consoleproxy.properties
|
||||
// as default values
|
||||
if(conf.get(key) == null)
|
||||
conf.put(key, props.get(key));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
s_logger.error(e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
start(conf);
|
||||
}
|
||||
|
||||
public static void start(Properties conf) {
|
||||
System.setProperty("java.awt.headless", "true");
|
||||
|
||||
configProxy(conf);
|
||||
|
||||
ConsoleProxyServerFactory factory = getHttpServerFactory();
|
||||
if(factory == null) {
|
||||
s_logger.error("Unable to load console proxy server factory");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if(httpListenPort != 0) {
|
||||
startupHttpMain();
|
||||
} else {
|
||||
s_logger.error("A valid HTTP server port is required to be specified, please check your consoleproxy.httpListenPort settings");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if(httpCmdListenPort > 0) {
|
||||
startupHttpCmdPort();
|
||||
} else {
|
||||
s_logger.info("HTTP command port is disabled");
|
||||
}
|
||||
|
||||
ViewerGCThread cthread = new ViewerGCThread(connectionMap);
|
||||
cthread.setName("Viewer GC Thread");
|
||||
cthread.start();
|
||||
|
||||
if(tcpListenPort > 0) {
|
||||
SSLServerSocket srvSock = null;
|
||||
try {
|
||||
srvSock = factory.createSSLServerSocket(tcpListenPort);
|
||||
s_logger.info("Listening for TCP on port " + tcpListenPort);
|
||||
} catch (IOException ioe) {
|
||||
s_logger.error(ioe.toString(), ioe);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if(srvSock != null) {
|
||||
while (true) {
|
||||
Socket conn = null;
|
||||
try {
|
||||
conn = srvSock.accept();
|
||||
String srcinfo = conn.getInetAddress().getHostAddress() + ":" + conn.getPort();
|
||||
s_logger.info("Accepted connection from " + srcinfo);
|
||||
conn.setSoLinger(false,0);
|
||||
ConsoleProxyClientHandler worker = new ConsoleProxyClientHandler(conn);
|
||||
worker.setName("Proxy Thread " + worker.getId() + " <" + srcinfo);
|
||||
worker.start();
|
||||
} catch (IOException ioe2) {
|
||||
s_logger.error(ioe2.toString(), ioe2);
|
||||
try {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
} catch (Throwable e) {
|
||||
// Something really bad happened
|
||||
// Terminate the program
|
||||
s_logger.error(e.toString(), e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s_logger.warn("TCP port is enabled in configuration but we are not able to instantiate server socket.");
|
||||
}
|
||||
} else {
|
||||
s_logger.info("TCP port is disabled for applet viewers");
|
||||
}
|
||||
}
|
||||
|
||||
private static void startupHttpMain() {
|
||||
try {
|
||||
ConsoleProxyServerFactory factory = getHttpServerFactory();
|
||||
if(factory == null) {
|
||||
s_logger.error("Unable to load HTTP server factory");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
HttpServer server = factory.createHttpServerInstance(httpListenPort);
|
||||
server.createContext("/getscreen", new ConsoleProxyThumbnailHandler());
|
||||
server.createContext("/resource/", new ConsoleProxyResourceHandler());
|
||||
server.createContext("/ajax", new ConsoleProxyAjaxHandler());
|
||||
server.createContext("/ajaximg", new ConsoleProxyAjaxImageHandler());
|
||||
server.setExecutor(new ThreadExecutor()); // creates a default executor
|
||||
server.start();
|
||||
} catch(Exception e) {
|
||||
s_logger.error(e.getMessage(), e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void startupHttpCmdPort() {
|
||||
try {
|
||||
s_logger.info("Listening for HTTP CMDs on port " + httpCmdListenPort);
|
||||
HttpServer cmdServer = HttpServer.create(new InetSocketAddress(httpCmdListenPort), 2);
|
||||
cmdServer.createContext("/cmd", new ConsoleProxyCmdHandler());
|
||||
cmdServer.setExecutor(new ThreadExecutor()); // creates a default executor
|
||||
cmdServer.start();
|
||||
} catch(Exception e) {
|
||||
s_logger.error(e.getMessage(), e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] argv) {
|
||||
standaloneStart = true;
|
||||
configLog4j();
|
||||
Logger.setFactory(new ConsoleProxyLoggerFactory());
|
||||
|
||||
InputStream confs = ConsoleProxy_obsolete.class.getResourceAsStream("/conf/consoleproxy.properties");
|
||||
Properties conf = new Properties();
|
||||
if (confs == null) {
|
||||
s_logger.info("Can't load consoleproxy.properties from classpath, will use default configuration");
|
||||
} else {
|
||||
try {
|
||||
conf.load(confs);
|
||||
} catch (Exception e) {
|
||||
s_logger.error(e.toString(), e);
|
||||
}
|
||||
}
|
||||
start(conf);
|
||||
}
|
||||
|
||||
static ConsoleProxyViewer createViewer() {
|
||||
ConsoleProxyViewer viewer = new ConsoleProxyViewer();
|
||||
viewer.compressServerMessage = compressServerMessage;
|
||||
return viewer;
|
||||
}
|
||||
|
||||
static void initViewer(ConsoleProxyViewer viewer, String host, int port, String tag, String sid, String ticket) throws AuthenticationException {
|
||||
ConsoleProxyViewer.authenticationExternally(host, String.valueOf(port), tag, sid, ticket);
|
||||
|
||||
viewer.host = host;
|
||||
viewer.port = port;
|
||||
viewer.tag = tag;
|
||||
viewer.passwordParam = sid;
|
||||
|
||||
viewer.init();
|
||||
}
|
||||
|
||||
static ConsoleProxyViewer getVncViewer(String host, int port, String sid, String tag, String ticket) throws Exception {
|
||||
ConsoleProxyViewer viewer = null;
|
||||
|
||||
boolean reportLoadChange = false;
|
||||
synchronized (connectionMap) {
|
||||
viewer = connectionMap.get(host + ":" + port);
|
||||
if (viewer == null) {
|
||||
viewer = createViewer();
|
||||
initViewer(viewer, host, port, tag, sid, ticket);
|
||||
connectionMap.put(host + ":" + port, viewer);
|
||||
s_logger.info("Added viewer object " + viewer);
|
||||
|
||||
reportLoadChange = true;
|
||||
} else if (!viewer.rfbThread.isAlive()) {
|
||||
s_logger.info("The rfb thread died, reinitializing the viewer " +
|
||||
viewer);
|
||||
initViewer(viewer, host, port, tag, sid, ticket);
|
||||
|
||||
reportLoadChange = true;
|
||||
} else if (!sid.equals(viewer.passwordParam)) {
|
||||
s_logger.warn("Bad sid detected(VNC port may be reused). sid in session: " + viewer.passwordParam + ", sid in request: " + sid);
|
||||
initViewer(viewer, host, port, tag, sid, ticket);
|
||||
|
||||
reportLoadChange = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(viewer != null) {
|
||||
if (viewer.status == ConsoleProxyViewer.STATUS_NORMAL_OPERATION) {
|
||||
// Do not update lastUsedTime if the viewer is in the process of starting up
|
||||
// or if it failed to authenticate.
|
||||
viewer.lastUsedTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
if(reportLoadChange) {
|
||||
ConsoleProxyStatus status = new ConsoleProxyStatus();
|
||||
status.setConnections(ConsoleProxy_obsolete.connectionMap);
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
String loadInfo = gson.toJson(status);
|
||||
|
||||
ConsoleProxy_obsolete.reportLoadInfo(loadInfo);
|
||||
if(s_logger.isDebugEnabled())
|
||||
s_logger.debug("Report load change : " + loadInfo);
|
||||
}
|
||||
|
||||
return viewer;
|
||||
}
|
||||
|
||||
static ConsoleProxyViewer getAjaxVncViewer(String host, int port, String sid, String tag, String ticket, String ajaxSession) throws Exception {
|
||||
boolean reportLoadChange = false;
|
||||
synchronized (connectionMap) {
|
||||
ConsoleProxyViewer viewer = connectionMap.get(host + ":" + port);
|
||||
// s_logger.info("view lookup " + host + ":" + port + " = " + viewer);
|
||||
|
||||
if (viewer == null) {
|
||||
viewer = createViewer();
|
||||
viewer.ajaxViewer = true;
|
||||
|
||||
initViewer(viewer, host, port, tag, sid, ticket);
|
||||
connectionMap.put(host + ":" + port, viewer);
|
||||
s_logger.info("Added viewer object " + viewer);
|
||||
reportLoadChange = true;
|
||||
} else if (!viewer.rfbThread.isAlive()) {
|
||||
s_logger.info("The rfb thread died, reinitializing the viewer " +
|
||||
viewer);
|
||||
initViewer(viewer, host, port, tag, sid, ticket);
|
||||
reportLoadChange = true;
|
||||
} else if (!sid.equals(viewer.passwordParam)) {
|
||||
s_logger.warn("Bad sid detected(VNC port may be reused). sid in session: " + viewer.passwordParam + ", sid in request: " + sid);
|
||||
initViewer(viewer, host, port, tag, sid, ticket);
|
||||
reportLoadChange = true;
|
||||
} else {
|
||||
if(ajaxSession == null || ajaxSession.isEmpty())
|
||||
ConsoleProxyViewer.authenticationExternally(host, String.valueOf(port), tag, sid, ticket);
|
||||
}
|
||||
|
||||
if (viewer.status == ConsoleProxyViewer.STATUS_NORMAL_OPERATION) {
|
||||
// Do not update lastUsedTime if the viewer is in the process of starting up
|
||||
// or if it failed to authenticate.
|
||||
viewer.lastUsedTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
if(reportLoadChange) {
|
||||
ConsoleProxyStatus status = new ConsoleProxyStatus();
|
||||
status.setConnections(ConsoleProxy_obsolete.connectionMap);
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
String loadInfo = gson.toJson(status);
|
||||
|
||||
ConsoleProxy_obsolete.reportLoadInfo(loadInfo);
|
||||
if(s_logger.isDebugEnabled())
|
||||
s_logger.debug("Report load change : " + loadInfo);
|
||||
}
|
||||
return viewer;
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeViewer(ConsoleProxyViewer viewer) {
|
||||
synchronized (connectionMap) {
|
||||
for(Map.Entry<String, ConsoleProxyViewer> entry : connectionMap.entrySet()) {
|
||||
if(entry.getValue() == viewer) {
|
||||
connectionMap.remove(entry.getKey());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void waitForViewerToStart(ConsoleProxyViewer viewer) throws Exception {
|
||||
if (viewer.status == ConsoleProxyViewer.STATUS_NORMAL_OPERATION) {
|
||||
return;
|
||||
}
|
||||
|
||||
Long startTime = System.currentTimeMillis();
|
||||
int delay = 500;
|
||||
|
||||
while (System.currentTimeMillis() < startTime + 30000 &&
|
||||
viewer.status != ConsoleProxyViewer.STATUS_NORMAL_OPERATION) {
|
||||
if (viewer.status == ConsoleProxyViewer.STATUS_AUTHENTICATION_FAILURE) {
|
||||
throw new Exception ("Authentication failure");
|
||||
}
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
delay = (int)(delay * 1.5);
|
||||
}
|
||||
|
||||
if (viewer.status != ConsoleProxyViewer.STATUS_NORMAL_OPERATION) {
|
||||
throw new Exception ("Cannot start VncViewer");
|
||||
}
|
||||
|
||||
s_logger.info("Waited " +
|
||||
(System.currentTimeMillis() - startTime) + "ms for VncViewer to start");
|
||||
}
|
||||
|
||||
static class ThreadExecutor implements Executor {
|
||||
public void execute(Runnable r) {
|
||||
new Thread(r).start();
|
||||
}
|
||||
}
|
||||
|
||||
static class ViewerGCThread extends Thread {
|
||||
Hashtable<String, ConsoleProxyViewer> connMap;
|
||||
long lastLogScan = 0L;
|
||||
|
||||
public ViewerGCThread(Hashtable<String, ConsoleProxyViewer> connMap) {
|
||||
this.connMap = connMap;
|
||||
}
|
||||
|
||||
private void cleanupLogging() {
|
||||
if(lastLogScan != 0 && System.currentTimeMillis() - lastLogScan < 3600000)
|
||||
return;
|
||||
lastLogScan = System.currentTimeMillis();
|
||||
|
||||
File logDir = new File("./logs");
|
||||
File files[] = logDir.listFiles();
|
||||
if(files != null) {
|
||||
for(File file : files) {
|
||||
if(System.currentTimeMillis() - file.lastModified() >= 86400000L) {
|
||||
try {
|
||||
file.delete();
|
||||
} catch(Throwable e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
cleanupLogging();
|
||||
|
||||
s_logger.info("connMap=" + connMap);
|
||||
Enumeration<String> e = connMap.keys();
|
||||
while (e.hasMoreElements()) {
|
||||
String key;
|
||||
ConsoleProxyViewer viewer;
|
||||
|
||||
synchronized (connMap) {
|
||||
key = e.nextElement();
|
||||
viewer = connMap.get(key);
|
||||
}
|
||||
|
||||
long seconds_unused = (System.currentTimeMillis() - viewer.lastUsedTime) / 1000;
|
||||
|
||||
if (seconds_unused > viewerLinger / 2 && viewer.clientStream != null) {
|
||||
s_logger.info("Pinging client for " + viewer +
|
||||
" which has not been used for " + seconds_unused + "sec");
|
||||
byte[] bs = new byte[2];
|
||||
bs[0] = (byte)250;
|
||||
bs[1] = 3;
|
||||
viewer.writeToClientStream(bs);
|
||||
}
|
||||
|
||||
if (seconds_unused < viewerLinger) {
|
||||
continue;
|
||||
}
|
||||
|
||||
synchronized (connMap) {
|
||||
connMap.remove(key);
|
||||
}
|
||||
// close the server connection
|
||||
s_logger.info("Dropping " + viewer +
|
||||
" which has not been used for " +
|
||||
seconds_unused + " seconds");
|
||||
viewer.dropMe = true;
|
||||
synchronized (viewer) {
|
||||
if (viewer.clientStream != null) {
|
||||
try {
|
||||
viewer.clientStream.close();
|
||||
} catch (IOException ioe) {
|
||||
// ignored
|
||||
}
|
||||
viewer.clientStream = null;
|
||||
viewer.clientStreamInfo = null;
|
||||
}
|
||||
if (viewer.rfb != null) {
|
||||
viewer.rfb.close();
|
||||
}
|
||||
}
|
||||
|
||||
// report load change for removal of the viewer
|
||||
ConsoleProxyStatus status = new ConsoleProxyStatus();
|
||||
status.setConnections(ConsoleProxy_obsolete.connectionMap);
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
String loadInfo = gson.toJson(status);
|
||||
|
||||
ConsoleProxy_obsolete.reportLoadInfo(loadInfo);
|
||||
if(s_logger.isDebugEnabled())
|
||||
s_logger.debug("Report load change : " + loadInfo);
|
||||
}
|
||||
try {
|
||||
Thread.sleep(30000);
|
||||
} catch (InterruptedException exp) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.cloud.consoleproxy;
|
||||
|
||||
public enum InputEventType {
|
||||
MOUSE_MOVE(1),
|
||||
MOUSE_DOWN(2),
|
||||
MOUSE_UP(3),
|
||||
KEY_PRESS(4),
|
||||
KEY_DOWN(5),
|
||||
KEY_UP(6),
|
||||
MOUSE_DBLCLICK(8);
|
||||
|
||||
int eventCode;
|
||||
private InputEventType(int eventCode) {
|
||||
this.eventCode = eventCode;
|
||||
}
|
||||
|
||||
public int getEventCode() {
|
||||
return eventCode;
|
||||
}
|
||||
|
||||
public static InputEventType fromEventCode(int eventCode) {
|
||||
switch(eventCode) {
|
||||
case 1 :
|
||||
return MOUSE_MOVE;
|
||||
case 2 :
|
||||
return MOUSE_DOWN;
|
||||
case 3 :
|
||||
return MOUSE_UP;
|
||||
case 4 :
|
||||
return KEY_PRESS;
|
||||
case 5 :
|
||||
return KEY_DOWN;
|
||||
case 6 :
|
||||
return KEY_UP;
|
||||
case 8 :
|
||||
return MOUSE_DBLCLICK;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupport event code: " + eventCode);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import java.awt.Canvas;
|
|||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
|
|
@ -80,6 +81,13 @@ public class BufferedImageCanvas extends Canvas implements FrameBufferCanvas {
|
|||
}
|
||||
}
|
||||
|
||||
@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 = 800;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.cloud.consoleproxy.vnc;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.console.TileInfo;
|
||||
|
||||
public interface FrameBufferCanvas {
|
||||
Image getFrameBufferScaledImage(int width, int height);
|
||||
public byte[] getFrameBufferJpeg();
|
||||
public byte[] getTilesMergedJpeg(List<TileInfo> tileList, int tileWidth, int tileHeight);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
package com.cloud.consoleproxy.vnc;
|
||||
|
||||
public interface FrameBufferEventListener {
|
||||
void onFramebufferSizeChange(int w, int h);
|
||||
void onFramebufferUpdate(int x, int y, int w, int h);
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
package com.cloud.consoleproxy.vnc;
|
||||
|
||||
public class SimpleLogger {
|
||||
|
||||
public static void log(String message) {
|
||||
System.out.println(getPrefix(1) + " LOG: " + message);
|
||||
}
|
||||
|
||||
public static void log(int skipFrames, String message) {
|
||||
System.out.println(getPrefix(1+skipFrames) + " LOG: " + message);
|
||||
}
|
||||
|
||||
public static void debug(String message) {
|
||||
System.out.println(getPrefix(1) + " DEBUG: " + message);
|
||||
}
|
||||
|
||||
public static void info(String message) {
|
||||
System.out.println(getPrefix(1) + " INFO: " + message);
|
||||
}
|
||||
|
||||
public static void warn(String message) {
|
||||
System.err.println(getPrefix(1) + " WARN: " + message);
|
||||
}
|
||||
|
||||
public static void error(String message) {
|
||||
System.err.println(getPrefix(1) + " ERROR: " + message);
|
||||
}
|
||||
|
||||
private static String getPrefix(int skipFrames) {
|
||||
StackTraceElement frame;
|
||||
try {
|
||||
throw new RuntimeException();
|
||||
} catch (Exception e) {
|
||||
frame = e.getStackTrace()[1+skipFrames];
|
||||
}
|
||||
|
||||
return "(" + frame.getFileName() + ":" + frame.getLineNumber() + ") " + frame.getMethodName() + "()";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,7 +16,13 @@ import javax.crypto.SecretKey;
|
|||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.DESKeySpec;
|
||||
|
||||
import com.cloud.console.Logger;
|
||||
import com.cloud.consoleproxy.ConsoleProxyClientListener;
|
||||
import com.cloud.consoleproxy.vnc.packet.client.KeyboardEventPacket;
|
||||
import com.cloud.consoleproxy.vnc.packet.client.MouseEventPacket;
|
||||
|
||||
public class VncClient {
|
||||
private static final Logger s_logger = Logger.getLogger(VncClient.class);
|
||||
|
||||
private Socket socket;
|
||||
private DataInputStream is;
|
||||
|
|
@ -28,7 +34,7 @@ public class VncClient {
|
|||
private VncServerPacketReceiver receiver;
|
||||
|
||||
private boolean noUI = false;
|
||||
private FrameBufferEventListener clientListener = null;
|
||||
private ConsoleProxyClientListener clientListener = null;
|
||||
|
||||
public static void main(String args[]) {
|
||||
if (args.length < 3) {
|
||||
|
|
@ -43,26 +49,31 @@ public class VncClient {
|
|||
try {
|
||||
new VncClient(host, Integer.parseInt(port), password, false, null);
|
||||
} catch (NumberFormatException e) {
|
||||
SimpleLogger.error("Incorrect VNC server port number: " + port + ".");
|
||||
s_logger.error("Incorrect VNC server port number: " + port + ".");
|
||||
System.exit(1);
|
||||
} catch (UnknownHostException e) {
|
||||
SimpleLogger.error("Incorrect VNC server host name: " + host + ".");
|
||||
s_logger.error("Incorrect VNC server host name: " + host + ".");
|
||||
System.exit(1);
|
||||
} catch (IOException e) {
|
||||
SimpleLogger.error("Cannot communicate with VNC server: " + e.getMessage());
|
||||
s_logger.error("Cannot communicate with VNC server: " + e.getMessage());
|
||||
System.exit(1);
|
||||
} catch (Throwable e) {
|
||||
SimpleLogger.error("An error happened: " + e.getMessage());
|
||||
System.exit(1);
|
||||
s_logger.error("An error happened: " + e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private static void printHelpMessage() {
|
||||
/* LOG */SimpleLogger.info("Usage: HOST PORT PASSWORD.");
|
||||
/* LOG */s_logger.info("Usage: HOST PORT PASSWORD.");
|
||||
}
|
||||
|
||||
public VncClient(ConsoleProxyClientListener clientListener) {
|
||||
this.noUI = true;
|
||||
this.clientListener = clientListener;
|
||||
}
|
||||
|
||||
public VncClient(String host, int port, String password, boolean noUI, FrameBufferEventListener clientListener)
|
||||
public VncClient(String host, int port, String password, boolean noUI, ConsoleProxyClientListener clientListener)
|
||||
throws UnknownHostException, IOException {
|
||||
|
||||
this.noUI = noUI;
|
||||
|
|
@ -70,33 +81,40 @@ public class VncClient {
|
|||
connectTo(host, port, password);
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
sender.closeConnection();
|
||||
receiver.closeConnection();
|
||||
public void shutdown() {
|
||||
if(sender != null)
|
||||
sender.closeConnection();
|
||||
|
||||
if(receiver != null)
|
||||
receiver.closeConnection();
|
||||
|
||||
try {
|
||||
is.close();
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
if(is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
os.close();
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
|
||||
try {
|
||||
socket.close();
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
if(os != null) {
|
||||
try {
|
||||
os.close();
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
}
|
||||
|
||||
if(socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
}
|
||||
|
||||
clientListener.onClientClose();
|
||||
}
|
||||
|
||||
public void connectTo(String host, int port, String password) throws UnknownHostException, IOException {
|
||||
// If port number is too small, then interpret it as display number.
|
||||
if (port < 100)
|
||||
port += 5900;
|
||||
|
||||
// Connect to server
|
||||
SimpleLogger.info("Connecting to VNC server " + host + ":" + port + "...");
|
||||
s_logger.info("Connecting to VNC server " + host + ":" + port + "...");
|
||||
this.socket = new Socket(host, port);
|
||||
is = new DataInputStream(socket.getInputStream());
|
||||
os = new DataOutputStream(socket.getOutputStream());
|
||||
|
|
@ -322,6 +340,8 @@ public class VncClient {
|
|||
int framebufferWidth = is.readUnsignedShort();
|
||||
int framebufferHeight = is.readUnsignedShort();
|
||||
screen.setFramebufferSize(framebufferWidth, framebufferHeight);
|
||||
if(clientListener != null)
|
||||
clientListener.onFramebufferSizeChange(framebufferWidth, framebufferHeight);
|
||||
}
|
||||
|
||||
// Read pixel format
|
||||
|
|
@ -362,4 +382,23 @@ public class VncClient {
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void requestUpdate(boolean fullUpdate) {
|
||||
if(fullUpdate)
|
||||
sender.requestFullScreenUpdate();
|
||||
else
|
||||
sender.imagePaintedOnScreen();
|
||||
}
|
||||
|
||||
public void sendClientKeyboardEvent(int event, int code, int modifiers) {
|
||||
sender.sendClientPacket(new KeyboardEventPacket(event, code));
|
||||
}
|
||||
|
||||
public void sendClientMouseEvent(int event, int x, int y, int code, int modifiers) {
|
||||
sender.sendClientPacket(new MouseEventPacket(event, x, y));
|
||||
}
|
||||
|
||||
public boolean isHostConnected() {
|
||||
return receiver != null && receiver.isConnectionAlive();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ public class VncClientPacketSender implements Runnable, PaintNotificationListene
|
|||
sendSetEncodings();
|
||||
requestFullScreenUpdate();
|
||||
}
|
||||
|
||||
public void sendClientPacket(ClientPacket packet) {
|
||||
queue.add(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
|
|
|||
|
|
@ -5,10 +5,13 @@ import java.awt.datatransfer.StringSelection;
|
|||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.cloud.console.Logger;
|
||||
import com.cloud.consoleproxy.ConsoleProxyClientListener;
|
||||
import com.cloud.consoleproxy.vnc.packet.server.FramebufferUpdatePacket;
|
||||
import com.cloud.consoleproxy.vnc.packet.server.ServerCutText;
|
||||
|
||||
public class VncServerPacketReceiver implements Runnable {
|
||||
private static final Logger s_logger = Logger.getLogger(VncServerPacketReceiver.class);
|
||||
|
||||
private final VncScreenDescription screen;
|
||||
private BufferedImageCanvas canvas;
|
||||
|
|
@ -17,10 +20,10 @@ public class VncServerPacketReceiver implements Runnable {
|
|||
private boolean connectionAlive = true;
|
||||
private VncClient vncConnection;
|
||||
private final FrameBufferUpdateListener fburListener;
|
||||
private final FrameBufferEventListener clientListener;
|
||||
private final ConsoleProxyClientListener clientListener;
|
||||
|
||||
public VncServerPacketReceiver(DataInputStream is, BufferedImageCanvas canvas, VncScreenDescription screen, VncClient vncConnection,
|
||||
FrameBufferUpdateListener fburListener, FrameBufferEventListener clientListener) {
|
||||
FrameBufferUpdateListener fburListener, ConsoleProxyClientListener clientListener) {
|
||||
this.screen = screen;
|
||||
this.canvas = canvas;
|
||||
this.is = is;
|
||||
|
|
@ -66,9 +69,9 @@ public class VncServerPacketReceiver implements Runnable {
|
|||
default:
|
||||
throw new RuntimeException("Unknown server packet type: " + messageType + ".");
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
|
||||
if (connectionAlive) {
|
||||
closeConnection();
|
||||
vncConnection.shutdown();
|
||||
|
|
@ -79,6 +82,10 @@ public class VncServerPacketReceiver implements Runnable {
|
|||
public void closeConnection() {
|
||||
connectionAlive = false;
|
||||
}
|
||||
|
||||
public boolean isConnectionAlive() {
|
||||
return connectionAlive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle server bell packet.
|
||||
|
|
@ -95,6 +102,6 @@ public class VncServerPacketReceiver implements Runnable {
|
|||
StringSelection contents = new StringSelection(clipboardContent.getContent());
|
||||
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(contents, null);
|
||||
|
||||
SimpleLogger.info("Server clipboard buffer: "+clipboardContent.getContent());
|
||||
s_logger.info("Server clipboard buffer: "+clipboardContent.getContent());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package com.cloud.consoleproxy.vnc.packet.server;
|
|||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.cloud.consoleproxy.ConsoleProxyClientListener;
|
||||
import com.cloud.consoleproxy.vnc.BufferedImageCanvas;
|
||||
import com.cloud.consoleproxy.vnc.RfbConstants;
|
||||
import com.cloud.consoleproxy.vnc.FrameBufferEventListener;
|
||||
import com.cloud.consoleproxy.vnc.VncScreenDescription;
|
||||
import com.cloud.consoleproxy.vnc.packet.server.CopyRect;
|
||||
import com.cloud.consoleproxy.vnc.packet.server.RawRect;
|
||||
|
|
@ -15,10 +15,10 @@ public class FramebufferUpdatePacket {
|
|||
|
||||
private final VncScreenDescription screen;
|
||||
private final BufferedImageCanvas canvas;
|
||||
private final FrameBufferEventListener clientListener;
|
||||
private final ConsoleProxyClientListener clientListener;
|
||||
|
||||
public FramebufferUpdatePacket(BufferedImageCanvas canvas, VncScreenDescription screen, DataInputStream is,
|
||||
FrameBufferEventListener clientListener) throws IOException {
|
||||
ConsoleProxyClientListener clientListener) throws IOException {
|
||||
|
||||
this.screen = screen;
|
||||
this.canvas = canvas;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ package com.cloud.consoleproxy.vnc.packet.server;
|
|||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.cloud.console.Logger;
|
||||
import com.cloud.consoleproxy.vnc.RfbConstants;
|
||||
import com.cloud.consoleproxy.vnc.SimpleLogger;
|
||||
|
||||
public class ServerCutText {
|
||||
private static final Logger s_logger = Logger.getLogger(ServerCutText.class);
|
||||
|
||||
private String content;
|
||||
|
||||
|
|
@ -26,7 +27,7 @@ public class ServerCutText {
|
|||
|
||||
content = new String(buf, RfbConstants.CHARSET);
|
||||
|
||||
/* LOG */SimpleLogger.log("Clippboard content: " + content);
|
||||
/* LOG */s_logger.info("Clippboard content: " + content);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue