diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxy.java b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxy.java
index b05badc917e..658cfe17d2a 100644
--- a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxy.java
+++ b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxy.java
@@ -1,688 +1,442 @@
-/**
- * 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 .
- *
- */
-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 {
- private static final Logger s_logger = Logger.getLogger(ConsoleProxy.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 connectionMap = new Hashtable();
- 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.ksBits, ConsoleProxy.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.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.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.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.context = context;
- ConsoleProxy.ksBits = ksBits;
- ConsoleProxy.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.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.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;
-
- /*
- throw new AuthenticationException ("Cannot use the existing viewer " +
- viewer + ": bad sid");
- */
- }
- }
-
- 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.connectionMap);
- Gson gson = new GsonBuilder().setPrettyPrinting().create();
- String loadInfo = gson.toJson(status);
-
- ConsoleProxy.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;
-
- /*
- throw new AuthenticationException ("Cannot use the existing viewer " +
- viewer + ": bad sid");
- */
- } 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.connectionMap);
- Gson gson = new GsonBuilder().setPrettyPrinting().create();
- String loadInfo = gson.toJson(status);
-
- ConsoleProxy.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 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 connMap;
- long lastLogScan = 0L;
-
- public ViewerGCThread(Hashtable 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 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.connectionMap);
- Gson gson = new GsonBuilder().setPrettyPrinting().create();
- String loadInfo = gson.toJson(status);
-
- ConsoleProxy.reportLoadInfo(loadInfo);
- if(s_logger.isDebugEnabled())
- s_logger.debug("Report load change : " + loadInfo);
- }
- try {
- Thread.sleep(30000);
- } catch (InterruptedException exp) {
- // Ignore
- }
- }
- }
- }
-}
+package com.cloud.consoleproxy;
+
+import java.io.File;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetSocketAddress;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Executor;
+
+import org.apache.log4j.xml.DOMConfigurator;
+
+import com.cloud.console.AuthenticationException;
+import com.cloud.console.Logger;
+import com.sun.net.httpserver.HttpServer;
+
+/**
+ *
+ * @author Kelven Yang
+ * ConsoleProxy, singleton class that manages overall activities in console proxy process. To make legacy code work, we still
+ * keep a lot of static memebers in this class
+ */
+public class ConsoleProxy {
+ private static final Logger s_logger = Logger.getLogger(ConsoleProxy.class);
+
+ public static final int KEYBOARD_RAW = 0;
+ public static final int KEYBOARD_COOKED = 1;
+
+ public static int VIEWER_LINGER_SECONDS = 180;
+
+ 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 connectionMap = new Hashtable();
+ static int httpListenPort = 80;
+ static int httpCmdListenPort = 8001;
+ 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 = ClassLoader.getSystemResource("log4j-cloud.xml");
+
+ if(configUrl == null)
+ configUrl = ClassLoader.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.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.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.ksBits, ConsoleProxy.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.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.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.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.context = context;
+ ConsoleProxy.ksBits = ksBits;
+ ConsoleProxy.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.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");
+ }
+
+ ConsoleProxyGCThread cthread = new ConsoleProxyGCThread(connectionMap);
+ cthread.setName("Console Proxy GC Thread");
+ cthread.start();
+ }
+
+ 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.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);
+ }
+
+ public static ConsoleProxyClient getVncViewer(String host, int port, String sid, String tag, String ticket) throws Exception {
+ ConsoleProxyClient viewer = null;
+
+ boolean reportLoadChange = false;
+ synchronized (connectionMap) {
+ viewer = connectionMap.get(host + ":" + port);
+ if (viewer == null) {
+ viewer = new ConsoleProxyVncClient();
+ viewer.initClient(host, port, sid, tag, ticket);
+ connectionMap.put(host + ":" + port, viewer);
+ s_logger.info("Added viewer object " + viewer);
+
+ reportLoadChange = true;
+ } else if (!viewer.isFrontEndAlive()) {
+ s_logger.info("The rfb thread died, reinitializing the viewer " +
+ viewer);
+ viewer.initClient(host, port, sid, tag, ticket);
+
+ reportLoadChange = true;
+ } else if (!sid.equals(viewer.getClientHostPassword())) {
+ s_logger.warn("Bad sid detected(VNC port may be reused). sid in session: " + viewer.getClientHostPassword()
+ + ", sid in request: " + sid);
+ viewer.initClient(host, port, sid, tag, ticket);
+
+ reportLoadChange = true;
+ }
+ }
+
+ if(reportLoadChange) {
+ ConsoleProxyClientStatsCollector statsCollector = getStatsCollector();
+ String loadInfo = statsCollector.getStatsReport();
+ reportLoadInfo(loadInfo);
+ if(s_logger.isDebugEnabled())
+ s_logger.debug("Report load change : " + loadInfo);
+ }
+
+ return viewer;
+ }
+
+ public static ConsoleProxyClient getAjaxVncViewer(String host, int port, String sid, String tag,
+ String ticket, String ajaxSession) throws Exception {
+
+ boolean reportLoadChange = false;
+ synchronized (connectionMap) {
+ ConsoleProxyClient viewer = connectionMap.get(host + ":" + port);
+ if (viewer == null) {
+ viewer = new ConsoleProxyVncClient();
+ viewer.initClient(host, port, sid, tag, ticket);
+
+ connectionMap.put(host + ":" + port, viewer);
+ s_logger.info("Added viewer object " + viewer);
+ reportLoadChange = true;
+ } else if (!viewer.isFrontEndAlive()) {
+ s_logger.info("The rfb thread died, reinitializing the viewer " +
+ viewer);
+ viewer.initClient(host, port, sid, tag, ticket);
+ reportLoadChange = true;
+ } else if (!sid.equals(viewer.getClientHostPassword())) {
+ s_logger.warn("Bad sid detected(VNC port may be reused). sid in session: "
+ + viewer.getClientHostPassword() + ", sid in request: " + sid);
+ viewer.initClient(host, port, sid, tag, ticket);
+ reportLoadChange = true;
+ } else {
+ if(ajaxSession == null || ajaxSession.isEmpty())
+ authenticationExternally(host, String.valueOf(port), tag, sid, ticket);
+ }
+
+ if(reportLoadChange) {
+ ConsoleProxyClientStatsCollector statsCollector = getStatsCollector();
+ String loadInfo = statsCollector.getStatsReport();
+ reportLoadInfo(loadInfo);
+ if(s_logger.isDebugEnabled())
+ s_logger.debug("Report load change : " + loadInfo);
+ }
+ return viewer;
+ }
+ }
+
+ public static void removeViewer(ConsoleProxyClient viewer) {
+ synchronized (connectionMap) {
+ for(Map.Entry entry : connectionMap.entrySet()) {
+ if(entry.getValue() == viewer) {
+ connectionMap.remove(entry.getKey());
+ return;
+ }
+ }
+ }
+ }
+
+ public static ConsoleProxyClientStatsCollector getStatsCollector() {
+ return new ConsoleProxyClientStatsCollector(connectionMap);
+ }
+
+ public static void authenticationExternally(String host, String port, String tag, String sid, String ticket) throws AuthenticationException {
+ if(!authenticateConsoleAccess(host, port, tag, sid, ticket)) {
+ s_logger.warn("External authenticator failed authencation request for vm " + tag + " with sid " + sid);
+
+ throw new AuthenticationException("External authenticator failed request for vm " + tag + " with sid " + sid);
+ }
+ }
+
+ static class ThreadExecutor implements Executor {
+ public void execute(Runnable r) {
+ new Thread(r).start();
+ }
+ }
+}
diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java
index ddfdb88a55f..3c9e18c0985 100644
--- a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java
+++ b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java
@@ -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 queryMap) {
+ private void handleClientEvent(ConsoleProxyClient viewer, int event, Map 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 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();
diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxImageHandler.java b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxImageHandler.java
index 812c4b4cb94..f151b6e4470 100644
--- a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxImageHandler.java
+++ b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxImageHandler.java
@@ -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();
diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClient.java b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClient.java
index 69e964ed51e..f83a4b06122 100644
--- a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClient.java
+++ b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClient.java
@@ -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 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();
}
diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientBase.java b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientBase.java
index 53315a87f8d..b66213e68eb 100644
--- a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientBase.java
+++ b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientBase.java
@@ -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" +
"