mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	CLOUDSTACK-61 Console proxy has plenty of files with CRLF line ending.
This commit is contained in:
		
							parent
							
								
									f03d438c4c
								
							
						
					
					
						commit
						0bf8c5a18f
					
				| @ -24,42 +24,42 @@ import java.util.Map; | |||||||
| import com.cloud.consoleproxy.util.Logger; | import com.cloud.consoleproxy.util.Logger; | ||||||
| 
 | 
 | ||||||
| public class AjaxFIFOImageCache { | public class AjaxFIFOImageCache { | ||||||
| 	private static final Logger s_logger = Logger.getLogger(AjaxFIFOImageCache.class); |     private static final Logger s_logger = Logger.getLogger(AjaxFIFOImageCache.class); | ||||||
|      |      | ||||||
| 	private List<Integer> fifoQueue; |     private List<Integer> fifoQueue; | ||||||
| 	private Map<Integer, byte[]> cache; |     private Map<Integer, byte[]> cache; | ||||||
| 	private int cacheSize; |     private int cacheSize; | ||||||
|     private int nextKey = 0; |     private int nextKey = 0; | ||||||
|      |      | ||||||
| 	public AjaxFIFOImageCache(int cacheSize) { |     public AjaxFIFOImageCache(int cacheSize) { | ||||||
| 		this.cacheSize = cacheSize; |         this.cacheSize = cacheSize; | ||||||
| 		fifoQueue = new ArrayList<Integer>(); |         fifoQueue = new ArrayList<Integer>(); | ||||||
| 		cache = new HashMap<Integer, byte[]>(); |         cache = new HashMap<Integer, byte[]>(); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public synchronized void clear() { |     public synchronized void clear() { | ||||||
| 		fifoQueue.clear(); |         fifoQueue.clear(); | ||||||
| 		cache.clear(); |         cache.clear(); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public synchronized int putImage(byte[] image) { |     public synchronized int putImage(byte[] image) { | ||||||
| 		while(cache.size() >= cacheSize) { |         while(cache.size() >= cacheSize) { | ||||||
| 			Integer keyToRemove = fifoQueue.remove(0); |             Integer keyToRemove = fifoQueue.remove(0); | ||||||
| 			cache.remove(keyToRemove); |             cache.remove(keyToRemove); | ||||||
|              |              | ||||||
| 			if(s_logger.isTraceEnabled()) |             if(s_logger.isTraceEnabled()) | ||||||
| 				s_logger.trace("Remove image from cache, key: " + keyToRemove); |                 s_logger.trace("Remove image from cache, key: " + keyToRemove); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		int key = getNextKey(); |         int key = getNextKey(); | ||||||
|          |          | ||||||
| 		if(s_logger.isTraceEnabled()) |         if(s_logger.isTraceEnabled()) | ||||||
| 			s_logger.trace("Add image to cache, key: " + key); |             s_logger.trace("Add image to cache, key: " + key); | ||||||
|          |          | ||||||
| 		cache.put(key, image); |         cache.put(key, image); | ||||||
| 		fifoQueue.add(key); |         fifoQueue.add(key); | ||||||
| 		return key; |         return key; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
|     public synchronized byte[] getImage(int key) { |     public synchronized byte[] getImage(int key) { | ||||||
|         if (key == 0) { |         if (key == 0) { | ||||||
|  | |||||||
| @ -17,17 +17,17 @@ | |||||||
| package com.cloud.consoleproxy; | package com.cloud.consoleproxy; | ||||||
| 
 | 
 | ||||||
| public class AuthenticationException extends Exception { | public class AuthenticationException extends Exception { | ||||||
| 	private static final long serialVersionUID = -393139302884898842L; |     private static final long serialVersionUID = -393139302884898842L; | ||||||
| 	public AuthenticationException() { |     public AuthenticationException() { | ||||||
| 		super(); |         super(); | ||||||
| 	} |     } | ||||||
| 	public AuthenticationException(String s) { |     public AuthenticationException(String s) { | ||||||
| 		super(s); |         super(s); | ||||||
| 	} |     } | ||||||
| 	public AuthenticationException(String message, Throwable cause) { |     public AuthenticationException(String message, Throwable cause) { | ||||||
| 		super(message, cause); |         super(message, cause); | ||||||
| 	} |     } | ||||||
| 	 public AuthenticationException(Throwable cause) { |      public AuthenticationException(Throwable cause) { | ||||||
| 		 super(cause); |          super(cause); | ||||||
| 	 } |      } | ||||||
| } | } | ||||||
| @ -32,375 +32,375 @@ import com.sun.net.httpserver.HttpExchange; | |||||||
| import com.sun.net.httpserver.HttpHandler; | import com.sun.net.httpserver.HttpHandler; | ||||||
| 
 | 
 | ||||||
| public class ConsoleProxyAjaxHandler implements HttpHandler { | public class ConsoleProxyAjaxHandler implements HttpHandler { | ||||||
| 	private static final Logger s_logger = Logger.getLogger(ConsoleProxyAjaxHandler.class); |     private static final Logger s_logger = Logger.getLogger(ConsoleProxyAjaxHandler.class); | ||||||
|      |      | ||||||
| 	public ConsoleProxyAjaxHandler() { |     public ConsoleProxyAjaxHandler() { | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void handle(HttpExchange t) throws IOException { |     public void handle(HttpExchange t) throws IOException { | ||||||
| 		try { |         try { | ||||||
| 	        if(s_logger.isTraceEnabled()) |             if(s_logger.isTraceEnabled()) | ||||||
| 	        	s_logger.trace("AjaxHandler " + t.getRequestURI()); |                 s_logger.trace("AjaxHandler " + t.getRequestURI()); | ||||||
|              |              | ||||||
| 	        long startTick = System.currentTimeMillis(); |             long startTick = System.currentTimeMillis(); | ||||||
|              |              | ||||||
| 	        doHandle(t); |             doHandle(t); | ||||||
|              |              | ||||||
| 	        if(s_logger.isTraceEnabled()) |             if(s_logger.isTraceEnabled()) | ||||||
| 	        	s_logger.trace(t.getRequestURI() + " process time " + (System.currentTimeMillis() - startTick) + " ms"); |                 s_logger.trace(t.getRequestURI() + " process time " + (System.currentTimeMillis() - startTick) + " ms"); | ||||||
| 		} catch (IOException e) { |         } catch (IOException e) { | ||||||
| 			throw e; |             throw e; | ||||||
| 		} catch (IllegalArgumentException e) { |         } catch (IllegalArgumentException e) { | ||||||
| 			s_logger.warn("Exception, ", e); |             s_logger.warn("Exception, ", e); | ||||||
| 			t.sendResponseHeaders(400, -1);		// bad request |             t.sendResponseHeaders(400, -1);     // bad request | ||||||
| 		} catch(Throwable e) { |         } catch(Throwable e) { | ||||||
| 			s_logger.error("Unexpected exception, ", e); |             s_logger.error("Unexpected exception, ", e); | ||||||
| 			t.sendResponseHeaders(500, -1);		// server error |             t.sendResponseHeaders(500, -1);     // server error | ||||||
| 		} finally { |         } finally { | ||||||
| 			t.close(); |             t.close(); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private void doHandle(HttpExchange t) throws Exception, IllegalArgumentException { |     private void doHandle(HttpExchange t) throws Exception, IllegalArgumentException { | ||||||
| 		String queries = t.getRequestURI().getQuery(); |         String queries = t.getRequestURI().getQuery(); | ||||||
| 		if(s_logger.isTraceEnabled()) |         if(s_logger.isTraceEnabled()) | ||||||
| 			s_logger.trace("Handle AJAX request: " + queries); |             s_logger.trace("Handle AJAX request: " + queries); | ||||||
|          |          | ||||||
| 		Map<String, String> queryMap = ConsoleProxyHttpHandlerHelper.getQueryMap(queries); |         Map<String, String> queryMap = ConsoleProxyHttpHandlerHelper.getQueryMap(queries); | ||||||
|          |          | ||||||
| 		String host = queryMap.get("host"); |         String host = queryMap.get("host"); | ||||||
| 		String portStr = queryMap.get("port"); |         String portStr = queryMap.get("port"); | ||||||
| 		String sid = queryMap.get("sid"); |         String sid = queryMap.get("sid"); | ||||||
| 		String tag = queryMap.get("tag"); |         String tag = queryMap.get("tag"); | ||||||
| 		String ticket = queryMap.get("ticket"); |         String ticket = queryMap.get("ticket"); | ||||||
| 		String ajaxSessionIdStr = queryMap.get("sess"); |         String ajaxSessionIdStr = queryMap.get("sess"); | ||||||
| 		String eventStr = queryMap.get("event"); |         String eventStr = queryMap.get("event"); | ||||||
| 		String console_url = queryMap.get("consoleurl"); |         String console_url = queryMap.get("consoleurl"); | ||||||
| 		String console_host_session = queryMap.get("sessionref"); |         String console_host_session = queryMap.get("sessionref"); | ||||||
|          |          | ||||||
| 		if(tag == null) |         if(tag == null) | ||||||
| 			tag = ""; |             tag = ""; | ||||||
|          |          | ||||||
| 		long ajaxSessionId = 0; |         long ajaxSessionId = 0; | ||||||
| 		int event = 0; |         int event = 0; | ||||||
|          |          | ||||||
| 		int port; |         int port; | ||||||
| 
 | 
 | ||||||
| 		if(host == null || portStr == null || sid == null)  |         if(host == null || portStr == null || sid == null)  | ||||||
| 			throw new IllegalArgumentException(); |             throw new IllegalArgumentException(); | ||||||
|          |          | ||||||
| 		try { |         try { | ||||||
| 			port = Integer.parseInt(portStr); |             port = Integer.parseInt(portStr); | ||||||
| 		} catch (NumberFormatException e) { |         } catch (NumberFormatException e) { | ||||||
| 			s_logger.warn("Invalid number parameter in query string: " + portStr); |             s_logger.warn("Invalid number parameter in query string: " + portStr); | ||||||
| 			throw new IllegalArgumentException(e); |             throw new IllegalArgumentException(e); | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		if(ajaxSessionIdStr != null) { |         if(ajaxSessionIdStr != null) { | ||||||
| 			try { |             try { | ||||||
| 				ajaxSessionId = Long.parseLong(ajaxSessionIdStr); |                 ajaxSessionId = Long.parseLong(ajaxSessionIdStr); | ||||||
| 			} catch (NumberFormatException e) { |             } catch (NumberFormatException e) { | ||||||
| 				s_logger.warn("Invalid number parameter in query string: " + ajaxSessionIdStr); |                 s_logger.warn("Invalid number parameter in query string: " + ajaxSessionIdStr); | ||||||
| 				throw new IllegalArgumentException(e); |                 throw new IllegalArgumentException(e); | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		if(eventStr != null) { |         if(eventStr != null) { | ||||||
| 			try { |             try { | ||||||
| 				event = Integer.parseInt(eventStr); |                 event = Integer.parseInt(eventStr); | ||||||
| 			} catch (NumberFormatException e) { |             } catch (NumberFormatException e) { | ||||||
| 				s_logger.warn("Invalid number parameter in query string: " + eventStr); |                 s_logger.warn("Invalid number parameter in query string: " + eventStr); | ||||||
| 				throw new IllegalArgumentException(e); |                 throw new IllegalArgumentException(e); | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		ConsoleProxyClient viewer = null; |         ConsoleProxyClient viewer = null; | ||||||
| 		try { |         try { | ||||||
| 			ConsoleProxyClientParam param = new ConsoleProxyClientParam(); |             ConsoleProxyClientParam param = new ConsoleProxyClientParam(); | ||||||
| 			param.setClientHostAddress(host); |             param.setClientHostAddress(host); | ||||||
| 			param.setClientHostPort(port); |             param.setClientHostPort(port); | ||||||
| 			param.setClientHostPassword(sid); |             param.setClientHostPassword(sid); | ||||||
| 			param.setClientTag(tag); |             param.setClientTag(tag); | ||||||
| 			param.setTicket(ticket); |             param.setTicket(ticket); | ||||||
| 			param.setClientTunnelUrl(console_url); |             param.setClientTunnelUrl(console_url); | ||||||
| 			param.setClientTunnelSession(console_host_session); |             param.setClientTunnelSession(console_host_session); | ||||||
|              |              | ||||||
| 			viewer = ConsoleProxy.getAjaxVncViewer(param, ajaxSessionIdStr); |             viewer = ConsoleProxy.getAjaxVncViewer(param, ajaxSessionIdStr); | ||||||
| 		} catch(Exception e) { |         } catch(Exception e) { | ||||||
| 
 | 
 | ||||||
| 			s_logger.warn("Failed to create viewer due to " + e.getMessage(), e); |             s_logger.warn("Failed to create viewer due to " + e.getMessage(), e); | ||||||
| 
 | 
 | ||||||
| 			String[] content = new String[] { |             String[] content = new String[] { | ||||||
| 				"<html><head></head><body>", |                 "<html><head></head><body>", | ||||||
| 				"<div id=\"main_panel\" tabindex=\"1\">", |                 "<div id=\"main_panel\" tabindex=\"1\">", | ||||||
| 				"<p>Access is denied for the console session. Please close the window and retry again</p>", |                 "<p>Access is denied for the console session. Please close the window and retry again</p>", | ||||||
| 				"</div></body></html>" |                 "</div></body></html>" | ||||||
| 			}; |             }; | ||||||
|              |              | ||||||
| 			StringBuffer sb = new StringBuffer(); |             StringBuffer sb = new StringBuffer(); | ||||||
| 			for(int i = 0; i < content.length; i++) |             for(int i = 0; i < content.length; i++) | ||||||
| 				sb.append(content[i]); |                 sb.append(content[i]); | ||||||
|              |              | ||||||
| 			sendResponse(t, "text/html", sb.toString()); |             sendResponse(t, "text/html", sb.toString()); | ||||||
| 			return; |             return; | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		if(event != 0) { |         if(event != 0) { | ||||||
| 			if(ajaxSessionId != 0 && ajaxSessionId == viewer.getAjaxSessionId()) { |             if(ajaxSessionId != 0 && ajaxSessionId == viewer.getAjaxSessionId()) { | ||||||
| 				if(event == 7) { |                 if(event == 7) { | ||||||
| 					// client send over an event bag |                     // client send over an event bag | ||||||
| 					InputStream is = t.getRequestBody(); |                     InputStream is = t.getRequestBody(); | ||||||
| 					handleClientEventBag(viewer, convertStreamToString(is, true)); |                     handleClientEventBag(viewer, convertStreamToString(is, true)); | ||||||
| 				} else { |                 } else { | ||||||
| 					handleClientEvent(viewer, event, queryMap); |                     handleClientEvent(viewer, event, queryMap); | ||||||
| 				} |                 } | ||||||
| 				sendResponse(t, "text/html", "OK"); |                 sendResponse(t, "text/html", "OK"); | ||||||
| 			} else { |             } else { | ||||||
| 				if(s_logger.isDebugEnabled()) |                 if(s_logger.isDebugEnabled()) | ||||||
| 					s_logger.debug("Ajax request comes from a different session, id in request: " + ajaxSessionId + ", id in viewer: " + viewer.getAjaxSessionId()); |                     s_logger.debug("Ajax request comes from a different session, id in request: " + ajaxSessionId + ", id in viewer: " + viewer.getAjaxSessionId()); | ||||||
|                  |                  | ||||||
| 				sendResponse(t, "text/html", "Invalid ajax client session id"); |                 sendResponse(t, "text/html", "Invalid ajax client session id"); | ||||||
| 			} |             } | ||||||
| 		} else { |         } else { | ||||||
| 			if(ajaxSessionId != 0 && ajaxSessionId != viewer.getAjaxSessionId()) { |             if(ajaxSessionId != 0 && ajaxSessionId != viewer.getAjaxSessionId()) { | ||||||
| 				s_logger.info("Ajax request comes from a different session, id in request: " + ajaxSessionId + ", id in viewer: " + viewer.getAjaxSessionId()); |                 s_logger.info("Ajax request comes from a different session, id in request: " + ajaxSessionId + ", id in viewer: " + viewer.getAjaxSessionId()); | ||||||
| 				handleClientKickoff(t, viewer); |                 handleClientKickoff(t, viewer); | ||||||
| 			} else if(ajaxSessionId == 0) { |             } else if(ajaxSessionId == 0) { | ||||||
| 				if(s_logger.isDebugEnabled()) |                 if(s_logger.isDebugEnabled()) | ||||||
| 					s_logger.debug("Ajax request indicates a fresh client start"); |                     s_logger.debug("Ajax request indicates a fresh client start"); | ||||||
|          |          | ||||||
| 				String title = queryMap.get("t"); |                 String title = queryMap.get("t"); | ||||||
| 				String guest = queryMap.get("guest"); |                 String guest = queryMap.get("guest"); | ||||||
| 				handleClientStart(t, viewer, title != null ? title : "", guest); |                 handleClientStart(t, viewer, title != null ? title : "", guest); | ||||||
| 			} else { |             } else { | ||||||
|                  |                  | ||||||
| 				if(s_logger.isTraceEnabled()) |                 if(s_logger.isTraceEnabled()) | ||||||
| 					s_logger.trace("Ajax request indicates client update"); |                     s_logger.trace("Ajax request indicates client update"); | ||||||
|                  |                  | ||||||
| 				handleClientUpdate(t, viewer); |                 handleClientUpdate(t, viewer); | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private static String convertStreamToString(InputStream is, boolean closeStreamAfterRead) {  |     private static String convertStreamToString(InputStream is, boolean closeStreamAfterRead) {  | ||||||
| 		BufferedReader reader = new BufferedReader(new InputStreamReader(is));  |         BufferedReader reader = new BufferedReader(new InputStreamReader(is));  | ||||||
| 		StringBuilder sb = new StringBuilder();  |         StringBuilder sb = new StringBuilder();  | ||||||
| 		String line = null;  |         String line = null;  | ||||||
| 		try {  |         try {  | ||||||
| 			while ((line = reader.readLine()) != null) {  |             while ((line = reader.readLine()) != null) {  | ||||||
| 				sb.append(line + "\n");  |                 sb.append(line + "\n");  | ||||||
| 			}  |             }  | ||||||
| 		} catch (IOException e) { |         } catch (IOException e) { | ||||||
| 			s_logger.warn("Exception while reading request body: ", e); |             s_logger.warn("Exception while reading request body: ", e); | ||||||
| 		} finally { |         } finally { | ||||||
| 			if(closeStreamAfterRead) { |             if(closeStreamAfterRead) { | ||||||
| 				try {  |                 try {  | ||||||
| 					is.close();  |                     is.close();  | ||||||
| 				} catch (IOException e) {  |                 } catch (IOException e) {  | ||||||
| 				}  |                 }  | ||||||
| 			} |             } | ||||||
| 		}  |         }  | ||||||
| 		return sb.toString();  |         return sb.toString();  | ||||||
| 	} 	 |     }    | ||||||
|      |      | ||||||
| 	private void sendResponse(HttpExchange t, String contentType, String response) throws IOException { |     private void sendResponse(HttpExchange t, String contentType, String response) throws IOException { | ||||||
| 		Headers hds = t.getResponseHeaders(); |         Headers hds = t.getResponseHeaders(); | ||||||
| 		hds.set("Content-Type", contentType); |         hds.set("Content-Type", contentType); | ||||||
|      |      | ||||||
| 		t.sendResponseHeaders(200, response.length()); |         t.sendResponseHeaders(200, response.length()); | ||||||
| 		OutputStream os = t.getResponseBody(); |         OutputStream os = t.getResponseBody(); | ||||||
| 		try { |         try { | ||||||
| 			os.write(response.getBytes()); |             os.write(response.getBytes()); | ||||||
| 		} finally { |         } finally { | ||||||
| 			os.close(); |             os.close(); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	@SuppressWarnings("deprecation") |     @SuppressWarnings("deprecation") | ||||||
| 	private void handleClientEventBag(ConsoleProxyClient viewer, String requestData) { |     private void handleClientEventBag(ConsoleProxyClient viewer, String requestData) { | ||||||
| 		if(s_logger.isTraceEnabled()) |         if(s_logger.isTraceEnabled()) | ||||||
| 			s_logger.trace("Handle event bag, event bag: " + requestData); |             s_logger.trace("Handle event bag, event bag: " + requestData); | ||||||
|          |          | ||||||
| 		int start = requestData.indexOf("="); |         int start = requestData.indexOf("="); | ||||||
| 		if(start < 0) |         if(start < 0) | ||||||
| 			start = 0; |             start = 0; | ||||||
| 		else if(start > 0) |         else if(start > 0) | ||||||
| 			start++; |             start++; | ||||||
| 		String data = URLDecoder.decode(requestData.substring(start)); |         String data = URLDecoder.decode(requestData.substring(start)); | ||||||
| 		String[] tokens = data.split("\\|"); |         String[] tokens = data.split("\\|"); | ||||||
| 		if(tokens != null && tokens.length > 0) { |         if(tokens != null && tokens.length > 0) { | ||||||
| 			int count = 0; |             int count = 0; | ||||||
| 			try { |             try { | ||||||
| 				count = Integer.parseInt(tokens[0]); |                 count = Integer.parseInt(tokens[0]); | ||||||
| 				int parsePos = 1; |                 int parsePos = 1; | ||||||
| 				int type, event, x, y, code, modifiers; |                 int type, event, x, y, code, modifiers; | ||||||
| 				for(int i = 0; i < count; i++) { |                 for(int i = 0; i < count; i++) { | ||||||
| 					type = Integer.parseInt(tokens[parsePos++]); |                     type = Integer.parseInt(tokens[parsePos++]); | ||||||
| 					if(type == 1) 	{ |                     if(type == 1)   { | ||||||
| 						// mouse event |                         // mouse event | ||||||
| 						event = Integer.parseInt(tokens[parsePos++]); |                         event = Integer.parseInt(tokens[parsePos++]); | ||||||
| 						x = Integer.parseInt(tokens[parsePos++]); |                         x = Integer.parseInt(tokens[parsePos++]); | ||||||
| 						y = Integer.parseInt(tokens[parsePos++]); |                         y = Integer.parseInt(tokens[parsePos++]); | ||||||
| 						code = Integer.parseInt(tokens[parsePos++]); |                         code = Integer.parseInt(tokens[parsePos++]); | ||||||
| 						modifiers = Integer.parseInt(tokens[parsePos++]); |                         modifiers = Integer.parseInt(tokens[parsePos++]); | ||||||
|                          |                          | ||||||
| 						Map<String, String> queryMap = new HashMap<String, String>(); |                         Map<String, String> queryMap = new HashMap<String, String>(); | ||||||
| 						queryMap.put("event", String.valueOf(event)); |                         queryMap.put("event", String.valueOf(event)); | ||||||
| 						queryMap.put("x", String.valueOf(x)); |                         queryMap.put("x", String.valueOf(x)); | ||||||
| 						queryMap.put("y", String.valueOf(y)); |                         queryMap.put("y", String.valueOf(y)); | ||||||
| 						queryMap.put("code", String.valueOf(code)); |                         queryMap.put("code", String.valueOf(code)); | ||||||
| 						queryMap.put("modifier", String.valueOf(modifiers)); |                         queryMap.put("modifier", String.valueOf(modifiers)); | ||||||
| 						handleClientEvent(viewer, event, queryMap); |                         handleClientEvent(viewer, event, queryMap); | ||||||
| 					} else { |                     } else { | ||||||
| 						// keyboard event |                         // keyboard event | ||||||
| 						event = Integer.parseInt(tokens[parsePos++]); |                         event = Integer.parseInt(tokens[parsePos++]); | ||||||
| 						code = Integer.parseInt(tokens[parsePos++]); |                         code = Integer.parseInt(tokens[parsePos++]); | ||||||
| 						modifiers = Integer.parseInt(tokens[parsePos++]); |                         modifiers = Integer.parseInt(tokens[parsePos++]); | ||||||
|                          |                          | ||||||
| 						Map<String, String> queryMap = new HashMap<String, String>(); |                         Map<String, String> queryMap = new HashMap<String, String>(); | ||||||
| 						queryMap.put("event", String.valueOf(event)); |                         queryMap.put("event", String.valueOf(event)); | ||||||
| 						queryMap.put("code", String.valueOf(code)); |                         queryMap.put("code", String.valueOf(code)); | ||||||
| 						queryMap.put("modifier", String.valueOf(modifiers)); |                         queryMap.put("modifier", String.valueOf(modifiers)); | ||||||
| 						handleClientEvent(viewer, event, queryMap); |                         handleClientEvent(viewer, event, queryMap); | ||||||
| 					} |                     } | ||||||
| 				} |                 } | ||||||
| 			} catch(NumberFormatException e) { |             } catch(NumberFormatException e) { | ||||||
| 				s_logger.warn("Exception in handle client event bag: " + data + ", ", e); |                 s_logger.warn("Exception in handle client event bag: " + data + ", ", e); | ||||||
| 			} catch(Exception e) { |             } catch(Exception e) { | ||||||
| 				s_logger.warn("Exception in handle client event bag: " + data + ", ", e); |                 s_logger.warn("Exception in handle client event bag: " + data + ", ", e); | ||||||
| 			} catch(OutOfMemoryError e) { |             } catch(OutOfMemoryError e) { | ||||||
| 				s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched"); |                 s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched"); | ||||||
| 				System.exit(1); |                 System.exit(1); | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private void handleClientEvent(ConsoleProxyClient viewer, int event, Map<String, String> queryMap) { |     private void handleClientEvent(ConsoleProxyClient viewer, int event, Map<String, String> queryMap) { | ||||||
| 		int code = 0; |         int code = 0; | ||||||
| 		int x = 0, y = 0; |         int x = 0, y = 0; | ||||||
| 		int modifiers = 0; |         int modifiers = 0; | ||||||
|          |          | ||||||
| 		String str; |         String str; | ||||||
| 		switch(event) { |         switch(event) { | ||||||
| 		case 1:		// mouse move |         case 1:     // mouse move | ||||||
| 		case 2:		// mouse down |         case 2:     // mouse down | ||||||
| 		case 3:		// mouse up |         case 3:     // mouse up | ||||||
| 		case 8:		// mouse double click |         case 8:     // mouse double click | ||||||
| 			str = queryMap.get("x"); |             str = queryMap.get("x"); | ||||||
| 			if(str != null) { |             if(str != null) { | ||||||
| 				try { |                 try { | ||||||
| 					x = Integer.parseInt(str); |                     x = Integer.parseInt(str); | ||||||
| 				} catch (NumberFormatException e) { |                 } catch (NumberFormatException e) { | ||||||
| 					s_logger.warn("Invalid number parameter in query string: " + str); |                     s_logger.warn("Invalid number parameter in query string: " + str); | ||||||
| 					throw new IllegalArgumentException(e); |                     throw new IllegalArgumentException(e); | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
| 			str = queryMap.get("y"); |             str = queryMap.get("y"); | ||||||
| 			if(str != null) { |             if(str != null) { | ||||||
| 				try { |                 try { | ||||||
| 					y = Integer.parseInt(str); |                     y = Integer.parseInt(str); | ||||||
| 				} catch (NumberFormatException e) { |                 } catch (NumberFormatException e) { | ||||||
| 					s_logger.warn("Invalid number parameter in query string: " + str); |                     s_logger.warn("Invalid number parameter in query string: " + str); | ||||||
| 					throw new IllegalArgumentException(e); |                     throw new IllegalArgumentException(e); | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
|              |              | ||||||
| 			if(event != 1) { |             if(event != 1) { | ||||||
| 				str = queryMap.get("code"); |                 str = queryMap.get("code"); | ||||||
| 				try { |                 try { | ||||||
| 					code = Integer.parseInt(str); |                     code = Integer.parseInt(str); | ||||||
| 				} catch (NumberFormatException e) { |                 } catch (NumberFormatException e) { | ||||||
| 					s_logger.warn("Invalid number parameter in query string: " + str); |                     s_logger.warn("Invalid number parameter in query string: " + str); | ||||||
| 					throw new IllegalArgumentException(e); |                     throw new IllegalArgumentException(e); | ||||||
| 				} |                 } | ||||||
|                  |                  | ||||||
| 				str = queryMap.get("modifier"); |                 str = queryMap.get("modifier"); | ||||||
| 				try { |                 try { | ||||||
| 					modifiers = Integer.parseInt(str); |                     modifiers = Integer.parseInt(str); | ||||||
| 				} catch (NumberFormatException e) { |                 } catch (NumberFormatException e) { | ||||||
| 					s_logger.warn("Invalid number parameter in query string: " + str); |                     s_logger.warn("Invalid number parameter in query string: " + str); | ||||||
| 					throw new IllegalArgumentException(e); |                     throw new IllegalArgumentException(e); | ||||||
| 				} |                 } | ||||||
|                  |                  | ||||||
| 				if(s_logger.isTraceEnabled()) |                 if(s_logger.isTraceEnabled()) | ||||||
| 					s_logger.trace("Handle client mouse event. event: " + event + ", x: " + x + ", y: " + y + ", button: " + code + ", modifier: " + modifiers); |                     s_logger.trace("Handle client mouse event. event: " + event + ", x: " + x + ", y: " + y + ", button: " + code + ", modifier: " + modifiers); | ||||||
| 			} else { |             } else { | ||||||
| 				if(s_logger.isTraceEnabled()) |                 if(s_logger.isTraceEnabled()) | ||||||
| 					s_logger.trace("Handle client mouse move event. x: " + x + ", y: " + y); |                     s_logger.trace("Handle client mouse move event. x: " + x + ", y: " + y); | ||||||
| 			} |             } | ||||||
| 			viewer.sendClientMouseEvent(InputEventType.fromEventCode(event), x, y, code, modifiers); |             viewer.sendClientMouseEvent(InputEventType.fromEventCode(event), x, y, code, modifiers); | ||||||
| 			break; |             break; | ||||||
|              |              | ||||||
| 		case 4:		// key press |         case 4:     // key press | ||||||
| 		case 5:		// key down |         case 5:     // key down | ||||||
| 		case 6:		// key up |         case 6:     // key up | ||||||
| 			str = queryMap.get("code"); |             str = queryMap.get("code"); | ||||||
| 			try { |             try { | ||||||
| 				code = Integer.parseInt(str); |                 code = Integer.parseInt(str); | ||||||
| 			} catch (NumberFormatException e) { |             } catch (NumberFormatException e) { | ||||||
| 				s_logger.warn("Invalid number parameter in query string: " + str); |                 s_logger.warn("Invalid number parameter in query string: " + str); | ||||||
| 				throw new IllegalArgumentException(e); |                 throw new IllegalArgumentException(e); | ||||||
| 			} |             } | ||||||
|              |              | ||||||
| 			str = queryMap.get("modifier"); |             str = queryMap.get("modifier"); | ||||||
| 			try { |             try { | ||||||
| 				modifiers = Integer.parseInt(str); |                 modifiers = Integer.parseInt(str); | ||||||
| 			} catch (NumberFormatException e) { |             } catch (NumberFormatException e) { | ||||||
| 				s_logger.warn("Invalid number parameter in query string: " + str); |                 s_logger.warn("Invalid number parameter in query string: " + str); | ||||||
| 				throw new IllegalArgumentException(e); |                 throw new IllegalArgumentException(e); | ||||||
| 			} |             } | ||||||
|              |              | ||||||
| 			if(s_logger.isDebugEnabled()) |             if(s_logger.isDebugEnabled()) | ||||||
| 				s_logger.debug("Handle client keyboard event. event: " + event + ", code: " + code + ", modifier: " + modifiers); |                 s_logger.debug("Handle client keyboard event. event: " + event + ", code: " + code + ", modifier: " + modifiers); | ||||||
| 			viewer.sendClientRawKeyboardEvent(InputEventType.fromEventCode(event), code, modifiers); |             viewer.sendClientRawKeyboardEvent(InputEventType.fromEventCode(event), code, modifiers); | ||||||
| 			break; |             break; | ||||||
|              |              | ||||||
| 		default : |         default : | ||||||
| 			break; |             break; | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private void handleClientKickoff(HttpExchange t, ConsoleProxyClient viewer) throws IOException { |     private void handleClientKickoff(HttpExchange t, ConsoleProxyClient viewer) throws IOException { | ||||||
| 		String response = viewer.onAjaxClientKickoff(); |         String response = viewer.onAjaxClientKickoff(); | ||||||
| 		t.sendResponseHeaders(200, response.length()); |         t.sendResponseHeaders(200, response.length()); | ||||||
| 		OutputStream os = t.getResponseBody(); |         OutputStream os = t.getResponseBody(); | ||||||
| 		try { |         try { | ||||||
| 			os.write(response.getBytes()); |             os.write(response.getBytes()); | ||||||
| 		} finally { |         } finally { | ||||||
| 			os.close(); |             os.close(); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private void handleClientStart(HttpExchange t, ConsoleProxyClient 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"); |         List<String> languages = t.getRequestHeaders().get("Accept-Language"); | ||||||
| 		String response = viewer.onAjaxClientStart(title, languages, guest); |         String response = viewer.onAjaxClientStart(title, languages, guest); | ||||||
|          |          | ||||||
| 		Headers hds = t.getResponseHeaders(); |         Headers hds = t.getResponseHeaders(); | ||||||
| 		hds.set("Content-Type", "text/html"); |         hds.set("Content-Type", "text/html"); | ||||||
| 		hds.set("Cache-Control", "no-cache"); |         hds.set("Cache-Control", "no-cache"); | ||||||
| 		hds.set("Cache-Control", "no-store"); |         hds.set("Cache-Control", "no-store"); | ||||||
| 		t.sendResponseHeaders(200, response.length()); |         t.sendResponseHeaders(200, response.length()); | ||||||
|          |          | ||||||
| 		OutputStream os = t.getResponseBody(); |         OutputStream os = t.getResponseBody(); | ||||||
| 		try { |         try { | ||||||
| 			os.write(response.getBytes()); |             os.write(response.getBytes()); | ||||||
| 		} finally { |         } finally { | ||||||
| 			os.close(); |             os.close(); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private void handleClientUpdate(HttpExchange t, ConsoleProxyClient viewer) throws IOException { |     private void handleClientUpdate(HttpExchange t, ConsoleProxyClient viewer) throws IOException { | ||||||
| 		String response = viewer.onAjaxClientUpdate(); |         String response = viewer.onAjaxClientUpdate(); | ||||||
|          |          | ||||||
| 		Headers hds = t.getResponseHeaders(); |         Headers hds = t.getResponseHeaders(); | ||||||
| 		hds.set("Content-Type", "text/javascript"); |         hds.set("Content-Type", "text/javascript"); | ||||||
| 		t.sendResponseHeaders(200, response.length()); |         t.sendResponseHeaders(200, response.length()); | ||||||
|          |          | ||||||
| 		OutputStream os = t.getResponseBody(); |         OutputStream os = t.getResponseBody(); | ||||||
| 		try { |         try { | ||||||
| 			os.write(response.getBytes()); |             os.write(response.getBytes()); | ||||||
| 		} finally { |         } finally { | ||||||
| 			os.close(); |             os.close(); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -30,47 +30,47 @@ import com.sun.net.httpserver.HttpExchange; | |||||||
| import com.sun.net.httpserver.HttpHandler; | import com.sun.net.httpserver.HttpHandler; | ||||||
| 
 | 
 | ||||||
| public class ConsoleProxyAjaxImageHandler implements HttpHandler { | public class ConsoleProxyAjaxImageHandler implements HttpHandler { | ||||||
| 	private static final Logger s_logger = Logger.getLogger(ConsoleProxyAjaxImageHandler.class); |     private static final Logger s_logger = Logger.getLogger(ConsoleProxyAjaxImageHandler.class); | ||||||
| 
 | 
 | ||||||
| 	public void handle(HttpExchange t) throws IOException { |     public void handle(HttpExchange t) throws IOException { | ||||||
| 		try { |         try { | ||||||
| 	        if(s_logger.isDebugEnabled()) |             if(s_logger.isDebugEnabled()) | ||||||
| 	        	s_logger.debug("AjaxImageHandler " + t.getRequestURI()); |                 s_logger.debug("AjaxImageHandler " + t.getRequestURI()); | ||||||
|              |              | ||||||
| 	        long startTick = System.currentTimeMillis(); |             long startTick = System.currentTimeMillis(); | ||||||
|              |              | ||||||
| 	        doHandle(t); |             doHandle(t); | ||||||
|              |              | ||||||
| 	        if(s_logger.isDebugEnabled()) |             if(s_logger.isDebugEnabled()) | ||||||
| 	        	s_logger.debug(t.getRequestURI() + "Process time " + (System.currentTimeMillis() - startTick) + " ms"); |                 s_logger.debug(t.getRequestURI() + "Process time " + (System.currentTimeMillis() - startTick) + " ms"); | ||||||
| 		} catch (IOException e) { |         } catch (IOException e) { | ||||||
| 			throw e; |             throw e; | ||||||
| 		} catch (IllegalArgumentException e) { |         } catch (IllegalArgumentException e) { | ||||||
| 			s_logger.warn("Exception, ", e); |             s_logger.warn("Exception, ", e); | ||||||
| 			t.sendResponseHeaders(400, -1);		// bad request |             t.sendResponseHeaders(400, -1);     // bad request | ||||||
| 		} catch(OutOfMemoryError e) { |         } catch(OutOfMemoryError e) { | ||||||
| 			s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched"); |             s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched"); | ||||||
| 			System.exit(1); |             System.exit(1); | ||||||
| 		} catch(Throwable e) { |         } catch(Throwable e) { | ||||||
| 			s_logger.error("Unexpected exception, ", e); |             s_logger.error("Unexpected exception, ", e); | ||||||
| 			t.sendResponseHeaders(500, -1);		// server error |             t.sendResponseHeaders(500, -1);     // server error | ||||||
| 		} finally { |         } finally { | ||||||
| 			t.close(); |             t.close(); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	private void doHandle(HttpExchange t) throws Exception, IllegalArgumentException { |     private void doHandle(HttpExchange t) throws Exception, IllegalArgumentException { | ||||||
| 		String queries = t.getRequestURI().getQuery(); |         String queries = t.getRequestURI().getQuery(); | ||||||
| 		Map<String, String> queryMap = ConsoleProxyHttpHandlerHelper.getQueryMap(queries); |         Map<String, String> queryMap = ConsoleProxyHttpHandlerHelper.getQueryMap(queries); | ||||||
|          |          | ||||||
| 		String host = queryMap.get("host"); |         String host = queryMap.get("host"); | ||||||
| 		String portStr = queryMap.get("port"); |         String portStr = queryMap.get("port"); | ||||||
| 		String sid = queryMap.get("sid"); |         String sid = queryMap.get("sid"); | ||||||
| 		String tag = queryMap.get("tag"); |         String tag = queryMap.get("tag"); | ||||||
| 		String ticket = queryMap.get("ticket"); |         String ticket = queryMap.get("ticket"); | ||||||
| 		String keyStr = queryMap.get("key"); |         String keyStr = queryMap.get("key"); | ||||||
| 		String console_url = queryMap.get("consoleurl"); |         String console_url = queryMap.get("consoleurl"); | ||||||
| 		String console_host_session = queryMap.get("sessionref"); |         String console_host_session = queryMap.get("sessionref"); | ||||||
|                 String w = queryMap.get("w");            |                 String w = queryMap.get("w");            | ||||||
|                 String h = queryMap.get("h"); |                 String h = queryMap.get("h"); | ||||||
|          |          | ||||||
| @ -78,23 +78,23 @@ public class ConsoleProxyAjaxImageHandler implements HttpHandler { | |||||||
|                 int width = 144; |                 int width = 144; | ||||||
|                 int height = 110; |                 int height = 110; | ||||||
|          |          | ||||||
| 		if(tag == null) |         if(tag == null) | ||||||
| 			tag = ""; |             tag = ""; | ||||||
|          |          | ||||||
| 		int port; |         int port; | ||||||
| 		if(host == null || portStr == null || sid == null) |         if(host == null || portStr == null || sid == null) | ||||||
| 			throw new IllegalArgumentException(); |             throw new IllegalArgumentException(); | ||||||
|          |          | ||||||
| 		try { |         try { | ||||||
| 			port = Integer.parseInt(portStr); |             port = Integer.parseInt(portStr); | ||||||
| 		} catch (NumberFormatException e) { |         } catch (NumberFormatException e) { | ||||||
| 			s_logger.warn("Invalid numeric parameter in query string: " + portStr); |             s_logger.warn("Invalid numeric parameter in query string: " + portStr); | ||||||
| 			throw new IllegalArgumentException(e); |             throw new IllegalArgumentException(e); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		try { |         try { | ||||||
|                     if (keyStr != null) |                     if (keyStr != null) | ||||||
|             	        key = Integer.parseInt(keyStr); |                         key = Integer.parseInt(keyStr); | ||||||
|                     if(null != w) |                     if(null != w) | ||||||
|                        width = Integer.parseInt(w); |                        width = Integer.parseInt(w); | ||||||
| 
 | 
 | ||||||
| @ -102,58 +102,58 @@ public class ConsoleProxyAjaxImageHandler implements HttpHandler { | |||||||
|                        height = Integer.parseInt(h); |                        height = Integer.parseInt(h); | ||||||
| 
 | 
 | ||||||
|              } catch (NumberFormatException e) { |              } catch (NumberFormatException e) { | ||||||
| 			s_logger.warn("Invalid numeric parameter in query string: " + keyStr); |             s_logger.warn("Invalid numeric parameter in query string: " + keyStr); | ||||||
| 			throw new IllegalArgumentException(e); |             throw new IllegalArgumentException(e); | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		ConsoleProxyClientParam param = new ConsoleProxyClientParam(); |         ConsoleProxyClientParam param = new ConsoleProxyClientParam(); | ||||||
| 		param.setClientHostAddress(host); |         param.setClientHostAddress(host); | ||||||
| 		param.setClientHostPort(port); |         param.setClientHostPort(port); | ||||||
| 		param.setClientHostPassword(sid); |         param.setClientHostPassword(sid); | ||||||
| 		param.setClientTag(tag); |         param.setClientTag(tag); | ||||||
| 		param.setTicket(ticket); |         param.setTicket(ticket); | ||||||
| 		param.setClientTunnelUrl(console_url); |         param.setClientTunnelUrl(console_url); | ||||||
| 		param.setClientTunnelSession(console_host_session); |         param.setClientTunnelSession(console_host_session); | ||||||
| 
 | 
 | ||||||
| 		ConsoleProxyClient viewer = ConsoleProxy.getVncViewer(param); |         ConsoleProxyClient viewer = ConsoleProxy.getVncViewer(param); | ||||||
| 
 | 
 | ||||||
| 		if (key == 0) { |         if (key == 0) { | ||||||
| 			Image scaledImage = viewer.getClientScaledImage(width, height); |             Image scaledImage = viewer.getClientScaledImage(width, height); | ||||||
| 			BufferedImage bufferedImage = new BufferedImage(width, height, |             BufferedImage bufferedImage = new BufferedImage(width, height, | ||||||
| 					BufferedImage.TYPE_3BYTE_BGR); |                     BufferedImage.TYPE_3BYTE_BGR); | ||||||
| 			Graphics2D bufImageGraphics = bufferedImage.createGraphics(); |             Graphics2D bufImageGraphics = bufferedImage.createGraphics(); | ||||||
| 			bufImageGraphics.drawImage(scaledImage, 0, 0, null); |             bufImageGraphics.drawImage(scaledImage, 0, 0, null); | ||||||
| 			ByteArrayOutputStream bos = new ByteArrayOutputStream(8196); |             ByteArrayOutputStream bos = new ByteArrayOutputStream(8196); | ||||||
| 			javax.imageio.ImageIO.write(bufferedImage, "jpg", bos); |             javax.imageio.ImageIO.write(bufferedImage, "jpg", bos); | ||||||
| 			byte[] bs = bos.toByteArray(); |             byte[] bs = bos.toByteArray(); | ||||||
| 			Headers hds = t.getResponseHeaders(); |             Headers hds = t.getResponseHeaders(); | ||||||
| 			hds.set("Content-Type", "image/jpeg"); |             hds.set("Content-Type", "image/jpeg"); | ||||||
| 			hds.set("Cache-Control", "no-cache"); |             hds.set("Cache-Control", "no-cache"); | ||||||
| 			hds.set("Cache-Control", "no-store"); |             hds.set("Cache-Control", "no-store"); | ||||||
| 			t.sendResponseHeaders(200, bs.length); |             t.sendResponseHeaders(200, bs.length); | ||||||
| 			OutputStream os = t.getResponseBody(); |             OutputStream os = t.getResponseBody(); | ||||||
| 			os.write(bs); |             os.write(bs); | ||||||
| 			os.close(); |             os.close(); | ||||||
| 		} else { |         } else { | ||||||
| 			AjaxFIFOImageCache imageCache = viewer.getAjaxImageCache(); |             AjaxFIFOImageCache imageCache = viewer.getAjaxImageCache(); | ||||||
| 	                byte[] img = imageCache.getImage(key); |                     byte[] img = imageCache.getImage(key); | ||||||
|      |      | ||||||
| 			if(img != null) { |             if(img != null) { | ||||||
| 				Headers hds = t.getResponseHeaders(); |                 Headers hds = t.getResponseHeaders(); | ||||||
| 				hds.set("Content-Type", "image/jpeg"); |                 hds.set("Content-Type", "image/jpeg"); | ||||||
| 				t.sendResponseHeaders(200, img.length); |                 t.sendResponseHeaders(200, img.length); | ||||||
|                  |                  | ||||||
| 				OutputStream os = t.getResponseBody(); |                 OutputStream os = t.getResponseBody(); | ||||||
| 				try { |                 try { | ||||||
| 					os.write(img, 0, img.length); |                     os.write(img, 0, img.length); | ||||||
| 				} finally { |                 } finally { | ||||||
| 					os.close(); |                     os.close(); | ||||||
| 				} |                 } | ||||||
| 			} else { |             } else { | ||||||
| 				if(s_logger.isInfoEnabled()) |                 if(s_logger.isInfoEnabled()) | ||||||
| 					s_logger.info("Image has already been swept out, key: " + key); |                     s_logger.info("Image has already been swept out, key: " + key); | ||||||
| 				t.sendResponseHeaders(404, -1); |                 t.sendResponseHeaders(404, -1); | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -18,64 +18,64 @@ package com.cloud.consoleproxy; | |||||||
| 
 | 
 | ||||||
| // duplicated class | // duplicated class | ||||||
| public class ConsoleProxyAuthenticationResult { | public class ConsoleProxyAuthenticationResult { | ||||||
| 	private boolean success; |     private boolean success; | ||||||
| 	private boolean isReauthentication; |     private boolean isReauthentication; | ||||||
| 	private String host; |     private String host; | ||||||
| 	private int port; |     private int port; | ||||||
| 	private String tunnelUrl; |     private String tunnelUrl; | ||||||
| 	private String tunnelSession; |     private String tunnelSession; | ||||||
|      |      | ||||||
| 	public ConsoleProxyAuthenticationResult() { |     public ConsoleProxyAuthenticationResult() { | ||||||
| 		success = false; |         success = false; | ||||||
| 		isReauthentication = false; |         isReauthentication = false; | ||||||
| 		port = 0; |         port = 0; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public boolean isSuccess() { |     public boolean isSuccess() { | ||||||
| 		return success; |         return success; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public void setSuccess(boolean success) { |     public void setSuccess(boolean success) { | ||||||
| 		this.success = success; |         this.success = success; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public boolean isReauthentication() { |     public boolean isReauthentication() { | ||||||
| 		return isReauthentication; |         return isReauthentication; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public void setReauthentication(boolean isReauthentication) { |     public void setReauthentication(boolean isReauthentication) { | ||||||
| 		this.isReauthentication = isReauthentication; |         this.isReauthentication = isReauthentication; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public String getHost() { |     public String getHost() { | ||||||
| 		return host; |         return host; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public void setHost(String host) { |     public void setHost(String host) { | ||||||
| 		this.host = host; |         this.host = host; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public int getPort() { |     public int getPort() { | ||||||
| 		return port; |         return port; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public void setPort(int port) { |     public void setPort(int port) { | ||||||
| 		this.port = port; |         this.port = port; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public String getTunnelUrl() { |     public String getTunnelUrl() { | ||||||
| 		return tunnelUrl; |         return tunnelUrl; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public void setTunnelUrl(String tunnelUrl) { |     public void setTunnelUrl(String tunnelUrl) { | ||||||
| 		this.tunnelUrl = tunnelUrl; |         this.tunnelUrl = tunnelUrl; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public String getTunnelSession() { |     public String getTunnelSession() { | ||||||
| 		return tunnelSession; |         return tunnelSession; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public void setTunnelSession(String tunnelSession) { |     public void setTunnelSession(String tunnelSession) { | ||||||
| 		this.tunnelSession = tunnelSession; |         this.tunnelSession = tunnelSession; | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -25,24 +25,24 @@ import com.cloud.consoleproxy.util.Logger; | |||||||
| import com.sun.net.httpserver.HttpServer; | import com.sun.net.httpserver.HttpServer; | ||||||
| 
 | 
 | ||||||
| public class ConsoleProxyBaseServerFactoryImpl implements ConsoleProxyServerFactory { | public class ConsoleProxyBaseServerFactoryImpl implements ConsoleProxyServerFactory { | ||||||
| 	private static final Logger s_logger = Logger.getLogger(ConsoleProxyBaseServerFactoryImpl.class); |     private static final Logger s_logger = Logger.getLogger(ConsoleProxyBaseServerFactoryImpl.class); | ||||||
|      |      | ||||||
| 	@Override |     @Override | ||||||
| 	public void init(byte[] ksBits, String ksPassword) { |     public void init(byte[] ksBits, String ksPassword) { | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	@Override |     @Override | ||||||
| 	public HttpServer createHttpServerInstance(int port) throws IOException { |     public HttpServer createHttpServerInstance(int port) throws IOException { | ||||||
| 		if(s_logger.isInfoEnabled()) |         if(s_logger.isInfoEnabled()) | ||||||
| 			s_logger.info("create HTTP server instance at port: " + port); |             s_logger.info("create HTTP server instance at port: " + port); | ||||||
| 		return HttpServer.create(new InetSocketAddress(port), 5); |         return HttpServer.create(new InetSocketAddress(port), 5); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	@Override |     @Override | ||||||
| 	public SSLServerSocket createSSLServerSocket(int port) throws IOException { |     public SSLServerSocket createSSLServerSocket(int port) throws IOException { | ||||||
| 		if(s_logger.isInfoEnabled()) |         if(s_logger.isInfoEnabled()) | ||||||
| 			s_logger.info("SSL server socket is not supported in ConsoleProxyBaseServerFactoryImpl"); |             s_logger.info("SSL server socket is not supported in ConsoleProxyBaseServerFactoryImpl"); | ||||||
|          |          | ||||||
| 		return null; |         return null; | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,9 +17,9 @@ | |||||||
| package com.cloud.consoleproxy; | package com.cloud.consoleproxy; | ||||||
| 
 | 
 | ||||||
| public interface ConsoleProxyClientListener { | public interface ConsoleProxyClientListener { | ||||||
| 	void onFramebufferSizeChange(int w, int h); |     void onFramebufferSizeChange(int w, int h); | ||||||
| 	void onFramebufferUpdate(int x, int y, int w, int h); |     void onFramebufferUpdate(int x, int y, int w, int h); | ||||||
| 
 | 
 | ||||||
| 	void onClientConnected(); |     void onClientConnected(); | ||||||
| 	void onClientClose(); |     void onClientClose(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -26,45 +26,45 @@ import com.sun.net.httpserver.HttpExchange; | |||||||
| import com.sun.net.httpserver.HttpHandler; | import com.sun.net.httpserver.HttpHandler; | ||||||
| 
 | 
 | ||||||
| public class ConsoleProxyCmdHandler implements HttpHandler { | public class ConsoleProxyCmdHandler implements HttpHandler { | ||||||
| 	private static final Logger s_logger = Logger.getLogger(ConsoleProxyCmdHandler.class); |     private static final Logger s_logger = Logger.getLogger(ConsoleProxyCmdHandler.class); | ||||||
|      |      | ||||||
| 	public void handle(HttpExchange t) throws IOException { |     public void handle(HttpExchange t) throws IOException { | ||||||
| 		try { |         try { | ||||||
| 	        Thread.currentThread().setName("Cmd Thread " +  |             Thread.currentThread().setName("Cmd Thread " +  | ||||||
| 	        		Thread.currentThread().getId() + " " + t.getRemoteAddress()); |                     Thread.currentThread().getId() + " " + t.getRemoteAddress()); | ||||||
| 			s_logger.info("CmdHandler " + t.getRequestURI()); |             s_logger.info("CmdHandler " + t.getRequestURI()); | ||||||
| 			doHandle(t); |             doHandle(t); | ||||||
| 		} catch (Exception e) { |         } catch (Exception e) { | ||||||
| 			s_logger.error(e.toString(), e); |             s_logger.error(e.toString(), e); | ||||||
| 			String response = "Not found"; |             String response = "Not found"; | ||||||
| 			t.sendResponseHeaders(404, response.length()); |             t.sendResponseHeaders(404, response.length()); | ||||||
| 			OutputStream os = t.getResponseBody(); |             OutputStream os = t.getResponseBody(); | ||||||
| 			os.write(response.getBytes()); |             os.write(response.getBytes()); | ||||||
| 			os.close(); |             os.close(); | ||||||
| 		} catch(OutOfMemoryError e) { |         } catch(OutOfMemoryError e) { | ||||||
| 			s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched"); |             s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched"); | ||||||
| 			System.exit(1); |             System.exit(1); | ||||||
| 		} catch (Throwable e) { |         } catch (Throwable e) { | ||||||
| 			s_logger.error(e.toString(), e); |             s_logger.error(e.toString(), e); | ||||||
| 		} finally { |         } finally { | ||||||
| 			t.close(); |             t.close(); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void doHandle(HttpExchange t) throws Exception { |     public void doHandle(HttpExchange t) throws Exception { | ||||||
| 		String path = t.getRequestURI().getPath(); |         String path = t.getRequestURI().getPath(); | ||||||
| 		int i = path.indexOf("/", 1); |         int i = path.indexOf("/", 1); | ||||||
| 		String cmd = path.substring(i + 1); |         String cmd = path.substring(i + 1); | ||||||
| 		s_logger.info("Get CMD request for " + cmd); |         s_logger.info("Get CMD request for " + cmd); | ||||||
| 		if (cmd.equals("getstatus")) { |         if (cmd.equals("getstatus")) { | ||||||
| 			ConsoleProxyClientStatsCollector statsCollector = ConsoleProxy.getStatsCollector(); |             ConsoleProxyClientStatsCollector statsCollector = ConsoleProxy.getStatsCollector(); | ||||||
|              |              | ||||||
| 			Headers hds = t.getResponseHeaders(); |             Headers hds = t.getResponseHeaders(); | ||||||
| 			hds.set("Content-Type", "text/plain"); |             hds.set("Content-Type", "text/plain"); | ||||||
| 			t.sendResponseHeaders(200, 0); |             t.sendResponseHeaders(200, 0); | ||||||
| 			OutputStreamWriter os = new OutputStreamWriter(t.getResponseBody()); |             OutputStreamWriter os = new OutputStreamWriter(t.getResponseBody()); | ||||||
| 			statsCollector.getStatsReport(os); |             statsCollector.getStatsReport(os); | ||||||
| 			os.close(); |             os.close(); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -22,53 +22,53 @@ import java.util.Map; | |||||||
| import com.cloud.consoleproxy.util.Logger; | import com.cloud.consoleproxy.util.Logger; | ||||||
| 
 | 
 | ||||||
| public class ConsoleProxyHttpHandlerHelper { | public class ConsoleProxyHttpHandlerHelper { | ||||||
| 	private static final Logger s_logger = Logger.getLogger(ConsoleProxyHttpHandlerHelper.class); |     private static final Logger s_logger = Logger.getLogger(ConsoleProxyHttpHandlerHelper.class); | ||||||
|      |      | ||||||
| 	public static Map<String, String> getQueryMap(String query) { |     public static Map<String, String> getQueryMap(String query) { | ||||||
| 		String[] params = query.split("&"); |         String[] params = query.split("&"); | ||||||
| 		Map<String, String> map = new HashMap<String, String>(); |         Map<String, String> map = new HashMap<String, String>(); | ||||||
| 		for (String param : params) { |         for (String param : params) { | ||||||
| 			String[] paramTokens = param.split("="); |             String[] paramTokens = param.split("="); | ||||||
| 			if(paramTokens != null && paramTokens.length == 2) { |             if(paramTokens != null && paramTokens.length == 2) { | ||||||
| 				String name = param.split("=")[0]; |                 String name = param.split("=")[0]; | ||||||
| 				String value = param.split("=")[1]; |                 String value = param.split("=")[1]; | ||||||
| 				map.put(name, value); |                 map.put(name, value); | ||||||
| 			} else if (paramTokens.length == 3) { |             } else if (paramTokens.length == 3) { | ||||||
| 				// very ugly, added for Xen tunneling url |                 // very ugly, added for Xen tunneling url | ||||||
| 				String name = paramTokens[0]; |                 String name = paramTokens[0]; | ||||||
| 				String value = paramTokens[1] + "=" + paramTokens[2]; |                 String value = paramTokens[1] + "=" + paramTokens[2]; | ||||||
| 				map.put(name, value); |                 map.put(name, value); | ||||||
| 			} else { |             } else { | ||||||
| 				if(s_logger.isDebugEnabled()) |                 if(s_logger.isDebugEnabled()) | ||||||
| 					s_logger.debug("Invalid paramemter in URL found. param: " + param); |                     s_logger.debug("Invalid paramemter in URL found. param: " + param); | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		// This is a ugly solution for now. We will do encryption/decryption translation |         // This is a ugly solution for now. We will do encryption/decryption translation | ||||||
| 		// here to make it transparent to rest of the code. |         // here to make it transparent to rest of the code. | ||||||
| 		if(map.get("token") != null) { |         if(map.get("token") != null) { | ||||||
| 			ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor( |             ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor( | ||||||
| 				ConsoleProxy.getEncryptorPassword()); |                 ConsoleProxy.getEncryptorPassword()); | ||||||
|              |              | ||||||
| 			ConsoleProxyClientParam param = encryptor.decryptObject(ConsoleProxyClientParam.class, map.get("token")); |             ConsoleProxyClientParam param = encryptor.decryptObject(ConsoleProxyClientParam.class, map.get("token")); | ||||||
| 			if(param != null) { |             if(param != null) { | ||||||
| 				if(param.getClientHostAddress() != null) |                 if(param.getClientHostAddress() != null) | ||||||
| 					map.put("host", param.getClientHostAddress()); |                     map.put("host", param.getClientHostAddress()); | ||||||
| 				if(param.getClientHostPort() != 0) |                 if(param.getClientHostPort() != 0) | ||||||
| 					map.put("port", String.valueOf(param.getClientHostPort())); |                     map.put("port", String.valueOf(param.getClientHostPort())); | ||||||
| 				if(param.getClientTag() != null) |                 if(param.getClientTag() != null) | ||||||
| 					map.put("tag", param.getClientTag()); |                     map.put("tag", param.getClientTag()); | ||||||
| 				if(param.getClientHostPassword() != null) |                 if(param.getClientHostPassword() != null) | ||||||
| 					map.put("sid", param.getClientHostPassword()); |                     map.put("sid", param.getClientHostPassword()); | ||||||
| 				if(param.getClientTunnelUrl() != null) |                 if(param.getClientTunnelUrl() != null) | ||||||
| 					map.put("consoleurl", param.getClientTunnelUrl()); |                     map.put("consoleurl", param.getClientTunnelUrl()); | ||||||
| 				if(param.getClientTunnelSession() != null) |                 if(param.getClientTunnelSession() != null) | ||||||
| 					map.put("sessionref", param.getClientTunnelSession()); |                     map.put("sessionref", param.getClientTunnelSession()); | ||||||
| 				if(param.getTicket() != null) |                 if(param.getTicket() != null) | ||||||
| 					map.put("ticket", param.getTicket()); |                     map.put("ticket", param.getTicket()); | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		return map; |         return map; | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -20,70 +20,70 @@ import com.cloud.consoleproxy.util.Logger; | |||||||
| import com.cloud.consoleproxy.util.LoggerFactory; | import com.cloud.consoleproxy.util.LoggerFactory; | ||||||
| 
 | 
 | ||||||
| public class ConsoleProxyLoggerFactory implements LoggerFactory { | public class ConsoleProxyLoggerFactory implements LoggerFactory { | ||||||
| 	public ConsoleProxyLoggerFactory() { |     public ConsoleProxyLoggerFactory() { | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public Logger getLogger(Class<?> clazz) { |     public Logger getLogger(Class<?> clazz) { | ||||||
| 		return new Log4jLogger(org.apache.log4j.Logger.getLogger(clazz)); |         return new Log4jLogger(org.apache.log4j.Logger.getLogger(clazz)); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public static class Log4jLogger extends Logger { |     public static class Log4jLogger extends Logger { | ||||||
| 		private org.apache.log4j.Logger logger; |         private org.apache.log4j.Logger logger; | ||||||
|          |          | ||||||
| 		public Log4jLogger(org.apache.log4j.Logger logger) { |         public Log4jLogger(org.apache.log4j.Logger logger) { | ||||||
| 			this.logger = logger; |             this.logger = logger; | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		public boolean isTraceEnabled() { |         public boolean isTraceEnabled() { | ||||||
| 			return logger.isTraceEnabled(); |             return logger.isTraceEnabled(); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		public boolean isDebugEnabled() { |         public boolean isDebugEnabled() { | ||||||
| 			return logger.isDebugEnabled(); |             return logger.isDebugEnabled(); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		public boolean isInfoEnabled() { |         public boolean isInfoEnabled() { | ||||||
| 			return logger.isInfoEnabled(); |             return logger.isInfoEnabled(); | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		public void trace(Object message) { |         public void trace(Object message) { | ||||||
| 			logger.trace(message); |             logger.trace(message); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		public void trace(Object message, Throwable exception) { |         public void trace(Object message, Throwable exception) { | ||||||
| 			logger.trace(message, exception); |             logger.trace(message, exception); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		public void info(Object message) { |         public void info(Object message) { | ||||||
| 			logger.info(message); |             logger.info(message); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		public void info(Object message, Throwable exception) { |         public void info(Object message, Throwable exception) { | ||||||
| 			logger.info(message, exception); |             logger.info(message, exception); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		public void debug(Object message) { |         public void debug(Object message) { | ||||||
| 			logger.debug(message); |             logger.debug(message); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		public void debug(Object message, Throwable exception) { |         public void debug(Object message, Throwable exception) { | ||||||
| 			logger.debug(message, exception); |             logger.debug(message, exception); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		public void warn(Object message) { |         public void warn(Object message) { | ||||||
| 			logger.warn(message); |             logger.warn(message); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		public void warn(Object message, Throwable exception) { |         public void warn(Object message, Throwable exception) { | ||||||
| 			logger.warn(message, exception); |             logger.warn(message, exception); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		public void error(Object message) { |         public void error(Object message) { | ||||||
| 			logger.error(message); |             logger.error(message); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		public void error(Object message, Throwable exception) { |         public void error(Object message, Throwable exception) { | ||||||
| 			logger.error(message, exception); |             logger.error(message, exception); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -34,120 +34,120 @@ import com.cloud.consoleproxy.util.Logger; | |||||||
| // itself and the shell script will re-launch console proxy | // itself and the shell script will re-launch console proxy | ||||||
| // | // | ||||||
| public class ConsoleProxyMonitor { | public class ConsoleProxyMonitor { | ||||||
| 	private static final Logger s_logger = Logger.getLogger(ConsoleProxyMonitor.class); |     private static final Logger s_logger = Logger.getLogger(ConsoleProxyMonitor.class); | ||||||
|      |      | ||||||
| 	private String[] _argv; |     private String[] _argv; | ||||||
| 	private Map<String, String> _argMap = new HashMap<String, String>(); |     private Map<String, String> _argMap = new HashMap<String, String>(); | ||||||
|      |      | ||||||
| 	private volatile Process _process; |     private volatile Process _process; | ||||||
| 	private boolean _quit = false; |     private boolean _quit = false; | ||||||
|      |      | ||||||
| 	public ConsoleProxyMonitor(String[] argv) { |     public ConsoleProxyMonitor(String[] argv) { | ||||||
| 		_argv = argv; |         _argv = argv; | ||||||
|          |          | ||||||
| 		for(String arg : _argv) { |         for(String arg : _argv) { | ||||||
| 			String[] tokens = arg.split("="); |             String[] tokens = arg.split("="); | ||||||
| 			if(tokens.length == 2) { |             if(tokens.length == 2) { | ||||||
| 				s_logger.info("Add argument " + tokens[0] + "=" + tokens[1] + " to the argument map"); |                 s_logger.info("Add argument " + tokens[0] + "=" + tokens[1] + " to the argument map"); | ||||||
| 
 | 
 | ||||||
| 				_argMap.put(tokens[0].trim(), tokens[1].trim()); |                 _argMap.put(tokens[0].trim(), tokens[1].trim()); | ||||||
| 			} else { |             } else { | ||||||
| 				s_logger.warn("unrecognized argument, skip adding it to argument map"); |                 s_logger.warn("unrecognized argument, skip adding it to argument map"); | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private void run() { |     private void run() { | ||||||
| 		Runtime.getRuntime().addShutdownHook(new Thread() { |         Runtime.getRuntime().addShutdownHook(new Thread() { | ||||||
| 			@Override |             @Override | ||||||
| 			public void run() { |             public void run() { | ||||||
| 				_quit = true; |                 _quit = true; | ||||||
| 				onShutdown(); |                 onShutdown(); | ||||||
| 			} |             } | ||||||
| 		}); |         }); | ||||||
|          |          | ||||||
| 		while(!_quit) { |         while(!_quit) { | ||||||
| 			String cmdLine = getLaunchCommandLine(); |             String cmdLine = getLaunchCommandLine(); | ||||||
|              |              | ||||||
| 			s_logger.info("Launch console proxy process with command line: " + cmdLine); |             s_logger.info("Launch console proxy process with command line: " + cmdLine); | ||||||
|              |              | ||||||
| 			try { |             try { | ||||||
| 				_process = Runtime.getRuntime().exec(cmdLine); |                 _process = Runtime.getRuntime().exec(cmdLine); | ||||||
| 			} catch (IOException e) { |             } catch (IOException e) { | ||||||
| 				s_logger.error("Unexpected exception ", e); |                 s_logger.error("Unexpected exception ", e); | ||||||
| 				System.exit(1); |                 System.exit(1); | ||||||
| 			} |             } | ||||||
|              |              | ||||||
| 			boolean waitSucceeded = false; |             boolean waitSucceeded = false; | ||||||
| 			int exitCode = 0; |             int exitCode = 0; | ||||||
| 			while(!waitSucceeded) { |             while(!waitSucceeded) { | ||||||
| 				try { |                 try { | ||||||
| 					exitCode = _process.waitFor(); |                     exitCode = _process.waitFor(); | ||||||
| 					waitSucceeded = true; |                     waitSucceeded = true; | ||||||
|                      |                      | ||||||
| 					if(s_logger.isInfoEnabled()) |                     if(s_logger.isInfoEnabled()) | ||||||
| 						s_logger.info("Console proxy process exits with code: " + exitCode); |                         s_logger.info("Console proxy process exits with code: " + exitCode); | ||||||
| 				} catch (InterruptedException e) { |                 } catch (InterruptedException e) { | ||||||
| 					if(s_logger.isInfoEnabled()) |                     if(s_logger.isInfoEnabled()) | ||||||
| 						s_logger.info("InterruptedException while waiting for termination of console proxy, will retry"); |                         s_logger.info("InterruptedException while waiting for termination of console proxy, will retry"); | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private String getLaunchCommandLine() { |     private String getLaunchCommandLine() { | ||||||
| 		StringBuffer sb = new StringBuffer("java "); |         StringBuffer sb = new StringBuffer("java "); | ||||||
| 		String jvmOptions = _argMap.get("jvmoptions"); |         String jvmOptions = _argMap.get("jvmoptions"); | ||||||
|          |          | ||||||
| 		if(jvmOptions != null) |         if(jvmOptions != null) | ||||||
| 			sb.append(jvmOptions); |             sb.append(jvmOptions); | ||||||
|          |          | ||||||
| 		for(Map.Entry<String, String> entry : _argMap.entrySet()) { |         for(Map.Entry<String, String> entry : _argMap.entrySet()) { | ||||||
| 			if(!"jvmoptions".equalsIgnoreCase(entry.getKey())) |             if(!"jvmoptions".equalsIgnoreCase(entry.getKey())) | ||||||
| 				sb.append(" ").append(entry.getKey()).append("=").append(entry.getValue()); |                 sb.append(" ").append(entry.getKey()).append("=").append(entry.getValue()); | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		return sb.toString(); |         return sb.toString(); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private void onShutdown() { |     private void onShutdown() { | ||||||
| 		if(_process != null) { |         if(_process != null) { | ||||||
| 			if(s_logger.isInfoEnabled()) |             if(s_logger.isInfoEnabled()) | ||||||
| 				s_logger.info("Console proxy monitor shuts dwon, terminate console proxy process"); |                 s_logger.info("Console proxy monitor shuts dwon, terminate console proxy process"); | ||||||
| 			_process.destroy(); |             _process.destroy(); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	private static void configLog4j() { |     private static void configLog4j() { | ||||||
| 		URL configUrl = System.class.getResource("/conf/log4j-cloud.xml"); |         URL configUrl = System.class.getResource("/conf/log4j-cloud.xml"); | ||||||
| 		if(configUrl == null) |         if(configUrl == null) | ||||||
| 			configUrl = ClassLoader.getSystemResource("log4j-cloud.xml"); |             configUrl = ClassLoader.getSystemResource("log4j-cloud.xml"); | ||||||
|          |          | ||||||
| 		if(configUrl == null) |         if(configUrl == null) | ||||||
| 			configUrl = ClassLoader.getSystemResource("conf/log4j-cloud.xml"); |             configUrl = ClassLoader.getSystemResource("conf/log4j-cloud.xml"); | ||||||
|              |              | ||||||
| 		if(configUrl != null) { |         if(configUrl != null) { | ||||||
| 			try { |             try { | ||||||
| 				System.out.println("Configure log4j using " + configUrl.toURI().toString()); |                 System.out.println("Configure log4j using " + configUrl.toURI().toString()); | ||||||
| 			} catch (URISyntaxException e1) { |             } catch (URISyntaxException e1) { | ||||||
| 				e1.printStackTrace(); |                 e1.printStackTrace(); | ||||||
| 			} |             } | ||||||
| 
 | 
 | ||||||
| 			try { |             try { | ||||||
| 				File file = new File(configUrl.toURI()); |                 File file = new File(configUrl.toURI()); | ||||||
|                  |                  | ||||||
| 				System.out.println("Log4j configuration from : " + file.getAbsolutePath()); |                 System.out.println("Log4j configuration from : " + file.getAbsolutePath()); | ||||||
| 				DOMConfigurator.configureAndWatch(file.getAbsolutePath(), 10000); |                 DOMConfigurator.configureAndWatch(file.getAbsolutePath(), 10000); | ||||||
| 			} catch (URISyntaxException e) { |             } catch (URISyntaxException e) { | ||||||
| 				System.out.println("Unable to convert log4j configuration Url to URI"); |                 System.out.println("Unable to convert log4j configuration Url to URI"); | ||||||
| 			} |             } | ||||||
| 		} else { |         } else { | ||||||
| 			System.out.println("Configure log4j with default properties"); |             System.out.println("Configure log4j with default properties"); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public static void main(String[] argv) { |     public static void main(String[] argv) { | ||||||
| 		configLog4j(); |         configLog4j(); | ||||||
| 		(new ConsoleProxyMonitor(argv)).run(); |         (new ConsoleProxyMonitor(argv)).run(); | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -30,152 +30,152 @@ import com.sun.net.httpserver.HttpExchange; | |||||||
| import com.sun.net.httpserver.HttpHandler; | import com.sun.net.httpserver.HttpHandler; | ||||||
| 
 | 
 | ||||||
| public class ConsoleProxyResourceHandler implements HttpHandler { | public class ConsoleProxyResourceHandler implements HttpHandler { | ||||||
| 	private static final Logger s_logger = Logger.getLogger(ConsoleProxyResourceHandler.class); |     private static final Logger s_logger = Logger.getLogger(ConsoleProxyResourceHandler.class); | ||||||
| 
 | 
 | ||||||
| 	static Map<String, String> s_mimeTypes; |     static Map<String, String> s_mimeTypes; | ||||||
| 	static { |     static { | ||||||
| 		s_mimeTypes = new HashMap<String, String>(); |         s_mimeTypes = new HashMap<String, String>(); | ||||||
| 		s_mimeTypes.put("jar", "application/java-archive"); |         s_mimeTypes.put("jar", "application/java-archive"); | ||||||
| 		s_mimeTypes.put("js", "text/javascript"); |         s_mimeTypes.put("js", "text/javascript"); | ||||||
| 		s_mimeTypes.put("css", "text/css"); |         s_mimeTypes.put("css", "text/css"); | ||||||
| 		s_mimeTypes.put("jpg", "image/jpeg"); |         s_mimeTypes.put("jpg", "image/jpeg"); | ||||||
| 		s_mimeTypes.put("html", "text/html"); |         s_mimeTypes.put("html", "text/html"); | ||||||
| 		s_mimeTypes.put("htm", "text/html"); |         s_mimeTypes.put("htm", "text/html"); | ||||||
| 		s_mimeTypes.put("log", "text/plain"); |         s_mimeTypes.put("log", "text/plain"); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	static Map<String, String> s_validResourceFolders; |     static Map<String, String> s_validResourceFolders; | ||||||
| 	static { |     static { | ||||||
| 		s_validResourceFolders = new HashMap<String, String>(); |         s_validResourceFolders = new HashMap<String, String>(); | ||||||
| 		s_validResourceFolders.put("applet", ""); |         s_validResourceFolders.put("applet", ""); | ||||||
| 		s_validResourceFolders.put("logs", ""); |         s_validResourceFolders.put("logs", ""); | ||||||
| 		s_validResourceFolders.put("images", ""); |         s_validResourceFolders.put("images", ""); | ||||||
| 		s_validResourceFolders.put("js", ""); |         s_validResourceFolders.put("js", ""); | ||||||
| 		s_validResourceFolders.put("css", ""); |         s_validResourceFolders.put("css", ""); | ||||||
| 		s_validResourceFolders.put("html", ""); |         s_validResourceFolders.put("html", ""); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public ConsoleProxyResourceHandler() { |     public ConsoleProxyResourceHandler() { | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void handle(HttpExchange t) throws IOException { |     public void handle(HttpExchange t) throws IOException { | ||||||
| 		try { |         try { | ||||||
| 	        if(s_logger.isDebugEnabled()) |             if(s_logger.isDebugEnabled()) | ||||||
| 	        	s_logger.debug("Resource Handler " + t.getRequestURI()); |                 s_logger.debug("Resource Handler " + t.getRequestURI()); | ||||||
|              |              | ||||||
| 	        long startTick = System.currentTimeMillis(); |             long startTick = System.currentTimeMillis(); | ||||||
|              |              | ||||||
| 	        doHandle(t); |             doHandle(t); | ||||||
|              |              | ||||||
| 	        if(s_logger.isDebugEnabled()) |             if(s_logger.isDebugEnabled()) | ||||||
| 	        	s_logger.debug(t.getRequestURI() + " Process time " + (System.currentTimeMillis() - startTick) + " ms"); |                 s_logger.debug(t.getRequestURI() + " Process time " + (System.currentTimeMillis() - startTick) + " ms"); | ||||||
| 		} catch (IOException e) { |         } catch (IOException e) { | ||||||
| 			throw e; |             throw e; | ||||||
| 		} catch(Throwable e) { |         } catch(Throwable e) { | ||||||
| 			s_logger.error("Unexpected exception, ", e); |             s_logger.error("Unexpected exception, ", e); | ||||||
| 			t.sendResponseHeaders(500, -1);		// server error |             t.sendResponseHeaders(500, -1);     // server error | ||||||
| 		} finally { |         } finally { | ||||||
| 			t.close(); |             t.close(); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	@SuppressWarnings("deprecation") |     @SuppressWarnings("deprecation") | ||||||
| 	private void doHandle(HttpExchange t) throws Exception { |     private void doHandle(HttpExchange t) throws Exception { | ||||||
| 		String path = t.getRequestURI().getPath(); |         String path = t.getRequestURI().getPath(); | ||||||
| 
 | 
 | ||||||
| 		if(s_logger.isInfoEnabled()) |         if(s_logger.isInfoEnabled()) | ||||||
| 			s_logger.info("Get resource request for " + path); |             s_logger.info("Get resource request for " + path); | ||||||
|          |          | ||||||
| 		int i = path.indexOf("/", 1); |         int i = path.indexOf("/", 1); | ||||||
| 		String filepath = path.substring(i + 1); |         String filepath = path.substring(i + 1); | ||||||
| 		i = path.lastIndexOf("."); |         i = path.lastIndexOf("."); | ||||||
| 		String extension = (i == -1) ? "" : path.substring(i + 1); |         String extension = (i == -1) ? "" : path.substring(i + 1); | ||||||
| 		String contentType = getContentType(extension); |         String contentType = getContentType(extension); | ||||||
| 
 | 
 | ||||||
| 		if(!validatePath(filepath)) { |         if(!validatePath(filepath)) { | ||||||
| 			if(s_logger.isInfoEnabled()) |             if(s_logger.isInfoEnabled()) | ||||||
| 				s_logger.info("Resource access is forbidden, uri: " + path); |                 s_logger.info("Resource access is forbidden, uri: " + path); | ||||||
|              |              | ||||||
| 			t.sendResponseHeaders(403, -1);		// forbidden |             t.sendResponseHeaders(403, -1);     // forbidden | ||||||
| 			return; |             return; | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		File f = new File ("./" + filepath); |         File f = new File ("./" + filepath); | ||||||
| 		if(f.exists()) { |         if(f.exists()) { | ||||||
| 			long lastModified = f.lastModified(); |             long lastModified = f.lastModified(); | ||||||
| 			String ifModifiedSince = t.getRequestHeaders().getFirst("If-Modified-Since"); |             String ifModifiedSince = t.getRequestHeaders().getFirst("If-Modified-Since"); | ||||||
| 			if (ifModifiedSince != null) { |             if (ifModifiedSince != null) { | ||||||
| 				long d = Date.parse(ifModifiedSince); |                 long d = Date.parse(ifModifiedSince); | ||||||
| 				if (d + 1000 >= lastModified) { |                 if (d + 1000 >= lastModified) { | ||||||
| 					Headers hds = t.getResponseHeaders(); |                     Headers hds = t.getResponseHeaders(); | ||||||
| 					hds.set("Content-Type", contentType); |                     hds.set("Content-Type", contentType); | ||||||
| 					t.sendResponseHeaders(304, -1); |                     t.sendResponseHeaders(304, -1); | ||||||
|                      |                      | ||||||
| 					if(s_logger.isInfoEnabled()) |                     if(s_logger.isInfoEnabled()) | ||||||
| 						s_logger.info("Sent 304 file has not been " + |                         s_logger.info("Sent 304 file has not been " + | ||||||
| 								"modified since " + ifModifiedSince); |                                 "modified since " + ifModifiedSince); | ||||||
| 					return; |                     return; | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
|              |              | ||||||
| 			long length = f.length(); |             long length = f.length(); | ||||||
| 			Headers hds = t.getResponseHeaders(); |             Headers hds = t.getResponseHeaders(); | ||||||
| 			hds.set("Content-Type", contentType); |             hds.set("Content-Type", contentType); | ||||||
| 			hds.set("Last-Modified", new Date(lastModified).toGMTString()); |             hds.set("Last-Modified", new Date(lastModified).toGMTString()); | ||||||
| 			t.sendResponseHeaders(200, length); |             t.sendResponseHeaders(200, length); | ||||||
| 			responseFileContent(t, f); |             responseFileContent(t, f); | ||||||
|              |              | ||||||
| 			if(s_logger.isInfoEnabled()) |             if(s_logger.isInfoEnabled()) | ||||||
| 				s_logger.info("Sent file " + path + " with content type " + contentType); |                 s_logger.info("Sent file " + path + " with content type " + contentType); | ||||||
| 		} else { |         } else { | ||||||
| 			if(s_logger.isInfoEnabled()) |             if(s_logger.isInfoEnabled()) | ||||||
| 				s_logger.info("file does not exist" + path); |                 s_logger.info("file does not exist" + path); | ||||||
| 			t.sendResponseHeaders(404, -1); |             t.sendResponseHeaders(404, -1); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private static String getContentType(String extension) { |     private static String getContentType(String extension) { | ||||||
| 		String key = extension.toLowerCase(); |         String key = extension.toLowerCase(); | ||||||
| 		if(s_mimeTypes.containsKey(key)) { |         if(s_mimeTypes.containsKey(key)) { | ||||||
| 			return s_mimeTypes.get(key); |             return s_mimeTypes.get(key); | ||||||
| 		} |         } | ||||||
| 		return "application/octet-stream";  |         return "application/octet-stream";  | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private static void responseFileContent(HttpExchange t, File f) throws Exception { |     private static void responseFileContent(HttpExchange t, File f) throws Exception { | ||||||
| 		OutputStream os = t.getResponseBody(); |         OutputStream os = t.getResponseBody(); | ||||||
| 		FileInputStream fis = new FileInputStream(f); |         FileInputStream fis = new FileInputStream(f); | ||||||
| 		while (true) { |         while (true) { | ||||||
| 			byte[] b = new byte[8192]; |             byte[] b = new byte[8192]; | ||||||
| 			int n = fis.read(b); |             int n = fis.read(b); | ||||||
| 			if (n < 0) { |             if (n < 0) { | ||||||
| 				break; |                 break; | ||||||
| 			} |             } | ||||||
| 			os.write(b, 0, n); |             os.write(b, 0, n); | ||||||
| 		} |         } | ||||||
| 		fis.close(); |         fis.close(); | ||||||
| 		os.close(); |         os.close(); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private static boolean validatePath(String path) { |     private static boolean validatePath(String path) { | ||||||
| 		int i = path.indexOf("/"); |         int i = path.indexOf("/"); | ||||||
| 		if(i == -1) { |         if(i == -1) { | ||||||
| 			if(s_logger.isInfoEnabled()) |             if(s_logger.isInfoEnabled()) | ||||||
| 				s_logger.info("Invalid resource path: can not start at resource root"); |                 s_logger.info("Invalid resource path: can not start at resource root"); | ||||||
| 			return false; |             return false; | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		if(path.contains("..")) { |         if(path.contains("..")) { | ||||||
| 			if(s_logger.isInfoEnabled()) |             if(s_logger.isInfoEnabled()) | ||||||
| 				s_logger.info("Invalid resource path: contains relative up-level navigation"); |                 s_logger.info("Invalid resource path: contains relative up-level navigation"); | ||||||
|              |              | ||||||
| 			return false; |             return false; | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		return isValidResourceFolder(path.substring(0, i)); |         return isValidResourceFolder(path.substring(0, i)); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private static boolean isValidResourceFolder(String name) { |     private static boolean isValidResourceFolder(String name) { | ||||||
| 		return s_validResourceFolders.containsKey(name);  |         return s_validResourceFolders.containsKey(name);  | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -37,109 +37,109 @@ import com.sun.net.httpserver.HttpsParameters; | |||||||
| import com.sun.net.httpserver.HttpsServer; | import com.sun.net.httpserver.HttpsServer; | ||||||
| 
 | 
 | ||||||
| public class ConsoleProxySecureServerFactoryImpl implements ConsoleProxyServerFactory  { | public class ConsoleProxySecureServerFactoryImpl implements ConsoleProxyServerFactory  { | ||||||
| 	private static final Logger s_logger = Logger.getLogger(ConsoleProxySecureServerFactoryImpl.class); |     private static final Logger s_logger = Logger.getLogger(ConsoleProxySecureServerFactoryImpl.class); | ||||||
|      |      | ||||||
| 	private SSLContext sslContext = null; |     private SSLContext sslContext = null; | ||||||
|      |      | ||||||
| 	public ConsoleProxySecureServerFactoryImpl() { |     public ConsoleProxySecureServerFactoryImpl() { | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	@Override |     @Override | ||||||
| 	public void init(byte[] ksBits, String ksPassword) { |     public void init(byte[] ksBits, String ksPassword) { | ||||||
| 	    s_logger.info("Start initializing SSL"); |         s_logger.info("Start initializing SSL"); | ||||||
| 
 | 
 | ||||||
| 	    if(ksBits == null) { |         if(ksBits == null) { | ||||||
| 			try { |             try { | ||||||
| 			    s_logger.info("Initializing SSL from built-in default certificate"); |                 s_logger.info("Initializing SSL from built-in default certificate"); | ||||||
|                  |                  | ||||||
| 				char[] passphrase = "vmops.com".toCharArray(); |                 char[] passphrase = "vmops.com".toCharArray(); | ||||||
| 				KeyStore ks = KeyStore.getInstance("JKS"); |                 KeyStore ks = KeyStore.getInstance("JKS"); | ||||||
|                  |                  | ||||||
| 				ks.load(new FileInputStream("certs/realhostip.keystore"), passphrase); |                 ks.load(new FileInputStream("certs/realhostip.keystore"), passphrase); | ||||||
| 				// ks.load(ConsoleProxy.class.getResourceAsStream("/realhostip.keystore"), passphrase); |                 // ks.load(ConsoleProxy.class.getResourceAsStream("/realhostip.keystore"), passphrase); | ||||||
|                  |                  | ||||||
| 			    s_logger.info("SSL certificate loaded"); |                 s_logger.info("SSL certificate loaded"); | ||||||
|                  |                  | ||||||
| 				KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); |                 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); | ||||||
| 				kmf.init(ks, passphrase); |                 kmf.init(ks, passphrase); | ||||||
| 			    s_logger.info("Key manager factory is initialized"); |                 s_logger.info("Key manager factory is initialized"); | ||||||
| 
 | 
 | ||||||
| 				TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); |                 TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); | ||||||
| 				tmf.init(ks); |                 tmf.init(ks); | ||||||
| 			    s_logger.info("Trust manager factory is initialized"); |                 s_logger.info("Trust manager factory is initialized"); | ||||||
| 
 | 
 | ||||||
| 				sslContext = SSLContext.getInstance("TLS"); |                 sslContext = SSLContext.getInstance("TLS"); | ||||||
| 				sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); |                 sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); | ||||||
| 			    s_logger.info("SSL context is initialized"); |                 s_logger.info("SSL context is initialized"); | ||||||
| 			} catch (Exception ioe) { |             } catch (Exception ioe) { | ||||||
| 				s_logger.error(ioe.toString(), ioe); |                 s_logger.error(ioe.toString(), ioe); | ||||||
| 			} |             } | ||||||
|              |              | ||||||
| 	    } else { |         } else { | ||||||
| 			char[] passphrase = ksPassword != null ? ksPassword.toCharArray() : null; |             char[] passphrase = ksPassword != null ? ksPassword.toCharArray() : null; | ||||||
| 			try { |             try { | ||||||
| 			    s_logger.info("Initializing SSL from passed-in certificate"); |                 s_logger.info("Initializing SSL from passed-in certificate"); | ||||||
|                  |                  | ||||||
| 				KeyStore ks = KeyStore.getInstance("JKS"); |                 KeyStore ks = KeyStore.getInstance("JKS"); | ||||||
| 				ks.load(new ByteArrayInputStream(ksBits), passphrase); |                 ks.load(new ByteArrayInputStream(ksBits), passphrase); | ||||||
|                  |                  | ||||||
| 				KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); |                 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); | ||||||
| 				kmf.init(ks, passphrase); |                 kmf.init(ks, passphrase); | ||||||
| 			    s_logger.info("Key manager factory is initialized"); |                 s_logger.info("Key manager factory is initialized"); | ||||||
|          |          | ||||||
| 				TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); |                 TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); | ||||||
| 				tmf.init(ks); |                 tmf.init(ks); | ||||||
| 			    s_logger.info("Trust manager factory is initialized"); |                 s_logger.info("Trust manager factory is initialized"); | ||||||
|          |          | ||||||
| 				sslContext = SSLContext.getInstance("TLS"); |                 sslContext = SSLContext.getInstance("TLS"); | ||||||
| 				sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); |                 sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); | ||||||
| 			    s_logger.info("SSL context is initialized"); |                 s_logger.info("SSL context is initialized"); | ||||||
| 			} catch(Exception e) { |             } catch(Exception e) { | ||||||
| 				s_logger.error("Unable to init factory due to exception ", e); |                 s_logger.error("Unable to init factory due to exception ", e); | ||||||
| 			} |             } | ||||||
| 	    } |         } | ||||||
|          |          | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public HttpServer createHttpServerInstance(int port) throws IOException { |     public HttpServer createHttpServerInstance(int port) throws IOException { | ||||||
| 		try { |         try { | ||||||
| 			HttpsServer server = HttpsServer.create(new InetSocketAddress(port), 5); |             HttpsServer server = HttpsServer.create(new InetSocketAddress(port), 5); | ||||||
| 		    server.setHttpsConfigurator (new HttpsConfigurator(sslContext) { |             server.setHttpsConfigurator (new HttpsConfigurator(sslContext) { | ||||||
| 		        @Override |                 @Override | ||||||
|                 public void configure (HttpsParameters params) { |                 public void configure (HttpsParameters params) { | ||||||
| 
 | 
 | ||||||
| 		        // get the remote address if needed |                 // get the remote address if needed | ||||||
| 		        InetSocketAddress remote = params.getClientAddress(); |                 InetSocketAddress remote = params.getClientAddress(); | ||||||
| 		        SSLContext c = getSSLContext(); |                 SSLContext c = getSSLContext(); | ||||||
| 
 | 
 | ||||||
| 		        // get the default parameters |                 // get the default parameters | ||||||
| 		        SSLParameters sslparams = c.getDefaultSSLParameters(); |                 SSLParameters sslparams = c.getDefaultSSLParameters(); | ||||||
| 
 | 
 | ||||||
| 		        params.setSSLParameters(sslparams); |                 params.setSSLParameters(sslparams); | ||||||
| 		        // statement above could throw IAE if any params invalid. |                 // statement above could throw IAE if any params invalid. | ||||||
| 		        // eg. if app has a UI and parameters supplied by a user. |                 // eg. if app has a UI and parameters supplied by a user. | ||||||
| 		        } |                 } | ||||||
| 		    }); |             }); | ||||||
|              |              | ||||||
| 		    s_logger.info("create HTTPS server instance on port: " + port); |             s_logger.info("create HTTPS server instance on port: " + port); | ||||||
| 		    return server; |             return server; | ||||||
| 		} catch (Exception ioe) { |         } catch (Exception ioe) { | ||||||
| 			s_logger.error(ioe.toString(), ioe); |             s_logger.error(ioe.toString(), ioe); | ||||||
| 		} |         } | ||||||
| 		return null; |         return null; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public SSLServerSocket createSSLServerSocket(int port) throws IOException { |     public SSLServerSocket createSSLServerSocket(int port) throws IOException { | ||||||
| 		try { |         try { | ||||||
| 			SSLServerSocket srvSock = null; |             SSLServerSocket srvSock = null; | ||||||
| 	        SSLServerSocketFactory ssf = sslContext.getServerSocketFactory(); |             SSLServerSocketFactory ssf = sslContext.getServerSocketFactory(); | ||||||
| 	        srvSock = (SSLServerSocket) ssf.createServerSocket(port); |             srvSock = (SSLServerSocket) ssf.createServerSocket(port); | ||||||
|              |              | ||||||
| 		    s_logger.info("create SSL server socket on port: " + port); |             s_logger.info("create SSL server socket on port: " + port); | ||||||
| 	        return srvSock; |             return srvSock; | ||||||
| 		} catch (Exception ioe) { |         } catch (Exception ioe) { | ||||||
| 			s_logger.error(ioe.toString(), ioe); |             s_logger.error(ioe.toString(), ioe); | ||||||
| 		} |         } | ||||||
| 		return null; |         return null; | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ import javax.net.ssl.SSLServerSocket; | |||||||
| import com.sun.net.httpserver.HttpServer; | import com.sun.net.httpserver.HttpServer; | ||||||
| 
 | 
 | ||||||
| public interface ConsoleProxyServerFactory { | public interface ConsoleProxyServerFactory { | ||||||
| 	void init(byte[] ksBits, String ksPassword); |     void init(byte[] ksBits, String ksPassword); | ||||||
| 	HttpServer createHttpServerInstance(int port) throws IOException; |     HttpServer createHttpServerInstance(int port) throws IOException; | ||||||
| 	SSLServerSocket createSSLServerSocket(int port) throws IOException; |     SSLServerSocket createSSLServerSocket(int port) throws IOException; | ||||||
| } | } | ||||||
|  | |||||||
| @ -34,179 +34,179 @@ import com.sun.net.httpserver.HttpExchange; | |||||||
| import com.sun.net.httpserver.HttpHandler; | import com.sun.net.httpserver.HttpHandler; | ||||||
| 
 | 
 | ||||||
| public class ConsoleProxyThumbnailHandler implements HttpHandler { | public class ConsoleProxyThumbnailHandler implements HttpHandler { | ||||||
| 	private static final Logger s_logger = Logger.getLogger(ConsoleProxyThumbnailHandler.class); |     private static final Logger s_logger = Logger.getLogger(ConsoleProxyThumbnailHandler.class); | ||||||
|      |      | ||||||
| 	public ConsoleProxyThumbnailHandler() { |     public ConsoleProxyThumbnailHandler() { | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public void handle(HttpExchange t) throws IOException { |     public void handle(HttpExchange t) throws IOException { | ||||||
| 		try { |         try { | ||||||
| 	        Thread.currentThread().setName("JPG Thread " +  |             Thread.currentThread().setName("JPG Thread " +  | ||||||
| 	        		Thread.currentThread().getId() + " " + t.getRemoteAddress()); |                     Thread.currentThread().getId() + " " + t.getRemoteAddress()); | ||||||
|              |              | ||||||
| 	        if(s_logger.isDebugEnabled()) |             if(s_logger.isDebugEnabled()) | ||||||
| 	        	s_logger.debug("ScreenHandler " + t.getRequestURI()); |                 s_logger.debug("ScreenHandler " + t.getRequestURI()); | ||||||
|              |              | ||||||
| 	        long startTick = System.currentTimeMillis(); |             long startTick = System.currentTimeMillis(); | ||||||
| 			doHandle(t); |             doHandle(t); | ||||||
|              |              | ||||||
| 	        if(s_logger.isDebugEnabled()) |             if(s_logger.isDebugEnabled()) | ||||||
| 	        	s_logger.debug(t.getRequestURI() + "Process time " + (System.currentTimeMillis() - startTick) + " ms"); |                 s_logger.debug(t.getRequestURI() + "Process time " + (System.currentTimeMillis() - startTick) + " ms"); | ||||||
| 		} catch (IllegalArgumentException e) { |         } catch (IllegalArgumentException e) { | ||||||
| 			String response = "Bad query string"; |             String response = "Bad query string"; | ||||||
| 			s_logger.error(response + ", request URI : " + t.getRequestURI()); |             s_logger.error(response + ", request URI : " + t.getRequestURI()); | ||||||
| 			t.sendResponseHeaders(200, response.length()); |             t.sendResponseHeaders(200, response.length()); | ||||||
| 			OutputStream os = t.getResponseBody(); |             OutputStream os = t.getResponseBody(); | ||||||
| 			os.write(response.getBytes()); |             os.write(response.getBytes()); | ||||||
| 			os.close(); |             os.close(); | ||||||
| 		} catch(OutOfMemoryError e) { |         } catch(OutOfMemoryError e) { | ||||||
| 			s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched"); |             s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched"); | ||||||
| 			System.exit(1); |             System.exit(1); | ||||||
| 		} catch (Throwable e) { |         } catch (Throwable e) { | ||||||
| 			s_logger.error("Unexpected exception while handing thumbnail request, ", e); |             s_logger.error("Unexpected exception while handing thumbnail request, ", e); | ||||||
|              |              | ||||||
| 			String queries = t.getRequestURI().getQuery(); |             String queries = t.getRequestURI().getQuery(); | ||||||
| 			Map<String, String> queryMap = getQueryMap(queries); |             Map<String, String> queryMap = getQueryMap(queries); | ||||||
| 			int width = 0; |             int width = 0; | ||||||
| 			int height = 0; |             int height = 0; | ||||||
| 			String ws = queryMap.get("w"); |             String ws = queryMap.get("w"); | ||||||
| 			String hs = queryMap.get("h"); |             String hs = queryMap.get("h"); | ||||||
| 			try { |             try { | ||||||
| 				width = Integer.parseInt(ws); |                 width = Integer.parseInt(ws); | ||||||
| 				height = Integer.parseInt(hs); |                 height = Integer.parseInt(hs); | ||||||
| 			} catch (NumberFormatException ex) { |             } catch (NumberFormatException ex) { | ||||||
| 			} |             } | ||||||
| 			width = Math.min(width, 800); |             width = Math.min(width, 800); | ||||||
| 			height = Math.min(height, 600); |             height = Math.min(height, 600); | ||||||
|              |              | ||||||
| 			BufferedImage img = generateTextImage(width, height, "Cannot Connect"); |             BufferedImage img = generateTextImage(width, height, "Cannot Connect"); | ||||||
| 			ByteArrayOutputStream bos = new ByteArrayOutputStream(8196); |             ByteArrayOutputStream bos = new ByteArrayOutputStream(8196); | ||||||
| 			javax.imageio.ImageIO.write(img, "jpg", bos); |             javax.imageio.ImageIO.write(img, "jpg", bos); | ||||||
| 			byte[] bs = bos.toByteArray(); |             byte[] bs = bos.toByteArray(); | ||||||
| 			Headers hds = t.getResponseHeaders(); |             Headers hds = t.getResponseHeaders(); | ||||||
| 			hds.set("Content-Type", "image/jpeg"); |             hds.set("Content-Type", "image/jpeg"); | ||||||
| 			hds.set("Cache-Control", "no-cache"); |             hds.set("Cache-Control", "no-cache"); | ||||||
| 			hds.set("Cache-Control", "no-store"); |             hds.set("Cache-Control", "no-store"); | ||||||
| 			t.sendResponseHeaders(200, bs.length); |             t.sendResponseHeaders(200, bs.length); | ||||||
| 			OutputStream os = t.getResponseBody(); |             OutputStream os = t.getResponseBody(); | ||||||
| 			os.write(bs); |             os.write(bs); | ||||||
| 			os.close(); |             os.close(); | ||||||
| 			s_logger.error("Cannot get console, sent error JPG response for " + t.getRequestURI()); |             s_logger.error("Cannot get console, sent error JPG response for " + t.getRequestURI()); | ||||||
| 			return; |             return; | ||||||
| 		} finally { |         } finally { | ||||||
| 			t.close(); |             t.close(); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private void doHandle(HttpExchange t) throws Exception, IllegalArgumentException { |     private void doHandle(HttpExchange t) throws Exception, IllegalArgumentException { | ||||||
| 		String queries = t.getRequestURI().getQuery(); |         String queries = t.getRequestURI().getQuery(); | ||||||
| 		Map<String, String> queryMap = getQueryMap(queries); |         Map<String, String> queryMap = getQueryMap(queries); | ||||||
| 		int width = 0; |         int width = 0; | ||||||
| 		int height = 0; |         int height = 0; | ||||||
| 		int port = 0; |         int port = 0; | ||||||
| 		String ws = queryMap.get("w"); |         String ws = queryMap.get("w"); | ||||||
| 		String hs = queryMap.get("h"); |         String hs = queryMap.get("h"); | ||||||
| 		String host = queryMap.get("host"); |         String host = queryMap.get("host"); | ||||||
| 		String portStr = queryMap.get("port"); |         String portStr = queryMap.get("port"); | ||||||
| 		String sid = queryMap.get("sid"); |         String sid = queryMap.get("sid"); | ||||||
| 		String tag = queryMap.get("tag"); |         String tag = queryMap.get("tag"); | ||||||
| 		String ticket = queryMap.get("ticket"); |         String ticket = queryMap.get("ticket"); | ||||||
| 		String console_url = queryMap.get("consoleurl"); |         String console_url = queryMap.get("consoleurl"); | ||||||
| 		String console_host_session = queryMap.get("sessionref"); |         String console_host_session = queryMap.get("sessionref"); | ||||||
| 
 | 
 | ||||||
| 		if(tag == null) |         if(tag == null) | ||||||
| 			tag = ""; |             tag = ""; | ||||||
|          |          | ||||||
| 		if (ws == null || hs == null || host == null || portStr == null || sid == null ) { |         if (ws == null || hs == null || host == null || portStr == null || sid == null ) { | ||||||
| 			throw new IllegalArgumentException(); |             throw new IllegalArgumentException(); | ||||||
| 		} |         } | ||||||
| 		try { |         try { | ||||||
| 			width = Integer.parseInt(ws); |             width = Integer.parseInt(ws); | ||||||
| 			height = Integer.parseInt(hs); |             height = Integer.parseInt(hs); | ||||||
| 			port = Integer.parseInt(portStr); |             port = Integer.parseInt(portStr); | ||||||
| 		} catch (NumberFormatException e) { |         } catch (NumberFormatException e) { | ||||||
| 			throw new IllegalArgumentException(e); |             throw new IllegalArgumentException(e); | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		ConsoleProxyClientParam param = new ConsoleProxyClientParam(); |         ConsoleProxyClientParam param = new ConsoleProxyClientParam(); | ||||||
| 		param.setClientHostAddress(host); |         param.setClientHostAddress(host); | ||||||
| 		param.setClientHostPort(port); |         param.setClientHostPort(port); | ||||||
| 		param.setClientHostPassword(sid); |         param.setClientHostPassword(sid); | ||||||
| 		param.setClientTag(tag); |         param.setClientTag(tag); | ||||||
| 		param.setTicket(ticket); |         param.setTicket(ticket); | ||||||
| 		param.setClientTunnelUrl(console_url); |         param.setClientTunnelUrl(console_url); | ||||||
| 		param.setClientTunnelSession(console_host_session); |         param.setClientTunnelSession(console_host_session); | ||||||
|          |          | ||||||
| 		ConsoleProxyClient viewer = ConsoleProxy.getVncViewer(param); |         ConsoleProxyClient viewer = ConsoleProxy.getVncViewer(param); | ||||||
|          |          | ||||||
| 		if (!viewer.isHostConnected()) { |         if (!viewer.isHostConnected()) { | ||||||
| 			// use generated image instead of static |             // use generated image instead of static | ||||||
| 			BufferedImage img = generateTextImage(width, height, "Connecting"); |             BufferedImage img = generateTextImage(width, height, "Connecting"); | ||||||
| 			ByteArrayOutputStream bos = new ByteArrayOutputStream(8196); |             ByteArrayOutputStream bos = new ByteArrayOutputStream(8196); | ||||||
| 			javax.imageio.ImageIO.write(img, "jpg", bos); |             javax.imageio.ImageIO.write(img, "jpg", bos); | ||||||
| 			byte[] bs = bos.toByteArray(); |             byte[] bs = bos.toByteArray(); | ||||||
| 			Headers hds = t.getResponseHeaders(); |             Headers hds = t.getResponseHeaders(); | ||||||
| 			hds.set("Content-Type", "image/jpeg"); |             hds.set("Content-Type", "image/jpeg"); | ||||||
| 			hds.set("Cache-Control", "no-cache"); |             hds.set("Cache-Control", "no-cache"); | ||||||
| 			hds.set("Cache-Control", "no-store"); |             hds.set("Cache-Control", "no-store"); | ||||||
| 			t.sendResponseHeaders(200, bs.length); |             t.sendResponseHeaders(200, bs.length); | ||||||
| 			OutputStream os = t.getResponseBody(); |             OutputStream os = t.getResponseBody(); | ||||||
| 			os.write(bs); |             os.write(bs); | ||||||
| 			os.close(); |             os.close(); | ||||||
|              |              | ||||||
| 			if(s_logger.isInfoEnabled()) |             if(s_logger.isInfoEnabled()) | ||||||
| 				s_logger.info("Console not ready, sent dummy JPG response"); |                 s_logger.info("Console not ready, sent dummy JPG response"); | ||||||
| 			return; |             return; | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		{ |         { | ||||||
| 			Image scaledImage = viewer.getClientScaledImage(width, height); |             Image scaledImage = viewer.getClientScaledImage(width, height); | ||||||
| 			BufferedImage bufferedImage = new BufferedImage(width, height, |             BufferedImage bufferedImage = new BufferedImage(width, height, | ||||||
| 					BufferedImage.TYPE_3BYTE_BGR); |                     BufferedImage.TYPE_3BYTE_BGR); | ||||||
| 			Graphics2D bufImageGraphics = bufferedImage.createGraphics(); |             Graphics2D bufImageGraphics = bufferedImage.createGraphics(); | ||||||
| 			bufImageGraphics.drawImage(scaledImage, 0, 0, null); |             bufImageGraphics.drawImage(scaledImage, 0, 0, null); | ||||||
| 			ByteArrayOutputStream bos = new ByteArrayOutputStream(8196); |             ByteArrayOutputStream bos = new ByteArrayOutputStream(8196); | ||||||
| 			javax.imageio.ImageIO.write(bufferedImage, "jpg", bos); |             javax.imageio.ImageIO.write(bufferedImage, "jpg", bos); | ||||||
| 			byte[] bs = bos.toByteArray(); |             byte[] bs = bos.toByteArray(); | ||||||
| 			Headers hds = t.getResponseHeaders(); |             Headers hds = t.getResponseHeaders(); | ||||||
| 			hds.set("Content-Type", "image/jpeg"); |             hds.set("Content-Type", "image/jpeg"); | ||||||
| 			hds.set("Cache-Control", "no-cache"); |             hds.set("Cache-Control", "no-cache"); | ||||||
| 			hds.set("Cache-Control", "no-store"); |             hds.set("Cache-Control", "no-store"); | ||||||
| 			t.sendResponseHeaders(200, bs.length); |             t.sendResponseHeaders(200, bs.length); | ||||||
| 			OutputStream os = t.getResponseBody(); |             OutputStream os = t.getResponseBody(); | ||||||
| 			os.write(bs); |             os.write(bs); | ||||||
| 			os.close(); |             os.close(); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public static BufferedImage generateTextImage(int w, int h, String text) { |     public static BufferedImage generateTextImage(int w, int h, String text) { | ||||||
| 		BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR); |         BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR); | ||||||
| 		Graphics2D g = img.createGraphics(); |         Graphics2D g = img.createGraphics(); | ||||||
| 		g.setColor(Color.BLACK); |         g.setColor(Color.BLACK); | ||||||
| 		g.fillRect(0, 0, w, h); |         g.fillRect(0, 0, w, h); | ||||||
| 		g.setColor(Color.WHITE); |         g.setColor(Color.WHITE); | ||||||
| 		try { |         try { | ||||||
| 			g.setFont(new Font(null, Font.PLAIN, 12)); |             g.setFont(new Font(null, Font.PLAIN, 12)); | ||||||
| 	  		FontMetrics fm = g.getFontMetrics(); |             FontMetrics fm = g.getFontMetrics(); | ||||||
| 	  		int textWidth = fm.stringWidth(text); |             int textWidth = fm.stringWidth(text); | ||||||
| 	  		int startx = (w-textWidth) / 2; |             int startx = (w-textWidth) / 2; | ||||||
| 	  		if(startx < 0) |             if(startx < 0) | ||||||
| 	  			startx = 0; |                 startx = 0; | ||||||
| 	  		g.drawString(text, startx, h/2); |             g.drawString(text, startx, h/2); | ||||||
| 		} catch (Throwable e) { |         } catch (Throwable e) { | ||||||
| 			s_logger.warn("Problem in generating text to thumnail image, return blank image"); |             s_logger.warn("Problem in generating text to thumnail image, return blank image"); | ||||||
| 		} |         } | ||||||
| 		return img; |         return img; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public static Map<String, String> getQueryMap(String query) { |     public static Map<String, String> getQueryMap(String query) { | ||||||
| 		String[] params = query.split("&"); |         String[] params = query.split("&"); | ||||||
| 		Map<String, String> map = new HashMap<String, String>(); |         Map<String, String> map = new HashMap<String, String>(); | ||||||
| 		for (String param : params) { |         for (String param : params) { | ||||||
| 			String name = param.split("=")[0]; |             String name = param.split("=")[0]; | ||||||
| 			String value = param.split("=")[1]; |             String value = param.split("=")[1]; | ||||||
| 			map.put(name, value); |             map.put(name, value); | ||||||
| 		} |         } | ||||||
| 		return map; |         return map; | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,42 +17,42 @@ | |||||||
| package com.cloud.consoleproxy; | package com.cloud.consoleproxy; | ||||||
| 
 | 
 | ||||||
| public enum InputEventType { | public enum InputEventType { | ||||||
| 	MOUSE_MOVE(1), |     MOUSE_MOVE(1), | ||||||
| 	MOUSE_DOWN(2), |     MOUSE_DOWN(2), | ||||||
| 	MOUSE_UP(3), |     MOUSE_UP(3), | ||||||
| 	KEY_PRESS(4), |     KEY_PRESS(4), | ||||||
| 	KEY_DOWN(5), |     KEY_DOWN(5), | ||||||
| 	KEY_UP(6), |     KEY_UP(6), | ||||||
| 	MOUSE_DBLCLICK(8); |     MOUSE_DBLCLICK(8); | ||||||
|      |      | ||||||
| 	int eventCode; |     int eventCode; | ||||||
| 	private InputEventType(int eventCode) { |     private InputEventType(int eventCode) { | ||||||
| 		this.eventCode = eventCode; |         this.eventCode = eventCode; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public int getEventCode() {  |     public int getEventCode() {  | ||||||
| 		return eventCode;  |         return eventCode;  | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public static InputEventType fromEventCode(int eventCode) { |     public static InputEventType fromEventCode(int eventCode) { | ||||||
| 		switch(eventCode) { |         switch(eventCode) { | ||||||
| 		case 1 : |         case 1 : | ||||||
| 			return MOUSE_MOVE; |             return MOUSE_MOVE; | ||||||
| 		case 2 : |         case 2 : | ||||||
| 			return MOUSE_DOWN; |             return MOUSE_DOWN; | ||||||
| 		case 3 : |         case 3 : | ||||||
| 			return MOUSE_UP; |             return MOUSE_UP; | ||||||
| 		case 4 : |         case 4 : | ||||||
| 			return KEY_PRESS; |             return KEY_PRESS; | ||||||
| 		case 5 : |         case 5 : | ||||||
| 			return KEY_DOWN; |             return KEY_DOWN; | ||||||
| 		case 6 : |         case 6 : | ||||||
| 			return KEY_UP; |             return KEY_UP; | ||||||
| 		case 8 : |         case 8 : | ||||||
| 			return MOUSE_DBLCLICK; |             return MOUSE_DBLCLICK; | ||||||
| 		default : |         default : | ||||||
| 			break; |             break; | ||||||
| 		} |         } | ||||||
| 		throw new IllegalArgumentException("Unsupport event code: " + eventCode); |         throw new IllegalArgumentException("Unsupport event code: " + eventCode); | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -20,6 +20,6 @@ import java.awt.Rectangle; | |||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
| public interface ITileScanListener { | public interface ITileScanListener { | ||||||
| 	boolean onTileChange(Rectangle rowMergedRect, int row, int col); |     boolean onTileChange(Rectangle rowMergedRect, int row, int col); | ||||||
| 	void onRegionChange(List<Region> regionList); |     void onRegionChange(List<Region> regionList); | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,12 +21,12 @@ import java.io.ByteArrayOutputStream; | |||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| 
 | 
 | ||||||
| public class ImageHelper { | public class ImageHelper { | ||||||
| 	public static byte[] jpegFromImage(BufferedImage image) throws IOException { |     public static byte[] jpegFromImage(BufferedImage image) throws IOException { | ||||||
| 		ByteArrayOutputStream bos = new ByteArrayOutputStream(128000); |         ByteArrayOutputStream bos = new ByteArrayOutputStream(128000); | ||||||
| 		javax.imageio.ImageIO.write(image, "jpg", bos); |         javax.imageio.ImageIO.write(image, "jpg", bos); | ||||||
|          |          | ||||||
| 		byte[] jpegBits = bos.toByteArray(); |         byte[] jpegBits = bos.toByteArray(); | ||||||
| 		bos.close(); |         bos.close(); | ||||||
| 		return jpegBits; |         return jpegBits; | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -18,206 +18,206 @@ package com.cloud.consoleproxy.util; | |||||||
| 
 | 
 | ||||||
| // logger facility for dynamic switch between console logger used in Applet and log4j based logger | // logger facility for dynamic switch between console logger used in Applet and log4j based logger | ||||||
| public class Logger { | public class Logger { | ||||||
| 	private static LoggerFactory factory = null; |     private static LoggerFactory factory = null; | ||||||
|      |      | ||||||
| 	public static final int LEVEL_TRACE = 1; |     public static final int LEVEL_TRACE = 1; | ||||||
| 	public static final int LEVEL_DEBUG = 2; |     public static final int LEVEL_DEBUG = 2; | ||||||
| 	public static final int LEVEL_INFO = 3; |     public static final int LEVEL_INFO = 3; | ||||||
| 	public static final int LEVEL_WARN = 4; |     public static final int LEVEL_WARN = 4; | ||||||
| 	public static final int LEVEL_ERROR = 5; |     public static final int LEVEL_ERROR = 5; | ||||||
|      |      | ||||||
| 	private Class<?> clazz; |     private Class<?> clazz; | ||||||
| 	private Logger logger; |     private Logger logger; | ||||||
|      |      | ||||||
| 	private static int level = LEVEL_INFO; |     private static int level = LEVEL_INFO; | ||||||
|      |      | ||||||
| 	public static Logger getLogger(Class<?> clazz) { |     public static Logger getLogger(Class<?> clazz) { | ||||||
| 		return new Logger(clazz); |         return new Logger(clazz); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public static void setFactory(LoggerFactory f) { |     public static void setFactory(LoggerFactory f) { | ||||||
| 		factory = f; |         factory = f; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public static void setLevel(int l) { |     public static void setLevel(int l) { | ||||||
| 		level = l; |         level = l; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public Logger(Class<?> clazz) { |     public Logger(Class<?> clazz) { | ||||||
| 		this.clazz = clazz; |         this.clazz = clazz; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	protected Logger() { |     protected Logger() { | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public boolean isTraceEnabled() { |     public boolean isTraceEnabled() { | ||||||
| 		if(factory != null) { |         if(factory != null) { | ||||||
| 			if(logger == null) |             if(logger == null) | ||||||
| 				logger = factory.getLogger(clazz); |                 logger = factory.getLogger(clazz); | ||||||
|              |              | ||||||
| 			return logger.isTraceEnabled(); |             return logger.isTraceEnabled(); | ||||||
| 		} |         } | ||||||
| 		return level <= LEVEL_TRACE; |         return level <= LEVEL_TRACE; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public boolean isDebugEnabled() { |     public boolean isDebugEnabled() { | ||||||
| 		if(factory != null) { |         if(factory != null) { | ||||||
| 			if(logger == null) |             if(logger == null) | ||||||
| 				logger = factory.getLogger(clazz); |                 logger = factory.getLogger(clazz); | ||||||
|              |              | ||||||
| 			return logger.isDebugEnabled(); |             return logger.isDebugEnabled(); | ||||||
| 		} |         } | ||||||
| 		return level <= LEVEL_DEBUG; |         return level <= LEVEL_DEBUG; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public boolean isInfoEnabled() { |     public boolean isInfoEnabled() { | ||||||
| 		if(factory != null) { |         if(factory != null) { | ||||||
| 			if(logger == null) |             if(logger == null) | ||||||
| 				logger = factory.getLogger(clazz); |                 logger = factory.getLogger(clazz); | ||||||
|              |              | ||||||
| 			return logger.isInfoEnabled(); |             return logger.isInfoEnabled(); | ||||||
| 		} |         } | ||||||
| 		return level <= LEVEL_INFO; |         return level <= LEVEL_INFO; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public void trace(Object message) { |     public void trace(Object message) { | ||||||
|          |          | ||||||
| 		if(factory != null) { |         if(factory != null) { | ||||||
| 			if(logger == null) |             if(logger == null) | ||||||
| 				logger = factory.getLogger(clazz); |                 logger = factory.getLogger(clazz); | ||||||
|              |              | ||||||
| 			logger.trace(message); |             logger.trace(message); | ||||||
| 		} else { |         } else { | ||||||
| 			if(level <= LEVEL_TRACE) |             if(level <= LEVEL_TRACE) | ||||||
| 				System.out.println(message); |                 System.out.println(message); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void trace(Object message, Throwable exception) { |     public void trace(Object message, Throwable exception) { | ||||||
| 		if(factory != null) { |         if(factory != null) { | ||||||
| 			if(logger == null) |             if(logger == null) | ||||||
| 				logger = factory.getLogger(clazz); |                 logger = factory.getLogger(clazz); | ||||||
|              |              | ||||||
| 			logger.trace(message, exception); |             logger.trace(message, exception); | ||||||
| 		} else { |         } else { | ||||||
| 			if(level <= LEVEL_TRACE) { |             if(level <= LEVEL_TRACE) { | ||||||
| 				System.out.println(message); |                 System.out.println(message); | ||||||
| 				if (exception != null) { |                 if (exception != null) { | ||||||
| 					exception.printStackTrace(System.out); |                     exception.printStackTrace(System.out); | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void info(Object message) { |     public void info(Object message) { | ||||||
| 		if(factory != null) { |         if(factory != null) { | ||||||
| 			if(logger == null) |             if(logger == null) | ||||||
| 				logger = factory.getLogger(clazz); |                 logger = factory.getLogger(clazz); | ||||||
|              |              | ||||||
| 			logger.info(message); |             logger.info(message); | ||||||
| 		} else { |         } else { | ||||||
| 			if(level <= LEVEL_INFO) |             if(level <= LEVEL_INFO) | ||||||
| 				System.out.println(message); |                 System.out.println(message); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void info(Object message, Throwable exception) { |     public void info(Object message, Throwable exception) { | ||||||
| 		if(factory != null) { |         if(factory != null) { | ||||||
| 			if(logger == null) |             if(logger == null) | ||||||
| 				logger = factory.getLogger(clazz); |                 logger = factory.getLogger(clazz); | ||||||
|              |              | ||||||
| 			logger.info(message, exception); |             logger.info(message, exception); | ||||||
| 		} else {		 |         } else {         | ||||||
| 			if(level <= LEVEL_INFO) { |             if(level <= LEVEL_INFO) { | ||||||
| 				System.out.println(message); |                 System.out.println(message); | ||||||
| 				if (exception != null) { |                 if (exception != null) { | ||||||
| 					exception.printStackTrace(System.out); |                     exception.printStackTrace(System.out); | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void debug(Object message) { |     public void debug(Object message) { | ||||||
| 		if(factory != null) { |         if(factory != null) { | ||||||
| 			if(logger == null) |             if(logger == null) | ||||||
| 				logger = factory.getLogger(clazz); |                 logger = factory.getLogger(clazz); | ||||||
|              |              | ||||||
| 			logger.debug(message); |             logger.debug(message); | ||||||
| 		} else { |         } else { | ||||||
| 			if(level <= LEVEL_DEBUG) |             if(level <= LEVEL_DEBUG) | ||||||
| 				System.out.println(message); |                 System.out.println(message); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void debug(Object message, Throwable exception) { |     public void debug(Object message, Throwable exception) { | ||||||
| 		if(factory != null) { |         if(factory != null) { | ||||||
| 			if(logger == null) |             if(logger == null) | ||||||
| 				logger = factory.getLogger(clazz); |                 logger = factory.getLogger(clazz); | ||||||
|              |              | ||||||
| 			logger.debug(message, exception); |             logger.debug(message, exception); | ||||||
| 		} else { |         } else { | ||||||
| 			if(level <= LEVEL_DEBUG) { |             if(level <= LEVEL_DEBUG) { | ||||||
| 				System.out.println(message); |                 System.out.println(message); | ||||||
| 				if (exception != null) { |                 if (exception != null) { | ||||||
| 					exception.printStackTrace(System.out); |                     exception.printStackTrace(System.out); | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void warn(Object message) { |     public void warn(Object message) { | ||||||
| 		if(factory != null) { |         if(factory != null) { | ||||||
| 			if(logger == null) |             if(logger == null) | ||||||
| 				logger = factory.getLogger(clazz); |                 logger = factory.getLogger(clazz); | ||||||
|              |              | ||||||
| 			logger.warn(message); |             logger.warn(message); | ||||||
| 		} else { |         } else { | ||||||
| 			if(level <= LEVEL_WARN) |             if(level <= LEVEL_WARN) | ||||||
| 				System.out.println(message); |                 System.out.println(message); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void warn(Object message, Throwable exception) { |     public void warn(Object message, Throwable exception) { | ||||||
| 		if(factory != null) { |         if(factory != null) { | ||||||
| 			if(logger == null) |             if(logger == null) | ||||||
| 				logger = factory.getLogger(clazz); |                 logger = factory.getLogger(clazz); | ||||||
|              |              | ||||||
| 			logger.warn(message, exception); |             logger.warn(message, exception); | ||||||
| 		} else { |         } else { | ||||||
| 			if(level <= LEVEL_WARN) { |             if(level <= LEVEL_WARN) { | ||||||
| 				System.out.println(message); |                 System.out.println(message); | ||||||
| 				if (exception != null) { |                 if (exception != null) { | ||||||
| 					exception.printStackTrace(System.out); |                     exception.printStackTrace(System.out); | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void error(Object message) { |     public void error(Object message) { | ||||||
| 		if(factory != null) { |         if(factory != null) { | ||||||
| 			if(logger == null) |             if(logger == null) | ||||||
| 				logger = factory.getLogger(clazz); |                 logger = factory.getLogger(clazz); | ||||||
|              |              | ||||||
| 			logger.error(message); |             logger.error(message); | ||||||
| 		} else { |         } else { | ||||||
| 			if(level <= LEVEL_ERROR) |             if(level <= LEVEL_ERROR) | ||||||
| 				System.out.println(message); |                 System.out.println(message); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void error(Object message, Throwable exception) { |     public void error(Object message, Throwable exception) { | ||||||
| 		if(factory != null) { |         if(factory != null) { | ||||||
| 			if(logger == null) |             if(logger == null) | ||||||
| 				logger = factory.getLogger(clazz); |                 logger = factory.getLogger(clazz); | ||||||
|              |              | ||||||
| 			logger.error(message, exception); |             logger.error(message, exception); | ||||||
| 		} else { |         } else { | ||||||
| 			if(level <= LEVEL_ERROR) { |             if(level <= LEVEL_ERROR) { | ||||||
| 				System.out.println(message); |                 System.out.println(message); | ||||||
| 				if (exception != null) { |                 if (exception != null) { | ||||||
| 					exception.printStackTrace(System.out); |                     exception.printStackTrace(System.out); | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,5 +17,5 @@ | |||||||
| package com.cloud.consoleproxy.util; | package com.cloud.consoleproxy.util; | ||||||
| 
 | 
 | ||||||
| public interface LoggerFactory { | public interface LoggerFactory { | ||||||
| 	Logger getLogger(Class<?> clazz); |     Logger getLogger(Class<?> clazz); | ||||||
| } | } | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ import javax.net.ssl.X509TrustManager; | |||||||
|  * connections and import/export operations. |  * connections and import/export operations. | ||||||
|  */ |  */ | ||||||
| public final class RawHTTP { | public final class RawHTTP { | ||||||
| 	private static final Logger s_logger = Logger.getLogger(RawHTTP.class); |     private static final Logger s_logger = Logger.getLogger(RawHTTP.class); | ||||||
| 
 | 
 | ||||||
|     private static final Pattern END_PATTERN = Pattern.compile("^\r\n$"); |     private static final Pattern END_PATTERN = Pattern.compile("^\r\n$"); | ||||||
|     private static final Pattern HEADER_PATTERN = Pattern |     private static final Pattern HEADER_PATTERN = Pattern | ||||||
| @ -55,47 +55,47 @@ public final class RawHTTP { | |||||||
|             .compile("^HTTP/\\d+\\.\\d+ (\\d*) (.*)\r\n$"); |             .compile("^HTTP/\\d+\\.\\d+ (\\d*) (.*)\r\n$"); | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| 	 * @uml.property  name="command" |      * @uml.property  name="command" | ||||||
| 	 */ |      */ | ||||||
|     private final String command; |     private final String command; | ||||||
|     /** |     /** | ||||||
| 	 * @uml.property  name="host" |      * @uml.property  name="host" | ||||||
| 	 */ |      */ | ||||||
|     private final String host; |     private final String host; | ||||||
|     /** |     /** | ||||||
| 	 * @uml.property  name="port" |      * @uml.property  name="port" | ||||||
| 	 */ |      */ | ||||||
|     private final int port; |     private final int port; | ||||||
|     /** |     /** | ||||||
| 	 * @uml.property  name="path" |      * @uml.property  name="path" | ||||||
| 	 */ |      */ | ||||||
|     private final String path; |     private final String path; | ||||||
|     /** |     /** | ||||||
| 	 * @uml.property  name="session" |      * @uml.property  name="session" | ||||||
| 	 */ |      */ | ||||||
|     private final String session; |     private final String session; | ||||||
|     /** |     /** | ||||||
| 	 * @uml.property  name="useSSL" |      * @uml.property  name="useSSL" | ||||||
| 	 */ |      */ | ||||||
|     private final boolean useSSL; |     private final boolean useSSL; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| 	 * @uml.property  name="responseHeaders" |      * @uml.property  name="responseHeaders" | ||||||
| 	 * @uml.associationEnd  qualifier="group:java.lang.String java.lang.String" |      * @uml.associationEnd  qualifier="group:java.lang.String java.lang.String" | ||||||
| 	 */ |      */ | ||||||
|     private final Map<String, String> responseHeaders = new HashMap<String, String>(); |     private final Map<String, String> responseHeaders = new HashMap<String, String>(); | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| 	 * @uml.property  name="ic" |      * @uml.property  name="ic" | ||||||
| 	 */ |      */ | ||||||
|     private InputStream ic; |     private InputStream ic; | ||||||
|     /** |     /** | ||||||
| 	 * @uml.property  name="oc" |      * @uml.property  name="oc" | ||||||
| 	 */ |      */ | ||||||
|     private OutputStream oc; |     private OutputStream oc; | ||||||
|     /** |     /** | ||||||
| 	 * @uml.property  name="s" |      * @uml.property  name="s" | ||||||
| 	 */ |      */ | ||||||
|     private Socket s; |     private Socket s; | ||||||
| 
 | 
 | ||||||
|     public InputStream getInputStream() { |     public InputStream getInputStream() { | ||||||
| @ -138,7 +138,7 @@ public final class RawHTTP { | |||||||
|         if (useSSL) { |         if (useSSL) { | ||||||
|             SSLContext context = getClientSSLContext(); |             SSLContext context = getClientSSLContext(); | ||||||
|             if(context == null) |             if(context == null) | ||||||
|             	throw new IOException("Unable to setup SSL context"); |                 throw new IOException("Unable to setup SSL context"); | ||||||
|              |              | ||||||
|             SSLSocket ssl = null; |             SSLSocket ssl = null; | ||||||
|             try { |             try { | ||||||
| @ -237,13 +237,13 @@ public final class RawHTTP { | |||||||
|      |      | ||||||
|     private SSLContext getClientSSLContext() { |     private SSLContext getClientSSLContext() { | ||||||
|         SSLContext sslContext = null; |         SSLContext sslContext = null; | ||||||
| 		try { |         try { | ||||||
| 			sslContext = SSLContext.getInstance("SSL", "SunJSSE"); |             sslContext = SSLContext.getInstance("SSL", "SunJSSE"); | ||||||
| 		} catch (NoSuchAlgorithmException e) { |         } catch (NoSuchAlgorithmException e) { | ||||||
| 			s_logger.error("Unexpected exception ", e); |             s_logger.error("Unexpected exception ", e); | ||||||
| 		} catch (NoSuchProviderException e) { |         } catch (NoSuchProviderException e) { | ||||||
| 			s_logger.error("Unexpected exception ", e); |             s_logger.error("Unexpected exception ", e); | ||||||
| 		} |         } | ||||||
|         return sslContext; |         return sslContext; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,70 +21,70 @@ import java.util.ArrayList; | |||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
| public class Region { | public class Region { | ||||||
| 	private Rectangle bound; |     private Rectangle bound; | ||||||
| 	private List<Rectangle> rectList; |     private List<Rectangle> rectList; | ||||||
| 
 | 
 | ||||||
| 	public Region() { |     public Region() { | ||||||
| 		bound = new Rectangle(0, 0, 0, 0); |         bound = new Rectangle(0, 0, 0, 0); | ||||||
| 		rectList = new ArrayList<Rectangle>(); |         rectList = new ArrayList<Rectangle>(); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public Region(Rectangle rect) { |     public Region(Rectangle rect) { | ||||||
| 		bound = new Rectangle(rect.x, rect.y, rect.width, rect.height); |         bound = new Rectangle(rect.x, rect.y, rect.width, rect.height); | ||||||
| 		rectList = new ArrayList<Rectangle>(); |         rectList = new ArrayList<Rectangle>(); | ||||||
| 		rectList.add(rect); |         rectList.add(rect); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public Rectangle getBound() { |     public Rectangle getBound() { | ||||||
| 		return bound; |         return bound; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void clearBound() { |     public void clearBound() { | ||||||
| 		assert(rectList.size() == 0); |         assert(rectList.size() == 0); | ||||||
| 		bound.x = bound.y = bound.width = bound.height = 0; |         bound.x = bound.y = bound.width = bound.height = 0; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public List<Rectangle> getRectangles() { |     public List<Rectangle> getRectangles() { | ||||||
| 		return rectList; |         return rectList; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public boolean add(Rectangle rect) { |     public boolean add(Rectangle rect) { | ||||||
| 		if(bound.isEmpty()) { |         if(bound.isEmpty()) { | ||||||
| 			assert(rectList.size() == 0); |             assert(rectList.size() == 0); | ||||||
| 			bound.x = rect.x; |             bound.x = rect.x; | ||||||
| 			bound.y = rect.y; |             bound.y = rect.y; | ||||||
| 			bound.width = rect.width; |             bound.width = rect.width; | ||||||
| 			bound.height = rect.height; |             bound.height = rect.height; | ||||||
|              |              | ||||||
| 			rectList.add(rect); |             rectList.add(rect); | ||||||
| 			return true; |             return true; | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		Rectangle rcInflated = new Rectangle(rect.x - 1, rect.y- 1, rect.width + 2, rect.height + 2); |         Rectangle rcInflated = new Rectangle(rect.x - 1, rect.y- 1, rect.width + 2, rect.height + 2); | ||||||
| 		if(!bound.intersects(rcInflated)) |         if(!bound.intersects(rcInflated)) | ||||||
| 			return false; |             return false; | ||||||
| 
 | 
 | ||||||
| 		for(Rectangle r : rectList) { |         for(Rectangle r : rectList) { | ||||||
| 			if(r.intersects(rcInflated)) { |             if(r.intersects(rcInflated)) { | ||||||
| 				if(!r.contains(rect)) { |                 if(!r.contains(rect)) { | ||||||
| 					enlargeBound(rect); |                     enlargeBound(rect); | ||||||
| 					rectList.add(rect); |                     rectList.add(rect); | ||||||
| 					return true; |                     return true; | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 		return false; |         return false; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private void enlargeBound(Rectangle rect) { |     private void enlargeBound(Rectangle rect) { | ||||||
| 		int boundLeft = Math.min(bound.x, rect.x); |         int boundLeft = Math.min(bound.x, rect.x); | ||||||
| 		int boundTop = Math.min(bound.y, rect.y); |         int boundTop = Math.min(bound.y, rect.y); | ||||||
| 		int boundRight = Math.max(bound.x + bound.width, rect.x + rect.width); |         int boundRight = Math.max(bound.x + bound.width, rect.x + rect.width); | ||||||
| 		int boundBottom = Math.max(bound.y + bound.height, rect.y + rect.height); |         int boundBottom = Math.max(bound.y + bound.height, rect.y + rect.height); | ||||||
|          |          | ||||||
| 		bound.x = boundLeft; |         bound.x = boundLeft; | ||||||
| 		bound.y = boundTop; |         bound.y = boundTop; | ||||||
| 		bound.width = boundRight - boundLeft; |         bound.width = boundRight - boundLeft; | ||||||
| 		bound.height = boundBottom - boundTop; |         bound.height = boundBottom - boundTop; | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,38 +21,38 @@ import java.util.ArrayList; | |||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
| public class RegionClassifier { | public class RegionClassifier { | ||||||
| 	private List<Region> regionList; |     private List<Region> regionList; | ||||||
|      |      | ||||||
| 	public RegionClassifier() { |     public RegionClassifier() { | ||||||
| 		regionList = new ArrayList<Region>(); |         regionList = new ArrayList<Region>(); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void add(Rectangle rect) { |     public void add(Rectangle rect) { | ||||||
| 		boolean newRegion = true; |         boolean newRegion = true; | ||||||
| 		Rectangle rcInflated = new Rectangle(rect.x - 1, rect.y - 1, rect.width + 2, rect.height + 2); |         Rectangle rcInflated = new Rectangle(rect.x - 1, rect.y - 1, rect.width + 2, rect.height + 2); | ||||||
| 		for(Region region : regionList) { |         for(Region region : regionList) { | ||||||
| 			if(region.getBound().intersects(rcInflated)) { |             if(region.getBound().intersects(rcInflated)) { | ||||||
| 				newRegion = false; |                 newRegion = false; | ||||||
| 				break; |                 break; | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		if(newRegion) { |         if(newRegion) { | ||||||
| 			regionList.add(new Region(rect)); |             regionList.add(new Region(rect)); | ||||||
| 		} else { |         } else { | ||||||
| 			for(Region region : regionList) { |             for(Region region : regionList) { | ||||||
| 				if(region.add(rect)) |                 if(region.add(rect)) | ||||||
| 					return; |                     return; | ||||||
| 			} |             } | ||||||
| 			regionList.add(new Region(rect)); |             regionList.add(new Region(rect)); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public List<Region> getRegionList() { |     public List<Region> getRegionList() { | ||||||
| 		return regionList; |         return regionList; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void clear() { |     public void clear() { | ||||||
| 		regionList.clear(); |         regionList.clear(); | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -19,37 +19,37 @@ package com.cloud.consoleproxy.util; | |||||||
| import java.awt.Rectangle; | import java.awt.Rectangle; | ||||||
| 
 | 
 | ||||||
| public class TileInfo { | public class TileInfo { | ||||||
| 	private int row; |     private int row; | ||||||
| 	private int col; |     private int col; | ||||||
| 	private Rectangle tileRect; |     private Rectangle tileRect; | ||||||
| 
 | 
 | ||||||
| 	public TileInfo(int row, int col, Rectangle tileRect) { |     public TileInfo(int row, int col, Rectangle tileRect) { | ||||||
| 		this.row = row; |         this.row = row; | ||||||
| 		this.col = col; |         this.col = col; | ||||||
| 		this.tileRect = tileRect; |         this.tileRect = tileRect; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public int getRow() { |     public int getRow() { | ||||||
| 		return row; |         return row; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void setRow(int row) { |     public void setRow(int row) { | ||||||
| 		this.row = row; |         this.row = row; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public int getCol() { |     public int getCol() { | ||||||
| 		return col; |         return col; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void setCol(int col) { |     public void setCol(int col) { | ||||||
| 		this.col = col; |         this.col = col; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public Rectangle getTileRect() { |     public Rectangle getTileRect() { | ||||||
| 		return tileRect; |         return tileRect; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void setTileRect(Rectangle tileRect) { |     public void setTileRect(Rectangle tileRect) { | ||||||
| 		this.tileRect = tileRect; |         this.tileRect = tileRect; | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -22,248 +22,248 @@ import java.util.List; | |||||||
| 
 | 
 | ||||||
| public class TileTracker { | public class TileTracker { | ||||||
|      |      | ||||||
| 	// 2 dimension tile status snapshot, a true value means the corresponding tile has been invalidated |     // 2 dimension tile status snapshot, a true value means the corresponding tile has been invalidated | ||||||
| 	private boolean[][] snapshot; |     private boolean[][] snapshot; | ||||||
|      |      | ||||||
| 	private int tileWidth = 0; |     private int tileWidth = 0; | ||||||
| 	private int tileHeight = 0; |     private int tileHeight = 0; | ||||||
| 	private int trackWidth = 0; |     private int trackWidth = 0; | ||||||
| 	private int trackHeight = 0; |     private int trackHeight = 0; | ||||||
|      |      | ||||||
| 	public TileTracker() { |     public TileTracker() { | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public int getTileWidth() { |     public int getTileWidth() { | ||||||
| 		return tileWidth; |         return tileWidth; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public void setTileWidth(int tileWidth) { |     public void setTileWidth(int tileWidth) { | ||||||
| 		this.tileWidth = tileWidth; |         this.tileWidth = tileWidth; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public int getTileHeight() { |     public int getTileHeight() { | ||||||
| 		return tileHeight; |         return tileHeight; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public void setTileHeight(int tileHeight) { |     public void setTileHeight(int tileHeight) { | ||||||
| 		this.tileHeight = tileHeight; |         this.tileHeight = tileHeight; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public int getTrackWidth() { |     public int getTrackWidth() { | ||||||
| 		return trackWidth; |         return trackWidth; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public void setTrackWidth(int trackWidth) { |     public void setTrackWidth(int trackWidth) { | ||||||
| 		this.trackWidth = trackWidth; |         this.trackWidth = trackWidth; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public int getTrackHeight() { |     public int getTrackHeight() { | ||||||
| 		return trackHeight; |         return trackHeight; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public void setTrackHeight(int trackHeight) { |     public void setTrackHeight(int trackHeight) { | ||||||
| 		this.trackHeight = trackHeight; |         this.trackHeight = trackHeight; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void initTracking(int tileWidth, int tileHeight, int trackWidth, int trackHeight) { |     public void initTracking(int tileWidth, int tileHeight, int trackWidth, int trackHeight) { | ||||||
| 		assert(tileWidth > 0); |         assert(tileWidth > 0); | ||||||
| 		assert(tileHeight > 0); |         assert(tileHeight > 0); | ||||||
| 		assert(trackWidth > 0); |         assert(trackWidth > 0); | ||||||
| 		assert(trackHeight > 0); |         assert(trackHeight > 0); | ||||||
| 		assert(tileWidth <= trackWidth); |         assert(tileWidth <= trackWidth); | ||||||
| 		assert(tileHeight <= trackHeight); |         assert(tileHeight <= trackHeight); | ||||||
|          |          | ||||||
| 		this.tileWidth = tileWidth; |         this.tileWidth = tileWidth; | ||||||
| 		this.tileHeight = tileHeight; |         this.tileHeight = tileHeight; | ||||||
| 		this.trackWidth = trackWidth; |         this.trackWidth = trackWidth; | ||||||
| 		this.trackHeight = trackHeight; |         this.trackHeight = trackHeight; | ||||||
|          |          | ||||||
| 		int cols = getTileCols(); |         int cols = getTileCols(); | ||||||
| 		int rows = getTileRows(); |         int rows = getTileRows(); | ||||||
| 		snapshot = new boolean[rows][cols]; |         snapshot = new boolean[rows][cols]; | ||||||
| 		for(int i = 0; i < rows; i++) |         for(int i = 0; i < rows; i++) | ||||||
| 			for(int j = 0; j < cols; j++) |             for(int j = 0; j < cols; j++) | ||||||
| 				snapshot[i][j] = false; |                 snapshot[i][j] = false; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public synchronized void resize(int trackWidth, int trackHeight) { |     public synchronized void resize(int trackWidth, int trackHeight) { | ||||||
| 		assert(tileWidth > 0); |         assert(tileWidth > 0); | ||||||
| 		assert(tileHeight > 0); |         assert(tileHeight > 0); | ||||||
| 		assert(trackWidth > 0); |         assert(trackWidth > 0); | ||||||
| 		assert(trackHeight > 0); |         assert(trackHeight > 0); | ||||||
|          |          | ||||||
| 		this.trackWidth = trackWidth; |         this.trackWidth = trackWidth; | ||||||
| 		this.trackHeight = trackHeight; |         this.trackHeight = trackHeight; | ||||||
|          |          | ||||||
| 		int cols = getTileCols(); |         int cols = getTileCols(); | ||||||
| 		int rows = getTileRows(); |         int rows = getTileRows(); | ||||||
| 		snapshot = new boolean[rows][cols]; |         snapshot = new boolean[rows][cols]; | ||||||
| 		for(int i = 0; i < rows; i++) |         for(int i = 0; i < rows; i++) | ||||||
| 			for(int j = 0; j < cols; j++) |             for(int j = 0; j < cols; j++) | ||||||
| 				snapshot[i][j] = true; |                 snapshot[i][j] = true; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void invalidate(Rectangle rect) { |     public void invalidate(Rectangle rect) { | ||||||
| 		setTileFlag(rect, true); |         setTileFlag(rect, true); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void validate(Rectangle rect) { |     public void validate(Rectangle rect) { | ||||||
| 		setTileFlag(rect, false); |         setTileFlag(rect, false); | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	public List<TileInfo> scan(boolean init) { |     public List<TileInfo> scan(boolean init) { | ||||||
| 		List<TileInfo> l = new ArrayList<TileInfo>(); |         List<TileInfo> l = new ArrayList<TileInfo>(); | ||||||
|          |          | ||||||
| 		synchronized(this) { |         synchronized(this) { | ||||||
| 			for(int i = 0; i < getTileRows(); i++) { |             for(int i = 0; i < getTileRows(); i++) { | ||||||
| 				for(int j = 0; j < getTileCols(); j++) { |                 for(int j = 0; j < getTileCols(); j++) { | ||||||
| 					if(init || snapshot[i][j]) { |                     if(init || snapshot[i][j]) { | ||||||
| 						Rectangle rect = new Rectangle(); |                         Rectangle rect = new Rectangle(); | ||||||
| 						rect.y = i*tileHeight; |                         rect.y = i*tileHeight; | ||||||
| 						rect.x = j*tileWidth; |                         rect.x = j*tileWidth; | ||||||
| 						rect.width = Math.min(trackWidth - rect.x, tileWidth); |                         rect.width = Math.min(trackWidth - rect.x, tileWidth); | ||||||
| 						rect.height = Math.min(trackHeight - rect.y, tileHeight); |                         rect.height = Math.min(trackHeight - rect.y, tileHeight); | ||||||
|                          |                          | ||||||
| 						l.add(new TileInfo(i, j, rect)); |                         l.add(new TileInfo(i, j, rect)); | ||||||
| 						snapshot[i][j] = false; |                         snapshot[i][j] = false; | ||||||
| 					} |                     } | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
|              |              | ||||||
| 			return l; |             return l; | ||||||
| 		}	 |         }     | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public boolean hasFullCoverage() { |     public boolean hasFullCoverage() { | ||||||
| 		synchronized(this) { |         synchronized(this) { | ||||||
| 			for(int i = 0; i < getTileRows(); i++) { |             for(int i = 0; i < getTileRows(); i++) { | ||||||
| 				for(int j = 0; j < getTileCols(); j++) { |                 for(int j = 0; j < getTileCols(); j++) { | ||||||
| 					if(!snapshot[i][j]) |                     if(!snapshot[i][j]) | ||||||
| 						return false; |                         return false; | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
| 		}	 |         }     | ||||||
| 		return true; |         return true; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
|      |      | ||||||
|      |      | ||||||
| 	public void initCoverageTest() { |     public void initCoverageTest() { | ||||||
| 		synchronized(this) { |         synchronized(this) { | ||||||
| 			for(int i = 0; i < getTileRows(); i++) { |             for(int i = 0; i < getTileRows(); i++) { | ||||||
| 				for(int j = 0; j < getTileCols(); j++) { |                 for(int j = 0; j < getTileCols(); j++) { | ||||||
| 					snapshot[i][j] = false; |                     snapshot[i][j] = false; | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
| 		}	 |         }     | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	// listener will be called while holding the object lock, use it |     // listener will be called while holding the object lock, use it | ||||||
| 	// with care to avoid deadlock condition being formed |     // with care to avoid deadlock condition being formed | ||||||
| 	public synchronized void scan(int nStartRow, int nStartCol, ITileScanListener listener) { |     public synchronized void scan(int nStartRow, int nStartCol, ITileScanListener listener) { | ||||||
| 		assert(listener != null); |         assert(listener != null); | ||||||
|          |          | ||||||
| 		int cols = getTileCols(); |         int cols = getTileCols(); | ||||||
| 		int rows = getTileRows(); |         int rows = getTileRows(); | ||||||
|          |          | ||||||
| 		nStartRow = nStartRow % rows; |         nStartRow = nStartRow % rows; | ||||||
| 		nStartCol = nStartCol % cols; |         nStartCol = nStartCol % cols; | ||||||
|          |          | ||||||
| 		int nPos = nStartRow*cols + nStartCol; |         int nPos = nStartRow*cols + nStartCol; | ||||||
| 		int nUnits = rows*cols; |         int nUnits = rows*cols; | ||||||
| 		int nStartPos = nPos; |         int nStartPos = nPos; | ||||||
| 		int nRow; |         int nRow; | ||||||
| 		int nCol; |         int nCol; | ||||||
| 		do { |         do { | ||||||
| 			nRow = nPos / cols; |             nRow = nPos / cols; | ||||||
| 			nCol = nPos % cols; |             nCol = nPos % cols; | ||||||
|              |              | ||||||
| 			if(snapshot[nRow][nCol]) { |             if(snapshot[nRow][nCol]) { | ||||||
| 				int nEndCol = nCol; |                 int nEndCol = nCol; | ||||||
| 				for(; nEndCol < cols && snapshot[nRow][nEndCol]; nEndCol++) { |                 for(; nEndCol < cols && snapshot[nRow][nEndCol]; nEndCol++) { | ||||||
| 					snapshot[nRow][nEndCol] = false; |                     snapshot[nRow][nEndCol] = false; | ||||||
| 				} |                 } | ||||||
|                  |                  | ||||||
| 				Rectangle rect = new Rectangle(); |                 Rectangle rect = new Rectangle(); | ||||||
| 				rect.y = nRow*tileHeight; |                 rect.y = nRow*tileHeight; | ||||||
| 				rect.height = tileHeight; |                 rect.height = tileHeight; | ||||||
| 				rect.x = nCol*tileWidth; |                 rect.x = nCol*tileWidth; | ||||||
| 				rect.width = (nEndCol - nCol)*tileWidth; |                 rect.width = (nEndCol - nCol)*tileWidth; | ||||||
|                  |                  | ||||||
| 				if(!listener.onTileChange(rect, nRow, nEndCol)) |                 if(!listener.onTileChange(rect, nRow, nEndCol)) | ||||||
| 					break; |                     break; | ||||||
| 			} |             } | ||||||
|              |              | ||||||
| 			nPos = (nPos + 1) % nUnits; |             nPos = (nPos + 1) % nUnits; | ||||||
| 		} while(nPos != nStartPos); |         } while(nPos != nStartPos); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public void capture(ITileScanListener listener) { |     public void capture(ITileScanListener listener) { | ||||||
| 		assert(listener != null); |         assert(listener != null); | ||||||
|          |          | ||||||
| 		int cols = getTileCols(); |         int cols = getTileCols(); | ||||||
| 		int rows = getTileRows(); |         int rows = getTileRows(); | ||||||
|          |          | ||||||
| 		RegionClassifier classifier = new RegionClassifier(); |         RegionClassifier classifier = new RegionClassifier(); | ||||||
| 		int left, top, right, bottom; |         int left, top, right, bottom; | ||||||
|          |          | ||||||
| 		synchronized(this) { |         synchronized(this) { | ||||||
| 			for(int i = 0; i < rows; i++) { |             for(int i = 0; i < rows; i++) { | ||||||
| 				top = i*tileHeight; |                 top = i*tileHeight; | ||||||
| 				bottom = Math.min(top + tileHeight, trackHeight);  |                 bottom = Math.min(top + tileHeight, trackHeight);  | ||||||
| 				for(int j = 0; j < cols; j++) { |                 for(int j = 0; j < cols; j++) { | ||||||
| 					left = j*tileWidth; |                     left = j*tileWidth; | ||||||
| 					right = Math.min(left + tileWidth, trackWidth); |                     right = Math.min(left + tileWidth, trackWidth); | ||||||
|                      |                      | ||||||
| 					if(snapshot[i][j]) { |                     if(snapshot[i][j]) { | ||||||
| 						snapshot[i][j] = false; |                         snapshot[i][j] = false; | ||||||
| 						classifier.add(new Rectangle(left, top, right - left, bottom - top)); |                         classifier.add(new Rectangle(left, top, right - left, bottom - top)); | ||||||
| 					} |                     } | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 		listener.onRegionChange(classifier.getRegionList()); |         listener.onRegionChange(classifier.getRegionList()); | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private synchronized void setTileFlag(Rectangle rect, boolean flag) { |     private synchronized void setTileFlag(Rectangle rect, boolean flag) { | ||||||
| 		int nStartTileRow; |         int nStartTileRow; | ||||||
| 		int nStartTileCol; |         int nStartTileCol; | ||||||
| 		int nEndTileRow; |         int nEndTileRow; | ||||||
| 		int nEndTileCol; |         int nEndTileCol; | ||||||
|          |          | ||||||
| 		int cols = getTileCols(); |         int cols = getTileCols(); | ||||||
| 		int rows = getTileRows(); |         int rows = getTileRows(); | ||||||
|          |          | ||||||
| 		if(rect != null) { |         if(rect != null) { | ||||||
| 			nStartTileRow = Math.min(getTileYPos(rect.y), rows - 1); |             nStartTileRow = Math.min(getTileYPos(rect.y), rows - 1); | ||||||
| 			nStartTileCol = Math.min(getTileXPos(rect.x), cols - 1); |             nStartTileCol = Math.min(getTileXPos(rect.x), cols - 1); | ||||||
| 			nEndTileRow = Math.min(getTileYPos(rect.y + rect.height - 1), rows -1); |             nEndTileRow = Math.min(getTileYPos(rect.y + rect.height - 1), rows -1); | ||||||
| 			nEndTileCol = Math.min(getTileXPos(rect.x + rect.width - 1), cols -1); |             nEndTileCol = Math.min(getTileXPos(rect.x + rect.width - 1), cols -1); | ||||||
| 		} else { |         } else { | ||||||
| 			nStartTileRow = 0; |             nStartTileRow = 0; | ||||||
| 			nStartTileCol = 0; |             nStartTileCol = 0; | ||||||
| 			nEndTileRow = rows - 1; |             nEndTileRow = rows - 1; | ||||||
| 			nEndTileCol = cols - 1; |             nEndTileCol = cols - 1; | ||||||
| 		} |         } | ||||||
|          |          | ||||||
| 		for(int i = nStartTileRow; i <= nEndTileRow; i++) |         for(int i = nStartTileRow; i <= nEndTileRow; i++) | ||||||
| 			for(int j = nStartTileCol; j <= nEndTileCol; j++) |             for(int j = nStartTileCol; j <= nEndTileCol; j++) | ||||||
| 				snapshot[i][j] = flag; |                 snapshot[i][j] = flag; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private int getTileRows() { |     private int getTileRows() { | ||||||
| 		return (trackHeight + tileHeight - 1) / tileHeight; |         return (trackHeight + tileHeight - 1) / tileHeight; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private int getTileCols() { |     private int getTileCols() { | ||||||
| 		return (trackWidth + tileWidth - 1) / tileWidth; |         return (trackWidth + tileWidth - 1) / tileWidth; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	private int getTileXPos(int x) { |     private int getTileXPos(int x) { | ||||||
| 		return x / tileWidth; |         return x / tileWidth; | ||||||
| 	} |     } | ||||||
|      |      | ||||||
| 	public int getTileYPos(int y) { |     public int getTileYPos(int y) { | ||||||
| 		return y / tileHeight; |         return y / tileHeight; | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -30,125 +30,121 @@ import com.cloud.consoleproxy.util.ImageHelper; | |||||||
| import com.cloud.consoleproxy.util.TileInfo; | import com.cloud.consoleproxy.util.TileInfo; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * A <code>BuffereImageCanvas</code> component represents frame buffer image on the |  * A <code>BuffereImageCanvas</code> component represents frame buffer image on | ||||||
|  * screen. It also notifies its subscribers when screen is repainted. |  * the screen. It also notifies its subscribers when screen is repainted. | ||||||
|  */ |  */ | ||||||
| public class BufferedImageCanvas extends Canvas implements FrameBufferCanvas { | public class BufferedImageCanvas extends Canvas implements FrameBufferCanvas { | ||||||
|   private static final long serialVersionUID = 1L; |     private static final long serialVersionUID = 1L; | ||||||
| 
 | 
 | ||||||
|    // Offline screen buffer |     // Offline screen buffer | ||||||
|   private BufferedImage offlineImage; |     private BufferedImage offlineImage; | ||||||
| 
 | 
 | ||||||
|   // Cached Graphics2D object for offline screen buffer |     // Cached Graphics2D object for offline screen buffer | ||||||
|   private Graphics2D graphics; |     private Graphics2D graphics; | ||||||
| 
 | 
 | ||||||
|   private PaintNotificationListener listener; |     private PaintNotificationListener listener; | ||||||
| 
 | 
 | ||||||
|   public BufferedImageCanvas(PaintNotificationListener listener, int width, int height) { |     public BufferedImageCanvas(PaintNotificationListener listener, int width, int height) { | ||||||
|     super(); |         super(); | ||||||
|     this.listener = listener; |         this.listener = listener; | ||||||
| 
 | 
 | ||||||
|     setBackground(Color.black); |         setBackground(Color.black); | ||||||
| 
 | 
 | ||||||
|     setFocusable(true); |         setFocusable(true); | ||||||
| 
 | 
 | ||||||
|     // Don't intercept TAB key |         // Don't intercept TAB key | ||||||
|     setFocusTraversalKeysEnabled(false); |         setFocusTraversalKeysEnabled(false); | ||||||
| 
 | 
 | ||||||
|     setCanvasSize(width, height); |         setCanvasSize(width, height); | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public void setCanvasSize(int width, int height) { |  | ||||||
|     this.offlineImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); |  | ||||||
|     graphics = offlineImage.createGraphics(); |  | ||||||
| 
 |  | ||||||
|     setSize(offlineImage.getWidth(), offlineImage.getHeight()); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void update(Graphics g) { |  | ||||||
|     // Call paint() directly, without clearing screen first |  | ||||||
|     paint(g); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void paint(Graphics g) { |  | ||||||
|     // Only part of image, requested with repaint(Rectangle), will be |  | ||||||
|     // painted on screen. |  | ||||||
|     synchronized(offlineImage) {	   |  | ||||||
|       g.drawImage(offlineImage, 0, 0, this); |  | ||||||
|     } |     } | ||||||
|     // Notify server that update is painted on screen |  | ||||||
|     listener.imagePaintedOnScreen(); |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   public BufferedImage getOfflineImage() { |     public void setCanvasSize(int width, int height) { | ||||||
|     return offlineImage; |         this.offlineImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); | ||||||
|   } |         graphics = offlineImage.createGraphics(); | ||||||
| 
 | 
 | ||||||
|   public Graphics2D getOfflineGraphics() { |         setSize(offlineImage.getWidth(), offlineImage.getHeight()); | ||||||
|     return graphics; |     } | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   public void copyTile(Graphics2D g, int x, int y, Rectangle rc) { |     @Override | ||||||
| 	synchronized(offlineImage) { |     public void update(Graphics g) { | ||||||
| 	  g.drawImage(offlineImage, x, y, x + rc.width, y + rc.height,  |         // Call paint() directly, without clearing screen first | ||||||
| 	    rc.x, rc.y, rc.x + rc.width, rc.y + rc.height, null); |         paint(g); | ||||||
| 	} |     } | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   @Override |     @Override | ||||||
|   public Image getFrameBufferScaledImage(int width, int height) { |     public void paint(Graphics g) { | ||||||
| 	  if(offlineImage != null) |         // Only part of image, requested with repaint(Rectangle), will be | ||||||
| 		  return offlineImage.getScaledInstance(width, height, Image.SCALE_DEFAULT); |         // painted on screen. | ||||||
| 	  return null; |         synchronized (offlineImage) { | ||||||
|   } |             g.drawImage(offlineImage, 0, 0, this); | ||||||
|  |         } | ||||||
|  |         // Notify server that update is painted on screen | ||||||
|  |         listener.imagePaintedOnScreen(); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|   @Override |     public BufferedImage getOfflineImage() { | ||||||
|   public byte[] getFrameBufferJpeg() { |         return offlineImage; | ||||||
| 	int width = 800; |     } | ||||||
| 	int height = 600; |  | ||||||
| 
 | 
 | ||||||
| 	width = offlineImage.getWidth(); |     public Graphics2D getOfflineGraphics() { | ||||||
| 	height = offlineImage.getHeight(); |         return graphics; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| 	BufferedImage bufferedImage = new BufferedImage(width, height, |     public void copyTile(Graphics2D g, int x, int y, Rectangle rc) { | ||||||
| 		BufferedImage.TYPE_3BYTE_BGR); |         synchronized (offlineImage) { | ||||||
| 	Graphics2D g = bufferedImage.createGraphics(); |             g.drawImage(offlineImage, x, y, x + rc.width, y + rc.height, rc.x, rc.y, rc.x + rc.width, rc.y + rc.height, null); | ||||||
| 	synchronized(offlineImage) { |         } | ||||||
| 	  g.drawImage(offlineImage, 0, 0, width, height, 0, 0, width, height, null); |     } | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	byte[] imgBits = null; |     @Override | ||||||
| 	try { |     public Image getFrameBufferScaledImage(int width, int height) { | ||||||
| 	  imgBits = ImageHelper.jpegFromImage(bufferedImage); |         if (offlineImage != null) | ||||||
| 	} catch (IOException e) { |             return offlineImage.getScaledInstance(width, height, Image.SCALE_DEFAULT); | ||||||
| 	} |         return null; | ||||||
| 	return imgBits; |     } | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   @Override |     @Override | ||||||
|   public byte[] getTilesMergedJpeg(List<TileInfo> tileList, int tileWidth, int tileHeight) { |     public byte[] getFrameBufferJpeg() { | ||||||
| 	int width = Math.max(tileWidth, tileWidth*tileList.size()); |         int width = 800; | ||||||
| 	BufferedImage bufferedImage = new BufferedImage(width, tileHeight, |         int height = 600; | ||||||
| 		BufferedImage.TYPE_3BYTE_BGR); |  | ||||||
| 	Graphics2D g = bufferedImage.createGraphics(); |  | ||||||
| 
 | 
 | ||||||
| 	synchronized(offlineImage) { |         width = offlineImage.getWidth(); | ||||||
| 	  int i = 0; |         height = offlineImage.getHeight(); | ||||||
| 	  for(TileInfo tile : tileList) { |  | ||||||
| 		Rectangle rc = tile.getTileRect(); |  | ||||||
| 		g.drawImage(offlineImage, i*tileWidth, 0, i*tileWidth + rc.width, rc.height,  |  | ||||||
| 		  rc.x, rc.y, rc.x + rc.width, rc.y + rc.height, null); |  | ||||||
| 		i++; |  | ||||||
| 	  } |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	byte[] imgBits = null; |         BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); | ||||||
| 	try { |         Graphics2D g = bufferedImage.createGraphics(); | ||||||
| 	  imgBits = ImageHelper.jpegFromImage(bufferedImage); |         synchronized (offlineImage) { | ||||||
| 	} catch (IOException e) { |             g.drawImage(offlineImage, 0, 0, width, height, 0, 0, width, height, null); | ||||||
| 	} |         } | ||||||
| 	return imgBits; | 
 | ||||||
|   } |         byte[] imgBits = null; | ||||||
|  |         try { | ||||||
|  |             imgBits = ImageHelper.jpegFromImage(bufferedImage); | ||||||
|  |         } catch (IOException e) { | ||||||
|  |         } | ||||||
|  |         return imgBits; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public byte[] getTilesMergedJpeg(List<TileInfo> tileList, int tileWidth, int tileHeight) { | ||||||
|  |         int width = Math.max(tileWidth, tileWidth * tileList.size()); | ||||||
|  |         BufferedImage bufferedImage = new BufferedImage(width, tileHeight, BufferedImage.TYPE_3BYTE_BGR); | ||||||
|  |         Graphics2D g = bufferedImage.createGraphics(); | ||||||
|  | 
 | ||||||
|  |         synchronized (offlineImage) { | ||||||
|  |             int i = 0; | ||||||
|  |             for (TileInfo tile : tileList) { | ||||||
|  |                 Rectangle rc = tile.getTileRect(); | ||||||
|  |                 g.drawImage(offlineImage, i * tileWidth, 0, i * tileWidth + rc.width, rc.height, rc.x, rc.y, rc.x + rc.width, rc.y + rc.height, null); | ||||||
|  |                 i++; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         byte[] imgBits = null; | ||||||
|  |         try { | ||||||
|  |             imgBits = ImageHelper.jpegFromImage(bufferedImage); | ||||||
|  |         } catch (IOException e) { | ||||||
|  |         } | ||||||
|  |         return imgBits; | ||||||
|  |     } | ||||||
| } | } | ||||||
| @ -22,7 +22,9 @@ import java.util.List; | |||||||
| import com.cloud.consoleproxy.util.TileInfo; | import com.cloud.consoleproxy.util.TileInfo; | ||||||
| 
 | 
 | ||||||
| public interface FrameBufferCanvas { | public interface FrameBufferCanvas { | ||||||
| 	Image getFrameBufferScaledImage(int width, int height); |     Image getFrameBufferScaledImage(int width, int height); | ||||||
| 	public byte[] getFrameBufferJpeg(); | 
 | ||||||
| 	public byte[] getTilesMergedJpeg(List<TileInfo> tileList, int tileWidth, int tileHeight); |     public byte[] getFrameBufferJpeg(); | ||||||
|  | 
 | ||||||
|  |     public byte[] getTilesMergedJpeg(List<TileInfo> tileList, int tileWidth, int tileHeight); | ||||||
| } | } | ||||||
|  | |||||||
| @ -18,9 +18,9 @@ package com.cloud.consoleproxy.vnc; | |||||||
| 
 | 
 | ||||||
| public interface FrameBufferUpdateListener { | public interface FrameBufferUpdateListener { | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Notify listener, that frame buffer update packet is received, so client is |      * Notify listener, that frame buffer update packet is received, so client | ||||||
|    * permitted (but not obligated) to ask server to send another update. |      * is permitted (but not obligated) to ask server to send another update. | ||||||
|    */ |      */ | ||||||
|   void frameBufferPacketReceived(); |     void frameBufferPacketReceived(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -18,10 +18,10 @@ package com.cloud.consoleproxy.vnc; | |||||||
| 
 | 
 | ||||||
| public interface PaintNotificationListener { | public interface PaintNotificationListener { | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Notify subscriber that screen is updated, so client can send another frame |      * Notify subscriber that screen is updated, so client can send another | ||||||
|    * buffer update request to server. |      * frame buffer update request to server. | ||||||
|    */ |      */ | ||||||
|   void imagePaintedOnScreen(); |     void imagePaintedOnScreen(); | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -20,62 +20,63 @@ import java.nio.charset.Charset; | |||||||
| 
 | 
 | ||||||
| public interface RfbConstants { | public interface RfbConstants { | ||||||
| 
 | 
 | ||||||
|   public static final String RFB_PROTOCOL_VERSION_MAJOR = "RFB 003."; |     public static final String RFB_PROTOCOL_VERSION_MAJOR = "RFB 003."; | ||||||
| //  public static final String VNC_PROTOCOL_VERSION_MINOR = "003"; |     // public static final String VNC_PROTOCOL_VERSION_MINOR = "003"; | ||||||
|   public static final String VNC_PROTOCOL_VERSION_MINOR = "003"; |     public static final String VNC_PROTOCOL_VERSION_MINOR = "003"; | ||||||
|   public static final String RFB_PROTOCOL_VERSION = RFB_PROTOCOL_VERSION_MAJOR + VNC_PROTOCOL_VERSION_MINOR; |     public static final String RFB_PROTOCOL_VERSION = RFB_PROTOCOL_VERSION_MAJOR + VNC_PROTOCOL_VERSION_MINOR; | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Server message types. |      * Server message types. | ||||||
|    */ |      */ | ||||||
|   final static int SERVER_FRAMEBUFFER_UPDATE = 0, SERVER_SET_COLOURMAP_ENTRIES = 1, SERVER_BELL = 2, SERVER_CUT_TEXT = 3; |     final static int SERVER_FRAMEBUFFER_UPDATE = 0, SERVER_SET_COLOURMAP_ENTRIES = 1, SERVER_BELL = 2, SERVER_CUT_TEXT = 3; | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Client message types. |      * Client message types. | ||||||
|    */ |      */ | ||||||
|   public static final int CLIENT_SET_PIXEL_FORMAT = 0, CLIENT_FIX_COLOURMAP_ENTRIES = 1, CLIENT_SET_ENCODINGS = 2, CLIENT_FRAMEBUFFER_UPDATE_REQUEST = 3, |     public static final int CLIENT_SET_PIXEL_FORMAT = 0, CLIENT_FIX_COLOURMAP_ENTRIES = 1, CLIENT_SET_ENCODINGS = 2, CLIENT_FRAMEBUFFER_UPDATE_REQUEST = 3, CLIENT_KEYBOARD_EVENT = 4, | ||||||
|       CLIENT_KEYBOARD_EVENT = 4, CLIENT_POINTER_EVENT = 5, CLIENT_CUT_TEXT = 6; |             CLIENT_POINTER_EVENT = 5, CLIENT_CUT_TEXT = 6; | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Server authorization type |      * Server authorization type | ||||||
|    */ |      */ | ||||||
|   public final static int CONNECTION_FAILED = 0, NO_AUTH = 1, VNC_AUTH = 2; |     public final static int CONNECTION_FAILED = 0, NO_AUTH = 1, VNC_AUTH = 2; | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Server authorization reply. |      * Server authorization reply. | ||||||
|    */ |      */ | ||||||
|   public final static int VNC_AUTH_OK = 0, VNC_AUTH_FAILED = 1, VNC_AUTH_TOO_MANY = 2; |     public final static int VNC_AUTH_OK = 0, VNC_AUTH_FAILED = 1, VNC_AUTH_TOO_MANY = 2; | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Encodings. |      * Encodings. | ||||||
|    */ |      */ | ||||||
|   public final static int ENCODING_RAW = 0, ENCODING_COPY_RECT = 1, ENCODING_RRE = 2, ENCODING_CO_RRE = 4, ENCODING_HEXTILE = 5, ENCODING_ZRLE = 16; |     public final static int ENCODING_RAW = 0, ENCODING_COPY_RECT = 1, ENCODING_RRE = 2, ENCODING_CO_RRE = 4, ENCODING_HEXTILE = 5, ENCODING_ZRLE = 16; | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Pseudo-encodings. |      * Pseudo-encodings. | ||||||
|    */ |      */ | ||||||
|   public final static int ENCODING_CURSOR = -239 /*0xFFFFFF11*/, ENCODING_DESKTOP_SIZE = -223 /*0xFFFFFF21*/; |     public final static int ENCODING_CURSOR = -239 /* 0xFFFFFF11 */, ENCODING_DESKTOP_SIZE = -223 /* 0xFFFFFF21 */; | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Encodings, which we support. |      * Encodings, which we support. | ||||||
|    */ |      */ | ||||||
|   public final static int[] SUPPORTED_ENCODINGS_ARRAY = { ENCODING_RAW, ENCODING_COPY_RECT, ENCODING_DESKTOP_SIZE }; |     public final static int[] SUPPORTED_ENCODINGS_ARRAY = { ENCODING_RAW, ENCODING_COPY_RECT, ENCODING_DESKTOP_SIZE }; | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Frame buffer update request type: update of whole screen or partial update. |      * Frame buffer update request type: update of whole screen or partial | ||||||
|    */ |      * update. | ||||||
|   public static final int FRAMEBUFFER_FULL_UPDATE_REQUEST = 0, FRAMEBUFFER_INCREMENTAL_UPDATE_REQUEST = 1; |      */ | ||||||
|  |     public static final int FRAMEBUFFER_FULL_UPDATE_REQUEST = 0, FRAMEBUFFER_INCREMENTAL_UPDATE_REQUEST = 1; | ||||||
| 
 | 
 | ||||||
|   public static final int KEY_UP = 0, KEY_DOWN = 1; |     public static final int KEY_UP = 0, KEY_DOWN = 1; | ||||||
| 
 | 
 | ||||||
|   public static final int LITTLE_ENDIAN = 0, BIG_ENDIAN = 1; |     public static final int LITTLE_ENDIAN = 0, BIG_ENDIAN = 1; | ||||||
| 
 | 
 | ||||||
|   public static final int EXCLUSIVE_ACCESS = 0, SHARED_ACCESS = 1; |     public static final int EXCLUSIVE_ACCESS = 0, SHARED_ACCESS = 1; | ||||||
| 
 | 
 | ||||||
|   public static final int PALETTE = 0, TRUE_COLOR = 1; |     public static final int PALETTE = 0, TRUE_COLOR = 1; | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Default charset to use when communicating with server. |      * Default charset to use when communicating with server. | ||||||
|    */ |      */ | ||||||
|   public static final Charset CHARSET = Charset.availableCharsets().get("US-ASCII"); |     public static final Charset CHARSET = Charset.availableCharsets().get("US-ASCII"); | ||||||
| } | } | ||||||
|  | |||||||
| @ -39,414 +39,413 @@ import com.cloud.consoleproxy.vnc.packet.client.KeyboardEventPacket; | |||||||
| import com.cloud.consoleproxy.vnc.packet.client.MouseEventPacket; | import com.cloud.consoleproxy.vnc.packet.client.MouseEventPacket; | ||||||
| 
 | 
 | ||||||
| public class VncClient { | public class VncClient { | ||||||
|   private static final Logger s_logger = Logger.getLogger(VncClient.class); |     private static final Logger s_logger = Logger.getLogger(VncClient.class); | ||||||
| 
 | 
 | ||||||
|   private Socket socket; |     private Socket socket; | ||||||
|   private DataInputStream is; |     private DataInputStream is; | ||||||
|   private DataOutputStream os; |     private DataOutputStream os; | ||||||
| 
 | 
 | ||||||
|   private VncScreenDescription screen = new VncScreenDescription(); |     private VncScreenDescription screen = new VncScreenDescription(); | ||||||
| 
 | 
 | ||||||
|   private VncClientPacketSender sender; |     private VncClientPacketSender sender; | ||||||
|   private VncServerPacketReceiver receiver; |     private VncServerPacketReceiver receiver; | ||||||
| 
 | 
 | ||||||
|   private boolean noUI = false; |     private boolean noUI = false; | ||||||
|   private ConsoleProxyClientListener clientListener = null; |     private ConsoleProxyClientListener clientListener = null; | ||||||
| 
 | 
 | ||||||
|   public static void main(String args[]) { |     public static void main(String args[]) { | ||||||
|     if (args.length < 3) { |         if (args.length < 3) { | ||||||
|       printHelpMessage(); |             printHelpMessage(); | ||||||
|       System.exit(1); |             System.exit(1); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         String host = args[0]; | ||||||
|  |         String port = args[1]; | ||||||
|  |         String password = args[2]; | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             new VncClient(host, Integer.parseInt(port), password, false, null); | ||||||
|  |         } catch (NumberFormatException e) { | ||||||
|  |             s_logger.error("Incorrect VNC server port number: " + port + "."); | ||||||
|  |             System.exit(1); | ||||||
|  |         } catch (UnknownHostException e) { | ||||||
|  |             s_logger.error("Incorrect VNC server host name: " + host + "."); | ||||||
|  |             System.exit(1); | ||||||
|  |         } catch (IOException e) { | ||||||
|  |             s_logger.error("Cannot communicate with VNC server: " + e.getMessage()); | ||||||
|  |             System.exit(1); | ||||||
|  |         } catch (Throwable e) { | ||||||
|  |             s_logger.error("An error happened: " + e.getMessage()); | ||||||
|  |             System.exit(1); | ||||||
|  |         } | ||||||
|  |         System.exit(0); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     String host = args[0]; |     private static void printHelpMessage() { | ||||||
|     String port = args[1]; |         /* LOG */s_logger.info("Usage: HOST PORT PASSWORD."); | ||||||
|     String password = args[2]; |  | ||||||
| 
 |  | ||||||
|     try { |  | ||||||
|       new VncClient(host, Integer.parseInt(port), password, false, null); |  | ||||||
|     } catch (NumberFormatException e) { |  | ||||||
|       s_logger.error("Incorrect VNC server port number: " + port + "."); |  | ||||||
|       System.exit(1); |  | ||||||
|     } catch (UnknownHostException e) { |  | ||||||
|     	s_logger.error("Incorrect VNC server host name: " + host + "."); |  | ||||||
|       System.exit(1); |  | ||||||
|     } catch (IOException e) { |  | ||||||
|     	s_logger.error("Cannot communicate with VNC server: " + e.getMessage()); |  | ||||||
|       System.exit(1); |  | ||||||
|     } catch (Throwable e) { |  | ||||||
|     	s_logger.error("An error happened: " + e.getMessage()); |  | ||||||
|     	System.exit(1); |  | ||||||
|     } |  | ||||||
|     System.exit(0); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private static void printHelpMessage() { |  | ||||||
|     /* 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, ConsoleProxyClientListener clientListener)  |  | ||||||
|   	throws UnknownHostException, IOException { |  | ||||||
| 	   |  | ||||||
|     this.noUI = noUI; |  | ||||||
|     this.clientListener = clientListener; |  | ||||||
|     connectTo(host, port, password); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public void shutdown() { |  | ||||||
| 	if(sender != null) |  | ||||||
| 		sender.closeConnection(); |  | ||||||
| 	 |  | ||||||
| 	if(receiver != null) |  | ||||||
| 		receiver.closeConnection(); |  | ||||||
| 
 |  | ||||||
| 	if(is != null) { |  | ||||||
| 	  try { |  | ||||||
| 	    is.close(); |  | ||||||
| 	  } catch (Throwable e) { |  | ||||||
| 	  } |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if(os != null) { |  | ||||||
| 	  try { |  | ||||||
| 	    os.close(); |  | ||||||
| 	  } catch (Throwable e) { |  | ||||||
| 	  } |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	if(socket != null) { |  | ||||||
| 	  try { |  | ||||||
| 	    socket.close(); |  | ||||||
| 	  } catch (Throwable e) { |  | ||||||
| 	  } |  | ||||||
| 	} |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public ConsoleProxyClientListener getClientListener() { |  | ||||||
| 	  return clientListener;  |  | ||||||
|   } |  | ||||||
|    |  | ||||||
|   public void connectTo(String host, int port, String path, |  | ||||||
|     String session, boolean useSSL, String sid) throws UnknownHostException, IOException { |  | ||||||
| 	if(port < 0) { |  | ||||||
| 		if(useSSL) |  | ||||||
| 			port = 443; |  | ||||||
| 		else |  | ||||||
| 			port = 80; |  | ||||||
| 	} |  | ||||||
| 		 |  | ||||||
| 	RawHTTP tunnel = new RawHTTP("CONNECT", host, port, path, session, useSSL); |  | ||||||
| 	this.socket = tunnel.connect(); |  | ||||||
| 	doConnect(sid); |  | ||||||
|   } |  | ||||||
|    |  | ||||||
|   public void connectTo(String host, int port, String password) throws UnknownHostException, IOException { |  | ||||||
|     // Connect to server |  | ||||||
| 	s_logger.info("Connecting to VNC server " + host + ":" + port + "..."); |  | ||||||
|     this.socket = new Socket(host, port); |  | ||||||
|     doConnect(password); |  | ||||||
|   } |  | ||||||
|    |  | ||||||
|   private void doConnect(String password) throws IOException { |  | ||||||
|     is = new DataInputStream(socket.getInputStream()); |  | ||||||
|     os = new DataOutputStream(socket.getOutputStream()); |  | ||||||
| 
 |  | ||||||
|     // Initialize connection |  | ||||||
|     handshake(); |  | ||||||
|     authenticate(password); |  | ||||||
|     initialize(); |  | ||||||
|      |  | ||||||
| 	s_logger.info("Connecting to VNC server succeeded, start session"); |  | ||||||
| 
 |  | ||||||
|     // Run client-to-server packet sender |  | ||||||
|     sender = new VncClientPacketSender(os, screen, this); |  | ||||||
| 
 |  | ||||||
|     // Create buffered image canvas |  | ||||||
|     BufferedImageCanvas canvas = new BufferedImageCanvas(sender, screen.getFramebufferWidth(), screen.getFramebufferHeight()); |  | ||||||
| 
 |  | ||||||
|     // Subscribe packet sender to various events |  | ||||||
|     canvas.addMouseListener(sender); |  | ||||||
|     canvas.addMouseMotionListener(sender); |  | ||||||
|     canvas.addKeyListener(sender); |  | ||||||
| 
 |  | ||||||
|     Frame frame = null; |  | ||||||
|     if(!noUI) |  | ||||||
|     	frame = createVncClientMainWindow(canvas, screen.getDesktopName()); |  | ||||||
| 
 |  | ||||||
|     new Thread(sender).start(); |  | ||||||
| 
 |  | ||||||
|     // Run server-to-client packet receiver |  | ||||||
|     receiver = new VncServerPacketReceiver(is, canvas, screen, this, sender, clientListener); |  | ||||||
|     try { |  | ||||||
|       receiver.run(); |  | ||||||
|     } finally { |  | ||||||
|       if(frame != null) { |  | ||||||
| 	    frame.setVisible(false); |  | ||||||
| 	    frame.dispose(); |  | ||||||
|       } |  | ||||||
|       this.shutdown(); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private Frame createVncClientMainWindow(BufferedImageCanvas canvas, String title) { |  | ||||||
|     // Create AWT windows |  | ||||||
|     final Frame frame = new Frame(title + " - VNCle"); |  | ||||||
| 
 |  | ||||||
|     // Use scrolling pane to support screens, which are larger than ours |  | ||||||
|     ScrollPane scroller = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED); |  | ||||||
|     scroller.add(canvas); |  | ||||||
|     scroller.setSize(screen.getFramebufferWidth(), screen.getFramebufferHeight()); |  | ||||||
| 
 |  | ||||||
|     frame.add(scroller); |  | ||||||
|     frame.pack(); |  | ||||||
|     frame.setVisible(true); |  | ||||||
| 
 |  | ||||||
|     frame.addWindowListener(new WindowAdapter() { |  | ||||||
|       public void windowClosing(WindowEvent evt) { |  | ||||||
|         frame.setVisible(false); |  | ||||||
|         shutdown(); |  | ||||||
|       } |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     return frame; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** |  | ||||||
|    * Handshake with VNC server. |  | ||||||
|    */ |  | ||||||
|   private void handshake() throws IOException { |  | ||||||
| 
 |  | ||||||
|     // Read protocol version |  | ||||||
|     byte[] buf = new byte[12]; |  | ||||||
|     is.readFully(buf); |  | ||||||
|     String rfbProtocol = new String(buf); |  | ||||||
| 
 |  | ||||||
|     // Server should use RFB protocol 3.x |  | ||||||
|     if (!rfbProtocol.contains(RfbConstants.RFB_PROTOCOL_VERSION_MAJOR)) { |  | ||||||
|       s_logger.error("Cannot handshake with VNC server. Unsupported protocol version: \"" + rfbProtocol + "\"."); |  | ||||||
|       throw new RuntimeException("Cannot handshake with VNC server. Unsupported protocol version: \"" + rfbProtocol + "\"."); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Send response: we support RFB 3.3 only |     public VncClient(ConsoleProxyClientListener clientListener) { | ||||||
|     String ourProtocolString = RfbConstants.RFB_PROTOCOL_VERSION + "\n"; |         this.noUI = true; | ||||||
|     os.write(ourProtocolString.getBytes()); |         this.clientListener = clientListener; | ||||||
|     os.flush(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** |  | ||||||
|    * VNC authentication. |  | ||||||
|    */ |  | ||||||
|   private void authenticate(String password) throws IOException { |  | ||||||
|     // Read security type |  | ||||||
|     int authType = is.readInt(); |  | ||||||
| 
 |  | ||||||
|     switch (authType) { |  | ||||||
|     case RfbConstants.CONNECTION_FAILED: { |  | ||||||
|       // Server forbids to connect. Read reason and throw exception |  | ||||||
| 
 |  | ||||||
|       int length = is.readInt(); |  | ||||||
|       byte[] buf = new byte[length]; |  | ||||||
|       is.readFully(buf); |  | ||||||
|       String reason = new String(buf, RfbConstants.CHARSET); |  | ||||||
|        |  | ||||||
|       s_logger.error("Authentication to VNC server is failed. Reason: " + reason); |  | ||||||
|       throw new RuntimeException("Authentication to VNC server is failed. Reason: " + reason); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     case RfbConstants.NO_AUTH: { |     public VncClient(String host, int port, String password, boolean noUI, ConsoleProxyClientListener clientListener) throws UnknownHostException, IOException { | ||||||
|       // Client can connect without authorization. Nothing to do. | 
 | ||||||
|       break; |         this.noUI = noUI; | ||||||
|  |         this.clientListener = clientListener; | ||||||
|  |         connectTo(host, port, password); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     case RfbConstants.VNC_AUTH: { |     public void shutdown() { | ||||||
|       s_logger.info("VNC server requires password authentication"); |         if (sender != null) | ||||||
|       doVncAuth(password); |             sender.closeConnection(); | ||||||
|       break; | 
 | ||||||
|  |         if (receiver != null) | ||||||
|  |             receiver.closeConnection(); | ||||||
|  | 
 | ||||||
|  |         if (is != null) { | ||||||
|  |             try { | ||||||
|  |                 is.close(); | ||||||
|  |             } catch (Throwable e) { | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (os != null) { | ||||||
|  |             try { | ||||||
|  |                 os.close(); | ||||||
|  |             } catch (Throwable e) { | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (socket != null) { | ||||||
|  |             try { | ||||||
|  |                 socket.close(); | ||||||
|  |             } catch (Throwable e) { | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     default: |     public ConsoleProxyClientListener getClientListener() { | ||||||
|       s_logger.error("Unsupported VNC protocol authorization scheme, scheme code: " + authType + "."); |         return clientListener; | ||||||
|       throw new RuntimeException("Unsupported VNC protocol authorization scheme, scheme code: " + authType + "."); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** |  | ||||||
|    * Encode client password and send it to server. |  | ||||||
|    */ |  | ||||||
|   private void doVncAuth(String password) throws IOException { |  | ||||||
| 
 |  | ||||||
|     // Read challenge |  | ||||||
|     byte[] challenge = new byte[16]; |  | ||||||
|     is.readFully(challenge); |  | ||||||
| 
 |  | ||||||
|     // Encode challenge with password |  | ||||||
|     byte[] response; |  | ||||||
|     try { |  | ||||||
|       response = encodePassword(challenge, password); |  | ||||||
|     } catch (Exception e) { |  | ||||||
|       s_logger.error("Cannot encrypt client password to send to server: " + e.getMessage()); |  | ||||||
|       throw new RuntimeException("Cannot encrypt client password to send to server: " + e.getMessage()); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Send encoded challenge |     public void connectTo(String host, int port, String path, String session, boolean useSSL, String sid) throws UnknownHostException, IOException { | ||||||
|     os.write(response); |         if (port < 0) { | ||||||
|     os.flush(); |             if (useSSL) | ||||||
|  |                 port = 443; | ||||||
|  |             else | ||||||
|  |                 port = 80; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|     // Read security result |         RawHTTP tunnel = new RawHTTP("CONNECT", host, port, path, session, useSSL); | ||||||
|     int authResult = is.readInt(); |         this.socket = tunnel.connect(); | ||||||
| 
 |         doConnect(sid); | ||||||
|     switch (authResult) { |  | ||||||
|     case RfbConstants.VNC_AUTH_OK: { |  | ||||||
|       // Nothing to do |  | ||||||
|       break; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     case RfbConstants.VNC_AUTH_TOO_MANY: |     public void connectTo(String host, int port, String password) throws UnknownHostException, IOException { | ||||||
|       s_logger.error("Connection to VNC server failed: too many wrong attempts."); |         // Connect to server | ||||||
|       throw new RuntimeException("Connection to VNC server failed: too many wrong attempts."); |         s_logger.info("Connecting to VNC server " + host + ":" + port + "..."); | ||||||
| 
 |         this.socket = new Socket(host, port); | ||||||
|     case RfbConstants.VNC_AUTH_FAILED: |         doConnect(password); | ||||||
|         s_logger.error("Connection to VNC server failed: wrong password."); |  | ||||||
|       throw new RuntimeException("Connection to VNC server failed: wrong password."); |  | ||||||
| 
 |  | ||||||
|     default: |  | ||||||
|       s_logger.error("Connection to VNC server failed, reason code: " + authResult); |  | ||||||
|       throw new RuntimeException("Connection to VNC server failed, reason code: " + authResult); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** |  | ||||||
|    * Encode password using DES encryption with given challenge. |  | ||||||
|    *  |  | ||||||
|    * @param challenge |  | ||||||
|    *          a random set of bytes. |  | ||||||
|    * @param password |  | ||||||
|    *          a password |  | ||||||
|    * @return DES hash of password and challenge |  | ||||||
|    */ |  | ||||||
|   public byte[] encodePassword(byte[] challenge, String password) throws Exception { |  | ||||||
|     // VNC password consist of up to eight ASCII characters. |  | ||||||
|     byte[] key = { 0, 0, 0, 0, 0, 0, 0, 0 }; // Padding |  | ||||||
|     byte[] passwordAsciiBytes = password.getBytes(RfbConstants.CHARSET); |  | ||||||
|     System.arraycopy(passwordAsciiBytes, 0, key, 0, Math.min(password.length(), 8)); |  | ||||||
| 
 |  | ||||||
|     // Flip bytes (reverse bits) in key |  | ||||||
|     for (int i = 0; i < key.length; i++) { |  | ||||||
|       key[i] = flipByte(key[i]); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     KeySpec desKeySpec = new DESKeySpec(key); |     private void doConnect(String password) throws IOException { | ||||||
|     SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES"); |         is = new DataInputStream(socket.getInputStream()); | ||||||
|     SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec); |         os = new DataOutputStream(socket.getOutputStream()); | ||||||
|     Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding"); |  | ||||||
|     cipher.init(Cipher.ENCRYPT_MODE, secretKey); |  | ||||||
| 
 | 
 | ||||||
|     byte[] response = cipher.doFinal(challenge); |         // Initialize connection | ||||||
|     return response; |         handshake(); | ||||||
|   } |         authenticate(password); | ||||||
|  |         initialize(); | ||||||
| 
 | 
 | ||||||
|   /** |         s_logger.info("Connecting to VNC server succeeded, start session"); | ||||||
|    * Reverse bits in byte, so least significant bit will be most significant |  | ||||||
|    * bit. E.g. 01001100 will become 00110010. |  | ||||||
|    *  |  | ||||||
|    * See also: http://www.vidarholen.net/contents/junk/vnc.html , |  | ||||||
|    * http://bytecrafter .blogspot.com/2010/09/des-encryption-as-used-in-vnc.html |  | ||||||
|    *  |  | ||||||
|    * @param b |  | ||||||
|    *          a byte |  | ||||||
|    * @return byte in reverse order |  | ||||||
|    */ |  | ||||||
|   private static byte flipByte(byte b) { |  | ||||||
|     int b1_8 = (b & 0x1) << 7; |  | ||||||
|     int b2_7 = (b & 0x2) << 5; |  | ||||||
|     int b3_6 = (b & 0x4) << 3; |  | ||||||
|     int b4_5 = (b & 0x8) << 1; |  | ||||||
|     int b5_4 = (b & 0x10) >>> 1; |  | ||||||
|     int b6_3 = (b & 0x20) >>> 3; |  | ||||||
|     int b7_2 = (b & 0x40) >>> 5; |  | ||||||
|     int b8_1 = (b & 0x80) >>> 7; |  | ||||||
|     byte c = (byte) (b1_8 | b2_7 | b3_6 | b4_5 | b5_4 | b6_3 | b7_2 | b8_1); |  | ||||||
|     return c; |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   private void initialize() throws IOException { |         // Run client-to-server packet sender | ||||||
|     // Send client initialization message |         sender = new VncClientPacketSender(os, screen, this); | ||||||
|     { | 
 | ||||||
|       // Send shared flag |         // Create buffered image canvas | ||||||
|       os.writeByte(RfbConstants.EXCLUSIVE_ACCESS); |         BufferedImageCanvas canvas = new BufferedImageCanvas(sender, screen.getFramebufferWidth(), screen.getFramebufferHeight()); | ||||||
|       os.flush(); | 
 | ||||||
|  |         // Subscribe packet sender to various events | ||||||
|  |         canvas.addMouseListener(sender); | ||||||
|  |         canvas.addMouseMotionListener(sender); | ||||||
|  |         canvas.addKeyListener(sender); | ||||||
|  | 
 | ||||||
|  |         Frame frame = null; | ||||||
|  |         if (!noUI) | ||||||
|  |             frame = createVncClientMainWindow(canvas, screen.getDesktopName()); | ||||||
|  | 
 | ||||||
|  |         new Thread(sender).start(); | ||||||
|  | 
 | ||||||
|  |         // Run server-to-client packet receiver | ||||||
|  |         receiver = new VncServerPacketReceiver(is, canvas, screen, this, sender, clientListener); | ||||||
|  |         try { | ||||||
|  |             receiver.run(); | ||||||
|  |         } finally { | ||||||
|  |             if (frame != null) { | ||||||
|  |                 frame.setVisible(false); | ||||||
|  |                 frame.dispose(); | ||||||
|  |             } | ||||||
|  |             this.shutdown(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Read server initialization message |     private Frame createVncClientMainWindow(BufferedImageCanvas canvas, String title) { | ||||||
|     { |         // Create AWT windows | ||||||
|       // Read frame buffer size |         final Frame frame = new Frame(title + " - VNCle"); | ||||||
|       int framebufferWidth = is.readUnsignedShort(); | 
 | ||||||
|       int framebufferHeight = is.readUnsignedShort(); |         // Use scrolling pane to support screens, which are larger than ours | ||||||
|       screen.setFramebufferSize(framebufferWidth, framebufferHeight); |         ScrollPane scroller = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED); | ||||||
|       if(clientListener != null) |         scroller.add(canvas); | ||||||
|     	  clientListener.onFramebufferSizeChange(framebufferWidth, framebufferHeight); |         scroller.setSize(screen.getFramebufferWidth(), screen.getFramebufferHeight()); | ||||||
|  | 
 | ||||||
|  |         frame.add(scroller); | ||||||
|  |         frame.pack(); | ||||||
|  |         frame.setVisible(true); | ||||||
|  | 
 | ||||||
|  |         frame.addWindowListener(new WindowAdapter() { | ||||||
|  |             public void windowClosing(WindowEvent evt) { | ||||||
|  |                 frame.setVisible(false); | ||||||
|  |                 shutdown(); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         return frame; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Read pixel format |     /** | ||||||
|     { |      * Handshake with VNC server. | ||||||
|       int bitsPerPixel = is.readUnsignedByte(); |      */ | ||||||
|       int depth = is.readUnsignedByte(); |     private void handshake() throws IOException { | ||||||
| 
 | 
 | ||||||
|       int bigEndianFlag = is.readUnsignedByte(); |         // Read protocol version | ||||||
|       int trueColorFlag = is.readUnsignedByte(); |         byte[] buf = new byte[12]; | ||||||
|  |         is.readFully(buf); | ||||||
|  |         String rfbProtocol = new String(buf); | ||||||
| 
 | 
 | ||||||
|       int redMax = is.readUnsignedShort(); |         // Server should use RFB protocol 3.x | ||||||
|       int greenMax = is.readUnsignedShort(); |         if (!rfbProtocol.contains(RfbConstants.RFB_PROTOCOL_VERSION_MAJOR)) { | ||||||
|       int blueMax = is.readUnsignedShort(); |             s_logger.error("Cannot handshake with VNC server. Unsupported protocol version: \"" + rfbProtocol + "\"."); | ||||||
|  |             throw new RuntimeException("Cannot handshake with VNC server. Unsupported protocol version: \"" + rfbProtocol + "\"."); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|       int redShift = is.readUnsignedByte(); |         // Send response: we support RFB 3.3 only | ||||||
|       int greenShift = is.readUnsignedByte(); |         String ourProtocolString = RfbConstants.RFB_PROTOCOL_VERSION + "\n"; | ||||||
|       int blueShift = is.readUnsignedByte(); |         os.write(ourProtocolString.getBytes()); | ||||||
| 
 |         os.flush(); | ||||||
|       // Skip padding |  | ||||||
|       is.skipBytes(3); |  | ||||||
| 
 |  | ||||||
|       screen.setPixelFormat(bitsPerPixel, depth, bigEndianFlag, trueColorFlag, redMax, greenMax, blueMax, redShift, greenShift, blueShift); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Read desktop name |     /** | ||||||
|     { |      * VNC authentication. | ||||||
|       int length = is.readInt(); |      */ | ||||||
|       byte buf[] = new byte[length]; |     private void authenticate(String password) throws IOException { | ||||||
|       is.readFully(buf); |         // Read security type | ||||||
|       String desktopName = new String(buf, RfbConstants.CHARSET); |         int authType = is.readInt(); | ||||||
|       screen.setDesktopName(desktopName); | 
 | ||||||
|  |         switch (authType) { | ||||||
|  |         case RfbConstants.CONNECTION_FAILED: { | ||||||
|  |             // Server forbids to connect. Read reason and throw exception | ||||||
|  | 
 | ||||||
|  |             int length = is.readInt(); | ||||||
|  |             byte[] buf = new byte[length]; | ||||||
|  |             is.readFully(buf); | ||||||
|  |             String reason = new String(buf, RfbConstants.CHARSET); | ||||||
|  | 
 | ||||||
|  |             s_logger.error("Authentication to VNC server is failed. Reason: " + reason); | ||||||
|  |             throw new RuntimeException("Authentication to VNC server is failed. Reason: " + reason); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         case RfbConstants.NO_AUTH: { | ||||||
|  |             // Client can connect without authorization. Nothing to do. | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         case RfbConstants.VNC_AUTH: { | ||||||
|  |             s_logger.info("VNC server requires password authentication"); | ||||||
|  |             doVncAuth(password); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  |             s_logger.error("Unsupported VNC protocol authorization scheme, scheme code: " + authType + "."); | ||||||
|  |             throw new RuntimeException("Unsupported VNC protocol authorization scheme, scheme code: " + authType + "."); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   public FrameBufferCanvas getFrameBufferCanvas() { |     /** | ||||||
|     if(receiver != null) |      * Encode client password and send it to server. | ||||||
|       return receiver.getCanvas(); |      */ | ||||||
|  |     private void doVncAuth(String password) throws IOException { | ||||||
| 
 | 
 | ||||||
| 	return null; |         // Read challenge | ||||||
|   } |         byte[] challenge = new byte[16]; | ||||||
|  |         is.readFully(challenge); | ||||||
| 
 | 
 | ||||||
|   public void requestUpdate(boolean fullUpdate) { |         // Encode challenge with password | ||||||
| 	if(fullUpdate) |         byte[] response; | ||||||
| 		sender.requestFullScreenUpdate(); |         try { | ||||||
| 	else |             response = encodePassword(challenge, password); | ||||||
| 		sender.imagePaintedOnScreen();   |         } catch (Exception e) { | ||||||
|   } |             s_logger.error("Cannot encrypt client password to send to server: " + e.getMessage()); | ||||||
|  |             throw new RuntimeException("Cannot encrypt client password to send to server: " + e.getMessage()); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|   public void sendClientKeyboardEvent(int event, int code, int modifiers) { |         // Send encoded challenge | ||||||
|     sender.sendClientPacket(new KeyboardEventPacket(event, code)); |         os.write(response); | ||||||
|   } |         os.flush(); | ||||||
| 
 | 
 | ||||||
|   public void sendClientMouseEvent(int event, int x, int y, int code, int modifiers) { |         // Read security result | ||||||
|     sender.sendClientPacket(new MouseEventPacket(event, x, y)); |         int authResult = is.readInt(); | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   public boolean isHostConnected() { |         switch (authResult) { | ||||||
| 	  return receiver != null && receiver.isConnectionAlive(); |         case RfbConstants.VNC_AUTH_OK: { | ||||||
|   } |             // Nothing to do | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         case RfbConstants.VNC_AUTH_TOO_MANY: | ||||||
|  |             s_logger.error("Connection to VNC server failed: too many wrong attempts."); | ||||||
|  |             throw new RuntimeException("Connection to VNC server failed: too many wrong attempts."); | ||||||
|  | 
 | ||||||
|  |         case RfbConstants.VNC_AUTH_FAILED: | ||||||
|  |             s_logger.error("Connection to VNC server failed: wrong password."); | ||||||
|  |             throw new RuntimeException("Connection to VNC server failed: wrong password."); | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  |             s_logger.error("Connection to VNC server failed, reason code: " + authResult); | ||||||
|  |             throw new RuntimeException("Connection to VNC server failed, reason code: " + authResult); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Encode password using DES encryption with given challenge. | ||||||
|  |      *  | ||||||
|  |      * @param challenge | ||||||
|  |      *            a random set of bytes. | ||||||
|  |      * @param password | ||||||
|  |      *            a password | ||||||
|  |      * @return DES hash of password and challenge | ||||||
|  |      */ | ||||||
|  |     public byte[] encodePassword(byte[] challenge, String password) throws Exception { | ||||||
|  |         // VNC password consist of up to eight ASCII characters. | ||||||
|  |         byte[] key = { 0, 0, 0, 0, 0, 0, 0, 0 }; // Padding | ||||||
|  |         byte[] passwordAsciiBytes = password.getBytes(RfbConstants.CHARSET); | ||||||
|  |         System.arraycopy(passwordAsciiBytes, 0, key, 0, Math.min(password.length(), 8)); | ||||||
|  | 
 | ||||||
|  |         // Flip bytes (reverse bits) in key | ||||||
|  |         for (int i = 0; i < key.length; i++) { | ||||||
|  |             key[i] = flipByte(key[i]); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         KeySpec desKeySpec = new DESKeySpec(key); | ||||||
|  |         SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES"); | ||||||
|  |         SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec); | ||||||
|  |         Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding"); | ||||||
|  |         cipher.init(Cipher.ENCRYPT_MODE, secretKey); | ||||||
|  | 
 | ||||||
|  |         byte[] response = cipher.doFinal(challenge); | ||||||
|  |         return response; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Reverse bits in byte, so least significant bit will be most significant | ||||||
|  |      * bit. E.g. 01001100 will become 00110010. | ||||||
|  |      *  | ||||||
|  |      * See also: http://www.vidarholen.net/contents/junk/vnc.html , | ||||||
|  |      * http://bytecrafter | ||||||
|  |      * .blogspot.com/2010/09/des-encryption-as-used-in-vnc.html | ||||||
|  |      *  | ||||||
|  |      * @param b | ||||||
|  |      *            a byte | ||||||
|  |      * @return byte in reverse order | ||||||
|  |      */ | ||||||
|  |     private static byte flipByte(byte b) { | ||||||
|  |         int b1_8 = (b & 0x1) << 7; | ||||||
|  |         int b2_7 = (b & 0x2) << 5; | ||||||
|  |         int b3_6 = (b & 0x4) << 3; | ||||||
|  |         int b4_5 = (b & 0x8) << 1; | ||||||
|  |         int b5_4 = (b & 0x10) >>> 1; | ||||||
|  |         int b6_3 = (b & 0x20) >>> 3; | ||||||
|  |         int b7_2 = (b & 0x40) >>> 5; | ||||||
|  |         int b8_1 = (b & 0x80) >>> 7; | ||||||
|  |         byte c = (byte) (b1_8 | b2_7 | b3_6 | b4_5 | b5_4 | b6_3 | b7_2 | b8_1); | ||||||
|  |         return c; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void initialize() throws IOException { | ||||||
|  |         // Send client initialization message | ||||||
|  |         { | ||||||
|  |             // Send shared flag | ||||||
|  |             os.writeByte(RfbConstants.EXCLUSIVE_ACCESS); | ||||||
|  |             os.flush(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Read server initialization message | ||||||
|  |         { | ||||||
|  |             // Read frame buffer size | ||||||
|  |             int framebufferWidth = is.readUnsignedShort(); | ||||||
|  |             int framebufferHeight = is.readUnsignedShort(); | ||||||
|  |             screen.setFramebufferSize(framebufferWidth, framebufferHeight); | ||||||
|  |             if (clientListener != null) | ||||||
|  |                 clientListener.onFramebufferSizeChange(framebufferWidth, framebufferHeight); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Read pixel format | ||||||
|  |         { | ||||||
|  |             int bitsPerPixel = is.readUnsignedByte(); | ||||||
|  |             int depth = is.readUnsignedByte(); | ||||||
|  | 
 | ||||||
|  |             int bigEndianFlag = is.readUnsignedByte(); | ||||||
|  |             int trueColorFlag = is.readUnsignedByte(); | ||||||
|  | 
 | ||||||
|  |             int redMax = is.readUnsignedShort(); | ||||||
|  |             int greenMax = is.readUnsignedShort(); | ||||||
|  |             int blueMax = is.readUnsignedShort(); | ||||||
|  | 
 | ||||||
|  |             int redShift = is.readUnsignedByte(); | ||||||
|  |             int greenShift = is.readUnsignedByte(); | ||||||
|  |             int blueShift = is.readUnsignedByte(); | ||||||
|  | 
 | ||||||
|  |             // Skip padding | ||||||
|  |             is.skipBytes(3); | ||||||
|  | 
 | ||||||
|  |             screen.setPixelFormat(bitsPerPixel, depth, bigEndianFlag, trueColorFlag, redMax, greenMax, blueMax, redShift, greenShift, blueShift); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Read desktop name | ||||||
|  |         { | ||||||
|  |             int length = is.readInt(); | ||||||
|  |             byte buf[] = new byte[length]; | ||||||
|  |             is.readFully(buf); | ||||||
|  |             String desktopName = new String(buf, RfbConstants.CHARSET); | ||||||
|  |             screen.setDesktopName(desktopName); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public FrameBufferCanvas getFrameBufferCanvas() { | ||||||
|  |         if (receiver != null) | ||||||
|  |             return receiver.getCanvas(); | ||||||
|  | 
 | ||||||
|  |         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(); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -35,226 +35,224 @@ import com.cloud.consoleproxy.vnc.packet.client.SetEncodingsPacket; | |||||||
| import com.cloud.consoleproxy.vnc.packet.client.SetPixelFormatPacket; | import com.cloud.consoleproxy.vnc.packet.client.SetPixelFormatPacket; | ||||||
| 
 | 
 | ||||||
| public class VncClientPacketSender implements Runnable, PaintNotificationListener, KeyListener, MouseListener, MouseMotionListener, FrameBufferUpdateListener { | public class VncClientPacketSender implements Runnable, PaintNotificationListener, KeyListener, MouseListener, MouseMotionListener, FrameBufferUpdateListener { | ||||||
|   private static final Logger s_logger = Logger.getLogger(VncClientPacketSender.class); |     private static final Logger s_logger = Logger.getLogger(VncClientPacketSender.class); | ||||||
| 
 | 
 | ||||||
|   // Queue for outgoing packets |     // Queue for outgoing packets | ||||||
|   private final BlockingQueue<ClientPacket> queue = new ArrayBlockingQueue<ClientPacket>(30); |     private final BlockingQueue<ClientPacket> queue = new ArrayBlockingQueue<ClientPacket>(30); | ||||||
| 
 | 
 | ||||||
|   private final DataOutputStream os; |     private final DataOutputStream os; | ||||||
|   private final VncScreenDescription screen; |     private final VncScreenDescription screen; | ||||||
|   private final VncClient vncConnection; |     private final VncClient vncConnection; | ||||||
| 
 | 
 | ||||||
|   private boolean connectionAlive = true; |     private boolean connectionAlive = true; | ||||||
| 
 | 
 | ||||||
|   // Don't send update request again until we receive next frame buffer update |     // Don't send update request again until we receive next frame buffer update | ||||||
|   private boolean updateRequestSent = false; |     private boolean updateRequestSent = false; | ||||||
| 
 | 
 | ||||||
|   public VncClientPacketSender(DataOutputStream os, VncScreenDescription screen, VncClient vncConnection) { |     public VncClientPacketSender(DataOutputStream os, VncScreenDescription screen, VncClient vncConnection) { | ||||||
|     this.os = os; |         this.os = os; | ||||||
|     this.screen = screen; |         this.screen = screen; | ||||||
|     this.vncConnection = vncConnection; |         this.vncConnection = vncConnection; | ||||||
| 
 | 
 | ||||||
|     sendSetPixelFormat(); |         sendSetPixelFormat(); | ||||||
|     sendSetEncodings(); |         sendSetEncodings(); | ||||||
|     requestFullScreenUpdate(); |         requestFullScreenUpdate(); | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   public void sendClientPacket(ClientPacket packet) { |     public void sendClientPacket(ClientPacket packet) { | ||||||
| 	  queue.add(packet); |         queue.add(packet); | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   @Override |     @Override | ||||||
|   public void run() { |     public void run() { | ||||||
|     try { |         try { | ||||||
|       while (connectionAlive) { |             while (connectionAlive) { | ||||||
|         ClientPacket packet = queue.poll(1, TimeUnit.SECONDS); |                 ClientPacket packet = queue.poll(1, TimeUnit.SECONDS); | ||||||
|         if (packet != null) { |                 if (packet != null) { | ||||||
|           packet.write(os); |                     packet.write(os); | ||||||
|           os.flush(); |                     os.flush(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } catch (Throwable e) { | ||||||
|  |             s_logger.error("Unexpected exception: ", e); | ||||||
|  |             if (connectionAlive) { | ||||||
|  |                 closeConnection(); | ||||||
|  |                 vncConnection.shutdown(); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|       } |  | ||||||
|     } catch (Throwable e) { |  | ||||||
|       s_logger.error("Unexpected exception: ", e); |  | ||||||
|       if (connectionAlive) { |  | ||||||
|         closeConnection(); |  | ||||||
|         vncConnection.shutdown(); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private void sendSetEncodings() { |  | ||||||
|     queue.add(new SetEncodingsPacket(RfbConstants.SUPPORTED_ENCODINGS_ARRAY)); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private void sendSetPixelFormat() { |  | ||||||
|     if (!screen.isRGB888_32_LE()) { |  | ||||||
|       queue.add(new SetPixelFormatPacket(screen, 32, 24, RfbConstants.LITTLE_ENDIAN, RfbConstants.TRUE_COLOR, 255, 255, 255, 16, 8, 0)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public void closeConnection() { |  | ||||||
|     connectionAlive = false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public void requestFullScreenUpdate() { |  | ||||||
|     queue.add(new FramebufferUpdateRequestPacket(RfbConstants.FRAMEBUFFER_FULL_UPDATE_REQUEST, 0, 0, screen.getFramebufferWidth(), screen |  | ||||||
|         .getFramebufferHeight())); |  | ||||||
|     updateRequestSent = true; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void imagePaintedOnScreen() { |  | ||||||
|     if (!updateRequestSent) { |  | ||||||
|       queue.add(new FramebufferUpdateRequestPacket(RfbConstants.FRAMEBUFFER_INCREMENTAL_UPDATE_REQUEST, 0, 0, screen.getFramebufferWidth(), screen |  | ||||||
|           .getFramebufferHeight())); |  | ||||||
|       updateRequestSent = true; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void frameBufferPacketReceived() { |  | ||||||
|     updateRequestSent = false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void mouseDragged(MouseEvent e) { |  | ||||||
|     queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY())); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void mouseMoved(MouseEvent e) { |  | ||||||
|     queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY())); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void mouseClicked(MouseEvent e) { |  | ||||||
|     // Nothing to do |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void mousePressed(MouseEvent e) { |  | ||||||
|     queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY())); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void mouseReleased(MouseEvent e) { |  | ||||||
|     queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY())); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void mouseEntered(MouseEvent e) { |  | ||||||
|     // Nothing to do |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void mouseExited(MouseEvent e) { |  | ||||||
|     // Nothing to do |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** |  | ||||||
|    * Current state of buttons 1 to 8 are represented by bits 0 to 7 of |  | ||||||
|    * button-mask respectively, 0 meaning up, 1 meaning down (pressed). On a |  | ||||||
|    * conventional mouse, buttons 1, 2 and 3 correspond to the left, middle and |  | ||||||
|    * right buttons on the mouse. On a wheel mouse, each step of the wheel |  | ||||||
|    * upwards is represented by a press and release of button 4, and each step |  | ||||||
|    * downwards is represented by a press and release of button 5. |  | ||||||
|    *  |  | ||||||
|    * @param modifiers |  | ||||||
|    *          extended modifiers from AWT mouse event |  | ||||||
|    * @return VNC mouse button mask |  | ||||||
|    */ |  | ||||||
|   public static int mapAwtModifiersToVncButtonMask(int modifiers) { |  | ||||||
|     int mask = (((modifiers & MouseEvent.BUTTON1_DOWN_MASK) != 0) ? 0x1 : 0) | (((modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0) ? 0x2 : 0) |  | ||||||
|         | (((modifiers & MouseEvent.BUTTON3_DOWN_MASK) != 0) ? 0x4 : 0); |  | ||||||
|     return mask; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void keyTyped(KeyEvent e) { |  | ||||||
|     // Do nothing |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void keyPressed(KeyEvent e) { |  | ||||||
|     ClientPacket request = new KeyboardEventPacket(RfbConstants.KEY_DOWN, mapAwtKeyToVncKey(e.getKeyCode())); |  | ||||||
|     queue.add(request); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void keyReleased(KeyEvent e) { |  | ||||||
|     ClientPacket request = new KeyboardEventPacket(RfbConstants.KEY_UP, mapAwtKeyToVncKey(e.getKeyCode())); |  | ||||||
|     queue.add(request); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private int mapAwtKeyToVncKey(int key) { |  | ||||||
|     switch (key) { |  | ||||||
|     case KeyEvent.VK_BACK_SPACE: |  | ||||||
|       return 0xff08; |  | ||||||
|     case KeyEvent.VK_TAB: |  | ||||||
|       return 0xff09; |  | ||||||
|     case KeyEvent.VK_ENTER: |  | ||||||
|       return 0xff0d; |  | ||||||
|     case KeyEvent.VK_ESCAPE: |  | ||||||
|       return 0xff1b; |  | ||||||
|     case KeyEvent.VK_INSERT: |  | ||||||
|       return 0xff63; |  | ||||||
|     case KeyEvent.VK_DELETE: |  | ||||||
|       return 0xffff; |  | ||||||
|     case KeyEvent.VK_HOME: |  | ||||||
|       return 0xff50; |  | ||||||
|     case KeyEvent.VK_END: |  | ||||||
|       return 0xff57; |  | ||||||
|     case KeyEvent.VK_PAGE_UP: |  | ||||||
|       return 0xff55; |  | ||||||
|     case KeyEvent.VK_PAGE_DOWN: |  | ||||||
|       return 0xff56; |  | ||||||
|     case KeyEvent.VK_LEFT: |  | ||||||
|       return 0xff51; |  | ||||||
|     case KeyEvent.VK_UP: |  | ||||||
|       return 0xff52; |  | ||||||
|     case KeyEvent.VK_RIGHT: |  | ||||||
|       return 0xff53; |  | ||||||
|     case KeyEvent.VK_DOWN: |  | ||||||
|       return 0xff54; |  | ||||||
|     case KeyEvent.VK_F1: |  | ||||||
|       return 0xffbe; |  | ||||||
|     case KeyEvent.VK_F2: |  | ||||||
|       return 0xffbf; |  | ||||||
|     case KeyEvent.VK_F3: |  | ||||||
|       return 0xffc0; |  | ||||||
|     case KeyEvent.VK_F4: |  | ||||||
|       return 0xffc1; |  | ||||||
|     case KeyEvent.VK_F5: |  | ||||||
|       return 0xffc2; |  | ||||||
|     case KeyEvent.VK_F6: |  | ||||||
|       return 0xffc3; |  | ||||||
|     case KeyEvent.VK_F7: |  | ||||||
|       return 0xffc4; |  | ||||||
|     case KeyEvent.VK_F8: |  | ||||||
|       return 0xffc5; |  | ||||||
|     case KeyEvent.VK_F9: |  | ||||||
|       return 0xffc6; |  | ||||||
|     case KeyEvent.VK_F10: |  | ||||||
|       return 0xffc7; |  | ||||||
|     case KeyEvent.VK_F11: |  | ||||||
|       return 0xffc8; |  | ||||||
|     case KeyEvent.VK_F12: |  | ||||||
|       return 0xffc9; |  | ||||||
|     case KeyEvent.VK_SHIFT: |  | ||||||
|       return 0xffe1; |  | ||||||
|     case KeyEvent.VK_CONTROL: |  | ||||||
|       return 0xffe3; |  | ||||||
|     case KeyEvent.VK_META: |  | ||||||
|       return 0xffe7; |  | ||||||
|     case KeyEvent.VK_ALT: |  | ||||||
|       return 0xffe9; |  | ||||||
|     case KeyEvent.VK_ALT_GRAPH: |  | ||||||
|       return 0xffea; |  | ||||||
|     case KeyEvent.VK_BACK_QUOTE: |  | ||||||
|       return 0x0060; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return key; |     private void sendSetEncodings() { | ||||||
|   } |         queue.add(new SetEncodingsPacket(RfbConstants.SUPPORTED_ENCODINGS_ARRAY)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void sendSetPixelFormat() { | ||||||
|  |         if (!screen.isRGB888_32_LE()) { | ||||||
|  |             queue.add(new SetPixelFormatPacket(screen, 32, 24, RfbConstants.LITTLE_ENDIAN, RfbConstants.TRUE_COLOR, 255, 255, 255, 16, 8, 0)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void closeConnection() { | ||||||
|  |         connectionAlive = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void requestFullScreenUpdate() { | ||||||
|  |         queue.add(new FramebufferUpdateRequestPacket(RfbConstants.FRAMEBUFFER_FULL_UPDATE_REQUEST, 0, 0, screen.getFramebufferWidth(), screen.getFramebufferHeight())); | ||||||
|  |         updateRequestSent = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void imagePaintedOnScreen() { | ||||||
|  |         if (!updateRequestSent) { | ||||||
|  |             queue.add(new FramebufferUpdateRequestPacket(RfbConstants.FRAMEBUFFER_INCREMENTAL_UPDATE_REQUEST, 0, 0, screen.getFramebufferWidth(), screen.getFramebufferHeight())); | ||||||
|  |             updateRequestSent = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void frameBufferPacketReceived() { | ||||||
|  |         updateRequestSent = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void mouseDragged(MouseEvent e) { | ||||||
|  |         queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY())); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void mouseMoved(MouseEvent e) { | ||||||
|  |         queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY())); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void mouseClicked(MouseEvent e) { | ||||||
|  |         // Nothing to do | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void mousePressed(MouseEvent e) { | ||||||
|  |         queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY())); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void mouseReleased(MouseEvent e) { | ||||||
|  |         queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY())); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void mouseEntered(MouseEvent e) { | ||||||
|  |         // Nothing to do | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void mouseExited(MouseEvent e) { | ||||||
|  |         // Nothing to do | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Current state of buttons 1 to 8 are represented by bits 0 to 7 of | ||||||
|  |      * button-mask respectively, 0 meaning up, 1 meaning down (pressed). On a | ||||||
|  |      * conventional mouse, buttons 1, 2 and 3 correspond to the left, middle and | ||||||
|  |      * right buttons on the mouse. On a wheel mouse, each step of the wheel | ||||||
|  |      * upwards is represented by a press and release of button 4, and each step | ||||||
|  |      * downwards is represented by a press and release of button 5. | ||||||
|  |      *  | ||||||
|  |      * @param modifiers | ||||||
|  |      *            extended modifiers from AWT mouse event | ||||||
|  |      * @return VNC mouse button mask | ||||||
|  |      */ | ||||||
|  |     public static int mapAwtModifiersToVncButtonMask(int modifiers) { | ||||||
|  |         int mask = (((modifiers & MouseEvent.BUTTON1_DOWN_MASK) != 0) ? 0x1 : 0) | (((modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0) ? 0x2 : 0) | ||||||
|  |                 | (((modifiers & MouseEvent.BUTTON3_DOWN_MASK) != 0) ? 0x4 : 0); | ||||||
|  |         return mask; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void keyTyped(KeyEvent e) { | ||||||
|  |         // Do nothing | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void keyPressed(KeyEvent e) { | ||||||
|  |         ClientPacket request = new KeyboardEventPacket(RfbConstants.KEY_DOWN, mapAwtKeyToVncKey(e.getKeyCode())); | ||||||
|  |         queue.add(request); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void keyReleased(KeyEvent e) { | ||||||
|  |         ClientPacket request = new KeyboardEventPacket(RfbConstants.KEY_UP, mapAwtKeyToVncKey(e.getKeyCode())); | ||||||
|  |         queue.add(request); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private int mapAwtKeyToVncKey(int key) { | ||||||
|  |         switch (key) { | ||||||
|  |         case KeyEvent.VK_BACK_SPACE: | ||||||
|  |             return 0xff08; | ||||||
|  |         case KeyEvent.VK_TAB: | ||||||
|  |             return 0xff09; | ||||||
|  |         case KeyEvent.VK_ENTER: | ||||||
|  |             return 0xff0d; | ||||||
|  |         case KeyEvent.VK_ESCAPE: | ||||||
|  |             return 0xff1b; | ||||||
|  |         case KeyEvent.VK_INSERT: | ||||||
|  |             return 0xff63; | ||||||
|  |         case KeyEvent.VK_DELETE: | ||||||
|  |             return 0xffff; | ||||||
|  |         case KeyEvent.VK_HOME: | ||||||
|  |             return 0xff50; | ||||||
|  |         case KeyEvent.VK_END: | ||||||
|  |             return 0xff57; | ||||||
|  |         case KeyEvent.VK_PAGE_UP: | ||||||
|  |             return 0xff55; | ||||||
|  |         case KeyEvent.VK_PAGE_DOWN: | ||||||
|  |             return 0xff56; | ||||||
|  |         case KeyEvent.VK_LEFT: | ||||||
|  |             return 0xff51; | ||||||
|  |         case KeyEvent.VK_UP: | ||||||
|  |             return 0xff52; | ||||||
|  |         case KeyEvent.VK_RIGHT: | ||||||
|  |             return 0xff53; | ||||||
|  |         case KeyEvent.VK_DOWN: | ||||||
|  |             return 0xff54; | ||||||
|  |         case KeyEvent.VK_F1: | ||||||
|  |             return 0xffbe; | ||||||
|  |         case KeyEvent.VK_F2: | ||||||
|  |             return 0xffbf; | ||||||
|  |         case KeyEvent.VK_F3: | ||||||
|  |             return 0xffc0; | ||||||
|  |         case KeyEvent.VK_F4: | ||||||
|  |             return 0xffc1; | ||||||
|  |         case KeyEvent.VK_F5: | ||||||
|  |             return 0xffc2; | ||||||
|  |         case KeyEvent.VK_F6: | ||||||
|  |             return 0xffc3; | ||||||
|  |         case KeyEvent.VK_F7: | ||||||
|  |             return 0xffc4; | ||||||
|  |         case KeyEvent.VK_F8: | ||||||
|  |             return 0xffc5; | ||||||
|  |         case KeyEvent.VK_F9: | ||||||
|  |             return 0xffc6; | ||||||
|  |         case KeyEvent.VK_F10: | ||||||
|  |             return 0xffc7; | ||||||
|  |         case KeyEvent.VK_F11: | ||||||
|  |             return 0xffc8; | ||||||
|  |         case KeyEvent.VK_F12: | ||||||
|  |             return 0xffc9; | ||||||
|  |         case KeyEvent.VK_SHIFT: | ||||||
|  |             return 0xffe1; | ||||||
|  |         case KeyEvent.VK_CONTROL: | ||||||
|  |             return 0xffe3; | ||||||
|  |         case KeyEvent.VK_META: | ||||||
|  |             return 0xffe7; | ||||||
|  |         case KeyEvent.VK_ALT: | ||||||
|  |             return 0xffe9; | ||||||
|  |         case KeyEvent.VK_ALT_GRAPH: | ||||||
|  |             return 0xffea; | ||||||
|  |         case KeyEvent.VK_BACK_QUOTE: | ||||||
|  |             return 0x0060; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return key; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,70 +21,69 @@ package com.cloud.consoleproxy.vnc; | |||||||
|  */ |  */ | ||||||
| public class VncScreenDescription { | public class VncScreenDescription { | ||||||
| 
 | 
 | ||||||
|   // Frame buffer size |     // Frame buffer size | ||||||
|   private int framebufferWidth = -1; |     private int framebufferWidth = -1; | ||||||
|   private int framebufferHeight = -1; |     private int framebufferHeight = -1; | ||||||
| 
 | 
 | ||||||
|   // Desktop name |     // Desktop name | ||||||
|   private String desktopName; |     private String desktopName; | ||||||
| 
 | 
 | ||||||
|   // Bytes per pixel |     // Bytes per pixel | ||||||
|   private int bytesPerPixel; |     private int bytesPerPixel; | ||||||
| 
 | 
 | ||||||
|   // Indicates that screen uses format which we want to use: |     // Indicates that screen uses format which we want to use: | ||||||
|   // RGB 24bit packed into 32bit little-endian int. |     // RGB 24bit packed into 32bit little-endian int. | ||||||
|   private boolean rgb888_32_le = false; |     private boolean rgb888_32_le = false; | ||||||
| 
 | 
 | ||||||
|   public VncScreenDescription() { |     public VncScreenDescription() { | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Store information about server pixel format. |      * Store information about server pixel format. | ||||||
|    */ |      */ | ||||||
|   public void setPixelFormat(int bitsPerPixel, int depth, int bigEndianFlag, int trueColorFlag, int redMax, int greenMax, int blueMax, int redShift, |     public void setPixelFormat(int bitsPerPixel, int depth, int bigEndianFlag, int trueColorFlag, int redMax, int greenMax, int blueMax, int redShift, int greenShift, int blueShift) { | ||||||
|       int greenShift, int blueShift) { |  | ||||||
| 
 | 
 | ||||||
|     bytesPerPixel = (bitsPerPixel + 7) / 8; |         bytesPerPixel = (bitsPerPixel + 7) / 8; | ||||||
| 
 | 
 | ||||||
|     rgb888_32_le = (depth == 24 && bitsPerPixel == 32 && redShift == 16 && greenShift == 8 && blueShift == 0 && redMax == 255 && greenMax == 255 |         rgb888_32_le = (depth == 24 && bitsPerPixel == 32 && redShift == 16 && greenShift == 8 && blueShift == 0 && redMax == 255 && greenMax == 255 && blueMax == 255 | ||||||
|         && blueMax == 255 && bigEndianFlag == RfbConstants.LITTLE_ENDIAN && trueColorFlag == RfbConstants.TRUE_COLOR); |                 && bigEndianFlag == RfbConstants.LITTLE_ENDIAN && trueColorFlag == RfbConstants.TRUE_COLOR); | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Store information about server screen size. |      * Store information about server screen size. | ||||||
|    */ |      */ | ||||||
|   public void setFramebufferSize(int framebufferWidth, int framebufferHeight) { |     public void setFramebufferSize(int framebufferWidth, int framebufferHeight) { | ||||||
|     this.framebufferWidth = framebufferWidth; |         this.framebufferWidth = framebufferWidth; | ||||||
|     this.framebufferHeight = framebufferHeight; |         this.framebufferHeight = framebufferHeight; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   /** |     /** | ||||||
|    * Store server desktop name. |      * Store server desktop name. | ||||||
|    */ |      */ | ||||||
|   public void setDesktopName(String desktopName) { |     public void setDesktopName(String desktopName) { | ||||||
|     this.desktopName = desktopName; |         this.desktopName = desktopName; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   // Getters for variables, as usual |     // Getters for variables, as usual | ||||||
| 
 | 
 | ||||||
|   public String getDesktopName() { |     public String getDesktopName() { | ||||||
|     return desktopName; |         return desktopName; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   public int getBytesPerPixel() { |     public int getBytesPerPixel() { | ||||||
|     return bytesPerPixel; |         return bytesPerPixel; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   public int getFramebufferHeight() { |     public int getFramebufferHeight() { | ||||||
|     return framebufferHeight; |         return framebufferHeight; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   public int getFramebufferWidth() { |     public int getFramebufferWidth() { | ||||||
|     return framebufferWidth; |         return framebufferWidth; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   public boolean isRGB888_32_LE() { |     public boolean isRGB888_32_LE() { | ||||||
|     return rgb888_32_le; |         return rgb888_32_le; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -27,97 +27,97 @@ import com.cloud.consoleproxy.vnc.packet.server.FramebufferUpdatePacket; | |||||||
| import com.cloud.consoleproxy.vnc.packet.server.ServerCutText; | import com.cloud.consoleproxy.vnc.packet.server.ServerCutText; | ||||||
| 
 | 
 | ||||||
| public class VncServerPacketReceiver implements Runnable { | public class VncServerPacketReceiver implements Runnable { | ||||||
|   private static final Logger s_logger = Logger.getLogger(VncServerPacketReceiver.class); |     private static final Logger s_logger = Logger.getLogger(VncServerPacketReceiver.class); | ||||||
| 
 | 
 | ||||||
|   private final VncScreenDescription screen; |     private final VncScreenDescription screen; | ||||||
|   private BufferedImageCanvas canvas; |     private BufferedImageCanvas canvas; | ||||||
|   private DataInputStream is; |     private DataInputStream is; | ||||||
| 
 | 
 | ||||||
|   private boolean connectionAlive = true; |     private boolean connectionAlive = true; | ||||||
|   private VncClient vncConnection; |     private VncClient vncConnection; | ||||||
|   private final FrameBufferUpdateListener fburListener; |     private final FrameBufferUpdateListener fburListener; | ||||||
|   private final ConsoleProxyClientListener clientListener; |     private final ConsoleProxyClientListener clientListener; | ||||||
| 
 | 
 | ||||||
|   public VncServerPacketReceiver(DataInputStream is, BufferedImageCanvas canvas, VncScreenDescription screen, VncClient vncConnection, |     public VncServerPacketReceiver(DataInputStream is, BufferedImageCanvas canvas, VncScreenDescription screen, VncClient vncConnection, FrameBufferUpdateListener fburListener, | ||||||
|       FrameBufferUpdateListener fburListener, ConsoleProxyClientListener clientListener) { |             ConsoleProxyClientListener clientListener) { | ||||||
|     this.screen = screen; |         this.screen = screen; | ||||||
|     this.canvas = canvas; |         this.canvas = canvas; | ||||||
|     this.is = is; |         this.is = is; | ||||||
|     this.vncConnection = vncConnection; |         this.vncConnection = vncConnection; | ||||||
|     this.fburListener = fburListener; |         this.fburListener = fburListener; | ||||||
|     this.clientListener = clientListener; |         this.clientListener = clientListener; | ||||||
|   } |  | ||||||
|    |  | ||||||
|   public BufferedImageCanvas getCanvas() {  |  | ||||||
| 	return canvas;  |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void run() { |  | ||||||
|     try { |  | ||||||
|       while (connectionAlive) { |  | ||||||
| 
 |  | ||||||
|         // Read server message type |  | ||||||
|         int messageType = is.readUnsignedByte(); |  | ||||||
| 
 |  | ||||||
|         // Invoke packet handler by packet type. |  | ||||||
|         switch (messageType) { |  | ||||||
| 
 |  | ||||||
|         case RfbConstants.SERVER_FRAMEBUFFER_UPDATE: { |  | ||||||
|           // Notify sender that frame buffer update is received, |  | ||||||
|           // so it can send another frame buffer update request |  | ||||||
|           fburListener.frameBufferPacketReceived(); |  | ||||||
|           // Handle frame buffer update |  | ||||||
|           new FramebufferUpdatePacket(canvas, screen, is, clientListener); |  | ||||||
|           break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         case RfbConstants.SERVER_BELL: { |  | ||||||
|           serverBell(); |  | ||||||
|           break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         case RfbConstants.SERVER_CUT_TEXT: { |  | ||||||
|           serverCutText(is); |  | ||||||
|           break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         default: |  | ||||||
|           throw new RuntimeException("Unknown server packet type: " + messageType + "."); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } catch (Throwable e) { |  | ||||||
|       s_logger.error("Unexpected exception: ", e); |  | ||||||
|       if (connectionAlive) { |  | ||||||
|         closeConnection(); |  | ||||||
|         vncConnection.shutdown(); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   public void closeConnection() { |     public BufferedImageCanvas getCanvas() { | ||||||
|     connectionAlive = false; |         return canvas; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   public boolean isConnectionAlive() { |     @Override | ||||||
| 	return connectionAlive; |     public void run() { | ||||||
|   } |         try { | ||||||
|  |             while (connectionAlive) { | ||||||
| 
 | 
 | ||||||
|   /** |                 // Read server message type | ||||||
|    * Handle server bell packet. |                 int messageType = is.readUnsignedByte(); | ||||||
|    */ |  | ||||||
|   private void serverBell() { |  | ||||||
|     Toolkit.getDefaultToolkit().beep(); |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   /** |                 // Invoke packet handler by packet type. | ||||||
|    * Handle packet with server clip-board. |                 switch (messageType) { | ||||||
|    */ |  | ||||||
|   private void serverCutText(DataInputStream is) throws IOException { |  | ||||||
|     ServerCutText clipboardContent = new ServerCutText(is); |  | ||||||
|     StringSelection contents = new StringSelection(clipboardContent.getContent()); |  | ||||||
|     Toolkit.getDefaultToolkit().getSystemClipboard().setContents(contents, null); |  | ||||||
| 
 | 
 | ||||||
|     s_logger.info("Server clipboard buffer: "+clipboardContent.getContent()); |                 case RfbConstants.SERVER_FRAMEBUFFER_UPDATE: { | ||||||
|   } |                     // Notify sender that frame buffer update is received, | ||||||
|  |                     // so it can send another frame buffer update request | ||||||
|  |                     fburListener.frameBufferPacketReceived(); | ||||||
|  |                     // Handle frame buffer update | ||||||
|  |                     new FramebufferUpdatePacket(canvas, screen, is, clientListener); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 case RfbConstants.SERVER_BELL: { | ||||||
|  |                     serverBell(); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 case RfbConstants.SERVER_CUT_TEXT: { | ||||||
|  |                     serverCutText(is); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 default: | ||||||
|  |                     throw new RuntimeException("Unknown server packet type: " + messageType + "."); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } catch (Throwable e) { | ||||||
|  |             s_logger.error("Unexpected exception: ", e); | ||||||
|  |             if (connectionAlive) { | ||||||
|  |                 closeConnection(); | ||||||
|  |                 vncConnection.shutdown(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void closeConnection() { | ||||||
|  |         connectionAlive = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public boolean isConnectionAlive() { | ||||||
|  |         return connectionAlive; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Handle server bell packet. | ||||||
|  |      */ | ||||||
|  |     private void serverBell() { | ||||||
|  |         Toolkit.getDefaultToolkit().beep(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Handle packet with server clip-board. | ||||||
|  |      */ | ||||||
|  |     private void serverCutText(DataInputStream is) throws IOException { | ||||||
|  |         ServerCutText clipboardContent = new ServerCutText(is); | ||||||
|  |         StringSelection contents = new StringSelection(clipboardContent.getContent()); | ||||||
|  |         Toolkit.getDefaultToolkit().getSystemClipboard().setContents(contents, null); | ||||||
|  | 
 | ||||||
|  |         s_logger.info("Server clipboard buffer: " + clipboardContent.getContent()); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,6 +21,6 @@ import java.io.IOException; | |||||||
| 
 | 
 | ||||||
| public interface ClientPacket { | public interface ClientPacket { | ||||||
| 
 | 
 | ||||||
|   void write(DataOutputStream os) throws IOException; |     void write(DataOutputStream os) throws IOException; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -28,27 +28,26 @@ import com.cloud.consoleproxy.vnc.RfbConstants; | |||||||
|  */ |  */ | ||||||
| public class FramebufferUpdateRequestPacket implements ClientPacket { | public class FramebufferUpdateRequestPacket implements ClientPacket { | ||||||
| 
 | 
 | ||||||
|   private final int incremental; |     private final int incremental; | ||||||
|   private final int x, y, width, height; |     private final int x, y, width, height; | ||||||
| 
 | 
 | ||||||
|   public FramebufferUpdateRequestPacket(int incremental, int x, int y, int width, int height) { |     public FramebufferUpdateRequestPacket(int incremental, int x, int y, int width, int height) { | ||||||
|     this.incremental = incremental; |         this.incremental = incremental; | ||||||
|     this.x = x; |         this.x = x; | ||||||
|     this.y = y; |         this.y = y; | ||||||
|     this.width = width; |         this.width = width; | ||||||
|     this.height = height; |         this.height = height; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Override | ||||||
|  |     public void write(DataOutputStream os) throws IOException { | ||||||
|  |         os.writeByte(RfbConstants.CLIENT_FRAMEBUFFER_UPDATE_REQUEST); | ||||||
| 
 | 
 | ||||||
|   @Override |         os.writeByte(incremental); | ||||||
|   public void write(DataOutputStream os) throws IOException { |         os.writeShort(x); | ||||||
|     os.writeByte(RfbConstants.CLIENT_FRAMEBUFFER_UPDATE_REQUEST); |         os.writeShort(y); | ||||||
| 
 |         os.writeShort(width); | ||||||
|     os.writeByte(incremental); |         os.writeShort(height); | ||||||
|     os.writeShort(x); |     } | ||||||
|     os.writeShort(y); |  | ||||||
|     os.writeShort(width); |  | ||||||
|     os.writeShort(height); |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -23,20 +23,20 @@ import com.cloud.consoleproxy.vnc.RfbConstants; | |||||||
| 
 | 
 | ||||||
| public class KeyboardEventPacket implements ClientPacket { | public class KeyboardEventPacket implements ClientPacket { | ||||||
| 
 | 
 | ||||||
|   private final int downFlag, key; |     private final int downFlag, key; | ||||||
| 
 | 
 | ||||||
|   public KeyboardEventPacket(int downFlag, int key) { |     public KeyboardEventPacket(int downFlag, int key) { | ||||||
|     this.downFlag = downFlag; |         this.downFlag = downFlag; | ||||||
|     this.key = key; |         this.key = key; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   @Override |     @Override | ||||||
|   public void write(DataOutputStream os) throws IOException { |     public void write(DataOutputStream os) throws IOException { | ||||||
|     os.writeByte(RfbConstants.CLIENT_KEYBOARD_EVENT); |         os.writeByte(RfbConstants.CLIENT_KEYBOARD_EVENT); | ||||||
| 
 | 
 | ||||||
|     os.writeByte(downFlag); |         os.writeByte(downFlag); | ||||||
|     os.writeShort(0); // padding |         os.writeShort(0); // padding | ||||||
|     os.writeInt(key); |         os.writeInt(key); | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -23,21 +23,21 @@ import com.cloud.consoleproxy.vnc.RfbConstants; | |||||||
| 
 | 
 | ||||||
| public class MouseEventPacket implements ClientPacket { | public class MouseEventPacket implements ClientPacket { | ||||||
| 
 | 
 | ||||||
|   private final int buttonMask, x, y; |     private final int buttonMask, x, y; | ||||||
| 
 | 
 | ||||||
|   public MouseEventPacket(int buttonMask, int x, int y) { |     public MouseEventPacket(int buttonMask, int x, int y) { | ||||||
|     this.buttonMask = buttonMask; |         this.buttonMask = buttonMask; | ||||||
|     this.x = x; |         this.x = x; | ||||||
|     this.y = y; |         this.y = y; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   @Override |     @Override | ||||||
|   public void write(DataOutputStream os) throws IOException { |     public void write(DataOutputStream os) throws IOException { | ||||||
|     os.writeByte(RfbConstants.CLIENT_POINTER_EVENT); |         os.writeByte(RfbConstants.CLIENT_POINTER_EVENT); | ||||||
| 
 | 
 | ||||||
|     os.writeByte(buttonMask); |         os.writeByte(buttonMask); | ||||||
|     os.writeShort(x); |         os.writeShort(x); | ||||||
|     os.writeShort(y); |         os.writeShort(y); | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -23,26 +23,23 @@ import com.cloud.consoleproxy.vnc.RfbConstants; | |||||||
| 
 | 
 | ||||||
| public class SetEncodingsPacket implements ClientPacket { | public class SetEncodingsPacket implements ClientPacket { | ||||||
| 
 | 
 | ||||||
|   private final int[] encodings; |     private final int[] encodings; | ||||||
| 
 | 
 | ||||||
|   public SetEncodingsPacket(int[] encodings) |     public SetEncodingsPacket(int[] encodings) { | ||||||
|   { |         this.encodings = encodings; | ||||||
|     this.encodings = encodings; |     } | ||||||
|   } | 
 | ||||||
|    |     @Override | ||||||
|   @Override |     public void write(DataOutputStream os) throws IOException { | ||||||
|   public void write(DataOutputStream os) throws IOException |         os.writeByte(RfbConstants.CLIENT_SET_ENCODINGS); | ||||||
|   { | 
 | ||||||
|     os.writeByte(RfbConstants.CLIENT_SET_ENCODINGS); |         os.writeByte(0);// padding | ||||||
|      | 
 | ||||||
|     os.writeByte(0);//padding |         os.writeShort(encodings.length); | ||||||
|      | 
 | ||||||
|     os.writeShort(encodings.length); |         for (int i = 0; i < encodings.length; i++) { | ||||||
|      |             os.writeInt(encodings[i]); | ||||||
|     for(int i=0;i<encodings.length;i++) |         } | ||||||
|     { |  | ||||||
|       os.writeInt(encodings[i]); |  | ||||||
|     } |     } | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -24,52 +24,52 @@ import com.cloud.consoleproxy.vnc.VncScreenDescription; | |||||||
| 
 | 
 | ||||||
| public class SetPixelFormatPacket implements ClientPacket { | public class SetPixelFormatPacket implements ClientPacket { | ||||||
| 
 | 
 | ||||||
|   private final int bitsPerPixel, depth, bigEndianFlag, trueColourFlag, redMax, greenMax, blueMax, redShift, greenShift, blueShift; |     private final int bitsPerPixel, depth, bigEndianFlag, trueColourFlag, redMax, greenMax, blueMax, redShift, greenShift, blueShift; | ||||||
| 
 | 
 | ||||||
|   private final VncScreenDescription screen; |     private final VncScreenDescription screen; | ||||||
| 
 | 
 | ||||||
|   public SetPixelFormatPacket(VncScreenDescription screen, int bitsPerPixel, int depth, int bigEndianFlag, int trueColorFlag, int redMax, int greenMax, |     public SetPixelFormatPacket(VncScreenDescription screen, int bitsPerPixel, int depth, int bigEndianFlag, int trueColorFlag, int redMax, int greenMax, int blueMax, int redShift, int greenShift, | ||||||
|       int blueMax, int redShift, int greenShift, int blueShift) { |             int blueShift) { | ||||||
|     this.screen = screen; |         this.screen = screen; | ||||||
|     this.bitsPerPixel = bitsPerPixel; |         this.bitsPerPixel = bitsPerPixel; | ||||||
|     this.depth = depth; |         this.depth = depth; | ||||||
|     this.bigEndianFlag = bigEndianFlag; |         this.bigEndianFlag = bigEndianFlag; | ||||||
|     this.trueColourFlag = trueColorFlag; |         this.trueColourFlag = trueColorFlag; | ||||||
|     this.redMax = redMax; |         this.redMax = redMax; | ||||||
|     this.greenMax = greenMax; |         this.greenMax = greenMax; | ||||||
|     this.blueMax = blueMax; |         this.blueMax = blueMax; | ||||||
|     this.redShift = redShift; |         this.redShift = redShift; | ||||||
|     this.greenShift = greenShift; |         this.greenShift = greenShift; | ||||||
|     this.blueShift = blueShift; |         this.blueShift = blueShift; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   @Override |     @Override | ||||||
|   public void write(DataOutputStream os) throws IOException { |     public void write(DataOutputStream os) throws IOException { | ||||||
|     os.writeByte(RfbConstants.CLIENT_SET_PIXEL_FORMAT); |         os.writeByte(RfbConstants.CLIENT_SET_PIXEL_FORMAT); | ||||||
| 
 | 
 | ||||||
|     // Padding |         // Padding | ||||||
|     os.writeByte(0); |         os.writeByte(0); | ||||||
|     os.writeByte(0); |         os.writeByte(0); | ||||||
|     os.writeByte(0); |         os.writeByte(0); | ||||||
| 
 | 
 | ||||||
|     // Send pixel format |         // Send pixel format | ||||||
|     os.writeByte(bitsPerPixel); |         os.writeByte(bitsPerPixel); | ||||||
|     os.writeByte(depth); |         os.writeByte(depth); | ||||||
|     os.writeByte(bigEndianFlag); |         os.writeByte(bigEndianFlag); | ||||||
|     os.writeByte(trueColourFlag); |         os.writeByte(trueColourFlag); | ||||||
|     os.writeShort(redMax); |         os.writeShort(redMax); | ||||||
|     os.writeShort(greenMax); |         os.writeShort(greenMax); | ||||||
|     os.writeShort(blueMax); |         os.writeShort(blueMax); | ||||||
|     os.writeByte(redShift); |         os.writeByte(redShift); | ||||||
|     os.writeByte(greenShift); |         os.writeByte(greenShift); | ||||||
|     os.writeByte(blueShift); |         os.writeByte(blueShift); | ||||||
| 
 | 
 | ||||||
|     // Padding |         // Padding | ||||||
|     os.writeByte(0); |         os.writeByte(0); | ||||||
|     os.writeByte(0); |         os.writeByte(0); | ||||||
|     os.writeByte(0); |         os.writeByte(0); | ||||||
| 
 | 
 | ||||||
|     screen.setPixelFormat(bitsPerPixel, depth, bigEndianFlag, trueColourFlag, redMax, greenMax, blueMax, redShift, greenShift, blueShift); |         screen.setPixelFormat(bitsPerPixel, depth, bigEndianFlag, trueColourFlag, redMax, greenMax, blueMax, redShift, greenShift, blueShift); | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -18,36 +18,36 @@ package com.cloud.consoleproxy.vnc.packet.server; | |||||||
| 
 | 
 | ||||||
| public abstract class AbstractRect implements Rect { | public abstract class AbstractRect implements Rect { | ||||||
| 
 | 
 | ||||||
|   protected final int x; |     protected final int x; | ||||||
|   protected final int y; |     protected final int y; | ||||||
|   protected final int width; |     protected final int width; | ||||||
|   protected final int height; |     protected final int height; | ||||||
| 
 | 
 | ||||||
|   public AbstractRect(int x, int y, int width, int height) { |     public AbstractRect(int x, int y, int width, int height) { | ||||||
|     this.x = x; |         this.x = x; | ||||||
|     this.y = y; |         this.y = y; | ||||||
|     this.width = width; |         this.width = width; | ||||||
|     this.height = height; |         this.height = height; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   @Override |     @Override | ||||||
|   public int getX() { |     public int getX() { | ||||||
|     return x; |         return x; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   @Override |     @Override | ||||||
|   public int getY() { |     public int getY() { | ||||||
|     return y; |         return y; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   @Override |     @Override | ||||||
|   public int getWidth() { |     public int getWidth() { | ||||||
|     return width; |         return width; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   @Override |     @Override | ||||||
|   public int getHeight() { |     public int getHeight() { | ||||||
|     return height; |         return height; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| @ -23,17 +23,17 @@ import java.io.IOException; | |||||||
| 
 | 
 | ||||||
| public class CopyRect extends AbstractRect { | public class CopyRect extends AbstractRect { | ||||||
| 
 | 
 | ||||||
|   private final int srcX, srcY; |     private final int srcX, srcY; | ||||||
| 
 | 
 | ||||||
|   public CopyRect(int x, int y, int width, int height, DataInputStream is) throws IOException { |     public CopyRect(int x, int y, int width, int height, DataInputStream is) throws IOException { | ||||||
|     super(x, y, width, height); |         super(x, y, width, height); | ||||||
| 
 | 
 | ||||||
|     srcX = is.readUnsignedShort(); |         srcX = is.readUnsignedShort(); | ||||||
|     srcY = is.readUnsignedShort(); |         srcY = is.readUnsignedShort(); | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   @Override |     @Override | ||||||
|   public void paint(BufferedImage image, Graphics2D graphics) { |     public void paint(BufferedImage image, Graphics2D graphics) { | ||||||
|     graphics.copyArea(srcX, srcY, width, height, x - srcX, y - srcY); |         graphics.copyArea(srcX, srcY, width, height, x - srcX, y - srcY); | ||||||
|   } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -23,17 +23,17 @@ import com.cloud.consoleproxy.vnc.BufferedImageCanvas; | |||||||
| 
 | 
 | ||||||
| public class FrameBufferSizeChangeRequest extends AbstractRect { | public class FrameBufferSizeChangeRequest extends AbstractRect { | ||||||
| 
 | 
 | ||||||
|   private final BufferedImageCanvas canvas; |     private final BufferedImageCanvas canvas; | ||||||
| 
 | 
 | ||||||
|   public FrameBufferSizeChangeRequest(BufferedImageCanvas canvas, int width, int height) { |     public FrameBufferSizeChangeRequest(BufferedImageCanvas canvas, int width, int height) { | ||||||
|     super(0, 0, width, height); |         super(0, 0, width, height); | ||||||
|     this.canvas = canvas; |         this.canvas = canvas; | ||||||
|     canvas.setCanvasSize(width, height); |         canvas.setCanvasSize(width, height); | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   @Override |     @Override | ||||||
|   public void paint(BufferedImage offlineImage, Graphics2D graphics) { |     public void paint(BufferedImage offlineImage, Graphics2D graphics) { | ||||||
|     canvas.setCanvasSize(width, height); |         canvas.setCanvasSize(width, height); | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -29,75 +29,74 @@ import com.cloud.consoleproxy.vnc.packet.server.Rect; | |||||||
| 
 | 
 | ||||||
| public class FramebufferUpdatePacket { | public class FramebufferUpdatePacket { | ||||||
| 
 | 
 | ||||||
|   private final VncScreenDescription screen; |     private final VncScreenDescription screen; | ||||||
|   private final BufferedImageCanvas canvas; |     private final BufferedImageCanvas canvas; | ||||||
|   private final ConsoleProxyClientListener clientListener; |     private final ConsoleProxyClientListener clientListener; | ||||||
| 
 | 
 | ||||||
|   public FramebufferUpdatePacket(BufferedImageCanvas canvas, VncScreenDescription screen, DataInputStream is,  |     public FramebufferUpdatePacket(BufferedImageCanvas canvas, VncScreenDescription screen, DataInputStream is, ConsoleProxyClientListener clientListener) throws IOException { | ||||||
|     ConsoleProxyClientListener clientListener) throws IOException { |  | ||||||
| 
 | 
 | ||||||
|     this.screen = screen; |         this.screen = screen; | ||||||
|     this.canvas = canvas; |         this.canvas = canvas; | ||||||
|     this.clientListener = clientListener; |         this.clientListener = clientListener; | ||||||
|     readPacketData(is); |         readPacketData(is); | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private void readPacketData(DataInputStream is) throws IOException { |  | ||||||
|     is.skipBytes(1);// Skip padding |  | ||||||
| 
 |  | ||||||
|     // Read number of rectangles |  | ||||||
|     int numberOfRectangles = is.readUnsignedShort(); |  | ||||||
| 
 |  | ||||||
|     // For all rectangles |  | ||||||
|     for (int i = 0; i < numberOfRectangles; i++) { |  | ||||||
| 
 |  | ||||||
|       // Read coordinate of rectangle |  | ||||||
|       int x = is.readUnsignedShort(); |  | ||||||
|       int y = is.readUnsignedShort(); |  | ||||||
|       int width = is.readUnsignedShort(); |  | ||||||
|       int height = is.readUnsignedShort(); |  | ||||||
| 
 |  | ||||||
|       int encodingType = is.readInt(); |  | ||||||
| 
 |  | ||||||
|       // Process rectangle |  | ||||||
|       Rect rect; |  | ||||||
|       switch (encodingType) { |  | ||||||
| 
 |  | ||||||
|       case RfbConstants.ENCODING_RAW: { |  | ||||||
|         rect = new RawRect(screen, x, y, width, height, is); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case RfbConstants.ENCODING_COPY_RECT: { |  | ||||||
|         rect = new CopyRect(x, y, width, height, is); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case RfbConstants.ENCODING_DESKTOP_SIZE: { |  | ||||||
|         rect = new FrameBufferSizeChangeRequest(canvas, width, height); |  | ||||||
|         if(this.clientListener != null) |  | ||||||
|           this.clientListener.onFramebufferSizeChange(width, height); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       default: |  | ||||||
|         throw new RuntimeException("Unsupported ecnoding: " + encodingType); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       paint(rect, canvas); |  | ||||||
|        |  | ||||||
|       if(this.clientListener != null) |  | ||||||
|     	  this.clientListener.onFramebufferUpdate(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   } |     private void readPacketData(DataInputStream is) throws IOException { | ||||||
|  |         is.skipBytes(1);// Skip padding | ||||||
| 
 | 
 | ||||||
|   public void paint(Rect rect, BufferedImageCanvas canvas) { |         // Read number of rectangles | ||||||
|     // Draw rectangle on offline buffer |         int numberOfRectangles = is.readUnsignedShort(); | ||||||
|     rect.paint(canvas.getOfflineImage(), canvas.getOfflineGraphics()); |  | ||||||
| 
 | 
 | ||||||
|     // Request update of repainted area |         // For all rectangles | ||||||
|     canvas.repaint(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); |         for (int i = 0; i < numberOfRectangles; i++) { | ||||||
|   } | 
 | ||||||
|  |             // Read coordinate of rectangle | ||||||
|  |             int x = is.readUnsignedShort(); | ||||||
|  |             int y = is.readUnsignedShort(); | ||||||
|  |             int width = is.readUnsignedShort(); | ||||||
|  |             int height = is.readUnsignedShort(); | ||||||
|  | 
 | ||||||
|  |             int encodingType = is.readInt(); | ||||||
|  | 
 | ||||||
|  |             // Process rectangle | ||||||
|  |             Rect rect; | ||||||
|  |             switch (encodingType) { | ||||||
|  | 
 | ||||||
|  |             case RfbConstants.ENCODING_RAW: { | ||||||
|  |                 rect = new RawRect(screen, x, y, width, height, is); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             case RfbConstants.ENCODING_COPY_RECT: { | ||||||
|  |                 rect = new CopyRect(x, y, width, height, is); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             case RfbConstants.ENCODING_DESKTOP_SIZE: { | ||||||
|  |                 rect = new FrameBufferSizeChangeRequest(canvas, width, height); | ||||||
|  |                 if (this.clientListener != null) | ||||||
|  |                     this.clientListener.onFramebufferSizeChange(width, height); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             default: | ||||||
|  |                 throw new RuntimeException("Unsupported ecnoding: " + encodingType); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             paint(rect, canvas); | ||||||
|  | 
 | ||||||
|  |             if (this.clientListener != null) | ||||||
|  |                 this.clientListener.onFramebufferUpdate(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void paint(Rect rect, BufferedImageCanvas canvas) { | ||||||
|  |         // Draw rectangle on offline buffer | ||||||
|  |         rect.paint(canvas.getOfflineImage(), canvas.getOfflineGraphics()); | ||||||
|  | 
 | ||||||
|  |         // Request update of repainted area | ||||||
|  |         canvas.repaint(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -26,51 +26,50 @@ import java.io.IOException; | |||||||
| import com.cloud.consoleproxy.vnc.VncScreenDescription; | import com.cloud.consoleproxy.vnc.VncScreenDescription; | ||||||
| 
 | 
 | ||||||
| public class RawRect extends AbstractRect { | public class RawRect extends AbstractRect { | ||||||
|   private final int[] buf; |     private final int[] buf; | ||||||
| 
 | 
 | ||||||
|   public RawRect(VncScreenDescription screen, int x, int y, int width, int height, DataInputStream is) throws IOException { |     public RawRect(VncScreenDescription screen, int x, int y, int width, int height, DataInputStream is) throws IOException { | ||||||
|     super(x, y, width, height); |         super(x, y, width, height); | ||||||
| 
 | 
 | ||||||
|     byte[] bbuf = new byte[width * height * screen.getBytesPerPixel()]; |         byte[] bbuf = new byte[width * height * screen.getBytesPerPixel()]; | ||||||
|     is.readFully(bbuf); |         is.readFully(bbuf); | ||||||
| 
 | 
 | ||||||
|     // Convert array of bytes to array of int |         // Convert array of bytes to array of int | ||||||
|     int size = width * height; |         int size = width * height; | ||||||
|     buf = new int[size]; |         buf = new int[size]; | ||||||
|     for (int i = 0, j = 0; i < size; i++, j += 4) { |         for (int i = 0, j = 0; i < size; i++, j += 4) { | ||||||
|       buf[i] = (bbuf[j + 0] & 0xFF) | ((bbuf[j + 1] & 0xFF) << 8) | ((bbuf[j + 2] & 0xFF) << 16) | ((bbuf[j + 3] & 0xFF) << 24); |             buf[i] = (bbuf[j + 0] & 0xFF) | ((bbuf[j + 1] & 0xFF) << 8) | ((bbuf[j + 2] & 0xFF) << 16) | ((bbuf[j + 3] & 0xFF) << 24); | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Override |  | ||||||
|   public void paint(BufferedImage image, Graphics2D graphics) { |  | ||||||
| 
 |  | ||||||
|     DataBuffer dataBuf = image.getRaster().getDataBuffer(); |  | ||||||
| 
 |  | ||||||
|     switch (dataBuf.getDataType()) { |  | ||||||
| 
 |  | ||||||
|     case DataBuffer.TYPE_INT: { |  | ||||||
|       // We chose RGB888 model, so Raster will use DataBufferInt type |  | ||||||
|       DataBufferInt dataBuffer = (DataBufferInt) dataBuf; |  | ||||||
| 
 |  | ||||||
|       int imageWidth = image.getWidth(); |  | ||||||
|       int imageHeight = image.getHeight(); |  | ||||||
| 
 |  | ||||||
|       // Paint rectangle directly on buffer, line by line |  | ||||||
|       int[] imageBuffer = dataBuffer.getData(); |  | ||||||
|       for (int srcLine = 0, dstLine = y; srcLine < height && dstLine < imageHeight; srcLine++, dstLine++) { |  | ||||||
|         try { |  | ||||||
|           System.arraycopy(buf, srcLine * width, imageBuffer, x + dstLine * imageWidth, width); |  | ||||||
|         } catch (IndexOutOfBoundsException e) { |  | ||||||
|         } |         } | ||||||
|       } | 
 | ||||||
|       break; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     default: |     @Override | ||||||
|       throw new RuntimeException("Unsupported data buffer in buffered image: expected data buffer of type int (DataBufferInt). Actual data buffer type: " |     public void paint(BufferedImage image, Graphics2D graphics) { | ||||||
|           + dataBuf.getClass().getSimpleName()); | 
 | ||||||
|  |         DataBuffer dataBuf = image.getRaster().getDataBuffer(); | ||||||
|  | 
 | ||||||
|  |         switch (dataBuf.getDataType()) { | ||||||
|  | 
 | ||||||
|  |         case DataBuffer.TYPE_INT: { | ||||||
|  |             // We chose RGB888 model, so Raster will use DataBufferInt type | ||||||
|  |             DataBufferInt dataBuffer = (DataBufferInt) dataBuf; | ||||||
|  | 
 | ||||||
|  |             int imageWidth = image.getWidth(); | ||||||
|  |             int imageHeight = image.getHeight(); | ||||||
|  | 
 | ||||||
|  |             // Paint rectangle directly on buffer, line by line | ||||||
|  |             int[] imageBuffer = dataBuffer.getData(); | ||||||
|  |             for (int srcLine = 0, dstLine = y; srcLine < height && dstLine < imageHeight; srcLine++, dstLine++) { | ||||||
|  |                 try { | ||||||
|  |                     System.arraycopy(buf, srcLine * width, imageBuffer, x + dstLine * imageWidth, width); | ||||||
|  |                 } catch (IndexOutOfBoundsException e) { | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  |             throw new RuntimeException("Unsupported data buffer in buffered image: expected data buffer of type int (DataBufferInt). Actual data buffer type: " + dataBuf.getClass().getSimpleName()); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|   } |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,10 +21,13 @@ import java.awt.image.BufferedImage; | |||||||
| 
 | 
 | ||||||
| public interface Rect { | public interface Rect { | ||||||
| 
 | 
 | ||||||
|   void paint(BufferedImage offlineImage, Graphics2D graphics); |     void paint(BufferedImage offlineImage, Graphics2D graphics); | ||||||
| 
 | 
 | ||||||
|   int getX(); |     int getX(); | ||||||
|   int getY(); | 
 | ||||||
|   int getWidth(); |     int getY(); | ||||||
|   int getHeight(); | 
 | ||||||
|  |     int getWidth(); | ||||||
|  | 
 | ||||||
|  |     int getHeight(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -23,27 +23,27 @@ import com.cloud.consoleproxy.util.Logger; | |||||||
| import com.cloud.consoleproxy.vnc.RfbConstants; | import com.cloud.consoleproxy.vnc.RfbConstants; | ||||||
| 
 | 
 | ||||||
| public class ServerCutText { | public class ServerCutText { | ||||||
|   private static final Logger s_logger = Logger.getLogger(ServerCutText.class); |     private static final Logger s_logger = Logger.getLogger(ServerCutText.class); | ||||||
| 
 | 
 | ||||||
|   private String content; |     private String content; | ||||||
| 
 | 
 | ||||||
|   public String getContent() { |     public String getContent() { | ||||||
|     return content; |         return content; | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   public ServerCutText(DataInputStream is) throws IOException { |     public ServerCutText(DataInputStream is) throws IOException { | ||||||
|     readPacketData(is); |         readPacketData(is); | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
|   private void readPacketData(DataInputStream is) throws IOException { |     private void readPacketData(DataInputStream is) throws IOException { | ||||||
|     is.skipBytes(3);// Skip padding |         is.skipBytes(3);// Skip padding | ||||||
|     int length = is.readInt(); |         int length = is.readInt(); | ||||||
|     byte buf[] = new byte[length]; |         byte buf[] = new byte[length]; | ||||||
|     is.readFully(buf); |         is.readFully(buf); | ||||||
| 
 | 
 | ||||||
|     content = new String(buf, RfbConstants.CHARSET); |         content = new String(buf, RfbConstants.CHARSET); | ||||||
| 
 | 
 | ||||||
|     /* LOG */s_logger.info("Clippboard content: " + content); |         /* LOG */s_logger.info("Clippboard content: " + content); | ||||||
|   } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user