Moved console-proxy into services
							
								
								
									
										35
									
								
								services/console-proxy/plugin/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,35 @@
 | 
			
		||||
<!--
 | 
			
		||||
  Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
  or more contributor license agreements. See the NOTICE file
 | 
			
		||||
  distributed with this work for additional information
 | 
			
		||||
  regarding copyright ownership. The ASF licenses this file
 | 
			
		||||
  to you under the Apache License, Version 2.0 (the
 | 
			
		||||
  "License"); you may not use this file except in compliance
 | 
			
		||||
  with the License. You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing,
 | 
			
		||||
  software distributed under the License is distributed on an
 | 
			
		||||
  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
  KIND, either express or implied. See the License for the
 | 
			
		||||
  specific language governing permissions and limitations
 | 
			
		||||
  under the License.
 | 
			
		||||
-->
 | 
			
		||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
			
		||||
  <modelVersion>4.0.0</modelVersion>
 | 
			
		||||
  <artifactId>cloud-plugin-console-proxy</artifactId>
 | 
			
		||||
  <name>Apache CloudStack Console Proxy Plugin</name>
 | 
			
		||||
  <packaging>pom</packaging>
 | 
			
		||||
  <parent>
 | 
			
		||||
    <groupId>org.apache.cloudstack</groupId>
 | 
			
		||||
    <artifactId>cloud-service-console-proxy</artifactId>
 | 
			
		||||
    <version>4.1.0-SNAPSHOT</version>
 | 
			
		||||
    <relativePath>../pom.xml</relativePath>
 | 
			
		||||
  </parent>
 | 
			
		||||
  <build>
 | 
			
		||||
    <defaultGoal>install</defaultGoal>
 | 
			
		||||
	<sourceDirectory>src</sourceDirectory>
 | 
			
		||||
	<testSourceDirectory>test</testSourceDirectory>
 | 
			
		||||
  </build>
 | 
			
		||||
</project>
 | 
			
		||||
							
								
								
									
										37
									
								
								services/console-proxy/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,37 @@
 | 
			
		||||
<!--
 | 
			
		||||
  Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
  or more contributor license agreements. See the NOTICE file
 | 
			
		||||
  distributed with this work for additional information
 | 
			
		||||
  regarding copyright ownership. The ASF licenses this file
 | 
			
		||||
  to you under the Apache License, Version 2.0 (the
 | 
			
		||||
  "License"); you may not use this file except in compliance
 | 
			
		||||
  with the License. You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing,
 | 
			
		||||
  software distributed under the License is distributed on an
 | 
			
		||||
  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
  KIND, either express or implied. See the License for the
 | 
			
		||||
  specific language governing permissions and limitations
 | 
			
		||||
  under the License.
 | 
			
		||||
-->
 | 
			
		||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
			
		||||
  <modelVersion>4.0.0</modelVersion>
 | 
			
		||||
  <artifactId>cloud-service-console-proxy</artifactId>
 | 
			
		||||
  <name>Apache CloudStack Console Proxy Service</name>
 | 
			
		||||
  <packaging>pom</packaging>
 | 
			
		||||
  <parent>
 | 
			
		||||
    <groupId>org.apache.cloudstack</groupId>
 | 
			
		||||
    <artifactId>cloud-services</artifactId>
 | 
			
		||||
    <version>4.1.0-SNAPSHOT</version>
 | 
			
		||||
    <relativePath>../pom.xml</relativePath>
 | 
			
		||||
  </parent>
 | 
			
		||||
  <build>
 | 
			
		||||
    <defaultGoal>install</defaultGoal>
 | 
			
		||||
  </build>
 | 
			
		||||
  <modules>
 | 
			
		||||
    <module>plugin</module>
 | 
			
		||||
    <module>server</module>
 | 
			
		||||
  </modules>
 | 
			
		||||
</project>
 | 
			
		||||
							
								
								
									
										220
									
								
								services/console-proxy/server/bindir/cloud-setup-console-proxy.in
									
									
									
									
									
										Executable file
									
								
							
							
						
						@ -0,0 +1,220 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import sys, os, subprocess, errno, re, getopt
 | 
			
		||||
 | 
			
		||||
# ---- This snippet of code adds the sources path and the waf configured PYTHONDIR to the Python path ----
 | 
			
		||||
# ---- We do this so cloud_utils can be looked up in the following order:
 | 
			
		||||
# ---- 1) Sources directory
 | 
			
		||||
# ---- 2) waf configured PYTHONDIR
 | 
			
		||||
# ---- 3) System Python path
 | 
			
		||||
for pythonpath in (
 | 
			
		||||
		"@PYTHONDIR@",
 | 
			
		||||
		os.path.join(os.path.dirname(__file__),os.path.pardir,os.path.pardir,"python","lib"),
 | 
			
		||||
	):
 | 
			
		||||
		if os.path.isdir(pythonpath): sys.path.insert(0,pythonpath)
 | 
			
		||||
# ---- End snippet of code ----
 | 
			
		||||
import cloud_utils
 | 
			
		||||
from cloud_utils import stderr
 | 
			
		||||
 | 
			
		||||
E_GENERIC= 1
 | 
			
		||||
E_NOKVM = 2
 | 
			
		||||
E_NODEFROUTE = 3
 | 
			
		||||
E_DHCP = 4
 | 
			
		||||
E_NOPERSISTENTNET = 5
 | 
			
		||||
E_NETRECONFIGFAILED = 6
 | 
			
		||||
E_VIRTRECONFIGFAILED = 7
 | 
			
		||||
E_FWRECONFIGFAILED = 8
 | 
			
		||||
E_CPRECONFIGFAILED = 9
 | 
			
		||||
E_CPFAILEDTOSTART = 10
 | 
			
		||||
E_NOFQDN = 11
 | 
			
		||||
 | 
			
		||||
def bail(errno=E_GENERIC,message=None,*args):
 | 
			
		||||
	if message: stderr(message,*args)
 | 
			
		||||
	stderr("Cloud Console Proxy setup aborted")
 | 
			
		||||
	sys.exit(errno)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#---------------- boilerplate for python 2.4 support 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# CENTOS does not have this -- we have to put this here
 | 
			
		||||
try:
 | 
			
		||||
	from subprocess import check_call
 | 
			
		||||
	from subprocess import CalledProcessError
 | 
			
		||||
except ImportError:
 | 
			
		||||
	def check_call(*popenargs, **kwargs):
 | 
			
		||||
		import subprocess
 | 
			
		||||
		retcode = subprocess.call(*popenargs, **kwargs)
 | 
			
		||||
		cmd = kwargs.get("args")
 | 
			
		||||
		if cmd is None: cmd = popenargs[0]
 | 
			
		||||
		if retcode: raise CalledProcessError(retcode, cmd)
 | 
			
		||||
		return retcode
 | 
			
		||||
 | 
			
		||||
	class CalledProcessError(Exception):
 | 
			
		||||
		def __init__(self, returncode, cmd):
 | 
			
		||||
			self.returncode = returncode ; self.cmd = cmd
 | 
			
		||||
		def __str__(self): return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
 | 
			
		||||
 | 
			
		||||
# ------------ end boilerplate -------------------------
 | 
			
		||||
 | 
			
		||||
def check_hostname(): return check_call(["hostname",'--fqdn'])
 | 
			
		||||
 | 
			
		||||
class Command:
 | 
			
		||||
	def __init__(self,name,parent=None):
 | 
			
		||||
		self.__name = name
 | 
			
		||||
		self.__parent = parent
 | 
			
		||||
	def __getattr__(self,name):
 | 
			
		||||
		if name == "_print": name = "print"
 | 
			
		||||
		return Command(name,self)
 | 
			
		||||
	def __call__(self,*args):
 | 
			
		||||
		cmd = self.__get_recursive_name() + list(args)
 | 
			
		||||
		#print "	",cmd
 | 
			
		||||
		popen = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
 | 
			
		||||
		m = popen.communicate()
 | 
			
		||||
		ret = popen.wait()
 | 
			
		||||
		if ret:
 | 
			
		||||
			e = CalledProcessError(ret,cmd)
 | 
			
		||||
			e.stdout,e.stderr = m
 | 
			
		||||
			raise e
 | 
			
		||||
		class CommandOutput:
 | 
			
		||||
			def __init__(self,stdout,stderr):
 | 
			
		||||
				self.stdout = stdout
 | 
			
		||||
				self.stderr = stderr
 | 
			
		||||
		return CommandOutput(*m)
 | 
			
		||||
	def __lt__(self,other):
 | 
			
		||||
		cmd = self.__get_recursive_name()
 | 
			
		||||
		#print "	",cmd,"<",other
 | 
			
		||||
		popen = subprocess.Popen(cmd,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
 | 
			
		||||
		m = popen.communicate(other)
 | 
			
		||||
		ret = popen.wait()
 | 
			
		||||
		if ret:
 | 
			
		||||
			e = CalledProcessError(ret,cmd)
 | 
			
		||||
			e.stdout,e.stderr = m
 | 
			
		||||
			raise e
 | 
			
		||||
		class CommandOutput:
 | 
			
		||||
			def __init__(self,stdout,stderr):
 | 
			
		||||
				self.stdout = stdout
 | 
			
		||||
				self.stderr = stderr
 | 
			
		||||
		return CommandOutput(*m)
 | 
			
		||||
		
 | 
			
		||||
	def __get_recursive_name(self,sep=None):
 | 
			
		||||
		m = self
 | 
			
		||||
		l = []
 | 
			
		||||
		while m is not None:
 | 
			
		||||
			l.append(m.__name)
 | 
			
		||||
			m = m.__parent
 | 
			
		||||
		l.reverse()
 | 
			
		||||
		if sep: return sep.join(l)
 | 
			
		||||
		else: return l
 | 
			
		||||
	def __str__(self):
 | 
			
		||||
		return '<Command %r>'%self.__get_recursive_name(sep=" ")
 | 
			
		||||
		
 | 
			
		||||
	def __repr__(self): return self.__str__()
 | 
			
		||||
 | 
			
		||||
ip = Command("ip")
 | 
			
		||||
service = Command("service")
 | 
			
		||||
chkconfig = Command("chkconfig")
 | 
			
		||||
ufw = Command("ufw")
 | 
			
		||||
iptables = Command("iptables")
 | 
			
		||||
augtool = Command("augtool")
 | 
			
		||||
ifconfig = Command("ifconfig")
 | 
			
		||||
uuidgen = Command("uuidgen")
 | 
			
		||||
 | 
			
		||||
Fedora = os.path.exists("/etc/fedora-release")
 | 
			
		||||
CentOS = os.path.exists("/etc/centos-release") or ( os.path.exists("/etc/redhat-release") and not os.path.exists("/etc/fedora-release") )
 | 
			
		||||
 | 
			
		||||
#--------------- procedure starts here ------------
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
	# parse cmd line	
 | 
			
		||||
	opts, args = getopt.getopt(sys.argv[1:], "a", ["host=", "zone=", "pod="])
 | 
			
		||||
	host=None
 | 
			
		||||
	zone=None
 | 
			
		||||
	pod=None
 | 
			
		||||
    	autoMode=False
 | 
			
		||||
	do_check_kvm = True	
 | 
			
		||||
	for opt, arg in opts:
 | 
			
		||||
		if opt == "--host":
 | 
			
		||||
			if arg != "":
 | 
			
		||||
				host = arg
 | 
			
		||||
		elif opt == "--zone":
 | 
			
		||||
			if arg != "":
 | 
			
		||||
				zone = arg
 | 
			
		||||
		elif opt == "--pod":
 | 
			
		||||
		        if arg != "":
 | 
			
		||||
				pod = arg
 | 
			
		||||
        	elif opt == "-a":
 | 
			
		||||
            		autoMode=True
 | 
			
		||||
	servicename = "@PACKAGE@-console-proxy"
 | 
			
		||||
	
 | 
			
		||||
	if autoMode:
 | 
			
		||||
		cloud_utils.setLogFile("/var/log/cloud/setupConsoleProxy.log")
 | 
			
		||||
 | 
			
		||||
	stderr("Welcome to the Cloud Console Proxy setup")
 | 
			
		||||
	stderr("")
 | 
			
		||||
 | 
			
		||||
	try:
 | 
			
		||||
		check_hostname()
 | 
			
		||||
		stderr("The hostname of this machine is properly set up")
 | 
			
		||||
	except CalledProcessError,e:
 | 
			
		||||
		bail(E_NOFQDN,"This machine does not have an FQDN (fully-qualified domain name) for a hostname")
 | 
			
		||||
 | 
			
		||||
	stderr("Stopping the Cloud Console Proxy")
 | 
			
		||||
	cloud_utils.stop_service(servicename)
 | 
			
		||||
	stderr("Cloud Console Proxy stopped")
 | 
			
		||||
 | 
			
		||||
	ports = "8002".split()
 | 
			
		||||
	if Fedora or CentOS:
 | 
			
		||||
		try:
 | 
			
		||||
			o = chkconfig("--list","iptables")
 | 
			
		||||
			if ":on" in o.stdout and os.path.exists("/etc/sysconfig/iptables"):
 | 
			
		||||
				stderr("Setting up firewall rules to permit traffic to Cloud services")
 | 
			
		||||
				service.iptables.start() ; print o.stdout + o.stderr
 | 
			
		||||
				for p in ports: iptables("-I","INPUT","1","-p","tcp","--dport",p,'-j','ACCEPT')
 | 
			
		||||
				o = service.iptables.save() ; print o.stdout + o.stderr
 | 
			
		||||
		except CalledProcessError,e:
 | 
			
		||||
			print e.stdout+e.stderr
 | 
			
		||||
			bail(E_FWRECONFIGFAILED,"Firewall rules could not be set")
 | 
			
		||||
	else:
 | 
			
		||||
		stderr("Setting up firewall rules to permit traffic to Cloud services")
 | 
			
		||||
		try:
 | 
			
		||||
			for p in ports: ufw.allow(p)
 | 
			
		||||
			stderr("Rules set")
 | 
			
		||||
		except CalledProcessError,e:
 | 
			
		||||
			print e.stdout+e.stderr
 | 
			
		||||
			bail(E_FWRECONFIGFAILED,"Firewall rules could not be set")
 | 
			
		||||
 | 
			
		||||
		stderr("We are going to enable ufw now.  This may disrupt network connectivity and service availability.  See the ufw documentation for information on how to manage ufw firewall policies.")
 | 
			
		||||
		try:
 | 
			
		||||
			o = ufw.enable < "y\n" ; print o.stdout + o.stderr
 | 
			
		||||
		except CalledProcessError,e:
 | 
			
		||||
			print e.stdout+e.stderr
 | 
			
		||||
			bail(E_FWRECONFIGFAILED,"Firewall could not be enabled")
 | 
			
		||||
 | 
			
		||||
	cloud_utils.setup_consoleproxy_config("@CPSYSCONFDIR@/agent.properties", host, zone, pod)
 | 
			
		||||
	stderr("Enabling and starting the Cloud Console Proxy")
 | 
			
		||||
	cloud_utils.enable_service(servicename)
 | 
			
		||||
	stderr("Cloud Console Proxy restarted")
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
	main()
 | 
			
		||||
 | 
			
		||||
# FIXMES: 1) nullify networkmanager on ubuntu (asking the user first) and enable the networking service permanently
 | 
			
		||||
							
								
								
									
										22
									
								
								services/console-proxy/server/certs/localhost.crt
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,22 @@
 | 
			
		||||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIDrTCCApWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJVUzEL
 | 
			
		||||
MAkGA1UECAwCQ0ExEjAQBgNVBAcMCUN1cGVydGlubzESMBAGA1UECgwJQ2xvdWQu
 | 
			
		||||
Y29tMRAwDgYDVQQLDAdEZWZhdWx0MRswGQYDVQQDDBJTZWNvbmRhcnlTdG9yYWdl
 | 
			
		||||
Vk0wHhcNMTAwNTI3MTgzNjI1WhcNMTMwMjIwMTgzNjI1WjBxMQswCQYDVQQGEwJV
 | 
			
		||||
UzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCUN1cGVydGlubzESMBAGA1UECgwJQ2xv
 | 
			
		||||
dWQuY29tMRAwDgYDVQQLDAdEZWZhdWx0MRswGQYDVQQDDBJTZWNvbmRhcnlTdG9y
 | 
			
		||||
YWdlVk0wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbhstQ5Gn2gzrk
 | 
			
		||||
ZX1es+tuz4rnrcONRHUzyY/UdoT5jiVfmmS9CML/GgSpKzmnEMNZcCSh7G/GKPwD
 | 
			
		||||
gBZywpTVD56nYT4ZzK0GjPxcg0a+BvxxA2esQ2/kFBvtdcZ1TNExtjdOqysjK0It
 | 
			
		||||
M6U2891wbn+Y9oHqooTA0uaZELTpe/MCg2eBx7A4+u26novHHfOaKEEqtBscpDP8
 | 
			
		||||
0+nQduNQf61haV25Lv2CDqrCIuv/FrNmgQhcUg8e1dFkk4VCsflEDuSYh9PpaD7J
 | 
			
		||||
t+oqmNTVw8k6u3JAYJFkcu457uYz0wrED7Cai7Y6gUy7xwmY2SSY/r2mJJHEpSpZ
 | 
			
		||||
NhiH47kZAgMBAAGjUDBOMB0GA1UdDgQWBBQ2hUX5Jdhn277SBisACnEABqg52zAf
 | 
			
		||||
BgNVHSMEGDAWgBQ2hUX5Jdhn277SBisACnEABqg52zAMBgNVHRMEBTADAQH/MA0G
 | 
			
		||||
CSqGSIb3DQEBBQUAA4IBAQBAVrkGGDPHDPQdZRgI1+1L87sX5xdNoet9sJUVRtz9
 | 
			
		||||
ZwhGWAmca30cJGlhSFNx5y01E6T7lHDLrF9HCf9nVC10t0FwQwTVYijE8VyM7fAA
 | 
			
		||||
4Hv/whSKg1kkQQSTis2ZW0wMU6TnanhJy6MrxwdhRampeXjNOpNtoLrF/5LbhWxO
 | 
			
		||||
Gm0S5u+4q7eYnUPD4o3sb17idG62kkejHeToPnJwXtDwyq0XYNlL/OoqRaaY5f0b
 | 
			
		||||
IKdeqqEkdtkzfU4N1dG7bJA29gBl48gPn+CSrh9u3D0s1OYM7MWi1/TjpwCR18ir
 | 
			
		||||
CslVzO6kVNyQoNEYhZ9+2Sz0ceZVrYDFFzp8qAF8qbZ7
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										27
									
								
								services/console-proxy/server/certs/localhost.key
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,27 @@
 | 
			
		||||
-----BEGIN RSA PRIVATE KEY-----
 | 
			
		||||
MIIEpAIBAAKCAQEAm4bLUORp9oM65GV9XrPrbs+K563DjUR1M8mP1HaE+Y4lX5pk
 | 
			
		||||
vQjC/xoEqSs5pxDDWXAkoexvxij8A4AWcsKU1Q+ep2E+GcytBoz8XINGvgb8cQNn
 | 
			
		||||
rENv5BQb7XXGdUzRMbY3TqsrIytCLTOlNvPdcG5/mPaB6qKEwNLmmRC06XvzAoNn
 | 
			
		||||
gcewOPrtup6Lxx3zmihBKrQbHKQz/NPp0HbjUH+tYWlduS79gg6qwiLr/xazZoEI
 | 
			
		||||
XFIPHtXRZJOFQrH5RA7kmIfT6Wg+ybfqKpjU1cPJOrtyQGCRZHLuOe7mM9MKxA+w
 | 
			
		||||
mou2OoFMu8cJmNkkmP69piSRxKUqWTYYh+O5GQIDAQABAoIBAQCI5S8VNtimaYBv
 | 
			
		||||
BX5C26+BzCECKIsWT4myWdrGMsR9PUdcTXQaiBnLncU4epm2miS5FuLHvGvuSqj5
 | 
			
		||||
E8eun+ONXsBRqGCXKPer6nE/pTWhklilyU9566oTYjfq3l4fZcxFK5SnJDdGL4+C
 | 
			
		||||
ZhEou6LQkhKyO1jDhOXBLGJZnMEBOf+zXhgZGLDbQwCcCQ5PAZUiSf0cnVRk3rI9
 | 
			
		||||
GwdsbCDNJk6awy8ANlFATemDvHwHZ7ZwmvVzsjsYlYJbY/vJYlOyxa7tzYROVAlm
 | 
			
		||||
m8oiPfDvGjnXcGxVQwT0pgDvwtUkUFijZORpkJOPavxqSkpOzDFrOe9UW6HJYGzH
 | 
			
		||||
ujhmZBVhAoGBAMnbfssRwYI5egfsxNbA62NkxRcGe5HIlnyZ1Ln0BCE8ae60frcf
 | 
			
		||||
4IluZzT53Ly3jUQP2uGdp6nJVq/5ymRYSySNr46DXek2qcJ2TMbtRBhjebPwi+Rb
 | 
			
		||||
qTNjccNSgqs0j+1qP78PoTUO5fUWGL9XqIlfPU6Vji4+SmdNMvz6z84lAoGBAMU9
 | 
			
		||||
/3l2WVXykD6FNrRbtvpzU1C9LDixOaVVpGnZHO8krW440LnhIZJbkXnXDVZXc7eI
 | 
			
		||||
D/doecfL8rtFteqeBr0LiXGQXU5mIMjXAOAPSvDqIciYzhL8KOK5CWEgVZo6RQlU
 | 
			
		||||
G3ne0mk93I+w8N0SE2VKeuxepz4yw0oiKUpAgWrlAoGAS06qNRSAvxa2YjKBFSWQ
 | 
			
		||||
K9qydO6kNzVAf2fcpytURxoE41tPUv5/hIY91tPI+Fb6SwQnQrjQjlVhE/H7Agi2
 | 
			
		||||
sAJ0FpUH+jO8jaIY7rYiC39BLlJ1vlI8A8H79UTZHwpTD93tvlgUankObas6vFf1
 | 
			
		||||
tppjgufkzXfLxlJUzXC9CkkCgYA7gy9YOKtP0XZQRuVwmdOl0bIrxEhZeq/IAQUw
 | 
			
		||||
or+mMEzb2uyviQwWGubT+l0d1hkmITmgDrff3tuIQcpX1gJ2e8qmp0Zf51SxBJ5Q
 | 
			
		||||
/IxCEILNAb374HV9oxL/aUAq3rYB0IzRwrd95ZptCJhEO7X6c/SO6ShRDgP6lEAd
 | 
			
		||||
FUV3OQKBgQCFC0Xx/fCX1yquARgoe5pbK7IpXWaTvjBu//gbHsfR2lk3dZbESdeg
 | 
			
		||||
OquPDdfp+jFPGISsDhPLzcfkZIPbz5ZVs8KdmpB/YLwyJwFqjDyjwVaDnRnuycb1
 | 
			
		||||
/4PlVWKp7j5SDDNCfleYvmiRn8k6P4mxVJOHKzwb/IwQcKghyqAF1w==
 | 
			
		||||
-----END RSA PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										31
									
								
								services/console-proxy/server/certs/realhostip.crt
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,31 @@
 | 
			
		||||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIFZTCCBE2gAwIBAgIHKBCduBUoKDANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
 | 
			
		||||
BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY
 | 
			
		||||
BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm
 | 
			
		||||
aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5
 | 
			
		||||
IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky
 | 
			
		||||
ODcwHhcNMTIwMjAzMDMzMDQwWhcNMTcwMjA3MDUxMTIzWjBZMRkwFwYDVQQKDBAq
 | 
			
		||||
LnJlYWxob3N0aXAuY29tMSEwHwYDVQQLDBhEb21haW4gQ29udHJvbCBWYWxpZGF0
 | 
			
		||||
ZWQxGTAXBgNVBAMMECoucmVhbGhvc3RpcC5jb20wggEiMA0GCSqGSIb3DQEBAQUA
 | 
			
		||||
A4IBDwAwggEKAoIBAQCDT9AtEfs+s/I8QXp6rrCw0iNJ0+GgsybNHheU+JpL39LM
 | 
			
		||||
TZykCrZhZnyDvwdxCoOfE38Sa32baHKNds+y2SHnMNsOkw8OcNucHEBX1FIpOBGp
 | 
			
		||||
h9D6xC+umx9od6xMWETUv7j6h2u+WC3OhBM8fHCBqIiAol31/IkcqDxxsHlQ8S/o
 | 
			
		||||
CfTlXJUY6Yn628OA1XijKdRnadV0hZ829cv/PZKljjwQUTyrd0KHQeksBH+YAYSo
 | 
			
		||||
2JUl8ekNLsOi8/cPtfojnltzRI1GXi0ZONs8VnDzJ0a2gqZY+uxlz+CGbLnGnlN4
 | 
			
		||||
j9cBpE+MfUE+35Dq121sTpsSgF85Mz+pVhn2S633AgMBAAGjggG+MIIBujAPBgNV
 | 
			
		||||
HRMBAf8EBTADAQEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNV
 | 
			
		||||
HQ8BAf8EBAMCBaAwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nb2RhZGR5
 | 
			
		||||
LmNvbS9nZHMxLTY0LmNybDBTBgNVHSAETDBKMEgGC2CGSAGG/W0BBxcBMDkwNwYI
 | 
			
		||||
KwYBBQUHAgEWK2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3Np
 | 
			
		||||
dG9yeS8wgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au
 | 
			
		||||
Z29kYWRkeS5jb20vMEoGCCsGAQUFBzAChj5odHRwOi8vY2VydGlmaWNhdGVzLmdv
 | 
			
		||||
ZGFkZHkuY29tL3JlcG9zaXRvcnkvZ2RfaW50ZXJtZWRpYXRlLmNydDAfBgNVHSME
 | 
			
		||||
GDAWgBT9rGEyk2xF1uLuhV+auud2mWjM5zArBgNVHREEJDAighAqLnJlYWxob3N0
 | 
			
		||||
aXAuY29tgg5yZWFsaG9zdGlwLmNvbTAdBgNVHQ4EFgQUZyJz9/QLy5TWIIscTXID
 | 
			
		||||
E8Xk47YwDQYJKoZIhvcNAQEFBQADggEBAKiUV3KK16mP0NpS92fmQkCLqm+qUWyN
 | 
			
		||||
BfBVgf9/M5pcT8EiTZlS5nAtzAE/eRpBeR3ubLlaAogj4rdH7YYVJcDDLLoB2qM3
 | 
			
		||||
qeCHu8LFoblkb93UuFDWqRaVPmMlJRnhsRkL1oa2gM2hwQTkBDkP7w5FG1BELCgl
 | 
			
		||||
gZI2ij2yxjge6pOEwSyZCzzbCcg9pN+dNrYyGEtB4k+BBnPA3N4r14CWbk+uxjrQ
 | 
			
		||||
6j2Ip+b7wOc5IuMEMl8xwTyjuX3lsLbAZyFI9RCyofwA9NqIZ1GeB6Zd196rubQp
 | 
			
		||||
93cmBqGGjZUs3wMrGlm7xdjlX6GQ9UvmvkMub9+lL99A5W50QgCmFeI=
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										15
									
								
								services/console-proxy/server/certs/realhostip.csr
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,15 @@
 | 
			
		||||
-----BEGIN NEW CERTIFICATE REQUEST-----
 | 
			
		||||
MIICsDCCAZgCAQAwazELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlDdXBlcnRp
 | 
			
		||||
bm8xDjAMBgNVBAoTBVZNT3BzMRAwDgYDVQQLEwdVbmtub3duMRkwFwYDVQQDDBAqLnJlYWxob3N0
 | 
			
		||||
aXAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg0/QLRH7PrPyPEF6eq6wsNIj
 | 
			
		||||
SdPhoLMmzR4XlPiaS9/SzE2cpAq2YWZ8g78HcQqDnxN/Emt9m2hyjXbPstkh5zDbDpMPDnDbnBxA
 | 
			
		||||
V9RSKTgRqYfQ+sQvrpsfaHesTFhE1L+4+odrvlgtzoQTPHxwgaiIgKJd9fyJHKg8cbB5UPEv6An0
 | 
			
		||||
5VyVGOmJ+tvDgNV4oynUZ2nVdIWfNvXL/z2SpY48EFE8q3dCh0HpLAR/mAGEqNiVJfHpDS7DovP3
 | 
			
		||||
D7X6I55bc0SNRl4tGTjbPFZw8ydGtoKmWPrsZc/ghmy5xp5TeI/XAaRPjH1BPt+Q6tdtbE6bEoBf
 | 
			
		||||
OTM/qVYZ9kut9wIDAQABoAAwDQYJKoZIhvcNAQEFBQADggEBAF5lhhni9dW9MqSL2ixNbViPWpFS
 | 
			
		||||
ecOggshYChJfZKrhsuZaDpumJ/+ebICS4zv/oxDwNLSmeAmydiaUQC9LFQEEwvPBYDTtTzwCrtwH
 | 
			
		||||
yyFJQSm6pyeIBP/Bih/5hLW8JPm0bDbp5ldrHCDEgKQeeyQhyYOKFODkTuMLw+FLD+V86IVHxElL
 | 
			
		||||
/urCRWyZEPwyMsgfsU6ywNX9XNShyk1uDHjFDE67sPhfw52ooxXrYQnBdTk+g0UXPbULzrCK/1kU
 | 
			
		||||
fjRq347V9Fwi5NFyGADOaA+q6mtnlb1i3uH1n1YVUzevvpnIr3/RxPSYHB47Kj9iYKeDlYdTRHJy
 | 
			
		||||
NpuvTfmQO2Y=
 | 
			
		||||
-----END NEW CERTIFICATE REQUEST-----
 | 
			
		||||
							
								
								
									
										24
									
								
								services/console-proxy/server/certs/realhostip.key
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,24 @@
 | 
			
		||||
-----BEGIN PRIVATE KEY-----
 | 
			
		||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCDT9AtEfs+s/I8QXp6rrCw0iNJ
 | 
			
		||||
0+GgsybNHheU+JpL39LMTZykCrZhZnyDvwdxCoOfE38Sa32baHKNds+y2SHnMNsOkw8OcNucHEBX
 | 
			
		||||
1FIpOBGph9D6xC+umx9od6xMWETUv7j6h2u+WC3OhBM8fHCBqIiAol31/IkcqDxxsHlQ8S/oCfTl
 | 
			
		||||
XJUY6Yn628OA1XijKdRnadV0hZ829cv/PZKljjwQUTyrd0KHQeksBH+YAYSo2JUl8ekNLsOi8/cP
 | 
			
		||||
tfojnltzRI1GXi0ZONs8VnDzJ0a2gqZY+uxlz+CGbLnGnlN4j9cBpE+MfUE+35Dq121sTpsSgF85
 | 
			
		||||
Mz+pVhn2S633AgMBAAECggEAH/Szd9RxbVADenCA6wxKSa3KErRyq1YN8ksJeCKMAj0FIt0caruE
 | 
			
		||||
qO11DebWW8cwQu1Otl/cYI6pmg24/BBldMrp9IELX/tNJo+lhPpRyGAxxC0eSXinFfoASb8d+jJd
 | 
			
		||||
Bd1mmemM6fSxqRlxSP4LrzIhjhR1g2CiyYuTsiM9UtoVKGyHwe7KfFwirUOJo3Mr18zUVNm7YqY4
 | 
			
		||||
IVhOSq59zkH3ULBlYq4bG50jpxa5mNSCZ7IpafPY/kE/CbR+FWNt30+rk69T+qb5abg6+XGm+OAm
 | 
			
		||||
bnQ18yZEqX6nJLk7Ch0cfA5orGgrTMOrM71wK7tBBDQ308kOxDGebx6j0qD36QKBgQDTRDr8kuhA
 | 
			
		||||
9sUyKr9vk2DQCMpNvEeiwI3JRMqmmxpNAtg01aJ3Ya57vX5Fc+zcuV87kP6FM1xgpHQvnw5LWo2J
 | 
			
		||||
s7ANwQcP8ricEW5zkZhSjI4ssMeAubmsHOloGxmLFYZqwx0JI7CWViGTLMcUlqKblmHcjeQDeDfP
 | 
			
		||||
P1TaCItFmwKBgQCfHZwVvIcaDs5vxVpZ4ftvflIrW8qq0uOVK6QIf9A/YTGhCXl2qxxTg2A6+0rg
 | 
			
		||||
ZqI7zKzUDxIbVv0KlgCbpHDC9d5+sdtDB3wW2pimuJ3p1z4/RHb4n/lDwXCACZl1S5l24yXX2pFZ
 | 
			
		||||
wdPCXmy5PYkHMssFLNhI24pprUIQs66M1QKBgQDQwjAjWisD3pRXESSfZRsaFkWJcM28hdbVFhPF
 | 
			
		||||
c6gWhwQLmTp0CuL2RPXcPUPFi6sN2iWWi3zxxi9Eyz+9uBn6AsOpo56N5MME/LiOnETO9TKb+Ib6
 | 
			
		||||
rQtKhjshcv3XkIqFPo2XdVvOAgglPO7vajX91iiXXuH7h7RmJud6l0y/lwKBgE+bi90gLuPtpoEr
 | 
			
		||||
VzIDKz40ED5bNYHT80NNy0rpT7J2GVN9nwStRYXPBBVeZq7xCpgqpgmO5LtDAWULeZBlbHlOdBwl
 | 
			
		||||
NhNKKl5wzdEUKwW0yBL1WSS5PQgWPwgARYP25/ggW22sj+49WIo1neXsEKPGWObk8e050f1fTt92
 | 
			
		||||
Vo1lAoGAb1gCoyBCzvi7sqFxm4V5oapnJeiQQJFjhoYWqGa26rQ+AvXXNuBcigIeDXNJPctSF0Uc
 | 
			
		||||
p11KbbCgiruBbckvM1vGsk6Sx4leRk+IFHRpJktFUek4o0eUg0shOsyyvyet48Dfg0a8FvcxROs0
 | 
			
		||||
gD+IYds5doiob/hcm1hnNB/3vk4=
 | 
			
		||||
-----END PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/certs/realhostip.keystore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										46
									
								
								services/console-proxy/server/conf.dom0/agent.properties.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,46 @@
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
# Sample configuration file for VMOPS console proxy
 | 
			
		||||
 | 
			
		||||
instance=ConsoleProxy
 | 
			
		||||
consoleproxy.httpListenPort=8002
 | 
			
		||||
 | 
			
		||||
#resource= the java class, which agent load to execute
 | 
			
		||||
resource=com.cloud.agent.resource.consoleproxy.ConsoleProxyResource
 | 
			
		||||
 | 
			
		||||
#host= The IP address of management server
 | 
			
		||||
host=localhost
 | 
			
		||||
 | 
			
		||||
#port = The port management server listening on, default is 8250
 | 
			
		||||
port=8250
 | 
			
		||||
 | 
			
		||||
#pod= The pod, which agent belonged to
 | 
			
		||||
pod=default
 | 
			
		||||
 | 
			
		||||
#zone= The zone, which agent belonged to
 | 
			
		||||
zone=default
 | 
			
		||||
 | 
			
		||||
#private.network.device= the private nic device
 | 
			
		||||
# if this is commented, it is autodetected on service startup
 | 
			
		||||
# private.network.device=cloudbr0
 | 
			
		||||
 | 
			
		||||
#public.network.device= the public nic device
 | 
			
		||||
# if this is commented, it is autodetected on service startup
 | 
			
		||||
# public.network.device=cloudbr0
 | 
			
		||||
 | 
			
		||||
#guid= a GUID to identify the agent
 | 
			
		||||
@ -0,0 +1,23 @@
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
consoleproxy.tcpListenPort=0
 | 
			
		||||
consoleproxy.httpListenPort=80
 | 
			
		||||
consoleproxy.httpCmdListenPort=8001
 | 
			
		||||
consoleproxy.jarDir=./applet/
 | 
			
		||||
consoleproxy.viewerLinger=180
 | 
			
		||||
consoleproxy.reconnectMaxRetry=5
 | 
			
		||||
							
								
								
									
										101
									
								
								services/console-proxy/server/conf.dom0/log4j-cloud.xml.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,101 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<!--
 | 
			
		||||
Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
distributed with this work for additional information
 | 
			
		||||
regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
to you under the Apache License, Version 2.0 (the
 | 
			
		||||
"License"); you may not use this file except in compliance
 | 
			
		||||
with the License.  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing,
 | 
			
		||||
software distributed under the License is distributed on an
 | 
			
		||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
KIND, either express or implied.  See the License for the
 | 
			
		||||
specific language governing permissions and limitations
 | 
			
		||||
under the License.
 | 
			
		||||
-->
 | 
			
		||||
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
 | 
			
		||||
 | 
			
		||||
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
 | 
			
		||||
 | 
			
		||||
   <!-- ================================= -->
 | 
			
		||||
   <!-- Preserve messages in a local file -->
 | 
			
		||||
   <!-- ================================= -->
 | 
			
		||||
 | 
			
		||||
   <!-- A time/date based rolling appender -->
 | 
			
		||||
   <appender name="FILE" class="org.apache.log4j.rolling.RollingFileAppender">
 | 
			
		||||
      <param name="Append" value="true"/>
 | 
			
		||||
      <param name="Threshold" value="WARN"/>
 | 
			
		||||
      <rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
 | 
			
		||||
        <param name="FileNamePattern" value="@CPLOG@.%d{yyyy-MM-dd}.gz"/>
 | 
			
		||||
        <param name="ActiveFileName" value="@CPLOG@"/>
 | 
			
		||||
      </rollingPolicy>
 | 
			
		||||
      <layout class="org.apache.log4j.EnhancedPatternLayout">
 | 
			
		||||
         <param name="ConversionPattern" value="%d{ISO8601} %-5p [%c{3}] (%t:%x) %m%n"/>
 | 
			
		||||
      </layout>
 | 
			
		||||
   </appender>
 | 
			
		||||
   
 | 
			
		||||
   <!-- ============================== -->
 | 
			
		||||
   <!-- Append messages to the console -->
 | 
			
		||||
   <!-- ============================== -->
 | 
			
		||||
 | 
			
		||||
   <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
 | 
			
		||||
      <param name="Target" value="System.out"/>
 | 
			
		||||
      <param name="Threshold" value="WARN"/>
 | 
			
		||||
 | 
			
		||||
      <layout class="org.apache.log4j.PatternLayout">
 | 
			
		||||
         <param name="ConversionPattern" value="%d{ABSOLUTE} %5p %c{1}:%L - %m%n"/>
 | 
			
		||||
      </layout>
 | 
			
		||||
   </appender>
 | 
			
		||||
 | 
			
		||||
   <!-- ================ -->
 | 
			
		||||
   <!-- Limit categories -->
 | 
			
		||||
   <!-- ================ -->
 | 
			
		||||
 | 
			
		||||
   <category name="com.cloud.console.ConsoleCanvas">
 | 
			
		||||
     <priority value="WARN"/>
 | 
			
		||||
   </category>
 | 
			
		||||
   
 | 
			
		||||
   <category name="com.cloud.consoleproxy.ConsoleProxyAjaxImageHandler">
 | 
			
		||||
     <priority value="WARN"/>
 | 
			
		||||
   </category>
 | 
			
		||||
   
 | 
			
		||||
   <category name="com.cloud.consoleproxy.ConsoleProxyViwer">
 | 
			
		||||
     <priority value="WARN"/>
 | 
			
		||||
   </category>
 | 
			
		||||
 | 
			
		||||
   <category name="com.cloud.consoleproxy">
 | 
			
		||||
     <priority value="INFO"/>
 | 
			
		||||
   </category>
 | 
			
		||||
 | 
			
		||||
   <category name="com.cloud">
 | 
			
		||||
     <priority value="DEBUG"/>
 | 
			
		||||
   </category>
 | 
			
		||||
   
 | 
			
		||||
   <!-- Limit the org.apache category to INFO as its DEBUG is verbose -->
 | 
			
		||||
   <category name="org.apache">
 | 
			
		||||
      <priority value="INFO"/>
 | 
			
		||||
   </category>
 | 
			
		||||
 | 
			
		||||
   <category name="org">
 | 
			
		||||
      <priority value="INFO"/>
 | 
			
		||||
   </category>
 | 
			
		||||
   
 | 
			
		||||
   <category name="net">
 | 
			
		||||
     <priority value="INFO"/>
 | 
			
		||||
   </category>
 | 
			
		||||
 | 
			
		||||
   <!-- ======================= -->
 | 
			
		||||
   <!-- Setup the Root category -->
 | 
			
		||||
   <!-- ======================= -->
 | 
			
		||||
 | 
			
		||||
   <root>
 | 
			
		||||
      <level value="INFO"/>
 | 
			
		||||
      <appender-ref ref="CONSOLE"/>
 | 
			
		||||
      <appender-ref ref="FILE"/>
 | 
			
		||||
   </root>
 | 
			
		||||
 | 
			
		||||
</log4j:configuration>
 | 
			
		||||
							
								
								
									
										19
									
								
								services/console-proxy/server/conf/agent.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,19 @@
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
instance=ConsoleProxy
 | 
			
		||||
resource=com.cloud.agent.resource.consoleproxy.ConsoleProxyResource
 | 
			
		||||
							
								
								
									
										23
									
								
								services/console-proxy/server/conf/consoleproxy.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,23 @@
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
consoleproxy.tcpListenPort=0
 | 
			
		||||
consoleproxy.httpListenPort=8088
 | 
			
		||||
consoleproxy.httpCmdListenPort=8001
 | 
			
		||||
consoleproxy.jarDir=./applet/
 | 
			
		||||
consoleproxy.viewerLinger=180
 | 
			
		||||
consoleproxy.reconnectMaxRetry=5
 | 
			
		||||
							
								
								
									
										102
									
								
								services/console-proxy/server/conf/log4j-cloud.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,102 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<!--
 | 
			
		||||
Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
distributed with this work for additional information
 | 
			
		||||
regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
to you under the Apache License, Version 2.0 (the
 | 
			
		||||
"License"); you may not use this file except in compliance
 | 
			
		||||
with the License.  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing,
 | 
			
		||||
software distributed under the License is distributed on an
 | 
			
		||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
KIND, either express or implied.  See the License for the
 | 
			
		||||
specific language governing permissions and limitations
 | 
			
		||||
under the License.
 | 
			
		||||
-->
 | 
			
		||||
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
 | 
			
		||||
 | 
			
		||||
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
 | 
			
		||||
 | 
			
		||||
   <!-- ================================= -->
 | 
			
		||||
   <!-- Preserve messages in a local file -->
 | 
			
		||||
   <!-- ================================= -->
 | 
			
		||||
 | 
			
		||||
   <!-- A time/date based rolling appender -->
 | 
			
		||||
   <appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
 | 
			
		||||
      <param name="File" value="/var/log/cloud/systemvm.log"/>
 | 
			
		||||
      <param name="Append" value="true"/>
 | 
			
		||||
      <param name="Threshold" value="DEBUG"/>
 | 
			
		||||
 | 
			
		||||
      <!-- Rollover at midnight each day -->
 | 
			
		||||
      <param name="DatePattern" value="'.'yyyy-MM-dd"/>
 | 
			
		||||
 | 
			
		||||
      <layout class="org.apache.log4j.PatternLayout">
 | 
			
		||||
         <param name="ConversionPattern" value="%d %-5p [%c{3}] (%t:%x) %m%n"/>
 | 
			
		||||
      </layout>
 | 
			
		||||
   </appender>
 | 
			
		||||
   
 | 
			
		||||
   <!-- ============================== -->
 | 
			
		||||
   <!-- Append messages to the console -->
 | 
			
		||||
   <!-- ============================== -->
 | 
			
		||||
 | 
			
		||||
   <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
 | 
			
		||||
      <param name="Target" value="System.out"/>
 | 
			
		||||
      <param name="Threshold" value="WARN"/>
 | 
			
		||||
 | 
			
		||||
      <layout class="org.apache.log4j.PatternLayout">
 | 
			
		||||
         <param name="ConversionPattern" value="%d{ABSOLUTE} %5p %c{1}:%L - %m%n"/>
 | 
			
		||||
      </layout>
 | 
			
		||||
   </appender>
 | 
			
		||||
 | 
			
		||||
   <!-- ================ -->
 | 
			
		||||
   <!-- Limit categories -->
 | 
			
		||||
   <!-- ================ -->
 | 
			
		||||
 | 
			
		||||
   <category name="com.cloud.console.ConsoleCanvas">
 | 
			
		||||
     <priority value="WARN"/>
 | 
			
		||||
   </category>
 | 
			
		||||
   
 | 
			
		||||
   <category name="com.cloud.consoleproxy.ConsoleProxyAjaxImageHandler">
 | 
			
		||||
     <priority value="WARN"/>
 | 
			
		||||
   </category>
 | 
			
		||||
   
 | 
			
		||||
   <category name="com.cloud.consoleproxy.ConsoleProxyViewer">
 | 
			
		||||
     <priority value="WARN"/>
 | 
			
		||||
   </category>
 | 
			
		||||
 | 
			
		||||
   <category name="com.cloud.consoleproxy">
 | 
			
		||||
     <priority value="INFO"/>
 | 
			
		||||
   </category>
 | 
			
		||||
 | 
			
		||||
   <category name="com.cloud">
 | 
			
		||||
     <priority value="DEBUG"/>
 | 
			
		||||
   </category>
 | 
			
		||||
   
 | 
			
		||||
   <!-- Limit the org.apache category to INFO as its DEBUG is verbose -->
 | 
			
		||||
   <category name="org.apache">
 | 
			
		||||
      <priority value="INFO"/>
 | 
			
		||||
   </category>
 | 
			
		||||
 | 
			
		||||
   <category name="org">
 | 
			
		||||
      <priority value="INFO"/>
 | 
			
		||||
   </category>
 | 
			
		||||
   
 | 
			
		||||
   <category name="net">
 | 
			
		||||
     <priority value="INFO"/>
 | 
			
		||||
   </category>
 | 
			
		||||
 | 
			
		||||
   <!-- ======================= -->
 | 
			
		||||
   <!-- Setup the Root category -->
 | 
			
		||||
   <!-- ======================= -->
 | 
			
		||||
 | 
			
		||||
   <root>
 | 
			
		||||
      <level value="INFO"/>
 | 
			
		||||
      <appender-ref ref="CONSOLE"/>
 | 
			
		||||
      <appender-ref ref="FILE"/>
 | 
			
		||||
   </root>
 | 
			
		||||
 | 
			
		||||
</log4j:configuration>
 | 
			
		||||
							
								
								
									
										144
									
								
								services/console-proxy/server/css/ajaxviewer.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,144 @@
 | 
			
		||||
/*
 | 
			
		||||
Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
distributed with this work for additional information
 | 
			
		||||
regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
to you under the Apache License, Version 2.0 (the
 | 
			
		||||
"License"); you may not use this file except in compliance
 | 
			
		||||
with the License.  You may obtain a copy of the License at
 | 
			
		||||
 
 | 
			
		||||
  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 
 | 
			
		||||
Unless required by applicable law or agreed to in writing,
 | 
			
		||||
software distributed under the License is distributed on an
 | 
			
		||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
KIND, either express or implied.  See the License for the
 | 
			
		||||
specific language governing permissions and limitations
 | 
			
		||||
under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
	margin:0 0;
 | 
			
		||||
	text-align: center;
 | 
			
		||||
}
 | 
			
		||||
	
 | 
			
		||||
#main_panel {
 | 
			
		||||
	clear:both;
 | 
			
		||||
	margin: 0 auto;
 | 
			
		||||
	text-align: left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.canvas_tile {
 | 
			
		||||
	cursor:crosshair;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#toolbar {
 | 
			
		||||
	font:normal 12px 'Trebuchet MS','Arial'; 
 | 
			
		||||
	margin:0 auto; 
 | 
			
		||||
	text-align: left;
 | 
			
		||||
	padding:0 0; 
 | 
			
		||||
	height:32px;
 | 
			
		||||
	background-image:url(/resource/images/back.gif); 
 | 
			
		||||
	background-repeat:repeat-x; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#toolbar ul { 
 | 
			
		||||
	margin:0 0; 
 | 
			
		||||
	padding:0 10px 0 10px; 
 | 
			
		||||
	float:left;
 | 
			
		||||
	display:block;
 | 
			
		||||
	line-height:32px;
 | 
			
		||||
	list-style:none; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#toolbar li {
 | 
			
		||||
	float:left; 
 | 
			
		||||
	display:inline; 
 | 
			
		||||
	padding:0;
 | 
			
		||||
	height:32px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#toolbar a { 
 | 
			
		||||
	color:white; 
 | 
			
		||||
	float:left;
 | 
			
		||||
	display:block;
 | 
			
		||||
	padding:0 3px 0 3px; 
 | 
			
		||||
	text-decoration:none;
 | 
			
		||||
	line-height:32px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#toolbar a span { 
 | 
			
		||||
	display:block; 
 | 
			
		||||
	float:none; 
 | 
			
		||||
	padding:0 10px 0 7px; 
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
#toolbar a span img { 
 | 
			
		||||
	border:none; 
 | 
			
		||||
	margin:8px 4px 0 0; 
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
#toolbar a:hover { 
 | 
			
		||||
	background: url(/resource/images/left.png) no-repeat left center; 
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
#toolbar a:hover span { 
 | 
			
		||||
	background:url(/resource/images/right.png) no-repeat right center; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#toolbar ul li ul {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top:32;
 | 
			
		||||
    width: 260;
 | 
			
		||||
    height: 65;
 | 
			
		||||
    display: block;
 | 
			
		||||
    display: none;
 | 
			
		||||
    border-top: 1px solid black;
 | 
			
		||||
    background-image:url(/resource/images/back.gif); 
 | 
			
		||||
    background-repeat:repeat-x repeat-y; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#toolbar ul li ul li {
 | 
			
		||||
    display: list-item;
 | 
			
		||||
    float:none;
 | 
			
		||||
    padding-left: 20;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#toolbar ul li ul li.current {
 | 
			
		||||
    background: url(/resource/images/cad.gif) no-repeat left center; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#toolbar ul li ul li a {
 | 
			
		||||
    display:block;
 | 
			
		||||
    padding:0 3px 0 3px; 
 | 
			
		||||
    text-decoration:none;
 | 
			
		||||
    line-height:32px;
 | 
			
		||||
    vertical-align: bottom;    /* this is to fix the list gap in IE */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#toolbar ul li ul li a:hover {
 | 
			
		||||
    background: url(/resource/images/left.png) no-repeat left center; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#toolbar ul li ul li a:hover span {
 | 
			
		||||
    background: url(/resource/images/right2.png) no-repeat right center; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
span.dark {
 | 
			
		||||
	margin-right:20px;
 | 
			
		||||
	float:right;
 | 
			
		||||
	display:block;
 | 
			
		||||
	width:32px;
 | 
			
		||||
	height:30px;
 | 
			
		||||
	background:url(/resource/images/gray-green.png) no-repeat center center; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
span.bright {
 | 
			
		||||
	margin-right:20px;
 | 
			
		||||
	float:right;
 | 
			
		||||
	display:block;
 | 
			
		||||
	width:32px;
 | 
			
		||||
	height:30px;
 | 
			
		||||
	background:url(/resource/images/bright-green.png) no-repeat center center; 
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										139
									
								
								services/console-proxy/server/css/logger.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,139 @@
 | 
			
		||||
/*
 | 
			
		||||
Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
distributed with this work for additional information
 | 
			
		||||
regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
to you under the Apache License, Version 2.0 (the
 | 
			
		||||
"License"); you may not use this file except in compliance
 | 
			
		||||
with the License.  You may obtain a copy of the License at
 | 
			
		||||
 
 | 
			
		||||
  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 
 | 
			
		||||
Unless required by applicable law or agreed to in writing,
 | 
			
		||||
software distributed under the License is distributed on an
 | 
			
		||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
KIND, either express or implied.  See the License for the
 | 
			
		||||
specific language governing permissions and limitations
 | 
			
		||||
under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
@charset "UTF-8";
 | 
			
		||||
.logwin {
 | 
			
		||||
      position: absolute;
 | 
			
		||||
 | 
			
		||||
      z-index:2147483648;
 | 
			
		||||
      width: 800px;
 | 
			
		||||
      border: 1px solid gray;
 | 
			
		||||
      background: white;
 | 
			
		||||
      text-align: left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.logwin_title{
 | 
			
		||||
	width:auto;
 | 
			
		||||
	  height: 23px;
 | 
			
		||||
	  background:url(../images/grid_headerbg.gif) repeat-x top left;
 | 
			
		||||
	  border: 1px sold #737373;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.logwin_title_actionbox{
 | 
			
		||||
	width:175px;
 | 
			
		||||
	height:16px;
 | 
			
		||||
	float:left;
 | 
			
		||||
	margin:4px 0 0 7px;
 | 
			
		||||
	display:inline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.logwin_title_actionbox .select {
 | 
			
		||||
	background: #424242; 
 | 
			
		||||
	font: normal 10px Arial, Helvetica, sans-serif; 
 | 
			
		||||
	float:left; 
 | 
			
		||||
	border: 1px solid #6e6e6e; 
 | 
			
		||||
	height: 16px; 
 | 
			
		||||
	width: 100px; 
 | 
			
		||||
	margin-left:3px; 
 | 
			
		||||
	padding:0 0 0 3px; 
 | 
			
		||||
	color:#CCC;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.logwin_title_rgtactionbox{
 | 
			
		||||
	width:49px;
 | 
			
		||||
	height:15px;
 | 
			
		||||
	float:right;
 | 
			
		||||
	margin:4px 0 0 7px;
 | 
			
		||||
	display:inline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
a.logwin_playbutton {
 | 
			
		||||
	width:18px;
 | 
			
		||||
	height:15px;
 | 
			
		||||
	float:left;
 | 
			
		||||
	background:url(../images/play_button.gif) no-repeat top left;
 | 
			
		||||
	margin-right:2px;
 | 
			
		||||
	padding:0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a:hover.logwin_playbutton {
 | 
			
		||||
	background:url(../images/play_button_hover.gif) no-repeat top left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a.logwin_stopbutton {
 | 
			
		||||
	width:18px;
 | 
			
		||||
	height:15px;
 | 
			
		||||
	float:left;
 | 
			
		||||
	background:url(../images/stop_button.gif) no-repeat top left;
 | 
			
		||||
	margin-right:2px;
 | 
			
		||||
	padding:0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a:hover.logwin_stopbutton {
 | 
			
		||||
	background:url(../images/stop_button_hover.gif) no-repeat top left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a.logwin_clrbutton {
 | 
			
		||||
	width:28px;
 | 
			
		||||
	height:15px;
 | 
			
		||||
	float:left;
 | 
			
		||||
	background:url(../images/clr_button.gif) no-repeat top left;
 | 
			
		||||
	margin:0;
 | 
			
		||||
	padding:0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a:hover.logwin_clrbutton {
 | 
			
		||||
	background:url(../images/clr_button_hover.gif) no-repeat top left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a.logwin_shrinkbutton {
 | 
			
		||||
	width:18px;
 | 
			
		||||
	height:15px;
 | 
			
		||||
	float:right;
 | 
			
		||||
	background:url(../images/shrink_button.gif) no-repeat top left;
 | 
			
		||||
	margin-right:7px;
 | 
			
		||||
	margin-top:4px;
 | 
			
		||||
	padding:0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a:hover.logwin_shrinkbutton {
 | 
			
		||||
	background:url(../images/shrink_button_hover.gif) no-repeat top left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a.logwin_minimizebutton {
 | 
			
		||||
	width:18px;
 | 
			
		||||
	height:15px;
 | 
			
		||||
	float:left;
 | 
			
		||||
	background:url(../images/minimize_button.gif) no-repeat top left;
 | 
			
		||||
	margin-right:2px;
 | 
			
		||||
	padding:0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a:hover.logwin_minimizebutton {
 | 
			
		||||
	background:url(../images/minimize_button_hover.gif) no-repeat top left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.logwin_content {
 | 
			
		||||
    overflow:scroll;
 | 
			
		||||
    height: 477px;
 | 
			
		||||
    background: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,98 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# chkconfig: 35 99 10
 | 
			
		||||
# description: Cloud Console Proxy
 | 
			
		||||
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
# WARNING: if this script is changed, then all other initscripts MUST BE changed to match it as well
 | 
			
		||||
 | 
			
		||||
. /etc/rc.d/init.d/functions
 | 
			
		||||
 | 
			
		||||
whatami=cloud-console-proxy
 | 
			
		||||
 | 
			
		||||
# set environment variables
 | 
			
		||||
 | 
			
		||||
SHORTNAME="$whatami"
 | 
			
		||||
PIDFILE=@PIDDIR@/"$whatami".pid
 | 
			
		||||
LOCKFILE=@LOCKDIR@/"$SHORTNAME"
 | 
			
		||||
LOGFILE=@CPLOG@
 | 
			
		||||
PROGNAME="Cloud Console Proxy"
 | 
			
		||||
 | 
			
		||||
unset OPTIONS
 | 
			
		||||
[ -r @SYSCONFDIR@/sysconfig/"$SHORTNAME" ] && source @SYSCONFDIR@/sysconfig/"$SHORTNAME"
 | 
			
		||||
DAEMONIZE=@BINDIR@/@PACKAGE@-daemonize
 | 
			
		||||
PROG=@LIBEXECDIR@/console-proxy-runner
 | 
			
		||||
 | 
			
		||||
start() {
 | 
			
		||||
        echo -n $"Starting $PROGNAME: "
 | 
			
		||||
	if hostname --fqdn >/dev/null 2>&1 ; then
 | 
			
		||||
		daemon --check=$SHORTNAME --pidfile=${PIDFILE} "$DAEMONIZE" \
 | 
			
		||||
			-n "$SHORTNAME" -p "$PIDFILE" -l "$LOGFILE" "$PROG" $OPTIONS
 | 
			
		||||
		RETVAL=$?
 | 
			
		||||
		echo
 | 
			
		||||
	else
 | 
			
		||||
		failure
 | 
			
		||||
		echo
 | 
			
		||||
		echo The host name does not resolve properly to an IP address.  Cannot start "$PROGNAME". > /dev/stderr
 | 
			
		||||
		RETVAL=9
 | 
			
		||||
	fi
 | 
			
		||||
	[ $RETVAL = 0 ] && touch ${LOCKFILE}
 | 
			
		||||
	return $RETVAL
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
stop() {
 | 
			
		||||
	echo -n $"Stopping $PROGNAME: "
 | 
			
		||||
	killproc -p ${PIDFILE} $SHORTNAME # -d 10 $SHORTNAME
 | 
			
		||||
	RETVAL=$?
 | 
			
		||||
	echo
 | 
			
		||||
	[ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# See how we were called.
 | 
			
		||||
case "$1" in
 | 
			
		||||
  start)
 | 
			
		||||
	start
 | 
			
		||||
	;;
 | 
			
		||||
  stop)
 | 
			
		||||
	stop
 | 
			
		||||
	;;
 | 
			
		||||
  status)
 | 
			
		||||
        status -p ${PIDFILE} $SHORTNAME
 | 
			
		||||
	RETVAL=$?
 | 
			
		||||
	;;
 | 
			
		||||
  restart)
 | 
			
		||||
	stop
 | 
			
		||||
	sleep 3
 | 
			
		||||
	start
 | 
			
		||||
	;;
 | 
			
		||||
  condrestart)
 | 
			
		||||
	if status -p ${PIDFILE} $SHORTNAME >&/dev/null; then
 | 
			
		||||
		stop
 | 
			
		||||
		sleep 3
 | 
			
		||||
		start
 | 
			
		||||
	fi
 | 
			
		||||
	;;
 | 
			
		||||
  *)
 | 
			
		||||
	echo $"Usage: $whatami {start|stop|restart|condrestart|status|help}"
 | 
			
		||||
	RETVAL=3
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
exit $RETVAL
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,98 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# chkconfig: 35 99 10
 | 
			
		||||
# description: Cloud Console Proxy
 | 
			
		||||
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
# WARNING: if this script is changed, then all other initscripts MUST BE changed to match it as well
 | 
			
		||||
 | 
			
		||||
. /etc/rc.d/init.d/functions
 | 
			
		||||
 | 
			
		||||
whatami=cloud-console-proxy
 | 
			
		||||
 | 
			
		||||
# set environment variables
 | 
			
		||||
 | 
			
		||||
SHORTNAME="$whatami"
 | 
			
		||||
PIDFILE=@PIDDIR@/"$whatami".pid
 | 
			
		||||
LOCKFILE=@LOCKDIR@/"$SHORTNAME"
 | 
			
		||||
LOGFILE=@CPLOG@
 | 
			
		||||
PROGNAME="Cloud Console Proxy"
 | 
			
		||||
 | 
			
		||||
unset OPTIONS
 | 
			
		||||
[ -r @SYSCONFDIR@/sysconfig/"$SHORTNAME" ] && source @SYSCONFDIR@/sysconfig/"$SHORTNAME"
 | 
			
		||||
DAEMONIZE=@BINDIR@/@PACKAGE@-daemonize
 | 
			
		||||
PROG=@LIBEXECDIR@/console-proxy-runner
 | 
			
		||||
 | 
			
		||||
start() {
 | 
			
		||||
        echo -n $"Starting $PROGNAME: "
 | 
			
		||||
	if hostname --fqdn >/dev/null 2>&1 ; then
 | 
			
		||||
		daemon --check=$SHORTNAME --pidfile=${PIDFILE} "$DAEMONIZE" \
 | 
			
		||||
			-n "$SHORTNAME" -p "$PIDFILE" -l "$LOGFILE" "$PROG" $OPTIONS
 | 
			
		||||
		RETVAL=$?
 | 
			
		||||
		echo
 | 
			
		||||
	else
 | 
			
		||||
		failure
 | 
			
		||||
		echo
 | 
			
		||||
		echo The host name does not resolve properly to an IP address.  Cannot start "$PROGNAME". > /dev/stderr
 | 
			
		||||
		RETVAL=9
 | 
			
		||||
	fi
 | 
			
		||||
	[ $RETVAL = 0 ] && touch ${LOCKFILE}
 | 
			
		||||
	return $RETVAL
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
stop() {
 | 
			
		||||
	echo -n $"Stopping $PROGNAME: "
 | 
			
		||||
	killproc -p ${PIDFILE} $SHORTNAME # -d 10 $SHORTNAME
 | 
			
		||||
	RETVAL=$?
 | 
			
		||||
	echo
 | 
			
		||||
	[ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# See how we were called.
 | 
			
		||||
case "$1" in
 | 
			
		||||
  start)
 | 
			
		||||
	start
 | 
			
		||||
	;;
 | 
			
		||||
  stop)
 | 
			
		||||
	stop
 | 
			
		||||
	;;
 | 
			
		||||
  status)
 | 
			
		||||
        status -p ${PIDFILE} $SHORTNAME
 | 
			
		||||
	RETVAL=$?
 | 
			
		||||
	;;
 | 
			
		||||
  restart)
 | 
			
		||||
	stop
 | 
			
		||||
	sleep 3
 | 
			
		||||
	start
 | 
			
		||||
	;;
 | 
			
		||||
  condrestart)
 | 
			
		||||
	if status -p ${PIDFILE} $SHORTNAME >&/dev/null; then
 | 
			
		||||
		stop
 | 
			
		||||
		sleep 3
 | 
			
		||||
		start
 | 
			
		||||
	fi
 | 
			
		||||
	;;
 | 
			
		||||
  *)
 | 
			
		||||
	echo $"Usage: $whatami {start|stop|restart|condrestart|status|help}"
 | 
			
		||||
	RETVAL=3
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
exit $RETVAL
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,98 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# chkconfig: 35 99 10
 | 
			
		||||
# description: Cloud Console Proxy
 | 
			
		||||
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
# WARNING: if this script is changed, then all other initscripts MUST BE changed to match it as well
 | 
			
		||||
 | 
			
		||||
. /etc/rc.d/init.d/functions
 | 
			
		||||
 | 
			
		||||
whatami=cloud-console-proxy
 | 
			
		||||
 | 
			
		||||
# set environment variables
 | 
			
		||||
 | 
			
		||||
SHORTNAME="$whatami"
 | 
			
		||||
PIDFILE=@PIDDIR@/"$whatami".pid
 | 
			
		||||
LOCKFILE=@LOCKDIR@/"$SHORTNAME"
 | 
			
		||||
LOGFILE=@CPLOG@
 | 
			
		||||
PROGNAME="Cloud Console Proxy"
 | 
			
		||||
 | 
			
		||||
unset OPTIONS
 | 
			
		||||
[ -r @SYSCONFDIR@/sysconfig/"$SHORTNAME" ] && source @SYSCONFDIR@/sysconfig/"$SHORTNAME"
 | 
			
		||||
DAEMONIZE=@BINDIR@/@PACKAGE@-daemonize
 | 
			
		||||
PROG=@LIBEXECDIR@/console-proxy-runner
 | 
			
		||||
 | 
			
		||||
start() {
 | 
			
		||||
        echo -n $"Starting $PROGNAME: "
 | 
			
		||||
	if hostname --fqdn >/dev/null 2>&1 ; then
 | 
			
		||||
		daemon --check=$SHORTNAME --pidfile=${PIDFILE} "$DAEMONIZE" \
 | 
			
		||||
			-n "$SHORTNAME" -p "$PIDFILE" -l "$LOGFILE" "$PROG" $OPTIONS
 | 
			
		||||
		RETVAL=$?
 | 
			
		||||
		echo
 | 
			
		||||
	else
 | 
			
		||||
		failure
 | 
			
		||||
		echo
 | 
			
		||||
		echo The host name does not resolve properly to an IP address.  Cannot start "$PROGNAME". > /dev/stderr
 | 
			
		||||
		RETVAL=9
 | 
			
		||||
	fi
 | 
			
		||||
	[ $RETVAL = 0 ] && touch ${LOCKFILE}
 | 
			
		||||
	return $RETVAL
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
stop() {
 | 
			
		||||
	echo -n $"Stopping $PROGNAME: "
 | 
			
		||||
	killproc -p ${PIDFILE} $SHORTNAME # -d 10 $SHORTNAME
 | 
			
		||||
	RETVAL=$?
 | 
			
		||||
	echo
 | 
			
		||||
	[ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# See how we were called.
 | 
			
		||||
case "$1" in
 | 
			
		||||
  start)
 | 
			
		||||
	start
 | 
			
		||||
	;;
 | 
			
		||||
  stop)
 | 
			
		||||
	stop
 | 
			
		||||
	;;
 | 
			
		||||
  status)
 | 
			
		||||
        status -p ${PIDFILE} $SHORTNAME
 | 
			
		||||
	RETVAL=$?
 | 
			
		||||
	;;
 | 
			
		||||
  restart)
 | 
			
		||||
	stop
 | 
			
		||||
	sleep 3
 | 
			
		||||
	start
 | 
			
		||||
	;;
 | 
			
		||||
  condrestart)
 | 
			
		||||
	if status -p ${PIDFILE} $SHORTNAME >&/dev/null; then
 | 
			
		||||
		stop
 | 
			
		||||
		sleep 3
 | 
			
		||||
		start
 | 
			
		||||
	fi
 | 
			
		||||
	;;
 | 
			
		||||
  *)
 | 
			
		||||
	echo $"Usage: $whatami {start|stop|restart|condrestart|status|help}"
 | 
			
		||||
	RETVAL=3
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
exit $RETVAL
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,112 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# chkconfig: 35 99 10
 | 
			
		||||
# description: Cloud Console Proxy
 | 
			
		||||
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
# WARNING: if this script is changed, then all other initscripts MUST BE changed to match it as well
 | 
			
		||||
 | 
			
		||||
. /lib/lsb/init-functions
 | 
			
		||||
. /etc/default/rcS
 | 
			
		||||
 | 
			
		||||
whatami=cloud-console-proxy
 | 
			
		||||
 | 
			
		||||
# set environment variables
 | 
			
		||||
 | 
			
		||||
SHORTNAME="$whatami"
 | 
			
		||||
PIDFILE=@PIDDIR@/"$whatami".pid
 | 
			
		||||
LOCKFILE=@LOCKDIR@/"$SHORTNAME"
 | 
			
		||||
LOGFILE=@CPLOG@
 | 
			
		||||
PROGNAME="Cloud Console Proxy"
 | 
			
		||||
 | 
			
		||||
unset OPTIONS
 | 
			
		||||
[ -r @SYSCONFDIR@/default/"$SHORTNAME" ] && source @SYSCONFDIR@/default/"$SHORTNAME"
 | 
			
		||||
DAEMONIZE=@BINDIR@/@PACKAGE@-daemonize
 | 
			
		||||
PROG=@LIBEXECDIR@/console-proxy-runner
 | 
			
		||||
 | 
			
		||||
start() {
 | 
			
		||||
        log_daemon_msg $"Starting $PROGNAME" "$SHORTNAME"
 | 
			
		||||
	if [ -s "$PIDFILE" ] && kill -0 $(cat "$PIDFILE") >/dev/null 2>&1; then
 | 
			
		||||
	      log_progress_msg "apparently already running"
 | 
			
		||||
	      log_end_msg 0
 | 
			
		||||
	      exit 0
 | 
			
		||||
	fi
 | 
			
		||||
	if hostname --fqdn >/dev/null 2>&1 ; then
 | 
			
		||||
		true
 | 
			
		||||
	else
 | 
			
		||||
		log_failure_msg "The host name does not resolve properly to an IP address.  Cannot start $PROGNAME"
 | 
			
		||||
		log_end_msg 1
 | 
			
		||||
		exit 1
 | 
			
		||||
	fi
 | 
			
		||||
 
 | 
			
		||||
	if start-stop-daemon --start --quiet \
 | 
			
		||||
		--pidfile "$PIDFILE" \
 | 
			
		||||
		--exec "$DAEMONIZE" -- -n "$SHORTNAME" -p "$PIDFILE" -l "$LOGFILE" "$PROG" $OPTIONS
 | 
			
		||||
		RETVAL=$?
 | 
			
		||||
	    then
 | 
			
		||||
		rc=0
 | 
			
		||||
		sleep 1
 | 
			
		||||
		if ! kill -0 $(cat "$PIDFILE") >/dev/null 2>&1; then
 | 
			
		||||
		    log_failure_msg "$PROG failed to start"
 | 
			
		||||
		    rc=1
 | 
			
		||||
		fi
 | 
			
		||||
	else
 | 
			
		||||
		rc=1
 | 
			
		||||
	fi
 | 
			
		||||
 | 
			
		||||
	if [ $rc -eq 0 ]; then
 | 
			
		||||
		log_end_msg 0
 | 
			
		||||
	else
 | 
			
		||||
		log_end_msg 1
 | 
			
		||||
		rm -f "$PIDFILE"
 | 
			
		||||
	fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
stop() {
 | 
			
		||||
	echo -n $"Stopping $PROGNAME" "$SHORTNAME"
 | 
			
		||||
	start-stop-daemon --stop --quiet --oknodo --pidfile "$PIDFILE"
 | 
			
		||||
	log_end_msg $?
 | 
			
		||||
	rm -f "$PIDFILE"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# See how we were called.
 | 
			
		||||
case "$1" in
 | 
			
		||||
  start)
 | 
			
		||||
	start
 | 
			
		||||
	;;
 | 
			
		||||
  stop)
 | 
			
		||||
	stop
 | 
			
		||||
	;;
 | 
			
		||||
  status)
 | 
			
		||||
        status_of_proc -p "$PIDFILE" "$PROG" "$SHORTNAME"
 | 
			
		||||
	RETVAL=$?
 | 
			
		||||
	;;
 | 
			
		||||
  restart)
 | 
			
		||||
	stop
 | 
			
		||||
	sleep 3
 | 
			
		||||
	start
 | 
			
		||||
	;;
 | 
			
		||||
  *)
 | 
			
		||||
	echo $"Usage: $whatami {start|stop|restart|status|help}"
 | 
			
		||||
	RETVAL=3
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
exit $RETVAL
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/back.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 149 B  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/bright-green.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.8 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/cad.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 918 B  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/cannotconnect.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.8 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/clr_button.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/clr_button_hover.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 437 B  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/dot.cur
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 326 B  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/gray-green.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.7 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/grid_headerbg.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 196 B  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/left.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.0 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/minimize_button.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 634 B  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/minimize_button_hover.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 227 B  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/notready.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.8 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/play_button.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 657 B  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/play_button_hover.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 243 B  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/right.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/right2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/shrink_button.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 655 B  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/shrink_button_hover.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 243 B  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/stop_button.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 649 B  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/stop_button_hover.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 231 B  | 
							
								
								
									
										
											BIN
										
									
								
								services/console-proxy/server/images/winlog.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.6 KiB  | 
							
								
								
									
										77
									
								
								services/console-proxy/server/js/ajaxkeys.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,77 @@
 | 
			
		||||
/*
 | 
			
		||||
Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
distributed with this work for additional information
 | 
			
		||||
regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
to you under the Apache License, Version 2.0 (the
 | 
			
		||||
"License"); you may not use this file except in compliance
 | 
			
		||||
with the License.  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing,
 | 
			
		||||
software distributed under the License is distributed on an
 | 
			
		||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
KIND, either express or implied.  See the License for the
 | 
			
		||||
specific language governing permissions and limitations
 | 
			
		||||
under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This var contains the limited keyboard translation tables.
 | 
			
		||||
 * This is the table that users can modify to make special keyboard to work properly.
 | 
			
		||||
 * They are used by the ajaxviewer.js
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
//client event type. corresponds to events in ajaxviewer. 
 | 
			
		||||
X11_KEY_CIRCUMFLEX_ACCENT = 0x5e;    // ^
 | 
			
		||||
X11_KEY_YEN_MARK = 0xa5;
 | 
			
		||||
X11_KEY_OPEN_BRACKET = 0x5b;
 | 
			
		||||
X11_KEY_CLOSE_BRACKET = 0x5d;
 | 
			
		||||
X11_KEY_COLON = 0x3a;
 | 
			
		||||
X11_KEY_REVERSE_SOLIUS = 0x5c;       // another back slash (back slash on JP keyboard)
 | 
			
		||||
X11_KEY_CAPSLOCK = 0xffe5;
 | 
			
		||||
X11_KEY_SEMI_COLON = 0x3b;
 | 
			
		||||
X11_KEY_SHIFT = 0xffe1;
 | 
			
		||||
X11_KEY_ADD = 0x2b;
 | 
			
		||||
 | 
			
		||||
KEY_DOWN = 5;
 | 
			
		||||
KEY_UP = 6;
 | 
			
		||||
 | 
			
		||||
//JP keyboard type
 | 
			
		||||
// 
 | 
			
		||||
var	keyboardTables = [
 | 
			
		||||
           {tindex: 0, keyboardType: "EN-Cooked", mappingTable: 
 | 
			
		||||
		{X11: [ {keycode: 222, entry: X11_KEY_CIRCUMFLEX_ACCENT},
 | 
			
		||||
                        {keycode: 220, entry: X11_KEY_YEN_MARK},
 | 
			
		||||
                        {keycode: 219, entry: X11_KEY_OPEN_BRACKET},
 | 
			
		||||
                        {keycode: 221, entry: X11_KEY_CLOSE_BRACKET},
 | 
			
		||||
                        {keycode: 59, entry: X11_KEY_COLON, browser: "Firefox"},
 | 
			
		||||
                        {keycode: 186, entry: X11_KEY_COLON, browser: "Chrome"},
 | 
			
		||||
                        {keycode: 9,  entry: 9, guestos: "XenServer"},
 | 
			
		||||
                        {keycode: 226, entry: X11_KEY_REVERSE_SOLIUS},
 | 
			
		||||
                        {keycode: 240, entry: [
 | 
			
		||||
                            {type: KEY_DOWN, code: X11_KEY_CAPSLOCK, modifiers: 0 },
 | 
			
		||||
                            {type: KEY_UP, code: X11_KEY_CAPSLOCK, modifiers: 0 },
 | 
			
		||||
                            ]
 | 
			
		||||
                        },
 | 
			
		||||
 		      ],
 | 
			
		||||
	         keyPress: [
 | 
			
		||||
                      {keycode: 59, entry: [
 | 
			
		||||
                         {type: KEY_DOWN, code: X11_KEY_SEMI_COLON, modifiers: 0 },
 | 
			
		||||
                         {type: KEY_UP, code: X11_KEY_SEMI_COLON, modifiers: 0 },
 | 
			
		||||
                         ]
 | 
			
		||||
                      },
 | 
			
		||||
                      {keycode: 43, entry: [
 | 
			
		||||
                         {type: KEY_DOWN, code: X11_KEY_SHIFT, modifiers: 0, shift: false },
 | 
			
		||||
                         {type: KEY_DOWN, code: X11_KEY_ADD, modifiers: 0, shift: false },
 | 
			
		||||
                         {type: KEY_UP, code: X11_KEY_ADD, modifiers: 0, shift: false },
 | 
			
		||||
                         {type: KEY_UP, code: X11_KEY_SHIFT, modifiers: 0, shift: false },
 | 
			
		||||
                         {type: KEY_DOWN, code: X11_KEY_ADD, modifiers: 0, shift: true },
 | 
			
		||||
                         {type: KEY_UP, code: X11_KEY_ADD, modifiers: 0, shift: true },
 | 
			
		||||
                         ]
 | 
			
		||||
                      },
 | 
			
		||||
                           ]
 | 
			
		||||
		}
 | 
			
		||||
	   }	]
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1444
									
								
								services/console-proxy/server/js/ajaxviewer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										338
									
								
								services/console-proxy/server/js/cloud.logger.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,338 @@
 | 
			
		||||
/*
 | 
			
		||||
Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
distributed with this work for additional information
 | 
			
		||||
regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
to you under the Apache License, Version 2.0 (the
 | 
			
		||||
"License"); you may not use this file except in compliance
 | 
			
		||||
with the License.  You may obtain a copy of the License at
 | 
			
		||||
 
 | 
			
		||||
  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 
 | 
			
		||||
Unless required by applicable law or agreed to in writing,
 | 
			
		||||
software distributed under the License is distributed on an
 | 
			
		||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
KIND, either express or implied.  See the License for the
 | 
			
		||||
specific language governing permissions and limitations
 | 
			
		||||
under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// Version: 1.9.1.152
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Javascript logger utility
 | 
			
		||||
// Author
 | 
			
		||||
//		Kelven Yang
 | 
			
		||||
//		2/25/2010
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
function Logger() {
 | 
			
		||||
	this.bDockEnabled = true;
 | 
			
		||||
	
 | 
			
		||||
	this.logWin = null;
 | 
			
		||||
	this.logger = null;
 | 
			
		||||
	this.header = null;
 | 
			
		||||
	
 | 
			
		||||
	this.bEnabled = true;
 | 
			
		||||
	this.level = 0;
 | 
			
		||||
	
 | 
			
		||||
	this.bMoving = false;
 | 
			
		||||
	this.offsetStart = {left: 0, top: 0};
 | 
			
		||||
	this.ptStart = {x: 0, y: 0};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Logger.DEFAULT_WIN_HEIGHT = 500;
 | 
			
		||||
Logger.LEVEL_TRACE = 0;
 | 
			
		||||
Logger.LEVEL_DEBUG = 1;
 | 
			
		||||
Logger.LEVEL_INFO = 2;
 | 
			
		||||
Logger.LEVEL_WARN = 3;
 | 
			
		||||
Logger.LEVEL_ERROR = 4;
 | 
			
		||||
Logger.LEVEL_FATAL = 5;
 | 
			
		||||
Logger.LEVEL_SYS = 100;
 | 
			
		||||
 | 
			
		||||
Logger.prototype = {
 | 
			
		||||
	
 | 
			
		||||
	open: function() {
 | 
			
		||||
		if(this.logWin) {
 | 
			
		||||
			this.logWin.show();
 | 
			
		||||
			
 | 
			
		||||
			this.log(Logger.LEVEL_SYS, "Logger is open in browser: " + this.objectToString($.browser));
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		var logger = this;
 | 
			
		||||
		var logWinMarkup = [ 
 | 
			
		||||
				'<div class="logwin">',
 | 
			
		||||
				'<div class="logwin_title">',
 | 
			
		||||
					'<div class="logwin_title_actionbox">',
 | 
			
		||||
		        		'<a class="logwin_playbutton" href="#" cmd="1"></a>', 
 | 
			
		||||
		        		'<a class="logwin_stopbutton" href="#" cmd="2"></a>',
 | 
			
		||||
		        		'<a class="logwin_clrbutton" href="#" cmd="3"></a>',
 | 
			
		||||
		        		'<form action="#">',
 | 
			
		||||
						'<select class="select" id="template_type">',
 | 
			
		||||
		                  '<option value="0">TRACE</option>',
 | 
			
		||||
		                  '<option value="1">DEBUG</option>',
 | 
			
		||||
		                  '<option value="2">INFO</option>',
 | 
			
		||||
		                  '<option value="3">WARN</option>',
 | 
			
		||||
		                  '<option value="4">ERROR</option>',
 | 
			
		||||
		                  '<option value="5">FATAL</option>',
 | 
			
		||||
		         		'</select>',
 | 
			
		||||
		         		'</form>',
 | 
			
		||||
		            '</div>',
 | 
			
		||||
		            '<div class="logwin_title_rgtactionbox">',
 | 
			
		||||
			        	'<a class="logwin_minimizebutton" href="#" cmd="4"></a>',
 | 
			
		||||
			            '<a class="logwin_shrinkbutton" href="#" cmd="5"></a>',
 | 
			
		||||
		            '</div>',
 | 
			
		||||
				'</div>',
 | 
			
		||||
				'<div class="logwin_content"></div>',
 | 
			
		||||
				'</div>'
 | 
			
		||||
		    ].join('');
 | 
			
		||||
		
 | 
			
		||||
		this.logWin = $(logWinMarkup).appendTo(document.body);
 | 
			
		||||
		this.header = $('.logwin_title:first', this.logWin);
 | 
			
		||||
		this.logger = $('.logwin_content:first', this.logWin);
 | 
			
		||||
 | 
			
		||||
		$(".logwin_title", this.logWin).mousedown(function(e) {
 | 
			
		||||
			if($(e.target).attr('cmd'))
 | 
			
		||||
				return true;
 | 
			
		||||
			
 | 
			
		||||
			if(!logger.bMoving) {
 | 
			
		||||
				logger.bMoving = true;
 | 
			
		||||
				logger.offsetStart = logger.logWin.offset();
 | 
			
		||||
				logger.ptStart = {x: e.pageX, y: e.pageY};
 | 
			
		||||
				
 | 
			
		||||
				$(document).bind("mousemove", function(e) {
 | 
			
		||||
					if(logger.bMoving) {
 | 
			
		||||
						logger.enableDocking(false);
 | 
			
		||||
						
 | 
			
		||||
						var logWinNewLeft = logger.offsetStart.left + e.pageX - logger.ptStart.x;
 | 
			
		||||
						var logWinNewTop = logger.offsetStart.top + e.pageY - logger.ptStart.y;
 | 
			
		||||
						
 | 
			
		||||
						logger.logWin.css("left", logWinNewLeft + "px").css("top", logWinNewTop + "px");
 | 
			
		||||
					}
 | 
			
		||||
					return false; 
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				$(document).bind("mouseup", function(e) {
 | 
			
		||||
					if(logger.bMoving) {
 | 
			
		||||
						logger.bMoving = false;
 | 
			
		||||
						$(document).unbind("mousemove", arguments.callee.name);
 | 
			
		||||
						$(document).unbind("mouseup", arguments.callee.name);
 | 
			
		||||
						
 | 
			
		||||
						return false;
 | 
			
		||||
					}
 | 
			
		||||
					return true;
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			// prevent default handling
 | 
			
		||||
			return false;
 | 
			
		||||
		}).dblclick(function(e) {
 | 
			
		||||
			logger.expand(!logger.isExpanded());
 | 
			
		||||
		});
 | 
			
		||||
		
 | 
			
		||||
		this.logWin.click(function(e) {
 | 
			
		||||
			if($(e.target).attr('cmd')) {
 | 
			
		||||
				switch($(e.target).attr('cmd')) {
 | 
			
		||||
				case '1' :
 | 
			
		||||
					logger.enable(true);
 | 
			
		||||
					break;
 | 
			
		||||
					
 | 
			
		||||
				case '2' :
 | 
			
		||||
					logger.enable(false);
 | 
			
		||||
					break;
 | 
			
		||||
					
 | 
			
		||||
				case '3' :
 | 
			
		||||
					logger.clear();
 | 
			
		||||
					break;
 | 
			
		||||
					
 | 
			
		||||
				case '4' :
 | 
			
		||||
					logger.enableDocking(true);
 | 
			
		||||
					logger.dockIn();
 | 
			
		||||
					break;
 | 
			
		||||
					
 | 
			
		||||
				case '5' :
 | 
			
		||||
					logger.expand(!logger.isExpanded());
 | 
			
		||||
					break;
 | 
			
		||||
					
 | 
			
		||||
				default :
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
		
 | 
			
		||||
		$("#template_type", this.logWin).change(function(e) {
 | 
			
		||||
			logger.setLevel(parseInt($(this).val()));
 | 
			
		||||
		});
 | 
			
		||||
		
 | 
			
		||||
		this.logWin.css("left", (($(document.body).width() - this.logWin.width()) / 2) + "px");
 | 
			
		||||
		this.dockIn();
 | 
			
		||||
		
 | 
			
		||||
		this.log(Logger.LEVEL_SYS, "Logger is open in browser: " + this.objectToString($.browser));
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	close: function() {
 | 
			
		||||
		if(this.logWin)
 | 
			
		||||
			this.logWin.hide();
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	isOpen: function() {
 | 
			
		||||
		if(this.logWin)
 | 
			
		||||
			return this.logWin.is(":visible");
 | 
			
		||||
		return false;
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	dockIn: function() {
 | 
			
		||||
		var logger = this;
 | 
			
		||||
		var offset = this.logWin.offset();
 | 
			
		||||
		var bottom = offset.top + this.logWin.height();
 | 
			
		||||
		var delta = bottom - 2;
 | 
			
		||||
		
 | 
			
		||||
		this.logWin.animate({top: (offset.top - delta) + "px"}, 200, 
 | 
			
		||||
			function() {
 | 
			
		||||
				logger.logWin.unbind("mouseleave");
 | 
			
		||||
				logger.logWin.bind("mouseenter", function(e) {
 | 
			
		||||
					if(logger.bDockEnabled)
 | 
			
		||||
						logger.dockOut();
 | 
			
		||||
				});
 | 
			
		||||
			} 
 | 
			
		||||
		);
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	dockOut: function() {
 | 
			
		||||
		var logger = this;
 | 
			
		||||
		this.logWin.animate({top: "0px"}, 200, 
 | 
			
		||||
			function() {
 | 
			
		||||
				logger.logWin.unbind("mouseenter");
 | 
			
		||||
				logger.logWin.bind("mouseleave", function(e) {
 | 
			
		||||
					if(logger.bDockEnabled) {
 | 
			
		||||
						var xPosInLogWin = e.pageX - logger.logWin.offset().left;
 | 
			
		||||
						var yPosInLogWin = e.pageY - logger.logWin.offset().top;
 | 
			
		||||
						
 | 
			
		||||
						if(xPosInLogWin < 0 || yPosInLogWin < 0 || 
 | 
			
		||||
							xPosInLogWin > logger.logWin.width() || yPosInLogWin > logger.logWin.height()) {
 | 
			
		||||
							logger.dockIn();
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
		);
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	enableDocking: function(bEnable) {
 | 
			
		||||
		this.bDockEnabled = bEnable;
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	log: function(level, message) {
 | 
			
		||||
		// Note : LEVEL_SYS message will always be logged
 | 
			
		||||
		if(this.logger && (level == Logger.LEVEL_SYS || this.bEnabled && level >= this.level)) {
 | 
			
		||||
			var curTime = new Date();
 | 
			
		||||
			var curTimeString = [
 | 
			
		||||
			    '', curTime.getMonth(),
 | 
			
		||||
			    '/', curTime.getDate(),
 | 
			
		||||
			    '/', curTime.getYear(),
 | 
			
		||||
			    ' ',
 | 
			
		||||
				curTime.getHours(),
 | 
			
		||||
				':', curTime.getMinutes(),
 | 
			
		||||
				":", curTime.getSeconds(),
 | 
			
		||||
				".", curTime.getMilliseconds()].join('');
 | 
			
		||||
			
 | 
			
		||||
			this.logger.append(this.getLevelDisplayString(level) + " - " + curTimeString + " - " + message + '<br>');
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	clear: function() {
 | 
			
		||||
		if(this.logger) {
 | 
			
		||||
			this.logger.empty();
 | 
			
		||||
			this.log(Logger.LEVEL_SYS, "Logger is cleared");
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	setLevel: function(level) {
 | 
			
		||||
		this.level = level;
 | 
			
		||||
		
 | 
			
		||||
		this.log(Logger.LEVEL_SYS, "Set logger trace level to " + this.getLevelDisplayString(level));
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	enable: function(bEnabled) {
 | 
			
		||||
		this.bEnabled = bEnabled;
 | 
			
		||||
		
 | 
			
		||||
		if(bEnabled)
 | 
			
		||||
			this.log(Logger.LEVEL_SYS, "Logger is enabled");
 | 
			
		||||
		else
 | 
			
		||||
			this.log(Logger.LEVEL_SYS, "Logger is disabled");
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	expand: function(bExpand) {
 | 
			
		||||
		if(bExpand) {
 | 
			
		||||
			this.logWin.height(Logger.DEFAULT_WIN_HEIGHT);
 | 
			
		||||
			this.logger.height(Logger.DEFAULT_WIN_HEIGHT - this.header.height());
 | 
			
		||||
		} else {
 | 
			
		||||
			this.logWin.height(this.header.height());
 | 
			
		||||
			this.logger.height(0);
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	isExpanded: function() {
 | 
			
		||||
		return this.logWin.height() > this.header.height();
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	getLevelDisplayString: function(level) {
 | 
			
		||||
		switch(level) {
 | 
			
		||||
		case Logger.LEVEL_TRACE :
 | 
			
		||||
			return "TRACE";
 | 
			
		||||
			
 | 
			
		||||
		case Logger.LEVEL_DEBUG :
 | 
			
		||||
			return "DEBUG";
 | 
			
		||||
			
 | 
			
		||||
		case Logger.LEVEL_INFO :
 | 
			
		||||
			return "INFO";
 | 
			
		||||
			
 | 
			
		||||
		case Logger.LEVEL_WARN :
 | 
			
		||||
			return "WARN";
 | 
			
		||||
			
 | 
			
		||||
		case Logger.LEVEL_ERROR :
 | 
			
		||||
			return "ERROR";
 | 
			
		||||
			
 | 
			
		||||
		case Logger.LEVEL_FATAL :
 | 
			
		||||
			return "FATAL";
 | 
			
		||||
			
 | 
			
		||||
		case Logger.LEVEL_SYS :
 | 
			
		||||
			return "SYSINFO";
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return "LEVEL " + level;
 | 
			
		||||
	},
 | 
			
		||||
	
 | 
			
		||||
	// this is a util function which actually can be put elsewhere instead of in this class
 | 
			
		||||
	objectToString : function(object) {
 | 
			
		||||
		if(object) {
 | 
			
		||||
			if(object instanceof Object) {
 | 
			
		||||
				var sb = ['{' ];
 | 
			
		||||
				
 | 
			
		||||
				$.each(object, function(name, val) {
 | 
			
		||||
					sb.push('' + name + ': ');
 | 
			
		||||
					
 | 
			
		||||
					if(val instanceof Object) {
 | 
			
		||||
						sb.push(this.objectToString(val));
 | 
			
		||||
					} else {
 | 
			
		||||
						sb.push('' + val);
 | 
			
		||||
					}
 | 
			
		||||
					
 | 
			
		||||
					sb.push(',');
 | 
			
		||||
				});
 | 
			
		||||
				
 | 
			
		||||
				if(sb[sb.length - 1] == ',' )
 | 
			
		||||
					sb.length = sb.length - 1;
 | 
			
		||||
				
 | 
			
		||||
				sb.push('}');
 | 
			
		||||
				return sb.join("");
 | 
			
		||||
			} else {
 | 
			
		||||
				return '' + object;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			return 'N/A';
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										72
									
								
								services/console-proxy/server/js/handler.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,72 @@
 | 
			
		||||
/*
 | 
			
		||||
Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
distributed with this work for additional information
 | 
			
		||||
regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
to you under the Apache License, Version 2.0 (the
 | 
			
		||||
"License"); you may not use this file except in compliance
 | 
			
		||||
with the License.  You may obtain a copy of the License at
 | 
			
		||||
 
 | 
			
		||||
  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 
 | 
			
		||||
Unless required by applicable law or agreed to in writing,
 | 
			
		||||
software distributed under the License is distributed on an
 | 
			
		||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
KIND, either express or implied.  See the License for the
 | 
			
		||||
specific language governing permissions and limitations
 | 
			
		||||
under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Callback handlers for AJAX viewer
 | 
			
		||||
// Author
 | 
			
		||||
//		Kelven Yang
 | 
			
		||||
//		11/18/2009
 | 
			
		||||
//
 | 
			
		||||
function onKickoff() {
 | 
			
		||||
	ajaxViewer.stop();
 | 
			
		||||
	$('#toolbar').remove();
 | 
			
		||||
	$('#main_panel').html('<p>This session is terminated because a session for the same VM has been created elsewhere.</p>');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function onDisconnect() {
 | 
			
		||||
	ajaxViewer.stop();
 | 
			
		||||
	$('#toolbar').remove();
 | 
			
		||||
	$('#main_panel').html('<p>This session is terminated as the machine you are accessing has terminated the connection.</p>');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function onClientError() {
 | 
			
		||||
	ajaxViewer.stop();
 | 
			
		||||
	$('#toolbar').remove();
 | 
			
		||||
	$('#main_panel').html('<p>Client communication error, please retry later.</p>');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function onCanvasSizeChange(width, height) {
 | 
			
		||||
	$('#toolbar').width(width);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function onStatusNotify(status) {
 | 
			
		||||
	if(status == ajaxViewer.STATUS_SENDING || status == ajaxViewer.STATUS_RECEIVING)
 | 
			
		||||
		$('#light').removeClass('dark').addClass('bright');
 | 
			
		||||
	else
 | 
			
		||||
		$('#light').removeClass('bright').addClass('dark');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sendCtrlAltDel() {
 | 
			
		||||
	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_DOWN, 45, ajaxViewer.CTRL_KEY | ajaxViewer.ALT_KEY);
 | 
			
		||||
	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_UP, 45, ajaxViewer.CTRL_KEY | ajaxViewer.ALT_KEY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sendCtrlEsc() {
 | 
			
		||||
	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_DOWN, 17, 0);
 | 
			
		||||
	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_DOWN, 27, ajaxViewer.CTRL_KEY);
 | 
			
		||||
	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_UP, 27, ajaxViewer.CTRL_KEY);
 | 
			
		||||
	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_UP, 17, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sendAltTab() {
 | 
			
		||||
	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_DOWN, 18, 0);
 | 
			
		||||
	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_DOWN, 9, ajaxViewer.ALT_KEY);
 | 
			
		||||
	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_UP, 9, ajaxViewer.ALT_KEY);
 | 
			
		||||
	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_UP, 18, 0);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								services/console-proxy/server/js/jquery.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										90
									
								
								services/console-proxy/server/libexec/console-proxy-runner.in
									
									
									
									
									
										Executable file
									
								
							
							
						
						@ -0,0 +1,90 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#run.sh runs the agent client.
 | 
			
		||||
 | 
			
		||||
cd `dirname "$0"`
 | 
			
		||||
 | 
			
		||||
SYSTEMJARS="@SYSTEMJARS@"
 | 
			
		||||
SCP=$(build-classpath $SYSTEMJARS) ; if [ $? != 0 ] ; then SCP="@SYSTEMCLASSPATH@" ; fi
 | 
			
		||||
DCP="@DEPSCLASSPATH@"
 | 
			
		||||
ACP="@AGENTCLASSPATH@"
 | 
			
		||||
export CLASSPATH=$SCP:$DCP:$ACP:@CPSYSCONFDIR@
 | 
			
		||||
for jarfile in "@PREMIUMJAVADIR@"/* ; do
 | 
			
		||||
	if [ ! -e "$jarfile" ] ; then continue ; fi
 | 
			
		||||
	CLASSPATH=$jarfile:$CLASSPATH
 | 
			
		||||
done
 | 
			
		||||
for plugin in "@PLUGINJAVADIR@"/* ; do
 | 
			
		||||
	if [ ! -e "$plugin" ] ; then continue ; fi
 | 
			
		||||
	CLASSPATH=$plugin:$CLASSPATH
 | 
			
		||||
done
 | 
			
		||||
export CLASSPATH
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
cd "@CPLIBDIR@"
 | 
			
		||||
echo Current directory is "$PWD"
 | 
			
		||||
echo CLASSPATH to run the console proxy: "$CLASSPATH"
 | 
			
		||||
 | 
			
		||||
export PATH=/sbin:/usr/sbin:"$PATH"
 | 
			
		||||
SERVICEARGS=
 | 
			
		||||
for x in private public ; do
 | 
			
		||||
	configuration=`grep -q "^$x.network.device" "@CPSYSCONFDIR@"/agent.properties || true`
 | 
			
		||||
	if [ -n "$CONFIGURATION" ] ; then
 | 
			
		||||
		echo "Using manually-configured network device $CONFIGURATION"
 | 
			
		||||
	else
 | 
			
		||||
		defaultroute=`ip route | grep ^default | cut -d ' ' -f 5`
 | 
			
		||||
		test -n "$defaultroute"
 | 
			
		||||
		echo "Using auto-discovered network device $defaultroute which is the default route"
 | 
			
		||||
		SERVICEARGS="$SERVICEARGS $x.network.device="$defaultroute
 | 
			
		||||
	fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
function termagent() {
 | 
			
		||||
    if [ "$agentpid" != "" ] ; then
 | 
			
		||||
	echo Killing VMOps Console Proxy "(PID $agentpid)" with SIGTERM >&2
 | 
			
		||||
	kill -TERM $agentpid
 | 
			
		||||
	echo Waiting for agent to exit >&2
 | 
			
		||||
	wait $agentpid
 | 
			
		||||
	ex=$?
 | 
			
		||||
	echo Agent exited with return code $ex >&2	
 | 
			
		||||
    else
 | 
			
		||||
	echo Agent PID is unknown >&2
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
trap termagent TERM
 | 
			
		||||
while true ; do
 | 
			
		||||
	java -Xms128M -Xmx384M -cp "$CLASSPATH" "$@" com.cloud.agent.AgentShell $SERVICEARGS &
 | 
			
		||||
	agentpid=$!
 | 
			
		||||
	echo "Console Proxy started.  PID: $!" >&2
 | 
			
		||||
	wait $agentpid
 | 
			
		||||
	ex=$?
 | 
			
		||||
	if [ $ex -gt 128 ]; then
 | 
			
		||||
		echo "wait on console proxy process interrupted by SIGTERM" >&2
 | 
			
		||||
		exit $ex
 | 
			
		||||
	fi
 | 
			
		||||
	echo "Console proxy exited with return code $ex" >&2
 | 
			
		||||
	if [ $ex -eq 0 ] || [ $ex -eq 1 ] || [ $ex -eq 66 ] || [ $ex -gt 128 ]; then
 | 
			
		||||
		echo "Exiting..." > /dev/stderr
 | 
			
		||||
		exit $ex
 | 
			
		||||
	fi
 | 
			
		||||
	echo "Restarting console proxy..." > /dev/stderr
 | 
			
		||||
	sleep 1
 | 
			
		||||
done
 | 
			
		||||
							
								
								
									
										247
									
								
								services/console-proxy/server/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,247 @@
 | 
			
		||||
<!--
 | 
			
		||||
  Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
  or more contributor license agreements. See the NOTICE file
 | 
			
		||||
  distributed with this work for additional information
 | 
			
		||||
  regarding copyright ownership. The ASF licenses this file
 | 
			
		||||
  to you under the Apache License, Version 2.0 (the
 | 
			
		||||
  "License"); you may not use this file except in compliance
 | 
			
		||||
  with the License. You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing,
 | 
			
		||||
  software distributed under the License is distributed on an
 | 
			
		||||
  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
  KIND, either express or implied. See the License for the
 | 
			
		||||
  specific language governing permissions and limitations
 | 
			
		||||
  under the License.
 | 
			
		||||
-->
 | 
			
		||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
			
		||||
  <modelVersion>4.0.0</modelVersion>
 | 
			
		||||
  <artifactId>cloud-console-proxy</artifactId>
 | 
			
		||||
  <name>Apache CloudStack Console Proxy</name>
 | 
			
		||||
  <parent>
 | 
			
		||||
    <groupId>org.apache.cloudstack</groupId>
 | 
			
		||||
    <artifactId>cloud-service-console-proxy</artifactId>
 | 
			
		||||
    <version>4.1.0-SNAPSHOT</version>
 | 
			
		||||
    <relativePath>../pom.xml</relativePath>
 | 
			
		||||
  </parent>
 | 
			
		||||
  <properties>
 | 
			
		||||
    <mkisofs>mkisofs</mkisofs>
 | 
			
		||||
  </properties>
 | 
			
		||||
  <dependencies>
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>log4j</groupId>
 | 
			
		||||
      <artifactId>log4j</artifactId>
 | 
			
		||||
      <version>${cs.log4j.version}</version>
 | 
			
		||||
    </dependency>
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>com.google.code.gson</groupId>
 | 
			
		||||
      <artifactId>gson</artifactId>
 | 
			
		||||
      <version>${cs.gson.version}</version>
 | 
			
		||||
    </dependency>
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>commons-codec</groupId>
 | 
			
		||||
      <artifactId>commons-codec</artifactId>
 | 
			
		||||
      <version>${cs.codec.version}</version>
 | 
			
		||||
    </dependency>
 | 
			
		||||
    <!-- required deps for the systemvm -->
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>org.apache.cloudstack</groupId>
 | 
			
		||||
      <artifactId>cloud-agent</artifactId>
 | 
			
		||||
      <version>${project.version}</version>
 | 
			
		||||
    </dependency>
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>org.apache.cloudstack</groupId>
 | 
			
		||||
      <artifactId>cloud-patches</artifactId>
 | 
			
		||||
      <version>${project.version}</version>
 | 
			
		||||
      <type>pom</type>
 | 
			
		||||
    </dependency>
 | 
			
		||||
  </dependencies>
 | 
			
		||||
  <build>
 | 
			
		||||
    <defaultGoal>install</defaultGoal>
 | 
			
		||||
    <sourceDirectory>src</sourceDirectory>
 | 
			
		||||
    <resources>
 | 
			
		||||
      <resource>
 | 
			
		||||
        <directory>certs</directory>
 | 
			
		||||
        <excludes>
 | 
			
		||||
          <exclude>realhostip.csr</exclude>
 | 
			
		||||
        </excludes>
 | 
			
		||||
      </resource>
 | 
			
		||||
    </resources>
 | 
			
		||||
    <plugins>
 | 
			
		||||
      <plugin>
 | 
			
		||||
        <artifactId>maven-assembly-plugin</artifactId>
 | 
			
		||||
        <version>2.3</version>
 | 
			
		||||
        <configuration>
 | 
			
		||||
          <finalName>systemvm</finalName>
 | 
			
		||||
          <appendAssemblyId>false</appendAssemblyId>
 | 
			
		||||
          <descriptors>
 | 
			
		||||
            <descriptor>systemvm-descriptor.xml</descriptor>
 | 
			
		||||
          </descriptors>
 | 
			
		||||
        </configuration>
 | 
			
		||||
        <executions>
 | 
			
		||||
          <execution>
 | 
			
		||||
            <id>make-systemvm</id>
 | 
			
		||||
            <phase>package</phase>
 | 
			
		||||
            <goals>
 | 
			
		||||
              <goal>single</goal>
 | 
			
		||||
            </goals>
 | 
			
		||||
          </execution>
 | 
			
		||||
        </executions>
 | 
			
		||||
      </plugin>
 | 
			
		||||
      <plugin>
 | 
			
		||||
        <artifactId>maven-resources-plugin</artifactId>
 | 
			
		||||
        <version>2.6</version>
 | 
			
		||||
        <executions>
 | 
			
		||||
          <execution>
 | 
			
		||||
            <id>copy-resources</id>
 | 
			
		||||
            <!-- here the phase you need -->
 | 
			
		||||
            <phase>package</phase>
 | 
			
		||||
            <goals>
 | 
			
		||||
              <goal>copy-resources</goal>
 | 
			
		||||
            </goals>
 | 
			
		||||
            <configuration>
 | 
			
		||||
              <outputDirectory>dist</outputDirectory>
 | 
			
		||||
              <resources>          
 | 
			
		||||
                <resource>
 | 
			
		||||
                  <directory>target</directory>
 | 
			
		||||
                  <includes>
 | 
			
		||||
                    <include>systemvm.zip</include>
 | 
			
		||||
                  </includes>
 | 
			
		||||
                </resource>
 | 
			
		||||
                <resource>
 | 
			
		||||
                  <directory>../patches/systemvm/debian/config/root/.ssh</directory>
 | 
			
		||||
                  <includes>
 | 
			
		||||
                    <include>authorized_keys</include>
 | 
			
		||||
                  </includes>
 | 
			
		||||
                </resource>
 | 
			
		||||
              </resources>              
 | 
			
		||||
            </configuration>            
 | 
			
		||||
          </execution>
 | 
			
		||||
        </executions>
 | 
			
		||||
      </plugin>
 | 
			
		||||
      <plugin>
 | 
			
		||||
        <artifactId>maven-antrun-plugin</artifactId>
 | 
			
		||||
        <version>1.7</version>
 | 
			
		||||
        <executions>
 | 
			
		||||
          <execution>
 | 
			
		||||
            <id>copy-cloud-scripts</id>
 | 
			
		||||
            <phase>package</phase>
 | 
			
		||||
            <goals>
 | 
			
		||||
              <goal>run</goal>
 | 
			
		||||
            </goals>
 | 
			
		||||
            <configuration>
 | 
			
		||||
              <target>
 | 
			
		||||
                <copy overwrite="true" file="../../../patches/target/cloud-scripts.tgz" tofile="${basedir}/dist/cloud-scripts.tgz"/>  
 | 
			
		||||
              </target>
 | 
			
		||||
            </configuration>
 | 
			
		||||
          </execution>
 | 
			
		||||
        </executions>
 | 
			
		||||
      </plugin>
 | 
			
		||||
<!-- Leave this to the systemvm profile
 | 
			
		||||
     Enable using the -P systemvm flag
 | 
			
		||||
      <plugin>
 | 
			
		||||
        <groupId>org.codehaus.mojo</groupId>
 | 
			
		||||
        <artifactId>exec-maven-plugin</artifactId>
 | 
			
		||||
        <version>1.2.1</version>
 | 
			
		||||
        <executions>
 | 
			
		||||
          <execution>
 | 
			
		||||
            <phase>package</phase>
 | 
			
		||||
            <goals>
 | 
			
		||||
              <goal>exec</goal>
 | 
			
		||||
            </goals>
 | 
			
		||||
          </execution>
 | 
			
		||||
        </executions>
 | 
			
		||||
        <configuration>
 | 
			
		||||
          <executable>mkisofs</executable>
 | 
			
		||||
          <workingDirectory>dist</workingDirectory>
 | 
			
		||||
          <arguments>
 | 
			
		||||
            <argument>-quiet</argument>
 | 
			
		||||
            <argument>-r</argument>
 | 
			
		||||
            <argument>-o</argument>
 | 
			
		||||
            <argument>systemvm.iso</argument>
 | 
			
		||||
            <argument>systemvm.zip</argument>
 | 
			
		||||
            <argument>cloud-scripts.tgz</argument>
 | 
			
		||||
            <argument>authorized_keys</argument>
 | 
			
		||||
          </arguments>
 | 
			
		||||
        </configuration>
 | 
			
		||||
      </plugin>
 | 
			
		||||
-->
 | 
			
		||||
    </plugins>
 | 
			
		||||
  </build>
 | 
			
		||||
  <profiles>
 | 
			
		||||
    <!-- Debian will never distribute mkisofs due to licensing issues.
 | 
			
		||||
         Fortunately genisoimage is a work-alike -->
 | 
			
		||||
    <profile>
 | 
			
		||||
      <id>genisoimage</id>
 | 
			
		||||
      <activation>
 | 
			
		||||
        <file>
 | 
			
		||||
          <exists>/usr/bin/genisoimage</exists>
 | 
			
		||||
        </file>
 | 
			
		||||
      </activation>
 | 
			
		||||
      <properties>
 | 
			
		||||
        <mkisofs>genisoimage</mkisofs>
 | 
			
		||||
      </properties>
 | 
			
		||||
    </profile>
 | 
			
		||||
    <profile>
 | 
			
		||||
      <id>vmware</id>
 | 
			
		||||
      <activation>
 | 
			
		||||
        <property>
 | 
			
		||||
          <name>nonoss</name>
 | 
			
		||||
        </property>
 | 
			
		||||
      </activation>
 | 
			
		||||
        <dependencies>
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>org.apache.cloudstack</groupId>
 | 
			
		||||
                <artifactId>cloud-plugin-hypervisor-vmware</artifactId>
 | 
			
		||||
                <version>${project.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>org.apache.cloudstack</groupId>
 | 
			
		||||
                <artifactId>cloud-vmware-base</artifactId>
 | 
			
		||||
                <version>${project.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
        </dependencies>
 | 
			
		||||
    </profile>
 | 
			
		||||
    <profile>
 | 
			
		||||
      <id>systemvm</id>
 | 
			
		||||
      <activation>
 | 
			
		||||
        <property>
 | 
			
		||||
          <name>systemvm</name>
 | 
			
		||||
        </property>
 | 
			
		||||
      </activation>
 | 
			
		||||
      <build>
 | 
			
		||||
      <plugins>
 | 
			
		||||
      <plugin>
 | 
			
		||||
        <groupId>org.codehaus.mojo</groupId>
 | 
			
		||||
        <artifactId>exec-maven-plugin</artifactId>
 | 
			
		||||
        <version>1.2.1</version>
 | 
			
		||||
        <executions>
 | 
			
		||||
          <execution>
 | 
			
		||||
            <phase>package</phase>
 | 
			
		||||
            <goals>
 | 
			
		||||
              <goal>exec</goal>
 | 
			
		||||
            </goals>
 | 
			
		||||
          </execution>
 | 
			
		||||
        </executions>
 | 
			
		||||
        <configuration>
 | 
			
		||||
          <executable>${mkisofs}</executable>
 | 
			
		||||
          <workingDirectory>dist</workingDirectory>
 | 
			
		||||
          <arguments>
 | 
			
		||||
            <argument>-quiet</argument>
 | 
			
		||||
            <argument>-r</argument>
 | 
			
		||||
            <argument>-o</argument>
 | 
			
		||||
            <argument>systemvm.iso</argument>
 | 
			
		||||
            <argument>systemvm.zip</argument>
 | 
			
		||||
            <argument>cloud-scripts.tgz</argument>
 | 
			
		||||
            <argument>authorized_keys</argument>
 | 
			
		||||
          </arguments>
 | 
			
		||||
        </configuration>
 | 
			
		||||
      </plugin>
 | 
			
		||||
      </plugins>
 | 
			
		||||
      </build>
 | 
			
		||||
    </profile>
 | 
			
		||||
  </profiles>
 | 
			
		||||
 | 
			
		||||
</project>
 | 
			
		||||
							
								
								
									
										63
									
								
								services/console-proxy/server/scripts/_run.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						@ -0,0 +1,63 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
#run.sh runs the console proxy.
 | 
			
		||||
 | 
			
		||||
# make sure we delete the old files from the original template 
 | 
			
		||||
rm console-proxy.jar
 | 
			
		||||
rm console-common.jar
 | 
			
		||||
rm conf/cloud.properties
 | 
			
		||||
 | 
			
		||||
set -x
 | 
			
		||||
 | 
			
		||||
CP=./:./conf
 | 
			
		||||
for file in *.jar
 | 
			
		||||
do
 | 
			
		||||
  CP=${CP}:$file
 | 
			
		||||
done
 | 
			
		||||
keyvalues=
 | 
			
		||||
 | 
			
		||||
CMDLINE=$(cat /var/cache/cloud/cmdline)
 | 
			
		||||
 | 
			
		||||
#CMDLINE="graphical utf8 eth0ip=0.0.0.0 eth0mask=255.255.255.0 eth1ip=192.168.140.40 eth1mask=255.255.255.0 eth2ip=172.24.0.50 eth2mask=255.255.0.0 gateway=172.24.0.1 dns1=72.52.126.11 template=domP dns2=72.52.126.12 host=192.168.1.142 port=8250 mgmtcidr=192.168.1.0/24 localgw=192.168.140.1 zone=5 pod=5"
 | 
			
		||||
for i in $CMDLINE
 | 
			
		||||
  do
 | 
			
		||||
     KEY=$(echo $i | cut -s -d= -f1)
 | 
			
		||||
     VALUE=$(echo $i | cut -s -d= -f2)
 | 
			
		||||
     [ "$KEY" == "" ] && continue
 | 
			
		||||
     case $KEY in
 | 
			
		||||
        *)
 | 
			
		||||
          keyvalues="${keyvalues} $KEY=$VALUE"
 | 
			
		||||
     esac
 | 
			
		||||
  done
 | 
			
		||||
   
 | 
			
		||||
tot_mem_k=$(cat /proc/meminfo | grep MemTotal | awk '{print $2}')
 | 
			
		||||
let "tot_mem_m=tot_mem_k>>10"
 | 
			
		||||
let "eightypcnt=$tot_mem_m*8/10"
 | 
			
		||||
let "maxmem=$tot_mem_m-80"
 | 
			
		||||
 | 
			
		||||
if [ $maxmem -gt $eightypcnt ]
 | 
			
		||||
then
 | 
			
		||||
  maxmem=$eightypcnt
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
java -Djavax.net.ssl.trustStore=./certs/realhostip.keystore -mx${maxmem}m -cp $CP com.cloud.agent.AgentShell $keyvalues $@
 | 
			
		||||
							
								
								
									
										69
									
								
								services/console-proxy/server/scripts/config_auth.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						@ -0,0 +1,69 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BASE_DIR="/var/www/html/copy/template/"
 | 
			
		||||
HTACCESS="$BASE_DIR/.htaccess"
 | 
			
		||||
 | 
			
		||||
PASSWDFILE="/etc/httpd/.htpasswd"
 | 
			
		||||
if [ -d /etc/apache2 ]
 | 
			
		||||
then
 | 
			
		||||
  PASSWDFILE="/etc/apache2/.htpasswd"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
config_htaccess() {
 | 
			
		||||
  mkdir -p $BASE_DIR
 | 
			
		||||
  result=$?
 | 
			
		||||
  echo "Options -Indexes" > $HTACCESS
 | 
			
		||||
  let "result=$result+$?"
 | 
			
		||||
  echo "AuthType Basic" >> $HTACCESS
 | 
			
		||||
  let "result=$result+$?"
 | 
			
		||||
  echo "AuthName \"Authentication Required\"" >> $HTACCESS
 | 
			
		||||
  let "result=$result+$?"
 | 
			
		||||
  echo "AuthUserFile  \"$PASSWDFILE\"" >> $HTACCESS
 | 
			
		||||
  let "result=$result+$?"
 | 
			
		||||
  echo "Require valid-user" >> $HTACCESS
 | 
			
		||||
  let "result=$result+$?"
 | 
			
		||||
  return $result 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
write_passwd() {
 | 
			
		||||
  local user=$1
 | 
			
		||||
  local passwd=$2
 | 
			
		||||
  htpasswd -bc $PASSWDFILE $user $passwd
 | 
			
		||||
  return $?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if [ $# -ne 2 ] ; then
 | 
			
		||||
	echo $"Usage: `basename $0` username password "
 | 
			
		||||
	exit 0
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
write_passwd $1 $2
 | 
			
		||||
if [ $? -ne 0 ]
 | 
			
		||||
then
 | 
			
		||||
  echo "Failed to update password"
 | 
			
		||||
  exit 2
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
config_htaccess 
 | 
			
		||||
exit $?
 | 
			
		||||
							
								
								
									
										174
									
								
								services/console-proxy/server/scripts/config_ssl.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						@ -0,0 +1,174 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
help() {
 | 
			
		||||
   printf " -c use customized key/cert\n"
 | 
			
		||||
   printf " -k path of private key\n"
 | 
			
		||||
   printf " -p path of certificate of public key\n"
 | 
			
		||||
   printf " -t path of certificate chain\n"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
config_httpd_conf() {
 | 
			
		||||
  local ip=$1
 | 
			
		||||
  local srvr=$2
 | 
			
		||||
  cp -f /etc/httpd/conf/httpd.conf.orig /etc/httpd/conf/httpd.conf
 | 
			
		||||
  sed -i -e "s/Listen.*:80$/Listen $ip:80/" /etc/httpd/conf/httpd.conf
 | 
			
		||||
  echo "<VirtualHost $ip:443> " >> /etc/httpd/conf/httpd.conf
 | 
			
		||||
  echo "  DocumentRoot /var/www/html/" >> /etc/httpd/conf/httpd.conf
 | 
			
		||||
  echo "  ServerName $srvr" >> /etc/httpd/conf/httpd.conf
 | 
			
		||||
  echo "  SSLEngine on" >>  /etc/httpd/conf/httpd.conf
 | 
			
		||||
  echo "  SSLCertificateFile /etc/httpd/ssl/certs/realhostip.crt" >>  /etc/httpd/conf/httpd.conf
 | 
			
		||||
  echo "  SSLCertificateKeyFile /etc/httpd/ssl/keys/realhostip.key" >> /etc/httpd/conf/httpd.conf
 | 
			
		||||
  echo "</VirtualHost>" >> /etc/httpd/conf/httpd.conf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
config_apache2_conf() {
 | 
			
		||||
  local ip=$1
 | 
			
		||||
  local srvr=$2
 | 
			
		||||
  cp -f /etc/apache2/sites-available/default.orig /etc/apache2/sites-available/default
 | 
			
		||||
  cp -f /etc/apache2/sites-available/default-ssl.orig /etc/apache2/sites-available/default-ssl
 | 
			
		||||
  sed -i -e "s/<VirtualHost.*>/<VirtualHost $ip:80>/" /etc/apache2/sites-available/default
 | 
			
		||||
  sed -i -e "s/<VirtualHost.*>/<VirtualHost $ip:443>/" /etc/apache2/sites-available/default-ssl
 | 
			
		||||
  sed -i -e "s/Listen .*:80/Listen $ip:80/g" /etc/apache2/ports.conf
 | 
			
		||||
  sed -i -e "s/Listen .*:443/Listen $ip:443/g" /etc/apache2/ports.conf
 | 
			
		||||
  sed -i -e "s/NameVirtualHost .*:80/NameVirtualHost $ip:80/g" /etc/apache2/ports.conf
 | 
			
		||||
  sed -i  's/ssl-cert-snakeoil.key/cert_apache.key/' /etc/apache2/sites-available/default-ssl
 | 
			
		||||
  sed -i  's/ssl-cert-snakeoil.pem/cert_apache.crt/' /etc/apache2/sites-available/default-ssl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
copy_certs() {
 | 
			
		||||
  local certdir=$(dirname $0)/certs
 | 
			
		||||
  local mydir=$(dirname $0)
 | 
			
		||||
  if [ -d $certdir ] && [ -f $customPrivKey ] &&  [ -f $customPrivCert ] ; then
 | 
			
		||||
       mkdir -p /etc/httpd/ssl/keys  &&  mkdir -p /etc/httpd/ssl/certs  &&  cp $customprivKey /etc/httpd/ssl/keys   &&  cp $customPrivCert /etc/httpd/ssl/certs
 | 
			
		||||
      return $?
 | 
			
		||||
  fi
 | 
			
		||||
  if [ ! -z customCertChain ] && [ -f $customCertChain ] ; then
 | 
			
		||||
     cp $customCertChain /etc/httpd/ssl/certs  
 | 
			
		||||
  fi
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
copy_certs_apache2() {
 | 
			
		||||
  local certdir=$(dirname $0)/certs
 | 
			
		||||
  local mydir=$(dirname $0)
 | 
			
		||||
  if [ -f $customPrivKey ] &&  [ -f $customPrivCert ] ; then
 | 
			
		||||
      cp $customPrivKey /etc/ssl/private/cert_apache.key   &&  cp $customPrivCert /etc/ssl/certs/cert_apache.crt
 | 
			
		||||
  fi
 | 
			
		||||
  if [ ! -z "$customCertChain" ] && [ -f "$customCertChain" ] ; then
 | 
			
		||||
     cp $customCertChain /etc/ssl/certs/cert_apache_chain.crt
 | 
			
		||||
  fi
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
cflag=
 | 
			
		||||
cpkflag=
 | 
			
		||||
cpcflag=
 | 
			
		||||
cccflag=
 | 
			
		||||
customPrivKey=$(dirname $0)/certs/realhostip.key
 | 
			
		||||
customPrivCert=$(dirname $0)/certs/realhostip.crt
 | 
			
		||||
customCertChain=
 | 
			
		||||
publicIp=
 | 
			
		||||
hostName=
 | 
			
		||||
while getopts 'i:h:k:p:t:c' OPTION
 | 
			
		||||
do
 | 
			
		||||
  case $OPTION in
 | 
			
		||||
     c) cflag=1
 | 
			
		||||
        ;;
 | 
			
		||||
     k) cpkflag=1
 | 
			
		||||
        customPrivKey="$OPTARG"
 | 
			
		||||
        ;;
 | 
			
		||||
     p) cpcflag=1
 | 
			
		||||
        customPrivCert="$OPTARG"
 | 
			
		||||
        ;;
 | 
			
		||||
     t) cccflag=1
 | 
			
		||||
        customCertChain="$OPTARG"
 | 
			
		||||
        ;;
 | 
			
		||||
     i) publicIp="$OPTARG"
 | 
			
		||||
        ;;
 | 
			
		||||
     h) hostName="$OPTARG"
 | 
			
		||||
        ;;
 | 
			
		||||
     ?) help
 | 
			
		||||
        ;;
 | 
			
		||||
   esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if [ -z "$publicIp" ] || [ -z "$hostName" ]
 | 
			
		||||
then
 | 
			
		||||
   help
 | 
			
		||||
   exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ "$cflag" == "1" ]
 | 
			
		||||
then
 | 
			
		||||
  if [ "$cpkflag$cpcflag" != "11" ] 
 | 
			
		||||
  then
 | 
			
		||||
     help
 | 
			
		||||
     exit 1
 | 
			
		||||
  fi
 | 
			
		||||
  if [ ! -f "$customPrivKey" ]
 | 
			
		||||
  then
 | 
			
		||||
     printf "priviate key file is not exist\n"
 | 
			
		||||
     exit 2
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ ! -f "$customPrivCert" ]
 | 
			
		||||
  then
 | 
			
		||||
     printf "public certificate is not exist\n"
 | 
			
		||||
     exit 3
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$cccflag" == "1" ] 
 | 
			
		||||
  then
 | 
			
		||||
     if [ ! -f "$customCertChain" ]
 | 
			
		||||
     then
 | 
			
		||||
        printf "certificate chain is not exist\n"
 | 
			
		||||
        exit 4
 | 
			
		||||
     fi
 | 
			
		||||
  fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ -d /etc/apache2 ]
 | 
			
		||||
then
 | 
			
		||||
  copy_certs_apache2
 | 
			
		||||
else
 | 
			
		||||
  copy_certs
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ $? -ne 0 ]
 | 
			
		||||
then
 | 
			
		||||
  echo "Failed to copy certificates"
 | 
			
		||||
  exit 2
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ -d /etc/apache2 ]
 | 
			
		||||
then
 | 
			
		||||
  config_apache2_conf $publicIp $hostName
 | 
			
		||||
  /etc/init.d/apache2 stop
 | 
			
		||||
  /etc/init.d/apache2 start
 | 
			
		||||
else
 | 
			
		||||
  config_httpd_conf $publicIp $hostName
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										50
									
								
								services/console-proxy/server/scripts/ipfirewall.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						@ -0,0 +1,50 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
BASE_DIR="/var/www/html/copy/"
 | 
			
		||||
HTACCESS="$BASE_DIR/.htaccess"
 | 
			
		||||
 | 
			
		||||
config_htaccess() {
 | 
			
		||||
  mkdir -p $BASE_DIR
 | 
			
		||||
  result=$?
 | 
			
		||||
  echo "Options -Indexes" > $HTACCESS
 | 
			
		||||
  let "result=$result+$?"
 | 
			
		||||
  echo "order deny,allow" >> $HTACCESS
 | 
			
		||||
  let "result=$result+$?"
 | 
			
		||||
  echo "deny from all" >> $HTACCESS
 | 
			
		||||
  let "result=$result+$?"
 | 
			
		||||
  return $result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ips(){
 | 
			
		||||
  echo "allow from $1" >> $HTACCESS
 | 
			
		||||
  result=$?
 | 
			
		||||
  return $result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
is_append="$1"
 | 
			
		||||
shift
 | 
			
		||||
if [ $is_append != "true" ]; then
 | 
			
		||||
	config_htaccess
 | 
			
		||||
fi
 | 
			
		||||
for i in $@
 | 
			
		||||
do
 | 
			
		||||
        ips "$i"
 | 
			
		||||
done
 | 
			
		||||
exit $?
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										48
									
								
								services/console-proxy/server/scripts/run-proxy.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,48 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
#run.sh runs the console proxy.
 | 
			
		||||
 | 
			
		||||
# make sure we delete the old files from the original template 
 | 
			
		||||
rm console-proxy.jar
 | 
			
		||||
rm console-common.jar
 | 
			
		||||
rm conf/cloud.properties
 | 
			
		||||
 | 
			
		||||
CP=./:./conf
 | 
			
		||||
for file in *.jar
 | 
			
		||||
do
 | 
			
		||||
  CP=${CP}:$file
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
#CMDLINE=$(cat /proc/cmdline)
 | 
			
		||||
#for i in $CMDLINE
 | 
			
		||||
#  do
 | 
			
		||||
#     KEY=$(echo $i | cut -d= -f1)
 | 
			
		||||
#     VALUE=$(echo $i | cut -d= -f2)
 | 
			
		||||
#     case $KEY in
 | 
			
		||||
#       mgmt_host)
 | 
			
		||||
#          MGMT_HOST=$VALUE
 | 
			
		||||
#          ;;
 | 
			
		||||
#     esac
 | 
			
		||||
#  done
 | 
			
		||||
   
 | 
			
		||||
java -mx700m -cp $CP:./conf com.cloud.consoleproxy.ConsoleProxy $@
 | 
			
		||||
							
								
								
									
										18
									
								
								services/console-proxy/server/scripts/run.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,18 @@
 | 
			
		||||
rem  Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
rem  or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
rem  distributed with this work for additional information
 | 
			
		||||
rem  regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
rem  to you under the Apache License, Version 2.0 (the
 | 
			
		||||
rem  "License"); you may not use this file except in compliance
 | 
			
		||||
rem  with the License.  You may obtain a copy of the License at
 | 
			
		||||
rem  
 | 
			
		||||
rem    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
rem  
 | 
			
		||||
rem  Unless required by applicable law or agreed to in writing,
 | 
			
		||||
rem  software distributed under the License is distributed on an
 | 
			
		||||
rem  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
rem  KIND, either express or implied.  See the License for the
 | 
			
		||||
rem  specific language governing permissions and limitations
 | 
			
		||||
rem  under the License.
 | 
			
		||||
 | 
			
		||||
java -mx700m -cp cloud-console-proxy.jar;;cloud-console-common.jar;log4j-1.2.15.jar;apache-log4j-extras-1.0.jar;gson-1.3.jar;commons-logging-1.1.1.jar;.;.\conf; com.cloud.consoleproxy.ConsoleProxy %*
 | 
			
		||||
							
								
								
									
										45
									
								
								services/console-proxy/server/scripts/run.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						@ -0,0 +1,45 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
#_run.sh runs the agent client.
 | 
			
		||||
 | 
			
		||||
# set -x
 | 
			
		||||
 
 | 
			
		||||
while true
 | 
			
		||||
do
 | 
			
		||||
  ./_run.sh "$@" &
 | 
			
		||||
  wait
 | 
			
		||||
  ex=$?
 | 
			
		||||
  if [ $ex -eq 0 ] || [ $ex -eq 1 ] || [ $ex -eq 66 ] || [ $ex -gt 128 ]; then
 | 
			
		||||
      # permanent errors
 | 
			
		||||
      sleep 5
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # user stop agent by service cloud stop
 | 
			
		||||
  grep 'stop' /usr/local/cloud/systemvm/user_request &>/dev/null
 | 
			
		||||
  if [ $? -eq 0 ]; then
 | 
			
		||||
      timestamp=$(date)
 | 
			
		||||
      echo "$timestamp User stops cloud.com service" >> /var/log/cloud.log
 | 
			
		||||
      exit 0
 | 
			
		||||
  fi
 | 
			
		||||
  sleep 5
 | 
			
		||||
done
 | 
			
		||||
							
								
								
									
										136
									
								
								services/console-proxy/server/scripts/ssvm-check.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,136 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
# or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
# distributed with this work for additional information
 | 
			
		||||
# regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
# to you under the Apache License, Version 2.0 (the
 | 
			
		||||
# "License"); you may not use this file except in compliance
 | 
			
		||||
# with the License.  You may obtain a copy of the License at
 | 
			
		||||
# 
 | 
			
		||||
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
# 
 | 
			
		||||
# Unless required by applicable law or agreed to in writing,
 | 
			
		||||
# software distributed under the License is distributed on an
 | 
			
		||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
# KIND, either express or implied.  See the License for the
 | 
			
		||||
# specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
# Health check script for the Secondary Storage VM
 | 
			
		||||
 | 
			
		||||
# DNS server is specified.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CMDLINE=/var/cache/cloud/cmdline
 | 
			
		||||
for i in `cat $CMDLINE`
 | 
			
		||||
do
 | 
			
		||||
   key=`echo $i | cut -d= -f1`
 | 
			
		||||
   value=`echo $i | cut -d= -f2`
 | 
			
		||||
   case $key in
 | 
			
		||||
      host)
 | 
			
		||||
         MGMTSERVER=$value       
 | 
			
		||||
         ;;
 | 
			
		||||
   esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# ping dns server
 | 
			
		||||
echo ================================================
 | 
			
		||||
DNSSERVER=`egrep '^nameserver' /etc/resolv.conf  | awk '{print $2}'| head -1`
 | 
			
		||||
echo "First DNS server is " $DNSSERVER
 | 
			
		||||
ping -c 2  $DNSSERVER
 | 
			
		||||
if [ $? -eq 0 ]
 | 
			
		||||
then
 | 
			
		||||
    echo "Good: Can ping DNS server"
 | 
			
		||||
else
 | 
			
		||||
    echo "WARNING: cannot ping DNS server"
 | 
			
		||||
    echo "route follows"
 | 
			
		||||
    route -n
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# check dns resolve
 | 
			
		||||
echo ================================================
 | 
			
		||||
nslookup download.cloud.com 1> /tmp/dns 2>&1
 | 
			
		||||
grep 'no servers could' /tmp/dns 1> /dev/null 2>&1
 | 
			
		||||
if [ $? -eq 0 ]
 | 
			
		||||
then
 | 
			
		||||
    echo "ERROR: DNS not resolving download.cloud.com"
 | 
			
		||||
    echo resolv.conf follows
 | 
			
		||||
    cat /etc/resolv.conf
 | 
			
		||||
    exit 2
 | 
			
		||||
else
 | 
			
		||||
    echo "Good: DNS resolves download.cloud.com"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# check to see if we have the NFS volume mounted
 | 
			
		||||
echo ================================================
 | 
			
		||||
mount|grep -v sunrpc|grep nfs 1> /dev/null 2>&1
 | 
			
		||||
if [ $? -eq 0 ]
 | 
			
		||||
then
 | 
			
		||||
    echo "NFS is currently mounted"
 | 
			
		||||
    # check for write access
 | 
			
		||||
    for MOUNTPT in `mount|grep -v sunrpc|grep nfs| awk '{print $3}'`
 | 
			
		||||
    do
 | 
			
		||||
        if [ $MOUNTPT != "/proc/xen" ] # mounted by xen
 | 
			
		||||
        then
 | 
			
		||||
            echo Mount point is $MOUNTPT
 | 
			
		||||
            touch $MOUNTPT/foo
 | 
			
		||||
            if [ $? -eq 0 ]
 | 
			
		||||
            then
 | 
			
		||||
                echo "Good: Can write to mount point"
 | 
			
		||||
                rm $MOUNTPT/foo
 | 
			
		||||
            else
 | 
			
		||||
                echo "ERROR: Cannot write to mount point"
 | 
			
		||||
                echo "You need to export with norootsquash"
 | 
			
		||||
            fi
 | 
			
		||||
        fi
 | 
			
		||||
     done
 | 
			
		||||
else
 | 
			
		||||
    echo "ERROR: NFS is not currently mounted"
 | 
			
		||||
    echo "Try manually mounting from inside the VM"
 | 
			
		||||
    NFSSERVER=`awk '{print $17}' $CMDLINE|awk -F= '{print $2}'|awk -F: '{print $1}'`
 | 
			
		||||
    echo "NFS server is " $NFSSERVER
 | 
			
		||||
    ping -c 2  $NFSSERVER
 | 
			
		||||
    if [ $? -eq 0 ]
 | 
			
		||||
    then
 | 
			
		||||
	echo "Good: Can ping NFS server"
 | 
			
		||||
    else
 | 
			
		||||
	echo "WARNING: cannot ping NFS server"
 | 
			
		||||
	echo routing table follows
 | 
			
		||||
	route -n
 | 
			
		||||
    fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# check for connectivity to the management server
 | 
			
		||||
echo ================================================
 | 
			
		||||
echo Management server is $MGMTSERVER.  Checking connectivity.
 | 
			
		||||
socatout=$(echo | socat - TCP:$MGMTSERVER:8250,connect-timeout=3 2>&1)
 | 
			
		||||
if [ $? -eq 0 ]
 | 
			
		||||
then
 | 
			
		||||
    echo "Good: Can connect to management server port 8250"
 | 
			
		||||
else
 | 
			
		||||
    echo "ERROR: Cannot connect to $MGMTSERVER port 8250"
 | 
			
		||||
    echo $socatout
 | 
			
		||||
    exit 4
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# check for the java process running
 | 
			
		||||
echo ================================================
 | 
			
		||||
ps -eaf|grep -v grep|grep java 1> /dev/null 2>&1
 | 
			
		||||
if [ $? -eq 0 ]
 | 
			
		||||
then
 | 
			
		||||
    echo "Good: Java process is running"
 | 
			
		||||
else
 | 
			
		||||
    echo "ERROR: Java process not running.  Try restarting the SSVM."
 | 
			
		||||
    exit 3
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo ================================================
 | 
			
		||||
echo Tests Complete.  Look for ERROR or WARNING above.  
 | 
			
		||||
 | 
			
		||||
exit 0
 | 
			
		||||
@ -0,0 +1,83 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
 | 
			
		||||
public class AjaxFIFOImageCache {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(AjaxFIFOImageCache.class);
 | 
			
		||||
    
 | 
			
		||||
    private List<Integer> fifoQueue;
 | 
			
		||||
    private Map<Integer, byte[]> cache;
 | 
			
		||||
    private int cacheSize;
 | 
			
		||||
    private int nextKey = 0;
 | 
			
		||||
    
 | 
			
		||||
    public AjaxFIFOImageCache(int cacheSize) {
 | 
			
		||||
        this.cacheSize = cacheSize;
 | 
			
		||||
        fifoQueue = new ArrayList<Integer>();
 | 
			
		||||
        cache = new HashMap<Integer, byte[]>();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public synchronized void clear() {
 | 
			
		||||
        fifoQueue.clear();
 | 
			
		||||
        cache.clear();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public synchronized int putImage(byte[] image) {
 | 
			
		||||
        while(cache.size() >= cacheSize) {
 | 
			
		||||
            Integer keyToRemove = fifoQueue.remove(0);
 | 
			
		||||
            cache.remove(keyToRemove);
 | 
			
		||||
            
 | 
			
		||||
            if(s_logger.isTraceEnabled())
 | 
			
		||||
                s_logger.trace("Remove image from cache, key: " + keyToRemove);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        int key = getNextKey();
 | 
			
		||||
        
 | 
			
		||||
        if(s_logger.isTraceEnabled())
 | 
			
		||||
            s_logger.trace("Add image to cache, key: " + key);
 | 
			
		||||
        
 | 
			
		||||
        cache.put(key, image);
 | 
			
		||||
        fifoQueue.add(key);
 | 
			
		||||
        return key;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public synchronized byte[] getImage(int key) {
 | 
			
		||||
        if (key == 0) {
 | 
			
		||||
            key = nextKey;
 | 
			
		||||
        }
 | 
			
		||||
        if (cache.containsKey(key)) {
 | 
			
		||||
            if (s_logger.isTraceEnabled())
 | 
			
		||||
                s_logger.trace("Retrieve image from cache, key: " + key);
 | 
			
		||||
 | 
			
		||||
            return cache.get(key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (s_logger.isTraceEnabled())
 | 
			
		||||
            s_logger.trace("Image is no long in cache, key: " + key);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public synchronized int getNextKey() {
 | 
			
		||||
        return ++nextKey;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,33 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
public class AuthenticationException extends Exception {
 | 
			
		||||
    private static final long serialVersionUID = -393139302884898842L;
 | 
			
		||||
    public AuthenticationException() {
 | 
			
		||||
        super();
 | 
			
		||||
    }
 | 
			
		||||
    public AuthenticationException(String s) {
 | 
			
		||||
        super(s);
 | 
			
		||||
    }
 | 
			
		||||
    public AuthenticationException(String message, Throwable cause) {
 | 
			
		||||
        super(message, cause);
 | 
			
		||||
    }
 | 
			
		||||
     public AuthenticationException(Throwable cause) {
 | 
			
		||||
         super(cause);
 | 
			
		||||
     }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,499 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.lang.reflect.InvocationTargetException;
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
import java.net.InetSocketAddress;
 | 
			
		||||
import java.net.URISyntaxException;
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
import java.security.NoSuchAlgorithmException;
 | 
			
		||||
import java.security.SecureRandom;
 | 
			
		||||
import java.util.Hashtable;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Properties;
 | 
			
		||||
import java.util.concurrent.Executor;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.codec.binary.Base64;
 | 
			
		||||
import org.apache.log4j.xml.DOMConfigurator;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
import com.google.gson.Gson;
 | 
			
		||||
import com.sun.net.httpserver.HttpServer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * ConsoleProxy, singleton class that manages overall activities in console proxy process. To make legacy code work, we still
 | 
			
		||||
 */
 | 
			
		||||
public class ConsoleProxy {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxy.class);
 | 
			
		||||
    
 | 
			
		||||
    public static final int KEYBOARD_RAW = 0;
 | 
			
		||||
    public static final int KEYBOARD_COOKED = 1;
 | 
			
		||||
    
 | 
			
		||||
    public static int VIEWER_LINGER_SECONDS = 180;
 | 
			
		||||
    
 | 
			
		||||
    public static Object context;
 | 
			
		||||
    
 | 
			
		||||
    // this has become more ugly, to store keystore info passed from management server (we now use management server managed keystore to support
 | 
			
		||||
    // dynamically changing to customer supplied certificate)
 | 
			
		||||
    public static byte[] ksBits;
 | 
			
		||||
    public static String ksPassword;
 | 
			
		||||
    
 | 
			
		||||
    public static Method authMethod;
 | 
			
		||||
    public static Method reportMethod;
 | 
			
		||||
    public static Method ensureRouteMethod;
 | 
			
		||||
    
 | 
			
		||||
    static Hashtable<String, ConsoleProxyClient> connectionMap = new Hashtable<String, ConsoleProxyClient>();
 | 
			
		||||
    static int httpListenPort = 80;
 | 
			
		||||
    static int httpCmdListenPort = 8001;
 | 
			
		||||
    static int reconnectMaxRetry = 5;
 | 
			
		||||
    static int readTimeoutSeconds = 90;
 | 
			
		||||
    static int keyboardType = KEYBOARD_RAW;
 | 
			
		||||
    static String factoryClzName;
 | 
			
		||||
    static boolean standaloneStart = false;
 | 
			
		||||
    
 | 
			
		||||
    static String encryptorPassword = genDefaultEncryptorPassword(); 
 | 
			
		||||
    
 | 
			
		||||
    private static String genDefaultEncryptorPassword() {
 | 
			
		||||
        try {
 | 
			
		||||
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
 | 
			
		||||
            
 | 
			
		||||
            byte[] randomBytes = new byte[16];
 | 
			
		||||
            random.nextBytes(randomBytes);
 | 
			
		||||
            return Base64.encodeBase64String(randomBytes);
 | 
			
		||||
        } catch (NoSuchAlgorithmException e) {
 | 
			
		||||
            s_logger.error("Unexpected exception ", e);
 | 
			
		||||
            assert(false);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return "Dummy";
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static void configLog4j() {
 | 
			
		||||
        URL configUrl = System.class.getResource("/conf/log4j-cloud.xml");
 | 
			
		||||
        if(configUrl == null)
 | 
			
		||||
            configUrl = ClassLoader.getSystemResource("log4j-cloud.xml");
 | 
			
		||||
        
 | 
			
		||||
        if(configUrl == null)
 | 
			
		||||
            configUrl = ClassLoader.getSystemResource("conf/log4j-cloud.xml");
 | 
			
		||||
            
 | 
			
		||||
        if(configUrl != null) {
 | 
			
		||||
            try {
 | 
			
		||||
                System.out.println("Configure log4j using " + configUrl.toURI().toString());
 | 
			
		||||
            } catch (URISyntaxException e1) {
 | 
			
		||||
                e1.printStackTrace();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                File file = new File(configUrl.toURI());
 | 
			
		||||
                
 | 
			
		||||
                System.out.println("Log4j configuration from : " + file.getAbsolutePath());
 | 
			
		||||
                DOMConfigurator.configureAndWatch(file.getAbsolutePath(), 10000);
 | 
			
		||||
            } catch (URISyntaxException e) {
 | 
			
		||||
                System.out.println("Unable to convert log4j configuration Url to URI");
 | 
			
		||||
            }
 | 
			
		||||
            // DOMConfigurator.configure(configUrl);
 | 
			
		||||
        } else {
 | 
			
		||||
            System.out.println("Configure log4j with default properties");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static void configProxy(Properties conf) {
 | 
			
		||||
        s_logger.info("Configure console proxy...");
 | 
			
		||||
        for(Object key : conf.keySet()) {
 | 
			
		||||
            s_logger.info("Property " + (String)key + ": " + conf.getProperty((String)key));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        String s = conf.getProperty("consoleproxy.httpListenPort");
 | 
			
		||||
        if (s!=null) {
 | 
			
		||||
            httpListenPort = Integer.parseInt(s);
 | 
			
		||||
            s_logger.info("Setting httpListenPort=" + s);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        s = conf.getProperty("premium");
 | 
			
		||||
        if(s != null && s.equalsIgnoreCase("true")) {
 | 
			
		||||
            s_logger.info("Premium setting will override settings from consoleproxy.properties, listen at port 443");
 | 
			
		||||
            httpListenPort = 443;
 | 
			
		||||
            factoryClzName = "com.cloud.consoleproxy.ConsoleProxySecureServerFactoryImpl";
 | 
			
		||||
        } else {
 | 
			
		||||
            factoryClzName = ConsoleProxyBaseServerFactoryImpl.class.getName();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        s = conf.getProperty("consoleproxy.httpCmdListenPort");
 | 
			
		||||
        if (s!=null) {
 | 
			
		||||
            httpCmdListenPort = Integer.parseInt(s);
 | 
			
		||||
            s_logger.info("Setting httpCmdListenPort=" + s);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        s = conf.getProperty("consoleproxy.reconnectMaxRetry");
 | 
			
		||||
        if (s!=null) {
 | 
			
		||||
            reconnectMaxRetry = Integer.parseInt(s);
 | 
			
		||||
            s_logger.info("Setting reconnectMaxRetry=" + reconnectMaxRetry);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        s = conf.getProperty("consoleproxy.readTimeoutSeconds");
 | 
			
		||||
        if (s!=null) {
 | 
			
		||||
            readTimeoutSeconds = Integer.parseInt(s);
 | 
			
		||||
            s_logger.info("Setting readTimeoutSeconds=" + readTimeoutSeconds);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static ConsoleProxyServerFactory getHttpServerFactory() {
 | 
			
		||||
        try {
 | 
			
		||||
            Class<?> clz = Class.forName(factoryClzName);
 | 
			
		||||
            try {
 | 
			
		||||
                ConsoleProxyServerFactory factory = (ConsoleProxyServerFactory)clz.newInstance();
 | 
			
		||||
                factory.init(ConsoleProxy.ksBits, ConsoleProxy.ksPassword);
 | 
			
		||||
                return factory;
 | 
			
		||||
            } catch (InstantiationException e) {
 | 
			
		||||
                s_logger.error(e.getMessage(), e);
 | 
			
		||||
                return null;
 | 
			
		||||
            } catch (IllegalAccessException e) {
 | 
			
		||||
                s_logger.error(e.getMessage(), e);
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        } catch (ClassNotFoundException e) {
 | 
			
		||||
            s_logger.warn("Unable to find http server factory class: " + factoryClzName);
 | 
			
		||||
            return new ConsoleProxyBaseServerFactoryImpl();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ConsoleProxyAuthenticationResult authenticateConsoleAccess(ConsoleProxyClientParam param, boolean reauthentication) {
 | 
			
		||||
 | 
			
		||||
        ConsoleProxyAuthenticationResult authResult = new ConsoleProxyAuthenticationResult();
 | 
			
		||||
        authResult.setSuccess(true);
 | 
			
		||||
        authResult.setReauthentication(reauthentication);
 | 
			
		||||
        authResult.setHost(param.getClientHostAddress());
 | 
			
		||||
        authResult.setPort(param.getClientHostPort());
 | 
			
		||||
        
 | 
			
		||||
        if(standaloneStart) {
 | 
			
		||||
            return authResult;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(authMethod != null) {
 | 
			
		||||
            Object result;
 | 
			
		||||
            try {
 | 
			
		||||
                result = authMethod.invoke(ConsoleProxy.context, 
 | 
			
		||||
                    param.getClientHostAddress(), 
 | 
			
		||||
                    String.valueOf(param.getClientHostPort()), 
 | 
			
		||||
                    param.getClientTag(), 
 | 
			
		||||
                    param.getClientHostPassword(), 
 | 
			
		||||
                    param.getTicket(),
 | 
			
		||||
                    new Boolean(reauthentication));
 | 
			
		||||
            } catch (IllegalAccessException e) {
 | 
			
		||||
                s_logger.error("Unable to invoke authenticateConsoleAccess due to IllegalAccessException" + " for vm: " + param.getClientTag(), e);
 | 
			
		||||
                authResult.setSuccess(false);
 | 
			
		||||
                return authResult;
 | 
			
		||||
            } catch (InvocationTargetException e) {
 | 
			
		||||
                s_logger.error("Unable to invoke authenticateConsoleAccess due to InvocationTargetException " + " for vm: " + param.getClientTag(), e);
 | 
			
		||||
                authResult.setSuccess(false);
 | 
			
		||||
                return authResult;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if(result != null && result instanceof String) {
 | 
			
		||||
                authResult = new Gson().fromJson((String)result, ConsoleProxyAuthenticationResult.class);
 | 
			
		||||
            } else {
 | 
			
		||||
                s_logger.error("Invalid authentication return object " + result + " for vm: " + param.getClientTag() + ", decline the access");
 | 
			
		||||
                authResult.setSuccess(false);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            s_logger.warn("Private channel towards management server is not setup. Switch to offline mode and allow access to vm: " + param.getClientTag());
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return authResult;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static void reportLoadInfo(String gsonLoadInfo) {
 | 
			
		||||
        if(reportMethod != null) {
 | 
			
		||||
            try {
 | 
			
		||||
                reportMethod.invoke(ConsoleProxy.context, gsonLoadInfo);
 | 
			
		||||
            } catch (IllegalAccessException e) {
 | 
			
		||||
                s_logger.error("Unable to invoke reportLoadInfo due to " + e.getMessage());
 | 
			
		||||
            } catch (InvocationTargetException e) {
 | 
			
		||||
                s_logger.error("Unable to invoke reportLoadInfo due to " + e.getMessage());
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            s_logger.warn("Private channel towards management server is not setup. Switch to offline mode and ignore load report");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static void ensureRoute(String address) {
 | 
			
		||||
        if(ensureRouteMethod != null) {
 | 
			
		||||
            try {
 | 
			
		||||
                ensureRouteMethod.invoke(ConsoleProxy.context, address);
 | 
			
		||||
            } catch (IllegalAccessException e) {
 | 
			
		||||
                s_logger.error("Unable to invoke ensureRoute due to " + e.getMessage());
 | 
			
		||||
            } catch (InvocationTargetException e) {
 | 
			
		||||
                s_logger.error("Unable to invoke ensureRoute due to " + e.getMessage());
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            s_logger.warn("Unable to find ensureRoute method, console proxy agent is not up to date");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void startWithContext(Properties conf, Object context, byte[] ksBits, String ksPassword) {
 | 
			
		||||
        s_logger.info("Start console proxy with context");
 | 
			
		||||
        if(conf != null) {
 | 
			
		||||
            for(Object key : conf.keySet()) {
 | 
			
		||||
                s_logger.info("Context property " + (String)key + ": " + conf.getProperty((String)key));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        configLog4j();
 | 
			
		||||
        Logger.setFactory(new ConsoleProxyLoggerFactory());
 | 
			
		||||
        
 | 
			
		||||
        // Using reflection to setup private/secure communication channel towards management server
 | 
			
		||||
        ConsoleProxy.context = context;
 | 
			
		||||
        ConsoleProxy.ksBits = ksBits;
 | 
			
		||||
        ConsoleProxy.ksPassword = ksPassword;
 | 
			
		||||
        try {
 | 
			
		||||
            Class<?> contextClazz = Class.forName("com.cloud.agent.resource.consoleproxy.ConsoleProxyResource");
 | 
			
		||||
            authMethod = contextClazz.getDeclaredMethod("authenticateConsoleAccess", String.class, String.class, String.class, String.class, String.class, Boolean.class);
 | 
			
		||||
            reportMethod = contextClazz.getDeclaredMethod("reportLoadInfo", String.class);
 | 
			
		||||
            ensureRouteMethod = contextClazz.getDeclaredMethod("ensureRoute", String.class);
 | 
			
		||||
        } catch (SecurityException e) {
 | 
			
		||||
            s_logger.error("Unable to setup private channel due to SecurityException", e);
 | 
			
		||||
        } catch (NoSuchMethodException e) {
 | 
			
		||||
            s_logger.error("Unable to setup private channel due to NoSuchMethodException", e);
 | 
			
		||||
        } catch (IllegalArgumentException e) {
 | 
			
		||||
            s_logger.error("Unable to setup private channel due to IllegalArgumentException", e);
 | 
			
		||||
        } catch(ClassNotFoundException e) {
 | 
			
		||||
            s_logger.error("Unable to setup private channel due to ClassNotFoundException", e);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // merge properties from conf file
 | 
			
		||||
        InputStream confs = ConsoleProxy.class.getResourceAsStream("/conf/consoleproxy.properties");
 | 
			
		||||
        Properties props = new Properties();
 | 
			
		||||
        if (confs == null) {
 | 
			
		||||
            s_logger.info("Can't load consoleproxy.properties from classpath, will use default configuration");
 | 
			
		||||
        } else {
 | 
			
		||||
            try {
 | 
			
		||||
                props.load(confs);
 | 
			
		||||
                
 | 
			
		||||
                for(Object key : props.keySet()) {
 | 
			
		||||
                    // give properties passed via context high priority, treat properties from consoleproxy.properties
 | 
			
		||||
                    // as default values
 | 
			
		||||
                    if(conf.get(key) == null)
 | 
			
		||||
                        conf.put(key, props.get(key));
 | 
			
		||||
                }
 | 
			
		||||
            }  catch (Exception e) {
 | 
			
		||||
                s_logger.error(e.toString(), e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        start(conf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void start(Properties conf) {
 | 
			
		||||
        System.setProperty("java.awt.headless", "true");
 | 
			
		||||
        
 | 
			
		||||
        configProxy(conf);
 | 
			
		||||
        
 | 
			
		||||
        ConsoleProxyServerFactory factory = getHttpServerFactory();
 | 
			
		||||
        if(factory == null) {
 | 
			
		||||
            s_logger.error("Unable to load console proxy server factory");
 | 
			
		||||
            System.exit(1);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(httpListenPort != 0) {
 | 
			
		||||
            startupHttpMain();
 | 
			
		||||
        } else {
 | 
			
		||||
            s_logger.error("A valid HTTP server port is required to be specified, please check your consoleproxy.httpListenPort settings");
 | 
			
		||||
            System.exit(1);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(httpCmdListenPort > 0) {
 | 
			
		||||
            startupHttpCmdPort();
 | 
			
		||||
        } else {
 | 
			
		||||
            s_logger.info("HTTP command port is disabled");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        ConsoleProxyGCThread cthread = new ConsoleProxyGCThread(connectionMap);
 | 
			
		||||
        cthread.setName("Console Proxy GC Thread");
 | 
			
		||||
        cthread.start();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static void startupHttpMain() {
 | 
			
		||||
        try {
 | 
			
		||||
            ConsoleProxyServerFactory factory = getHttpServerFactory();
 | 
			
		||||
            if(factory == null) {
 | 
			
		||||
                s_logger.error("Unable to load HTTP server factory");
 | 
			
		||||
                System.exit(1);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            HttpServer server = factory.createHttpServerInstance(httpListenPort);
 | 
			
		||||
            server.createContext("/getscreen", new ConsoleProxyThumbnailHandler());
 | 
			
		||||
            server.createContext("/resource/", new ConsoleProxyResourceHandler());
 | 
			
		||||
            server.createContext("/ajax", new ConsoleProxyAjaxHandler());
 | 
			
		||||
            server.createContext("/ajaximg", new ConsoleProxyAjaxImageHandler());
 | 
			
		||||
            server.setExecutor(new ThreadExecutor()); // creates a default executor
 | 
			
		||||
            server.start();
 | 
			
		||||
        } catch(Exception e) {
 | 
			
		||||
            s_logger.error(e.getMessage(), e);
 | 
			
		||||
            System.exit(1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static void startupHttpCmdPort() {
 | 
			
		||||
        try {
 | 
			
		||||
            s_logger.info("Listening for HTTP CMDs on port " + httpCmdListenPort);
 | 
			
		||||
            HttpServer cmdServer = HttpServer.create(new InetSocketAddress(httpCmdListenPort), 2);
 | 
			
		||||
            cmdServer.createContext("/cmd", new ConsoleProxyCmdHandler());
 | 
			
		||||
            cmdServer.setExecutor(new ThreadExecutor()); // creates a default executor
 | 
			
		||||
            cmdServer.start();
 | 
			
		||||
        } catch(Exception e) {
 | 
			
		||||
            s_logger.error(e.getMessage(), e);
 | 
			
		||||
            System.exit(1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static void main(String[] argv) {
 | 
			
		||||
        standaloneStart = true;
 | 
			
		||||
        configLog4j();
 | 
			
		||||
        Logger.setFactory(new ConsoleProxyLoggerFactory());
 | 
			
		||||
        
 | 
			
		||||
        InputStream confs = ConsoleProxy.class.getResourceAsStream("/conf/consoleproxy.properties");
 | 
			
		||||
        Properties conf = new Properties();
 | 
			
		||||
        if (confs == null) {
 | 
			
		||||
            s_logger.info("Can't load consoleproxy.properties from classpath, will use default configuration");
 | 
			
		||||
        } else {
 | 
			
		||||
            try {
 | 
			
		||||
                conf.load(confs);
 | 
			
		||||
            }  catch (Exception e) {
 | 
			
		||||
                s_logger.error(e.toString(), e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        start(conf);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static ConsoleProxyClient getVncViewer(ConsoleProxyClientParam param) throws Exception {
 | 
			
		||||
        ConsoleProxyClient viewer = null;
 | 
			
		||||
        
 | 
			
		||||
        boolean reportLoadChange = false;
 | 
			
		||||
        String clientKey = param.getClientMapKey();
 | 
			
		||||
        synchronized (connectionMap) {
 | 
			
		||||
            viewer = connectionMap.get(clientKey);
 | 
			
		||||
            if (viewer == null) {
 | 
			
		||||
                viewer = new ConsoleProxyVncClient();
 | 
			
		||||
                viewer.initClient(param);
 | 
			
		||||
                connectionMap.put(clientKey, viewer);
 | 
			
		||||
                s_logger.info("Added viewer object " + viewer);
 | 
			
		||||
                
 | 
			
		||||
                reportLoadChange = true;
 | 
			
		||||
            } else if (!viewer.isFrontEndAlive()) {
 | 
			
		||||
                s_logger.info("The rfb thread died, reinitializing the viewer " + viewer);
 | 
			
		||||
                viewer.initClient(param);
 | 
			
		||||
            } else if (!param.getClientHostPassword().equals(viewer.getClientHostPassword())) {
 | 
			
		||||
                s_logger.warn("Bad sid detected(VNC port may be reused). sid in session: " + viewer.getClientHostPassword()
 | 
			
		||||
                    + ", sid in request: " + param.getClientHostPassword());
 | 
			
		||||
                viewer.initClient(param);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(reportLoadChange) {
 | 
			
		||||
            ConsoleProxyClientStatsCollector statsCollector = getStatsCollector();
 | 
			
		||||
            String loadInfo = statsCollector.getStatsReport();
 | 
			
		||||
            reportLoadInfo(loadInfo);
 | 
			
		||||
            if(s_logger.isDebugEnabled())
 | 
			
		||||
                s_logger.debug("Report load change : " + loadInfo);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return viewer;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static ConsoleProxyClient getAjaxVncViewer(ConsoleProxyClientParam param, String ajaxSession) throws Exception {
 | 
			
		||||
        
 | 
			
		||||
        boolean reportLoadChange = false;
 | 
			
		||||
        String clientKey = param.getClientMapKey();
 | 
			
		||||
        synchronized (connectionMap) {
 | 
			
		||||
            ConsoleProxyClient viewer = connectionMap.get(clientKey);
 | 
			
		||||
            if (viewer == null) {
 | 
			
		||||
                viewer = new ConsoleProxyVncClient();
 | 
			
		||||
                viewer.initClient(param);
 | 
			
		||||
                
 | 
			
		||||
                connectionMap.put(clientKey, viewer);
 | 
			
		||||
                s_logger.info("Added viewer object " + viewer);
 | 
			
		||||
                reportLoadChange = true;
 | 
			
		||||
            } else if (!viewer.isFrontEndAlive()) {
 | 
			
		||||
                s_logger.info("The rfb thread died, reinitializing the viewer " + viewer);
 | 
			
		||||
                viewer.initClient(param);
 | 
			
		||||
            } else if (!param.getClientHostPassword().equals(viewer.getClientHostPassword())) {
 | 
			
		||||
                s_logger.warn("Bad sid detected(VNC port may be reused). sid in session: " 
 | 
			
		||||
                    + viewer.getClientHostPassword() + ", sid in request: " + param.getClientHostPassword());
 | 
			
		||||
                viewer.initClient(param);
 | 
			
		||||
            } else {
 | 
			
		||||
                if(ajaxSession == null || ajaxSession.isEmpty())
 | 
			
		||||
                    authenticationExternally(param);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if(reportLoadChange) {
 | 
			
		||||
                ConsoleProxyClientStatsCollector statsCollector = getStatsCollector();
 | 
			
		||||
                String loadInfo = statsCollector.getStatsReport();
 | 
			
		||||
                reportLoadInfo(loadInfo);
 | 
			
		||||
                if(s_logger.isDebugEnabled())
 | 
			
		||||
                    s_logger.debug("Report load change : " + loadInfo);
 | 
			
		||||
            }
 | 
			
		||||
            return viewer;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static void removeViewer(ConsoleProxyClient viewer) {
 | 
			
		||||
        synchronized (connectionMap) {
 | 
			
		||||
            for(Map.Entry<String, ConsoleProxyClient> entry : connectionMap.entrySet()) {
 | 
			
		||||
                if(entry.getValue() == viewer) {
 | 
			
		||||
                    connectionMap.remove(entry.getKey());
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static ConsoleProxyClientStatsCollector getStatsCollector() {
 | 
			
		||||
        return new ConsoleProxyClientStatsCollector(connectionMap);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static void authenticationExternally(ConsoleProxyClientParam param) throws AuthenticationException {
 | 
			
		||||
        ConsoleProxyAuthenticationResult authResult = authenticateConsoleAccess(param, false);
 | 
			
		||||
        
 | 
			
		||||
        if(authResult == null || !authResult.isSuccess()) {
 | 
			
		||||
            s_logger.warn("External authenticator failed authencation request for vm " + param.getClientTag() + " with sid " + param.getClientHostPassword());
 | 
			
		||||
            
 | 
			
		||||
            throw new AuthenticationException("External authenticator failed request for vm " + param.getClientTag() + " with sid " + param.getClientHostPassword());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static ConsoleProxyAuthenticationResult reAuthenticationExternally(ConsoleProxyClientParam param) {
 | 
			
		||||
        return authenticateConsoleAccess(param, true);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static String getEncryptorPassword() { 
 | 
			
		||||
        return encryptorPassword; 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static void setEncryptorPassword(String password) {
 | 
			
		||||
        encryptorPassword = password;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    static class ThreadExecutor implements Executor {
 | 
			
		||||
         public void execute(Runnable r) {
 | 
			
		||||
             new Thread(r).start();
 | 
			
		||||
         }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,406 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.InputStreamReader;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.net.URLDecoder;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
import com.sun.net.httpserver.Headers;
 | 
			
		||||
import com.sun.net.httpserver.HttpExchange;
 | 
			
		||||
import com.sun.net.httpserver.HttpHandler;
 | 
			
		||||
 | 
			
		||||
public class ConsoleProxyAjaxHandler implements HttpHandler {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxyAjaxHandler.class);
 | 
			
		||||
    
 | 
			
		||||
    public ConsoleProxyAjaxHandler() {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void handle(HttpExchange t) throws IOException {
 | 
			
		||||
        try {
 | 
			
		||||
            if(s_logger.isTraceEnabled())
 | 
			
		||||
                s_logger.trace("AjaxHandler " + t.getRequestURI());
 | 
			
		||||
            
 | 
			
		||||
            long startTick = System.currentTimeMillis();
 | 
			
		||||
            
 | 
			
		||||
            doHandle(t);
 | 
			
		||||
            
 | 
			
		||||
            if(s_logger.isTraceEnabled())
 | 
			
		||||
                s_logger.trace(t.getRequestURI() + " process time " + (System.currentTimeMillis() - startTick) + " ms");
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            throw e;
 | 
			
		||||
        } catch (IllegalArgumentException e) {
 | 
			
		||||
            s_logger.warn("Exception, ", e);
 | 
			
		||||
            t.sendResponseHeaders(400, -1);     // bad request
 | 
			
		||||
        } catch(Throwable e) {
 | 
			
		||||
            s_logger.error("Unexpected exception, ", e);
 | 
			
		||||
            t.sendResponseHeaders(500, -1);     // server error
 | 
			
		||||
        } finally {
 | 
			
		||||
            t.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void doHandle(HttpExchange t) throws Exception, IllegalArgumentException {
 | 
			
		||||
        String queries = t.getRequestURI().getQuery();
 | 
			
		||||
        if(s_logger.isTraceEnabled())
 | 
			
		||||
            s_logger.trace("Handle AJAX request: " + queries);
 | 
			
		||||
        
 | 
			
		||||
        Map<String, String> queryMap = ConsoleProxyHttpHandlerHelper.getQueryMap(queries);
 | 
			
		||||
        
 | 
			
		||||
        String host = queryMap.get("host");
 | 
			
		||||
        String portStr = queryMap.get("port");
 | 
			
		||||
        String sid = queryMap.get("sid");
 | 
			
		||||
        String tag = queryMap.get("tag");
 | 
			
		||||
        String ticket = queryMap.get("ticket");
 | 
			
		||||
        String ajaxSessionIdStr = queryMap.get("sess");
 | 
			
		||||
        String eventStr = queryMap.get("event");
 | 
			
		||||
        String console_url = queryMap.get("consoleurl");
 | 
			
		||||
        String console_host_session = queryMap.get("sessionref");
 | 
			
		||||
        
 | 
			
		||||
        if(tag == null)
 | 
			
		||||
            tag = "";
 | 
			
		||||
        
 | 
			
		||||
        long ajaxSessionId = 0;
 | 
			
		||||
        int event = 0;
 | 
			
		||||
        
 | 
			
		||||
        int port;
 | 
			
		||||
 | 
			
		||||
        if(host == null || portStr == null || sid == null) 
 | 
			
		||||
            throw new IllegalArgumentException();
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
            port = Integer.parseInt(portStr);
 | 
			
		||||
        } catch (NumberFormatException e) {
 | 
			
		||||
            s_logger.warn("Invalid number parameter in query string: " + portStr);
 | 
			
		||||
            throw new IllegalArgumentException(e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(ajaxSessionIdStr != null) {
 | 
			
		||||
            try {
 | 
			
		||||
                ajaxSessionId = Long.parseLong(ajaxSessionIdStr);
 | 
			
		||||
            } catch (NumberFormatException e) {
 | 
			
		||||
                s_logger.warn("Invalid number parameter in query string: " + ajaxSessionIdStr);
 | 
			
		||||
                throw new IllegalArgumentException(e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(eventStr != null) {
 | 
			
		||||
            try {
 | 
			
		||||
                event = Integer.parseInt(eventStr);
 | 
			
		||||
            } catch (NumberFormatException e) {
 | 
			
		||||
                s_logger.warn("Invalid number parameter in query string: " + eventStr);
 | 
			
		||||
                throw new IllegalArgumentException(e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        ConsoleProxyClient viewer = null;
 | 
			
		||||
        try {
 | 
			
		||||
            ConsoleProxyClientParam param = new ConsoleProxyClientParam();
 | 
			
		||||
            param.setClientHostAddress(host);
 | 
			
		||||
            param.setClientHostPort(port);
 | 
			
		||||
            param.setClientHostPassword(sid);
 | 
			
		||||
            param.setClientTag(tag);
 | 
			
		||||
            param.setTicket(ticket);
 | 
			
		||||
            param.setClientTunnelUrl(console_url);
 | 
			
		||||
            param.setClientTunnelSession(console_host_session);
 | 
			
		||||
            
 | 
			
		||||
            viewer = ConsoleProxy.getAjaxVncViewer(param, ajaxSessionIdStr);
 | 
			
		||||
        } catch(Exception e) {
 | 
			
		||||
 | 
			
		||||
            s_logger.warn("Failed to create viewer due to " + e.getMessage(), e);
 | 
			
		||||
 | 
			
		||||
            String[] content = new String[] {
 | 
			
		||||
                "<html><head></head><body>",
 | 
			
		||||
                "<div id=\"main_panel\" tabindex=\"1\">",
 | 
			
		||||
                "<p>Access is denied for the console session. Please close the window and retry again</p>",
 | 
			
		||||
                "</div></body></html>"
 | 
			
		||||
            };
 | 
			
		||||
            
 | 
			
		||||
            StringBuffer sb = new StringBuffer();
 | 
			
		||||
            for(int i = 0; i < content.length; i++)
 | 
			
		||||
                sb.append(content[i]);
 | 
			
		||||
            
 | 
			
		||||
            sendResponse(t, "text/html", sb.toString());
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(event != 0) {
 | 
			
		||||
            if(ajaxSessionId != 0 && ajaxSessionId == viewer.getAjaxSessionId()) {
 | 
			
		||||
                if(event == 7) {
 | 
			
		||||
                    // client send over an event bag
 | 
			
		||||
                    InputStream is = t.getRequestBody();
 | 
			
		||||
                    handleClientEventBag(viewer, convertStreamToString(is, true));
 | 
			
		||||
                } else {
 | 
			
		||||
                    handleClientEvent(viewer, event, queryMap);
 | 
			
		||||
                }
 | 
			
		||||
                sendResponse(t, "text/html", "OK");
 | 
			
		||||
            } else {
 | 
			
		||||
                if(s_logger.isDebugEnabled())
 | 
			
		||||
                    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");
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            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());
 | 
			
		||||
                handleClientKickoff(t, viewer);
 | 
			
		||||
            } else if(ajaxSessionId == 0) {
 | 
			
		||||
                if(s_logger.isDebugEnabled())
 | 
			
		||||
                    s_logger.debug("Ajax request indicates a fresh client start");
 | 
			
		||||
        
 | 
			
		||||
                String title = queryMap.get("t");
 | 
			
		||||
                String guest = queryMap.get("guest");
 | 
			
		||||
                handleClientStart(t, viewer, title != null ? title : "", guest);
 | 
			
		||||
            } else {
 | 
			
		||||
                
 | 
			
		||||
                if(s_logger.isTraceEnabled())
 | 
			
		||||
                    s_logger.trace("Ajax request indicates client update");
 | 
			
		||||
                
 | 
			
		||||
                handleClientUpdate(t, viewer);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static String convertStreamToString(InputStream is, boolean closeStreamAfterRead) { 
 | 
			
		||||
        BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 
 | 
			
		||||
        StringBuilder sb = new StringBuilder(); 
 | 
			
		||||
        String line = null; 
 | 
			
		||||
        try { 
 | 
			
		||||
            while ((line = reader.readLine()) != null) { 
 | 
			
		||||
                sb.append(line + "\n"); 
 | 
			
		||||
            } 
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            s_logger.warn("Exception while reading request body: ", e);
 | 
			
		||||
        } finally {
 | 
			
		||||
            if(closeStreamAfterRead) {
 | 
			
		||||
                try { 
 | 
			
		||||
                    is.close(); 
 | 
			
		||||
                } catch (IOException e) { 
 | 
			
		||||
                } 
 | 
			
		||||
            }
 | 
			
		||||
        } 
 | 
			
		||||
        return sb.toString(); 
 | 
			
		||||
    }   
 | 
			
		||||
    
 | 
			
		||||
    private void sendResponse(HttpExchange t, String contentType, String response) throws IOException {
 | 
			
		||||
        Headers hds = t.getResponseHeaders();
 | 
			
		||||
        hds.set("Content-Type", contentType);
 | 
			
		||||
    
 | 
			
		||||
        t.sendResponseHeaders(200, response.length());
 | 
			
		||||
        OutputStream os = t.getResponseBody();
 | 
			
		||||
        try {
 | 
			
		||||
            os.write(response.getBytes());
 | 
			
		||||
        } finally {
 | 
			
		||||
            os.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @SuppressWarnings("deprecation")
 | 
			
		||||
    private void handleClientEventBag(ConsoleProxyClient viewer, String requestData) {
 | 
			
		||||
        if(s_logger.isTraceEnabled())
 | 
			
		||||
            s_logger.trace("Handle event bag, event bag: " + requestData);
 | 
			
		||||
        
 | 
			
		||||
        int start = requestData.indexOf("=");
 | 
			
		||||
        if(start < 0)
 | 
			
		||||
            start = 0;
 | 
			
		||||
        else if(start > 0)
 | 
			
		||||
            start++;
 | 
			
		||||
        String data = URLDecoder.decode(requestData.substring(start));
 | 
			
		||||
        String[] tokens = data.split("\\|");
 | 
			
		||||
        if(tokens != null && tokens.length > 0) {
 | 
			
		||||
            int count = 0;
 | 
			
		||||
            try {
 | 
			
		||||
                count = Integer.parseInt(tokens[0]);
 | 
			
		||||
                int parsePos = 1;
 | 
			
		||||
                int type, event, x, y, code, modifiers;
 | 
			
		||||
                for(int i = 0; i < count; i++) {
 | 
			
		||||
                    type = Integer.parseInt(tokens[parsePos++]);
 | 
			
		||||
                    if(type == 1)   {
 | 
			
		||||
                        // mouse event
 | 
			
		||||
                        event = Integer.parseInt(tokens[parsePos++]);
 | 
			
		||||
                        x = Integer.parseInt(tokens[parsePos++]);
 | 
			
		||||
                        y = Integer.parseInt(tokens[parsePos++]);
 | 
			
		||||
                        code = Integer.parseInt(tokens[parsePos++]);
 | 
			
		||||
                        modifiers = Integer.parseInt(tokens[parsePos++]);
 | 
			
		||||
                        
 | 
			
		||||
                        Map<String, String> queryMap = new HashMap<String, String>();
 | 
			
		||||
                        queryMap.put("event", String.valueOf(event));
 | 
			
		||||
                        queryMap.put("x", String.valueOf(x));
 | 
			
		||||
                        queryMap.put("y", String.valueOf(y));
 | 
			
		||||
                        queryMap.put("code", String.valueOf(code));
 | 
			
		||||
                        queryMap.put("modifier", String.valueOf(modifiers));
 | 
			
		||||
                        handleClientEvent(viewer, event, queryMap);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // keyboard event
 | 
			
		||||
                        event = Integer.parseInt(tokens[parsePos++]);
 | 
			
		||||
                        code = Integer.parseInt(tokens[parsePos++]);
 | 
			
		||||
                        modifiers = Integer.parseInt(tokens[parsePos++]);
 | 
			
		||||
                        
 | 
			
		||||
                        Map<String, String> queryMap = new HashMap<String, String>();
 | 
			
		||||
                        queryMap.put("event", String.valueOf(event));
 | 
			
		||||
                        queryMap.put("code", String.valueOf(code));
 | 
			
		||||
                        queryMap.put("modifier", String.valueOf(modifiers));
 | 
			
		||||
                        handleClientEvent(viewer, event, queryMap);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } catch(NumberFormatException e) {
 | 
			
		||||
                s_logger.warn("Exception in handle client event bag: " + data + ", ", e);
 | 
			
		||||
            } catch(Exception e) {
 | 
			
		||||
                s_logger.warn("Exception in handle client event bag: " + data + ", ", e);
 | 
			
		||||
            } catch(OutOfMemoryError e) {
 | 
			
		||||
                s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched");
 | 
			
		||||
                System.exit(1);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void handleClientEvent(ConsoleProxyClient viewer, int event, Map<String, String> queryMap) {
 | 
			
		||||
        int code = 0;
 | 
			
		||||
        int x = 0, y = 0;
 | 
			
		||||
        int modifiers = 0;
 | 
			
		||||
        
 | 
			
		||||
        String str;
 | 
			
		||||
        switch(event) {
 | 
			
		||||
        case 1:     // mouse move
 | 
			
		||||
        case 2:     // mouse down
 | 
			
		||||
        case 3:     // mouse up
 | 
			
		||||
        case 8:     // mouse double click
 | 
			
		||||
            str = queryMap.get("x");
 | 
			
		||||
            if(str != null) {
 | 
			
		||||
                try {
 | 
			
		||||
                    x = Integer.parseInt(str);
 | 
			
		||||
                } catch (NumberFormatException e) {
 | 
			
		||||
                    s_logger.warn("Invalid number parameter in query string: " + str);
 | 
			
		||||
                    throw new IllegalArgumentException(e);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            str = queryMap.get("y");
 | 
			
		||||
            if(str != null) {
 | 
			
		||||
                try {
 | 
			
		||||
                    y = Integer.parseInt(str);
 | 
			
		||||
                } catch (NumberFormatException e) {
 | 
			
		||||
                    s_logger.warn("Invalid number parameter in query string: " + str);
 | 
			
		||||
                    throw new IllegalArgumentException(e);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if(event != 1) {
 | 
			
		||||
                str = queryMap.get("code");
 | 
			
		||||
                try {
 | 
			
		||||
                    code = Integer.parseInt(str);
 | 
			
		||||
                } catch (NumberFormatException e) {
 | 
			
		||||
                    s_logger.warn("Invalid number parameter in query string: " + str);
 | 
			
		||||
                    throw new IllegalArgumentException(e);
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                str = queryMap.get("modifier");
 | 
			
		||||
                try {
 | 
			
		||||
                    modifiers = Integer.parseInt(str);
 | 
			
		||||
                } catch (NumberFormatException e) {
 | 
			
		||||
                    s_logger.warn("Invalid number parameter in query string: " + str);
 | 
			
		||||
                    throw new IllegalArgumentException(e);
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if(s_logger.isTraceEnabled())
 | 
			
		||||
                    s_logger.trace("Handle client mouse event. event: " + event + ", x: " + x + ", y: " + y + ", button: " + code + ", modifier: " + modifiers);
 | 
			
		||||
            } else {
 | 
			
		||||
                if(s_logger.isTraceEnabled())
 | 
			
		||||
                    s_logger.trace("Handle client mouse move event. x: " + x + ", y: " + y);
 | 
			
		||||
            }
 | 
			
		||||
            viewer.sendClientMouseEvent(InputEventType.fromEventCode(event), x, y, code, modifiers);
 | 
			
		||||
            break;
 | 
			
		||||
            
 | 
			
		||||
        case 4:     // key press
 | 
			
		||||
        case 5:     // key down
 | 
			
		||||
        case 6:     // key up
 | 
			
		||||
            str = queryMap.get("code");
 | 
			
		||||
            try {
 | 
			
		||||
                code = Integer.parseInt(str);
 | 
			
		||||
            } catch (NumberFormatException e) {
 | 
			
		||||
                s_logger.warn("Invalid number parameter in query string: " + str);
 | 
			
		||||
                throw new IllegalArgumentException(e);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            str = queryMap.get("modifier");
 | 
			
		||||
            try {
 | 
			
		||||
                modifiers = Integer.parseInt(str);
 | 
			
		||||
            } catch (NumberFormatException e) {
 | 
			
		||||
                s_logger.warn("Invalid number parameter in query string: " + str);
 | 
			
		||||
                throw new IllegalArgumentException(e);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if(s_logger.isDebugEnabled())
 | 
			
		||||
                s_logger.debug("Handle client keyboard event. event: " + event + ", code: " + code + ", modifier: " + modifiers);
 | 
			
		||||
            viewer.sendClientRawKeyboardEvent(InputEventType.fromEventCode(event), code, modifiers);
 | 
			
		||||
            break;
 | 
			
		||||
            
 | 
			
		||||
        default :
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void handleClientKickoff(HttpExchange t, ConsoleProxyClient viewer) throws IOException {
 | 
			
		||||
        String response = viewer.onAjaxClientKickoff();
 | 
			
		||||
        t.sendResponseHeaders(200, response.length());
 | 
			
		||||
        OutputStream os = t.getResponseBody();
 | 
			
		||||
        try {
 | 
			
		||||
            os.write(response.getBytes());
 | 
			
		||||
        } finally {
 | 
			
		||||
            os.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void handleClientStart(HttpExchange t, ConsoleProxyClient viewer, String title, String guest) throws IOException {
 | 
			
		||||
        List<String> languages = t.getRequestHeaders().get("Accept-Language");
 | 
			
		||||
        String response = viewer.onAjaxClientStart(title, languages, guest);
 | 
			
		||||
        
 | 
			
		||||
        Headers hds = t.getResponseHeaders();
 | 
			
		||||
        hds.set("Content-Type", "text/html");
 | 
			
		||||
        hds.set("Cache-Control", "no-cache");
 | 
			
		||||
        hds.set("Cache-Control", "no-store");
 | 
			
		||||
        t.sendResponseHeaders(200, response.length());
 | 
			
		||||
        
 | 
			
		||||
        OutputStream os = t.getResponseBody();
 | 
			
		||||
        try {
 | 
			
		||||
            os.write(response.getBytes());
 | 
			
		||||
        } finally {
 | 
			
		||||
            os.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void handleClientUpdate(HttpExchange t, ConsoleProxyClient viewer) throws IOException {
 | 
			
		||||
        String response = viewer.onAjaxClientUpdate();
 | 
			
		||||
        
 | 
			
		||||
        Headers hds = t.getResponseHeaders();
 | 
			
		||||
        hds.set("Content-Type", "text/javascript");
 | 
			
		||||
        t.sendResponseHeaders(200, response.length());
 | 
			
		||||
        
 | 
			
		||||
        OutputStream os = t.getResponseBody();
 | 
			
		||||
        try {
 | 
			
		||||
            os.write(response.getBytes());
 | 
			
		||||
        } finally {
 | 
			
		||||
            os.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,159 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.awt.Graphics2D;
 | 
			
		||||
import java.awt.Image;
 | 
			
		||||
import java.awt.image.BufferedImage;
 | 
			
		||||
import java.io.ByteArrayOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
import com.sun.net.httpserver.Headers;
 | 
			
		||||
import com.sun.net.httpserver.HttpExchange;
 | 
			
		||||
import com.sun.net.httpserver.HttpHandler;
 | 
			
		||||
 | 
			
		||||
public class ConsoleProxyAjaxImageHandler implements HttpHandler {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxyAjaxImageHandler.class);
 | 
			
		||||
 | 
			
		||||
    public void handle(HttpExchange t) throws IOException {
 | 
			
		||||
        try {
 | 
			
		||||
            if(s_logger.isDebugEnabled())
 | 
			
		||||
                s_logger.debug("AjaxImageHandler " + t.getRequestURI());
 | 
			
		||||
            
 | 
			
		||||
            long startTick = System.currentTimeMillis();
 | 
			
		||||
            
 | 
			
		||||
            doHandle(t);
 | 
			
		||||
            
 | 
			
		||||
            if(s_logger.isDebugEnabled())
 | 
			
		||||
                s_logger.debug(t.getRequestURI() + "Process time " + (System.currentTimeMillis() - startTick) + " ms");
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            throw e;
 | 
			
		||||
        } catch (IllegalArgumentException e) {
 | 
			
		||||
            s_logger.warn("Exception, ", e);
 | 
			
		||||
            t.sendResponseHeaders(400, -1);     // bad request
 | 
			
		||||
        } catch(OutOfMemoryError e) {
 | 
			
		||||
            s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched");
 | 
			
		||||
            System.exit(1);
 | 
			
		||||
        } catch(Throwable e) {
 | 
			
		||||
            s_logger.error("Unexpected exception, ", e);
 | 
			
		||||
            t.sendResponseHeaders(500, -1);     // server error
 | 
			
		||||
        } finally {
 | 
			
		||||
            t.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void doHandle(HttpExchange t) throws Exception, IllegalArgumentException {
 | 
			
		||||
        String queries = t.getRequestURI().getQuery();
 | 
			
		||||
        Map<String, String> queryMap = ConsoleProxyHttpHandlerHelper.getQueryMap(queries);
 | 
			
		||||
        
 | 
			
		||||
        String host = queryMap.get("host");
 | 
			
		||||
        String portStr = queryMap.get("port");
 | 
			
		||||
        String sid = queryMap.get("sid");
 | 
			
		||||
        String tag = queryMap.get("tag");
 | 
			
		||||
        String ticket = queryMap.get("ticket");
 | 
			
		||||
        String keyStr = queryMap.get("key");
 | 
			
		||||
        String console_url = queryMap.get("consoleurl");
 | 
			
		||||
        String console_host_session = queryMap.get("sessionref");
 | 
			
		||||
                String w = queryMap.get("w");           
 | 
			
		||||
                String h = queryMap.get("h");
 | 
			
		||||
        
 | 
			
		||||
                int key = 0;
 | 
			
		||||
                int width = 144;
 | 
			
		||||
                int height = 110;
 | 
			
		||||
        
 | 
			
		||||
        if(tag == null)
 | 
			
		||||
            tag = "";
 | 
			
		||||
        
 | 
			
		||||
        int port;
 | 
			
		||||
        if(host == null || portStr == null || sid == null)
 | 
			
		||||
            throw new IllegalArgumentException();
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
            port = Integer.parseInt(portStr);
 | 
			
		||||
        } catch (NumberFormatException e) {
 | 
			
		||||
            s_logger.warn("Invalid numeric parameter in query string: " + portStr);
 | 
			
		||||
            throw new IllegalArgumentException(e);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
                    if (keyStr != null)
 | 
			
		||||
                        key = Integer.parseInt(keyStr);
 | 
			
		||||
                    if(null != w)
 | 
			
		||||
                       width = Integer.parseInt(w);
 | 
			
		||||
 | 
			
		||||
                    if(null != h)
 | 
			
		||||
                       height = Integer.parseInt(h);
 | 
			
		||||
 | 
			
		||||
             } catch (NumberFormatException e) {
 | 
			
		||||
            s_logger.warn("Invalid numeric parameter in query string: " + keyStr);
 | 
			
		||||
            throw new IllegalArgumentException(e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ConsoleProxyClientParam param = new ConsoleProxyClientParam();
 | 
			
		||||
        param.setClientHostAddress(host);
 | 
			
		||||
        param.setClientHostPort(port);
 | 
			
		||||
        param.setClientHostPassword(sid);
 | 
			
		||||
        param.setClientTag(tag);
 | 
			
		||||
        param.setTicket(ticket);
 | 
			
		||||
        param.setClientTunnelUrl(console_url);
 | 
			
		||||
        param.setClientTunnelSession(console_host_session);
 | 
			
		||||
 | 
			
		||||
        ConsoleProxyClient viewer = ConsoleProxy.getVncViewer(param);
 | 
			
		||||
 | 
			
		||||
        if (key == 0) {
 | 
			
		||||
            Image scaledImage = viewer.getClientScaledImage(width, height);
 | 
			
		||||
            BufferedImage bufferedImage = new BufferedImage(width, height,
 | 
			
		||||
                    BufferedImage.TYPE_3BYTE_BGR);
 | 
			
		||||
            Graphics2D bufImageGraphics = bufferedImage.createGraphics();
 | 
			
		||||
            bufImageGraphics.drawImage(scaledImage, 0, 0, null);
 | 
			
		||||
            ByteArrayOutputStream bos = new ByteArrayOutputStream(8196);
 | 
			
		||||
            javax.imageio.ImageIO.write(bufferedImage, "jpg", bos);
 | 
			
		||||
            byte[] bs = bos.toByteArray();
 | 
			
		||||
            Headers hds = t.getResponseHeaders();
 | 
			
		||||
            hds.set("Content-Type", "image/jpeg");
 | 
			
		||||
            hds.set("Cache-Control", "no-cache");
 | 
			
		||||
            hds.set("Cache-Control", "no-store");
 | 
			
		||||
            t.sendResponseHeaders(200, bs.length);
 | 
			
		||||
            OutputStream os = t.getResponseBody();
 | 
			
		||||
            os.write(bs);
 | 
			
		||||
            os.close();
 | 
			
		||||
        } else {
 | 
			
		||||
            AjaxFIFOImageCache imageCache = viewer.getAjaxImageCache();
 | 
			
		||||
                    byte[] img = imageCache.getImage(key);
 | 
			
		||||
    
 | 
			
		||||
            if(img != null) {
 | 
			
		||||
                Headers hds = t.getResponseHeaders();
 | 
			
		||||
                hds.set("Content-Type", "image/jpeg");
 | 
			
		||||
                t.sendResponseHeaders(200, img.length);
 | 
			
		||||
                
 | 
			
		||||
                OutputStream os = t.getResponseBody();
 | 
			
		||||
                try {
 | 
			
		||||
                    os.write(img, 0, img.length);
 | 
			
		||||
                } finally {
 | 
			
		||||
                    os.close();
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                if(s_logger.isInfoEnabled())
 | 
			
		||||
                    s_logger.info("Image has already been swept out, key: " + key);
 | 
			
		||||
                t.sendResponseHeaders(404, -1);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,81 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
// duplicated class
 | 
			
		||||
public class ConsoleProxyAuthenticationResult {
 | 
			
		||||
    private boolean success;
 | 
			
		||||
    private boolean isReauthentication;
 | 
			
		||||
    private String host;
 | 
			
		||||
    private int port;
 | 
			
		||||
    private String tunnelUrl;
 | 
			
		||||
    private String tunnelSession;
 | 
			
		||||
    
 | 
			
		||||
    public ConsoleProxyAuthenticationResult() {
 | 
			
		||||
        success = false;
 | 
			
		||||
        isReauthentication = false;
 | 
			
		||||
        port = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isSuccess() {
 | 
			
		||||
        return success;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSuccess(boolean success) {
 | 
			
		||||
        this.success = success;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isReauthentication() {
 | 
			
		||||
        return isReauthentication;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setReauthentication(boolean isReauthentication) {
 | 
			
		||||
        this.isReauthentication = isReauthentication;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getHost() {
 | 
			
		||||
        return host;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setHost(String host) {
 | 
			
		||||
        this.host = host;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getPort() {
 | 
			
		||||
        return port;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setPort(int port) {
 | 
			
		||||
        this.port = port;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getTunnelUrl() {
 | 
			
		||||
        return tunnelUrl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTunnelUrl(String tunnelUrl) {
 | 
			
		||||
        this.tunnelUrl = tunnelUrl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getTunnelSession() {
 | 
			
		||||
        return tunnelSession;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTunnelSession(String tunnelSession) {
 | 
			
		||||
        this.tunnelSession = tunnelSession;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,48 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.InetSocketAddress;
 | 
			
		||||
 | 
			
		||||
import javax.net.ssl.SSLServerSocket;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
import com.sun.net.httpserver.HttpServer;
 | 
			
		||||
 | 
			
		||||
public class ConsoleProxyBaseServerFactoryImpl implements ConsoleProxyServerFactory {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxyBaseServerFactoryImpl.class);
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void init(byte[] ksBits, String ksPassword) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public HttpServer createHttpServerInstance(int port) throws IOException {
 | 
			
		||||
        if(s_logger.isInfoEnabled())
 | 
			
		||||
            s_logger.info("create HTTP server instance at port: " + port);
 | 
			
		||||
        return HttpServer.create(new InetSocketAddress(port), 5);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public SSLServerSocket createSSLServerSocket(int port) throws IOException {
 | 
			
		||||
        if(s_logger.isInfoEnabled())
 | 
			
		||||
            s_logger.info("SSL server socket is not supported in ConsoleProxyBaseServerFactoryImpl");
 | 
			
		||||
        
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,69 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.awt.Image;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ConsoleProxyClient defines an standard interface that a console client should implement,
 | 
			
		||||
 * 
 | 
			
		||||
 * ConsoleProxyClient maintains a session towards the target host, it glues the session
 | 
			
		||||
 * to a AJAX front-end viewer 
 | 
			
		||||
 */
 | 
			
		||||
public interface ConsoleProxyClient {
 | 
			
		||||
    int getClientId();
 | 
			
		||||
    
 | 
			
		||||
    //
 | 
			
		||||
    // Quick status
 | 
			
		||||
    //
 | 
			
		||||
    boolean isHostConnected();
 | 
			
		||||
    boolean isFrontEndAlive();
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // AJAX viewer
 | 
			
		||||
    //
 | 
			
		||||
    long getAjaxSessionId();
 | 
			
		||||
    AjaxFIFOImageCache getAjaxImageCache();
 | 
			
		||||
    Image getClientScaledImage(int width, int height);                  // client thumbnail support
 | 
			
		||||
    
 | 
			
		||||
    String onAjaxClientStart(String title, List<String> languages, String guest);
 | 
			
		||||
    String onAjaxClientUpdate();
 | 
			
		||||
    String onAjaxClientKickoff();
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // Input handling
 | 
			
		||||
    //
 | 
			
		||||
    void sendClientRawKeyboardEvent(InputEventType event, int code, int modifiers);
 | 
			
		||||
    void sendClientMouseEvent(InputEventType event, int x, int y, int code, int modifiers);
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // Info/Stats
 | 
			
		||||
    //
 | 
			
		||||
    long getClientCreateTime();
 | 
			
		||||
    long getClientLastFrontEndActivityTime();
 | 
			
		||||
    String getClientHostAddress();
 | 
			
		||||
    int getClientHostPort();
 | 
			
		||||
    String getClientHostPassword();
 | 
			
		||||
    String getClientTag();
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // Setup/house-keeping
 | 
			
		||||
    //
 | 
			
		||||
    void initClient(ConsoleProxyClientParam param);
 | 
			
		||||
    void closeClient();
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,457 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.awt.Image;
 | 
			
		||||
import java.awt.Rectangle;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.apache.log4j.Logger;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.TileInfo;
 | 
			
		||||
import com.cloud.consoleproxy.util.TileTracker;
 | 
			
		||||
import com.cloud.consoleproxy.vnc.FrameBufferCanvas;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * an instance of specialized console protocol implementation, such as VNC or RDP
 | 
			
		||||
 * 
 | 
			
		||||
 * It mainly implements the features needed by front-end AJAX viewer
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
public abstract class ConsoleProxyClientBase implements ConsoleProxyClient, ConsoleProxyClientListener {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxyClientBase.class);
 | 
			
		||||
    
 | 
			
		||||
    private static int s_nextClientId = 0;
 | 
			
		||||
    protected int clientId = getNextClientId();
 | 
			
		||||
    
 | 
			
		||||
    protected long ajaxSessionId = 0;
 | 
			
		||||
    
 | 
			
		||||
    protected boolean dirtyFlag = false;
 | 
			
		||||
    protected Object tileDirtyEvent = new Object();
 | 
			
		||||
    protected TileTracker tracker;
 | 
			
		||||
    protected AjaxFIFOImageCache ajaxImageCache = new AjaxFIFOImageCache(2);
 | 
			
		||||
 | 
			
		||||
    protected ConsoleProxyClientParam clientParam;
 | 
			
		||||
    protected String clientToken;
 | 
			
		||||
    
 | 
			
		||||
    protected long createTime = System.currentTimeMillis();
 | 
			
		||||
    protected long lastFrontEndActivityTime = System.currentTimeMillis();
 | 
			
		||||
 | 
			
		||||
    protected boolean framebufferResized = false;
 | 
			
		||||
    protected int resizedFramebufferWidth;
 | 
			
		||||
    protected int resizedFramebufferHeight;
 | 
			
		||||
 | 
			
		||||
    public ConsoleProxyClientBase() {
 | 
			
		||||
        tracker = new TileTracker();
 | 
			
		||||
        tracker.initTracking(64, 64, 800, 600);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // interface ConsoleProxyClient
 | 
			
		||||
    //
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getClientId() {
 | 
			
		||||
        return clientId;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public abstract boolean isHostConnected();
 | 
			
		||||
    public abstract boolean isFrontEndAlive();
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public long getAjaxSessionId() {
 | 
			
		||||
        return this.ajaxSessionId;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public AjaxFIFOImageCache getAjaxImageCache() {
 | 
			
		||||
        return ajaxImageCache;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public Image getClientScaledImage(int width, int height) {
 | 
			
		||||
        FrameBufferCanvas canvas = getFrameBufferCavas();
 | 
			
		||||
        if(canvas != null)
 | 
			
		||||
            return canvas.getFrameBufferScaledImage(width, height);
 | 
			
		||||
        
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public abstract void sendClientRawKeyboardEvent(InputEventType event, int code, int modifiers);
 | 
			
		||||
    public abstract void sendClientMouseEvent(InputEventType event, int x, int y, int code, int modifiers);
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public long getClientCreateTime() {
 | 
			
		||||
        return createTime;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public long getClientLastFrontEndActivityTime() {
 | 
			
		||||
        return lastFrontEndActivityTime;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getClientHostAddress() {
 | 
			
		||||
        return clientParam.getClientHostAddress();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getClientHostPort() {
 | 
			
		||||
        return clientParam.getClientHostPort();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getClientHostPassword() {
 | 
			
		||||
        return clientParam.getClientHostPassword();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getClientTag() {
 | 
			
		||||
        if(clientParam.getClientTag() != null)
 | 
			
		||||
            return clientParam.getClientTag();
 | 
			
		||||
        return "";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public abstract void initClient(ConsoleProxyClientParam param);
 | 
			
		||||
        
 | 
			
		||||
    @Override
 | 
			
		||||
    public abstract void closeClient();
 | 
			
		||||
    
 | 
			
		||||
    //
 | 
			
		||||
    // interface FrameBufferEventListener
 | 
			
		||||
    //
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onFramebufferSizeChange(int w, int h) {
 | 
			
		||||
        tracker.resize(w, h);
 | 
			
		||||
 | 
			
		||||
        synchronized(this) {
 | 
			
		||||
            framebufferResized = true;
 | 
			
		||||
            resizedFramebufferWidth = w;
 | 
			
		||||
            resizedFramebufferHeight = h;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        signalTileDirtyEvent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onFramebufferUpdate(int x, int y, int w, int h) {
 | 
			
		||||
        if(s_logger.isTraceEnabled())
 | 
			
		||||
            s_logger.trace("Frame buffer update {" + x + "," + y + "," + w + "," + h + "}");
 | 
			
		||||
        tracker.invalidate(new Rectangle(x, y, w, h));
 | 
			
		||||
        
 | 
			
		||||
        signalTileDirtyEvent();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    //
 | 
			
		||||
    // AJAX Image manipulation 
 | 
			
		||||
    //
 | 
			
		||||
    public byte[] getFrameBufferJpeg() {
 | 
			
		||||
        FrameBufferCanvas canvas = getFrameBufferCavas();
 | 
			
		||||
        if(canvas != null)
 | 
			
		||||
            return canvas.getFrameBufferJpeg();
 | 
			
		||||
        
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public byte[] getTilesMergedJpeg(List<TileInfo> tileList, int tileWidth, int tileHeight) {
 | 
			
		||||
        FrameBufferCanvas canvas = getFrameBufferCavas();
 | 
			
		||||
        if(canvas != null)
 | 
			
		||||
            return canvas.getTilesMergedJpeg(tileList, tileWidth, tileHeight);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private String prepareAjaxImage(List<TileInfo> tiles, boolean init) {
 | 
			
		||||
        byte[] imgBits;
 | 
			
		||||
        if(init)
 | 
			
		||||
            imgBits = getFrameBufferJpeg();
 | 
			
		||||
        else 
 | 
			
		||||
            imgBits = getTilesMergedJpeg(tiles, tracker.getTileWidth(), tracker.getTileHeight());
 | 
			
		||||
        
 | 
			
		||||
        if(imgBits == null) {
 | 
			
		||||
            s_logger.warn("Unable to generate jpeg image");
 | 
			
		||||
        } else {
 | 
			
		||||
            if(s_logger.isTraceEnabled())
 | 
			
		||||
                s_logger.trace("Generated jpeg image size: " + imgBits.length);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        int key = ajaxImageCache.putImage(imgBits);
 | 
			
		||||
        StringBuffer sb = new StringBuffer();
 | 
			
		||||
        sb.append("/ajaximg?token=").append(clientToken);
 | 
			
		||||
        sb.append("&key=").append(key);
 | 
			
		||||
        sb.append("&ts=").append(System.currentTimeMillis());
 | 
			
		||||
        
 | 
			
		||||
        return sb.toString();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private String prepareAjaxSession(boolean init) {
 | 
			
		||||
        if(init) {
 | 
			
		||||
            synchronized(this) {
 | 
			
		||||
                ajaxSessionId++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        StringBuffer sb = new StringBuffer();
 | 
			
		||||
        sb.append("/ajax?token=").append(clientToken).append("&sess=").append(ajaxSessionId);
 | 
			
		||||
        return sb.toString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String onAjaxClientKickoff() {
 | 
			
		||||
        return "onKickoff();";
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private boolean waitForViewerReady() {
 | 
			
		||||
        long startTick = System.currentTimeMillis();
 | 
			
		||||
        while(System.currentTimeMillis() - startTick < 5000) {
 | 
			
		||||
            if(getFrameBufferCavas() != null)
 | 
			
		||||
                return true;
 | 
			
		||||
            
 | 
			
		||||
            try {
 | 
			
		||||
                Thread.sleep(100);
 | 
			
		||||
            } catch (InterruptedException e) {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private String onAjaxClientConnectFailed() {
 | 
			
		||||
        return "<html><head></head><body><div id=\"main_panel\" tabindex=\"1\"><p>" + 
 | 
			
		||||
            "Unable to start console session as connection is refused by the machine you are accessing" +
 | 
			
		||||
            "</p></div></body></html>";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String onAjaxClientStart(String title, List<String> languages, String guest) {
 | 
			
		||||
        updateFrontEndActivityTime();
 | 
			
		||||
        
 | 
			
		||||
        if(!waitForViewerReady())
 | 
			
		||||
            return onAjaxClientConnectFailed();
 | 
			
		||||
        
 | 
			
		||||
        synchronized(this) {
 | 
			
		||||
            ajaxSessionId++;
 | 
			
		||||
            framebufferResized = false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        int tileWidth = tracker.getTileWidth();
 | 
			
		||||
        int tileHeight = tracker.getTileHeight();
 | 
			
		||||
        int width = tracker.getTrackWidth();
 | 
			
		||||
        int height = tracker.getTrackHeight();
 | 
			
		||||
        
 | 
			
		||||
        if(s_logger.isTraceEnabled())
 | 
			
		||||
            s_logger.trace("Ajax client start, frame buffer w: " + width + ", " + height);
 | 
			
		||||
        
 | 
			
		||||
        int retry = 0;
 | 
			
		||||
        tracker.initCoverageTest();
 | 
			
		||||
        while(!tracker.hasFullCoverage() && retry < 10) {
 | 
			
		||||
            try {
 | 
			
		||||
                Thread.sleep(1000);
 | 
			
		||||
            } catch (InterruptedException e) {
 | 
			
		||||
            }
 | 
			
		||||
            retry++;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        List<TileInfo> tiles = tracker.scan(true);
 | 
			
		||||
        String imgUrl = prepareAjaxImage(tiles, true);
 | 
			
		||||
        String updateUrl = prepareAjaxSession(true);
 | 
			
		||||
        
 | 
			
		||||
        StringBuffer sbTileSequence = new StringBuffer();
 | 
			
		||||
        int i = 0;
 | 
			
		||||
        for(TileInfo tile : tiles) {
 | 
			
		||||
            sbTileSequence.append("[").append(tile.getRow()).append(",").append(tile.getCol()).append("]");
 | 
			
		||||
            if(i < tiles.size() - 1)
 | 
			
		||||
                sbTileSequence.append(",");
 | 
			
		||||
            
 | 
			
		||||
            i++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return getAjaxViewerPageContent(sbTileSequence.toString(), imgUrl, 
 | 
			
		||||
            updateUrl, width, height, tileWidth, tileHeight, title, 
 | 
			
		||||
            ConsoleProxy.keyboardType == ConsoleProxy.KEYBOARD_RAW, 
 | 
			
		||||
            languages, guest);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private String getAjaxViewerPageContent(String tileSequence, String imgUrl, String updateUrl, int width,
 | 
			
		||||
        int height, int tileWidth, int tileHeight, String title, boolean rawKeyboard, List<String> languages, String guest) {
 | 
			
		||||
 | 
			
		||||
        StringBuffer sbLanguages = new StringBuffer("");
 | 
			
		||||
        if(languages != null) {
 | 
			
		||||
            for(String lang : languages) {
 | 
			
		||||
                if(sbLanguages.length() > 0) {
 | 
			
		||||
                    sbLanguages.append(",");
 | 
			
		||||
                }
 | 
			
		||||
                sbLanguages.append(lang);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        String[] content = new String[] {
 | 
			
		||||
            "<html>",
 | 
			
		||||
            "<head>",
 | 
			
		||||
            "<script type=\"text/javascript\" language=\"javascript\" src=\"/resource/js/jquery.js\"></script>",
 | 
			
		||||
            "<script type=\"text/javascript\" language=\"javascript\" src=\"/resource/js/cloud.logger.js\"></script>",
 | 
			
		||||
            "<script type=\"text/javascript\" language=\"javascript\" src=\"/resource/js/ajaxkeys.js\"></script>",
 | 
			
		||||
            "<script type=\"text/javascript\" language=\"javascript\" src=\"/resource/js/ajaxviewer.js\"></script>",
 | 
			
		||||
            "<script type=\"text/javascript\" language=\"javascript\" src=\"/resource/js/handler.js\"></script>",
 | 
			
		||||
            "<link rel=\"stylesheet\" type=\"text/css\" href=\"/resource/css/ajaxviewer.css\"></link>",
 | 
			
		||||
            "<link rel=\"stylesheet\" type=\"text/css\" href=\"/resource/css/logger.css\"></link>",
 | 
			
		||||
            "<title>" + title + "</title>",
 | 
			
		||||
            "</head>",
 | 
			
		||||
            "<body>",
 | 
			
		||||
            "<div id=\"toolbar\">",
 | 
			
		||||
            "<ul>",
 | 
			
		||||
                "<li>", 
 | 
			
		||||
                    "<a href=\"#\" cmd=\"sendCtrlAltDel\">", 
 | 
			
		||||
                        "<span><img align=\"left\" src=\"/resource/images/cad.gif\" alt=\"Ctrl-Alt-Del\" />Ctrl-Alt-Del</span>", 
 | 
			
		||||
                    "</a>", 
 | 
			
		||||
                "</li>",
 | 
			
		||||
                "<li>", 
 | 
			
		||||
                    "<a href=\"#\" cmd=\"sendCtrlEsc\">", 
 | 
			
		||||
                        "<span><img align=\"left\" src=\"/resource/images/winlog.png\" alt=\"Ctrl-Esc\" style=\"width:16px;height:16px\"/>Ctrl-Esc</span>",
 | 
			
		||||
                    "</a>", 
 | 
			
		||||
                "</li>",
 | 
			
		||||
                
 | 
			
		||||
                "<li class=\"pulldown\">", 
 | 
			
		||||
                    "<a href=\"#\">", 
 | 
			
		||||
                        "<span><img align=\"left\" src=\"/resource/images/winlog.png\" alt=\"Keyboard\" style=\"width:16px;height:16px\"/>Keyboard</span>",
 | 
			
		||||
                    "</a>", 
 | 
			
		||||
                    "<ul>",
 | 
			
		||||
                        "<li><a href=\"#\" cmd=\"keyboard_us\"><span>Standard (US) keyboard</span></a></li>",
 | 
			
		||||
                        "<li><a href=\"#\" cmd=\"keyboard_jp\"><span>Japanese keyboard</span></a></li>",
 | 
			
		||||
                    "</ul>",
 | 
			
		||||
                "</li>",
 | 
			
		||||
            "</ul>",
 | 
			
		||||
            "<span id=\"light\" class=\"dark\" cmd=\"toggle_logwin\"></span>", 
 | 
			
		||||
            "</div>",
 | 
			
		||||
            "<div id=\"main_panel\" tabindex=\"1\"></div>",
 | 
			
		||||
            "<script language=\"javascript\">",
 | 
			
		||||
            "var acceptLanguages = '" + sbLanguages.toString() + "';",
 | 
			
		||||
            "var tileMap = [ " + tileSequence + " ];",
 | 
			
		||||
            "var ajaxViewer = new AjaxViewer('main_panel', '" + imgUrl + "', '" + updateUrl + "', tileMap, ", 
 | 
			
		||||
                String.valueOf(width) + ", " + String.valueOf(height) + ", " + String.valueOf(tileWidth) + ", " + String.valueOf(tileHeight) + ");",
 | 
			
		||||
 | 
			
		||||
            "$(function() {",
 | 
			
		||||
                "ajaxViewer.start();",
 | 
			
		||||
            "});",
 | 
			
		||||
 | 
			
		||||
            "</script>",
 | 
			
		||||
            "</body>",
 | 
			
		||||
            "</html>"   
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        StringBuffer sb = new StringBuffer();
 | 
			
		||||
        for(int i = 0; i < content.length; i++)
 | 
			
		||||
            sb.append(content[i]);
 | 
			
		||||
        
 | 
			
		||||
        return sb.toString();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public String onAjaxClientDisconnected() {
 | 
			
		||||
        return "onDisconnect();";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String onAjaxClientUpdate() {
 | 
			
		||||
        updateFrontEndActivityTime();
 | 
			
		||||
        if(!waitForViewerReady())
 | 
			
		||||
            return onAjaxClientDisconnected();
 | 
			
		||||
        
 | 
			
		||||
        synchronized(tileDirtyEvent) {
 | 
			
		||||
            if(!dirtyFlag) {
 | 
			
		||||
                try {
 | 
			
		||||
                    tileDirtyEvent.wait(3000);
 | 
			
		||||
                } catch(InterruptedException e) {
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        boolean doResize = false;
 | 
			
		||||
        synchronized(this) {
 | 
			
		||||
            if(framebufferResized) {
 | 
			
		||||
                framebufferResized = false;
 | 
			
		||||
                doResize = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        List<TileInfo> tiles;
 | 
			
		||||
        
 | 
			
		||||
        if(doResize)
 | 
			
		||||
            tiles = tracker.scan(true);
 | 
			
		||||
        else
 | 
			
		||||
            tiles = tracker.scan(false);
 | 
			
		||||
        dirtyFlag = false;
 | 
			
		||||
        
 | 
			
		||||
        String imgUrl = prepareAjaxImage(tiles, false);
 | 
			
		||||
        StringBuffer sbTileSequence = new StringBuffer();
 | 
			
		||||
        int i = 0;
 | 
			
		||||
        for(TileInfo tile : tiles) {
 | 
			
		||||
            sbTileSequence.append("[").append(tile.getRow()).append(",").append(tile.getCol()).append("]");
 | 
			
		||||
            if(i < tiles.size() - 1)
 | 
			
		||||
                sbTileSequence.append(",");
 | 
			
		||||
            
 | 
			
		||||
            i++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return getAjaxViewerUpdatePageContent(sbTileSequence.toString(), imgUrl, doResize, 
 | 
			
		||||
            resizedFramebufferWidth, resizedFramebufferHeight, 
 | 
			
		||||
            tracker.getTileWidth(), tracker.getTileHeight());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private String getAjaxViewerUpdatePageContent(String tileSequence, String imgUrl, boolean resized, int width,
 | 
			
		||||
        int height, int tileWidth, int tileHeight) {
 | 
			
		||||
        
 | 
			
		||||
        String[] content = new String[] {
 | 
			
		||||
            "tileMap = [ " + tileSequence + " ];",
 | 
			
		||||
            resized ? "ajaxViewer.resize('main_panel', " + width + ", " + height + " , " + tileWidth + ", " + tileHeight + ");" : "", 
 | 
			
		||||
            "ajaxViewer.refresh('" + imgUrl + "', tileMap, false);"
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        StringBuffer sb = new StringBuffer();
 | 
			
		||||
        for(int i = 0; i < content.length; i++)
 | 
			
		||||
            sb.append(content[i]);
 | 
			
		||||
        
 | 
			
		||||
        return sb.toString();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    //
 | 
			
		||||
    // Helpers
 | 
			
		||||
    //
 | 
			
		||||
    private synchronized static int getNextClientId() {
 | 
			
		||||
        return ++s_nextClientId;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void signalTileDirtyEvent() {
 | 
			
		||||
        synchronized(tileDirtyEvent) {
 | 
			
		||||
            dirtyFlag = true;
 | 
			
		||||
            tileDirtyEvent.notifyAll();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void updateFrontEndActivityTime() {
 | 
			
		||||
        lastFrontEndActivityTime = System.currentTimeMillis(); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract FrameBufferCanvas getFrameBufferCavas();
 | 
			
		||||
 | 
			
		||||
    public ConsoleProxyClientParam getClientParam() {
 | 
			
		||||
        return clientParam;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setClientParam(ConsoleProxyClientParam clientParam) {
 | 
			
		||||
        this.clientParam = clientParam;
 | 
			
		||||
        ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(ConsoleProxy.getEncryptorPassword());
 | 
			
		||||
        this.clientToken = encryptor.encryptObject(ConsoleProxyClientParam.class, clientParam);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,25 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
public interface ConsoleProxyClientListener {
 | 
			
		||||
    void onFramebufferSizeChange(int w, int h);
 | 
			
		||||
    void onFramebufferUpdate(int x, int y, int w, int h);
 | 
			
		||||
 | 
			
		||||
    void onClientConnected();
 | 
			
		||||
    void onClientClose();
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,110 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * Data object to store parameter info needed by client to connect to its host
 | 
			
		||||
 */
 | 
			
		||||
public class ConsoleProxyClientParam {
 | 
			
		||||
    
 | 
			
		||||
    private String clientHostAddress;
 | 
			
		||||
    private int clientHostPort; 
 | 
			
		||||
    private String clientHostPassword;
 | 
			
		||||
    private String clientTag;
 | 
			
		||||
    private String ticket;
 | 
			
		||||
    
 | 
			
		||||
    private String clientTunnelUrl;
 | 
			
		||||
    private String clientTunnelSession;
 | 
			
		||||
    
 | 
			
		||||
    private String ajaxSessionId;
 | 
			
		||||
    
 | 
			
		||||
    public ConsoleProxyClientParam() {
 | 
			
		||||
        clientHostPort = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getClientHostAddress() {
 | 
			
		||||
        return clientHostAddress;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setClientHostAddress(String clientHostAddress) {
 | 
			
		||||
        this.clientHostAddress = clientHostAddress;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getClientHostPort() {
 | 
			
		||||
        return clientHostPort;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setClientHostPort(int clientHostPort) {
 | 
			
		||||
        this.clientHostPort = clientHostPort;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getClientHostPassword() {
 | 
			
		||||
        return clientHostPassword;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setClientHostPassword(String clientHostPassword) {
 | 
			
		||||
        this.clientHostPassword = clientHostPassword;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getClientTag() {
 | 
			
		||||
        return clientTag;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setClientTag(String clientTag) {
 | 
			
		||||
        this.clientTag = clientTag;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getTicket() {
 | 
			
		||||
        return ticket;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTicket(String ticket) {
 | 
			
		||||
        this.ticket = ticket;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public String getClientTunnelUrl() {
 | 
			
		||||
        return clientTunnelUrl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setClientTunnelUrl(String clientTunnelUrl) {
 | 
			
		||||
        this.clientTunnelUrl = clientTunnelUrl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getClientTunnelSession() {
 | 
			
		||||
        return clientTunnelSession;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setClientTunnelSession(String clientTunnelSession) {
 | 
			
		||||
        this.clientTunnelSession = clientTunnelSession;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public String getAjaxSessionId() {
 | 
			
		||||
        return this.ajaxSessionId;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void setAjaxSessionId(String ajaxSessionId) {
 | 
			
		||||
        this.ajaxSessionId = ajaxSessionId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getClientMapKey() {
 | 
			
		||||
        if(clientTag != null && !clientTag.isEmpty())
 | 
			
		||||
            return clientTag;
 | 
			
		||||
        
 | 
			
		||||
        return clientHostAddress + ":" + clientHostPort;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,88 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.io.OutputStreamWriter;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Enumeration;
 | 
			
		||||
import java.util.Hashtable;
 | 
			
		||||
 | 
			
		||||
import com.google.gson.Gson;
 | 
			
		||||
import com.google.gson.GsonBuilder;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * ConsoleProxyClientStatsCollector collects client stats for console proxy agent to report
 | 
			
		||||
 */
 | 
			
		||||
public class ConsoleProxyClientStatsCollector {
 | 
			
		||||
    
 | 
			
		||||
    ArrayList<ConsoleProxyConnection> connections;
 | 
			
		||||
    
 | 
			
		||||
    public ConsoleProxyClientStatsCollector() {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public ConsoleProxyClientStatsCollector(Hashtable<String, ConsoleProxyClient> connMap) {
 | 
			
		||||
        setConnections(connMap);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public String getStatsReport() {
 | 
			
		||||
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
 | 
			
		||||
        return gson.toJson(this);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void getStatsReport(OutputStreamWriter os) {
 | 
			
		||||
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
 | 
			
		||||
        gson.toJson(this, os);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void setConnections(Hashtable<String, ConsoleProxyClient> connMap) {
 | 
			
		||||
        
 | 
			
		||||
        ArrayList<ConsoleProxyConnection> conns = new ArrayList<ConsoleProxyConnection>();
 | 
			
		||||
        Enumeration<String> e = connMap.keys();
 | 
			
		||||
        while (e.hasMoreElements()) {
 | 
			
		||||
            synchronized (connMap) {
 | 
			
		||||
                String key = e.nextElement();
 | 
			
		||||
                ConsoleProxyClient client = connMap.get(key);
 | 
			
		||||
                 
 | 
			
		||||
                ConsoleProxyConnection conn = new ConsoleProxyConnection();
 | 
			
		||||
                 
 | 
			
		||||
                conn.id = client.getClientId();
 | 
			
		||||
                conn.clientInfo = "";
 | 
			
		||||
                conn.host = client.getClientHostAddress();
 | 
			
		||||
                conn.port = client.getClientHostPort();
 | 
			
		||||
                conn.tag = client.getClientTag();
 | 
			
		||||
                conn.createTime = client.getClientCreateTime();
 | 
			
		||||
                conn.lastUsedTime = client.getClientLastFrontEndActivityTime();
 | 
			
		||||
                conns.add(conn);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        connections = conns;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static class ConsoleProxyConnection {
 | 
			
		||||
        public int id;
 | 
			
		||||
        public String clientInfo;
 | 
			
		||||
        public String host;
 | 
			
		||||
        public int port;
 | 
			
		||||
        public String tag;
 | 
			
		||||
        public long createTime;
 | 
			
		||||
        public long lastUsedTime;
 | 
			
		||||
        
 | 
			
		||||
        public ConsoleProxyConnection() {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,70 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.io.OutputStreamWriter;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
import com.sun.net.httpserver.Headers;
 | 
			
		||||
import com.sun.net.httpserver.HttpExchange;
 | 
			
		||||
import com.sun.net.httpserver.HttpHandler;
 | 
			
		||||
 | 
			
		||||
public class ConsoleProxyCmdHandler implements HttpHandler {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxyCmdHandler.class);
 | 
			
		||||
    
 | 
			
		||||
    public void handle(HttpExchange t) throws IOException {
 | 
			
		||||
        try {
 | 
			
		||||
            Thread.currentThread().setName("Cmd Thread " + 
 | 
			
		||||
                    Thread.currentThread().getId() + " " + t.getRemoteAddress());
 | 
			
		||||
            s_logger.info("CmdHandler " + t.getRequestURI());
 | 
			
		||||
            doHandle(t);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            s_logger.error(e.toString(), e);
 | 
			
		||||
            String response = "Not found";
 | 
			
		||||
            t.sendResponseHeaders(404, response.length());
 | 
			
		||||
            OutputStream os = t.getResponseBody();
 | 
			
		||||
            os.write(response.getBytes());
 | 
			
		||||
            os.close();
 | 
			
		||||
        } catch(OutOfMemoryError e) {
 | 
			
		||||
            s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched");
 | 
			
		||||
            System.exit(1);
 | 
			
		||||
        } catch (Throwable e) {
 | 
			
		||||
            s_logger.error(e.toString(), e);
 | 
			
		||||
        } finally {
 | 
			
		||||
            t.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void doHandle(HttpExchange t) throws Exception {
 | 
			
		||||
        String path = t.getRequestURI().getPath();
 | 
			
		||||
        int i = path.indexOf("/", 1);
 | 
			
		||||
        String cmd = path.substring(i + 1);
 | 
			
		||||
        s_logger.info("Get CMD request for " + cmd);
 | 
			
		||||
        if (cmd.equals("getstatus")) {
 | 
			
		||||
            ConsoleProxyClientStatsCollector statsCollector = ConsoleProxy.getStatsCollector();
 | 
			
		||||
            
 | 
			
		||||
            Headers hds = t.getResponseHeaders();
 | 
			
		||||
            hds.set("Content-Type", "text/plain");
 | 
			
		||||
            t.sendResponseHeaders(200, 0);
 | 
			
		||||
            OutputStreamWriter os = new OutputStreamWriter(t.getResponseBody());
 | 
			
		||||
            statsCollector.getStatsReport(os);
 | 
			
		||||
            os.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,109 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.util.Enumeration;
 | 
			
		||||
import java.util.Hashtable;
 | 
			
		||||
 | 
			
		||||
import org.apache.log4j.Logger;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * ConsoleProxyGCThread does house-keeping work for the process, it helps cleanup log files,
 | 
			
		||||
 * recycle idle client sessions without front-end activities and report client stats to external
 | 
			
		||||
 * management software 
 | 
			
		||||
 */
 | 
			
		||||
public class ConsoleProxyGCThread extends Thread {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxyGCThread.class);
 | 
			
		||||
    
 | 
			
		||||
    private final static int MAX_SESSION_IDLE_SECONDS = 180;
 | 
			
		||||
 | 
			
		||||
    private Hashtable<String, ConsoleProxyClient> connMap;
 | 
			
		||||
    private long lastLogScan = 0;
 | 
			
		||||
    
 | 
			
		||||
    public ConsoleProxyGCThread(Hashtable<String, ConsoleProxyClient> connMap) {
 | 
			
		||||
        this.connMap = connMap;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void cleanupLogging() {
 | 
			
		||||
        if(lastLogScan != 0 && System.currentTimeMillis() - lastLogScan < 3600000)
 | 
			
		||||
            return;
 | 
			
		||||
        
 | 
			
		||||
        lastLogScan = System.currentTimeMillis();
 | 
			
		||||
        
 | 
			
		||||
        File logDir = new File("./logs");
 | 
			
		||||
        File files[] = logDir.listFiles();
 | 
			
		||||
        if(files != null) {
 | 
			
		||||
            for(File file : files) {
 | 
			
		||||
                if(System.currentTimeMillis() - file.lastModified() >= 86400000L) {
 | 
			
		||||
                    try {
 | 
			
		||||
                        file.delete();
 | 
			
		||||
                    } catch(Throwable e) {
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void run() {
 | 
			
		||||
        
 | 
			
		||||
        boolean bReportLoad = false;
 | 
			
		||||
        while (true) {
 | 
			
		||||
            cleanupLogging();
 | 
			
		||||
            bReportLoad = false;
 | 
			
		||||
            
 | 
			
		||||
            if(s_logger.isDebugEnabled())
 | 
			
		||||
                s_logger.debug("connMap=" + connMap);
 | 
			
		||||
            Enumeration<String> e = connMap.keys();
 | 
			
		||||
            while (e.hasMoreElements()) {
 | 
			
		||||
                String key;
 | 
			
		||||
                ConsoleProxyClient client;
 | 
			
		||||
                
 | 
			
		||||
                synchronized (connMap) {
 | 
			
		||||
                    key  = e.nextElement();
 | 
			
		||||
                    client  = connMap.get(key);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                long seconds_unused = (System.currentTimeMillis() - client.getClientLastFrontEndActivityTime()) / 1000;
 | 
			
		||||
                if (seconds_unused < MAX_SESSION_IDLE_SECONDS) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                synchronized (connMap) {
 | 
			
		||||
                    connMap.remove(key);
 | 
			
		||||
                    bReportLoad = true;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // close the server connection
 | 
			
		||||
                s_logger.info("Dropping " + client + " which has not been used for " + seconds_unused + " seconds");
 | 
			
		||||
                client.closeClient();
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if(bReportLoad) {
 | 
			
		||||
                // report load changes
 | 
			
		||||
                String loadInfo = new ConsoleProxyClientStatsCollector(connMap).getStatsReport(); 
 | 
			
		||||
                ConsoleProxy.reportLoadInfo(loadInfo);
 | 
			
		||||
                if(s_logger.isDebugEnabled())
 | 
			
		||||
                    s_logger.debug("Report load change : " + loadInfo);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            try { Thread.sleep(5000); } catch (InterruptedException ex) {}
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,74 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
 | 
			
		||||
public class ConsoleProxyHttpHandlerHelper {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxyHttpHandlerHelper.class);
 | 
			
		||||
    
 | 
			
		||||
    public static Map<String, String> getQueryMap(String query) {
 | 
			
		||||
        String[] params = query.split("&");
 | 
			
		||||
        Map<String, String> map = new HashMap<String, String>();
 | 
			
		||||
        for (String param : params) {
 | 
			
		||||
            String[] paramTokens = param.split("=");
 | 
			
		||||
            if(paramTokens != null && paramTokens.length == 2) {
 | 
			
		||||
                String name = param.split("=")[0];
 | 
			
		||||
                String value = param.split("=")[1];
 | 
			
		||||
                map.put(name, value);
 | 
			
		||||
            } else if (paramTokens.length == 3) {
 | 
			
		||||
                // very ugly, added for Xen tunneling url
 | 
			
		||||
                String name = paramTokens[0];
 | 
			
		||||
                String value = paramTokens[1] + "=" + paramTokens[2];
 | 
			
		||||
                map.put(name, value);
 | 
			
		||||
            } else {
 | 
			
		||||
                if(s_logger.isDebugEnabled())
 | 
			
		||||
                    s_logger.debug("Invalid paramemter in URL found. param: " + param);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // This is a ugly solution for now. We will do encryption/decryption translation
 | 
			
		||||
        // here to make it transparent to rest of the code.
 | 
			
		||||
        if(map.get("token") != null) {
 | 
			
		||||
            ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(
 | 
			
		||||
                ConsoleProxy.getEncryptorPassword());
 | 
			
		||||
            
 | 
			
		||||
            ConsoleProxyClientParam param = encryptor.decryptObject(ConsoleProxyClientParam.class, map.get("token"));
 | 
			
		||||
            if(param != null) {
 | 
			
		||||
                if(param.getClientHostAddress() != null)
 | 
			
		||||
                    map.put("host", param.getClientHostAddress());
 | 
			
		||||
                if(param.getClientHostPort() != 0)
 | 
			
		||||
                    map.put("port", String.valueOf(param.getClientHostPort()));
 | 
			
		||||
                if(param.getClientTag() != null)
 | 
			
		||||
                    map.put("tag", param.getClientTag());
 | 
			
		||||
                if(param.getClientHostPassword() != null)
 | 
			
		||||
                    map.put("sid", param.getClientHostPassword());
 | 
			
		||||
                if(param.getClientTunnelUrl() != null)
 | 
			
		||||
                    map.put("consoleurl", param.getClientTunnelUrl());
 | 
			
		||||
                if(param.getClientTunnelSession() != null)
 | 
			
		||||
                    map.put("sessionref", param.getClientTunnelSession());
 | 
			
		||||
                if(param.getTicket() != null)
 | 
			
		||||
                    map.put("ticket", param.getTicket());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return map;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,89 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
import com.cloud.consoleproxy.util.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
public class ConsoleProxyLoggerFactory implements LoggerFactory {
 | 
			
		||||
    public ConsoleProxyLoggerFactory() {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public Logger getLogger(Class<?> clazz) {
 | 
			
		||||
        return new Log4jLogger(org.apache.log4j.Logger.getLogger(clazz));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static class Log4jLogger extends Logger {
 | 
			
		||||
        private org.apache.log4j.Logger logger;
 | 
			
		||||
        
 | 
			
		||||
        public Log4jLogger(org.apache.log4j.Logger logger) {
 | 
			
		||||
            this.logger = logger;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public boolean isTraceEnabled() {
 | 
			
		||||
            return logger.isTraceEnabled();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public boolean isDebugEnabled() {
 | 
			
		||||
            return logger.isDebugEnabled();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public boolean isInfoEnabled() {
 | 
			
		||||
            return logger.isInfoEnabled();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void trace(Object message) {
 | 
			
		||||
            logger.trace(message);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public void trace(Object message, Throwable exception) {
 | 
			
		||||
            logger.trace(message, exception);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public void info(Object message) {
 | 
			
		||||
            logger.info(message);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public void info(Object message, Throwable exception) {
 | 
			
		||||
            logger.info(message, exception);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public void debug(Object message) {
 | 
			
		||||
            logger.debug(message);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public void debug(Object message, Throwable exception) {
 | 
			
		||||
            logger.debug(message, exception);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public void warn(Object message) {
 | 
			
		||||
            logger.warn(message);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public void warn(Object message, Throwable exception) {
 | 
			
		||||
            logger.warn(message, exception);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public void error(Object message) {
 | 
			
		||||
            logger.error(message);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public void error(Object message, Throwable exception) {
 | 
			
		||||
            logger.error(message, exception);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,153 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.URISyntaxException;
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import org.apache.log4j.xml.DOMConfigurator;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
// I switched to a simpler solution to monitor only unrecoverable exceptions, under these cases, console proxy process will exit
 | 
			
		||||
// itself and the shell script will re-launch console proxy
 | 
			
		||||
//
 | 
			
		||||
public class ConsoleProxyMonitor {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxyMonitor.class);
 | 
			
		||||
    
 | 
			
		||||
    private String[] _argv;
 | 
			
		||||
    private Map<String, String> _argMap = new HashMap<String, String>();
 | 
			
		||||
    
 | 
			
		||||
    private volatile Process _process;
 | 
			
		||||
    private boolean _quit = false;
 | 
			
		||||
    
 | 
			
		||||
    public ConsoleProxyMonitor(String[] argv) {
 | 
			
		||||
        _argv = argv;
 | 
			
		||||
        
 | 
			
		||||
        for(String arg : _argv) {
 | 
			
		||||
            String[] tokens = arg.split("=");
 | 
			
		||||
            if(tokens.length == 2) {
 | 
			
		||||
                s_logger.info("Add argument " + tokens[0] + "=" + tokens[1] + " to the argument map");
 | 
			
		||||
 | 
			
		||||
                _argMap.put(tokens[0].trim(), tokens[1].trim());
 | 
			
		||||
            } else {
 | 
			
		||||
                s_logger.warn("unrecognized argument, skip adding it to argument map");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void run() {
 | 
			
		||||
        Runtime.getRuntime().addShutdownHook(new Thread() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void run() {
 | 
			
		||||
                _quit = true;
 | 
			
		||||
                onShutdown();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        while(!_quit) {
 | 
			
		||||
            String cmdLine = getLaunchCommandLine();
 | 
			
		||||
            
 | 
			
		||||
            s_logger.info("Launch console proxy process with command line: " + cmdLine);
 | 
			
		||||
            
 | 
			
		||||
            try {
 | 
			
		||||
                _process = Runtime.getRuntime().exec(cmdLine);
 | 
			
		||||
            } catch (IOException e) {
 | 
			
		||||
                s_logger.error("Unexpected exception ", e);
 | 
			
		||||
                System.exit(1);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            boolean waitSucceeded = false;
 | 
			
		||||
            int exitCode = 0;
 | 
			
		||||
            while(!waitSucceeded) {
 | 
			
		||||
                try {
 | 
			
		||||
                    exitCode = _process.waitFor();
 | 
			
		||||
                    waitSucceeded = true;
 | 
			
		||||
                    
 | 
			
		||||
                    if(s_logger.isInfoEnabled())
 | 
			
		||||
                        s_logger.info("Console proxy process exits with code: " + exitCode);
 | 
			
		||||
                } catch (InterruptedException e) {
 | 
			
		||||
                    if(s_logger.isInfoEnabled())
 | 
			
		||||
                        s_logger.info("InterruptedException while waiting for termination of console proxy, will retry");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private String getLaunchCommandLine() {
 | 
			
		||||
        StringBuffer sb = new StringBuffer("java ");
 | 
			
		||||
        String jvmOptions = _argMap.get("jvmoptions");
 | 
			
		||||
        
 | 
			
		||||
        if(jvmOptions != null)
 | 
			
		||||
            sb.append(jvmOptions);
 | 
			
		||||
        
 | 
			
		||||
        for(Map.Entry<String, String> entry : _argMap.entrySet()) {
 | 
			
		||||
            if(!"jvmoptions".equalsIgnoreCase(entry.getKey()))
 | 
			
		||||
                sb.append(" ").append(entry.getKey()).append("=").append(entry.getValue());
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return sb.toString();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void onShutdown() {
 | 
			
		||||
        if(_process != null) {
 | 
			
		||||
            if(s_logger.isInfoEnabled())
 | 
			
		||||
                s_logger.info("Console proxy monitor shuts dwon, terminate console proxy process");
 | 
			
		||||
            _process.destroy();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void configLog4j() {
 | 
			
		||||
        URL configUrl = System.class.getResource("/conf/log4j-cloud.xml");
 | 
			
		||||
        if(configUrl == null)
 | 
			
		||||
            configUrl = ClassLoader.getSystemResource("log4j-cloud.xml");
 | 
			
		||||
        
 | 
			
		||||
        if(configUrl == null)
 | 
			
		||||
            configUrl = ClassLoader.getSystemResource("conf/log4j-cloud.xml");
 | 
			
		||||
            
 | 
			
		||||
        if(configUrl != null) {
 | 
			
		||||
            try {
 | 
			
		||||
                System.out.println("Configure log4j using " + configUrl.toURI().toString());
 | 
			
		||||
            } catch (URISyntaxException e1) {
 | 
			
		||||
                e1.printStackTrace();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                File file = new File(configUrl.toURI());
 | 
			
		||||
                
 | 
			
		||||
                System.out.println("Log4j configuration from : " + file.getAbsolutePath());
 | 
			
		||||
                DOMConfigurator.configureAndWatch(file.getAbsolutePath(), 10000);
 | 
			
		||||
            } catch (URISyntaxException e) {
 | 
			
		||||
                System.out.println("Unable to convert log4j configuration Url to URI");
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            System.out.println("Configure log4j with default properties");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static void main(String[] argv) {
 | 
			
		||||
        configLog4j();
 | 
			
		||||
        (new ConsoleProxyMonitor(argv)).run();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,142 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.security.InvalidKeyException;
 | 
			
		||||
import java.security.NoSuchAlgorithmException;
 | 
			
		||||
 | 
			
		||||
import javax.crypto.BadPaddingException;
 | 
			
		||||
import javax.crypto.Cipher;
 | 
			
		||||
import javax.crypto.IllegalBlockSizeException;
 | 
			
		||||
import javax.crypto.NoSuchPaddingException;
 | 
			
		||||
import javax.crypto.spec.SecretKeySpec;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.codec.binary.Base64;
 | 
			
		||||
import org.apache.log4j.Logger;
 | 
			
		||||
 | 
			
		||||
import com.google.gson.Gson;
 | 
			
		||||
import com.google.gson.GsonBuilder;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * A simple password based encyrptor based on DES. It can serialize simple POJO object into URL safe string
 | 
			
		||||
 * and deserialize it back.
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
public class ConsoleProxyPasswordBasedEncryptor {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxyPasswordBasedEncryptor.class);
 | 
			
		||||
    
 | 
			
		||||
    private String password;
 | 
			
		||||
    private Gson gson;
 | 
			
		||||
    
 | 
			
		||||
    public ConsoleProxyPasswordBasedEncryptor(String password) {
 | 
			
		||||
        this.password = password;
 | 
			
		||||
        gson = new GsonBuilder().create();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public String encryptText(String text) {
 | 
			
		||||
        if(text == null || text.isEmpty())
 | 
			
		||||
            return text;
 | 
			
		||||
        
 | 
			
		||||
        assert(password != null);
 | 
			
		||||
        assert(!password.isEmpty());
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
            Cipher cipher = Cipher.getInstance("DES");
 | 
			
		||||
            int maxKeySize = 8;
 | 
			
		||||
            SecretKeySpec keySpec = new SecretKeySpec(normalizeKey(password.getBytes(), maxKeySize), "DES");
 | 
			
		||||
            cipher.init(Cipher.ENCRYPT_MODE, keySpec);
 | 
			
		||||
            byte[] encryptedBytes = cipher.doFinal(text.getBytes());
 | 
			
		||||
            return Base64.encodeBase64URLSafeString(encryptedBytes);
 | 
			
		||||
        } catch (NoSuchAlgorithmException e) {
 | 
			
		||||
            s_logger.error("Unexpected exception ", e);
 | 
			
		||||
            return null;
 | 
			
		||||
        } catch (NoSuchPaddingException e) {
 | 
			
		||||
            s_logger.error("Unexpected exception ", e);
 | 
			
		||||
            return null;
 | 
			
		||||
        } catch (IllegalBlockSizeException e) {
 | 
			
		||||
            s_logger.error("Unexpected exception ", e);
 | 
			
		||||
            return null;
 | 
			
		||||
        } catch (BadPaddingException e) {
 | 
			
		||||
            s_logger.error("Unexpected exception ", e);
 | 
			
		||||
            return null;
 | 
			
		||||
        } catch (InvalidKeyException e) {
 | 
			
		||||
            s_logger.error("Unexpected exception ", e);
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String decryptText(String encryptedText) {
 | 
			
		||||
        if(encryptedText == null || encryptedText.isEmpty())
 | 
			
		||||
            return encryptedText;
 | 
			
		||||
 | 
			
		||||
        assert(password != null);
 | 
			
		||||
        assert(!password.isEmpty());
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            Cipher cipher = Cipher.getInstance("DES");
 | 
			
		||||
            int maxKeySize = 8;
 | 
			
		||||
            SecretKeySpec keySpec = new SecretKeySpec(normalizeKey(password.getBytes(), maxKeySize), "DES");
 | 
			
		||||
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
 | 
			
		||||
            
 | 
			
		||||
            byte[] encryptedBytes = Base64.decodeBase64(encryptedText);
 | 
			
		||||
            return new String(cipher.doFinal(encryptedBytes));
 | 
			
		||||
        } catch (NoSuchAlgorithmException e) {
 | 
			
		||||
            s_logger.error("Unexpected exception ", e);
 | 
			
		||||
            return null;
 | 
			
		||||
        } catch (NoSuchPaddingException e) {
 | 
			
		||||
            s_logger.error("Unexpected exception ", e);
 | 
			
		||||
            return null;
 | 
			
		||||
        } catch (IllegalBlockSizeException e) {
 | 
			
		||||
            s_logger.error("Unexpected exception ", e);
 | 
			
		||||
            return null;
 | 
			
		||||
        } catch (BadPaddingException e) {
 | 
			
		||||
            s_logger.error("Unexpected exception ", e);
 | 
			
		||||
            return null;
 | 
			
		||||
        } catch (InvalidKeyException e) {
 | 
			
		||||
            s_logger.error("Unexpected exception ", e);
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public <T> String encryptObject(Class<?> clz, T obj) {
 | 
			
		||||
        if(obj == null)
 | 
			
		||||
            return null;
 | 
			
		||||
        
 | 
			
		||||
        String json = gson.toJson(obj);
 | 
			
		||||
        return encryptText(json);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    public <T> T decryptObject(Class<?> clz, String encrypted) {
 | 
			
		||||
        if(encrypted == null || encrypted.isEmpty())
 | 
			
		||||
            return null;
 | 
			
		||||
        
 | 
			
		||||
        String json = decryptText(encrypted);
 | 
			
		||||
        return (T)gson.fromJson(json, clz);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static byte[] normalizeKey(byte[] keyBytes, int keySize) {
 | 
			
		||||
        assert(keySize > 0);
 | 
			
		||||
        byte[] key = new byte[keySize];
 | 
			
		||||
        
 | 
			
		||||
        for(int i = 0; i < keyBytes.length; i++)
 | 
			
		||||
            key[i%keySize] ^= keyBytes[i];
 | 
			
		||||
        
 | 
			
		||||
        return key;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,181 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
import com.sun.net.httpserver.Headers;
 | 
			
		||||
import com.sun.net.httpserver.HttpExchange;
 | 
			
		||||
import com.sun.net.httpserver.HttpHandler;
 | 
			
		||||
 | 
			
		||||
public class ConsoleProxyResourceHandler implements HttpHandler {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxyResourceHandler.class);
 | 
			
		||||
 | 
			
		||||
    static Map<String, String> s_mimeTypes;
 | 
			
		||||
    static {
 | 
			
		||||
        s_mimeTypes = new HashMap<String, String>();
 | 
			
		||||
        s_mimeTypes.put("jar", "application/java-archive");
 | 
			
		||||
        s_mimeTypes.put("js", "text/javascript");
 | 
			
		||||
        s_mimeTypes.put("css", "text/css");
 | 
			
		||||
        s_mimeTypes.put("jpg", "image/jpeg");
 | 
			
		||||
        s_mimeTypes.put("html", "text/html");
 | 
			
		||||
        s_mimeTypes.put("htm", "text/html");
 | 
			
		||||
        s_mimeTypes.put("log", "text/plain");
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    static Map<String, String> s_validResourceFolders;
 | 
			
		||||
    static {
 | 
			
		||||
        s_validResourceFolders = new HashMap<String, String>();
 | 
			
		||||
        s_validResourceFolders.put("applet", "");
 | 
			
		||||
        s_validResourceFolders.put("logs", "");
 | 
			
		||||
        s_validResourceFolders.put("images", "");
 | 
			
		||||
        s_validResourceFolders.put("js", "");
 | 
			
		||||
        s_validResourceFolders.put("css", "");
 | 
			
		||||
        s_validResourceFolders.put("html", "");
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public ConsoleProxyResourceHandler() {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void handle(HttpExchange t) throws IOException {
 | 
			
		||||
        try {
 | 
			
		||||
            if(s_logger.isDebugEnabled())
 | 
			
		||||
                s_logger.debug("Resource Handler " + t.getRequestURI());
 | 
			
		||||
            
 | 
			
		||||
            long startTick = System.currentTimeMillis();
 | 
			
		||||
            
 | 
			
		||||
            doHandle(t);
 | 
			
		||||
            
 | 
			
		||||
            if(s_logger.isDebugEnabled())
 | 
			
		||||
                s_logger.debug(t.getRequestURI() + " Process time " + (System.currentTimeMillis() - startTick) + " ms");
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            throw e;
 | 
			
		||||
        } catch(Throwable e) {
 | 
			
		||||
            s_logger.error("Unexpected exception, ", e);
 | 
			
		||||
            t.sendResponseHeaders(500, -1);     // server error
 | 
			
		||||
        } finally {
 | 
			
		||||
            t.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @SuppressWarnings("deprecation")
 | 
			
		||||
    private void doHandle(HttpExchange t) throws Exception {
 | 
			
		||||
        String path = t.getRequestURI().getPath();
 | 
			
		||||
 | 
			
		||||
        if(s_logger.isInfoEnabled())
 | 
			
		||||
            s_logger.info("Get resource request for " + path);
 | 
			
		||||
        
 | 
			
		||||
        int i = path.indexOf("/", 1);
 | 
			
		||||
        String filepath = path.substring(i + 1);
 | 
			
		||||
        i = path.lastIndexOf(".");
 | 
			
		||||
        String extension = (i == -1) ? "" : path.substring(i + 1);
 | 
			
		||||
        String contentType = getContentType(extension);
 | 
			
		||||
 | 
			
		||||
        if(!validatePath(filepath)) {
 | 
			
		||||
            if(s_logger.isInfoEnabled())
 | 
			
		||||
                s_logger.info("Resource access is forbidden, uri: " + path);
 | 
			
		||||
            
 | 
			
		||||
            t.sendResponseHeaders(403, -1);     // forbidden
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        File f = new File ("./" + filepath);
 | 
			
		||||
        if(f.exists()) {
 | 
			
		||||
            long lastModified = f.lastModified();
 | 
			
		||||
            String ifModifiedSince = t.getRequestHeaders().getFirst("If-Modified-Since");
 | 
			
		||||
            if (ifModifiedSince != null) {
 | 
			
		||||
                long d = Date.parse(ifModifiedSince);
 | 
			
		||||
                if (d + 1000 >= lastModified) {
 | 
			
		||||
                    Headers hds = t.getResponseHeaders();
 | 
			
		||||
                    hds.set("Content-Type", contentType);
 | 
			
		||||
                    t.sendResponseHeaders(304, -1);
 | 
			
		||||
                    
 | 
			
		||||
                    if(s_logger.isInfoEnabled())
 | 
			
		||||
                        s_logger.info("Sent 304 file has not been " +
 | 
			
		||||
                                "modified since " + ifModifiedSince);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            long length = f.length();
 | 
			
		||||
            Headers hds = t.getResponseHeaders();
 | 
			
		||||
            hds.set("Content-Type", contentType);
 | 
			
		||||
            hds.set("Last-Modified", new Date(lastModified).toGMTString());
 | 
			
		||||
            t.sendResponseHeaders(200, length);
 | 
			
		||||
            responseFileContent(t, f);
 | 
			
		||||
            
 | 
			
		||||
            if(s_logger.isInfoEnabled())
 | 
			
		||||
                s_logger.info("Sent file " + path + " with content type " + contentType);
 | 
			
		||||
        } else {
 | 
			
		||||
            if(s_logger.isInfoEnabled())
 | 
			
		||||
                s_logger.info("file does not exist" + path);
 | 
			
		||||
            t.sendResponseHeaders(404, -1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static String getContentType(String extension) {
 | 
			
		||||
        String key = extension.toLowerCase();
 | 
			
		||||
        if(s_mimeTypes.containsKey(key)) {
 | 
			
		||||
            return s_mimeTypes.get(key);
 | 
			
		||||
        }
 | 
			
		||||
        return "application/octet-stream"; 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static void responseFileContent(HttpExchange t, File f) throws Exception {
 | 
			
		||||
        OutputStream os = t.getResponseBody();
 | 
			
		||||
        FileInputStream fis = new FileInputStream(f);
 | 
			
		||||
        while (true) {
 | 
			
		||||
            byte[] b = new byte[8192];
 | 
			
		||||
            int n = fis.read(b);
 | 
			
		||||
            if (n < 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            os.write(b, 0, n);
 | 
			
		||||
        }
 | 
			
		||||
        fis.close();
 | 
			
		||||
        os.close();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static boolean validatePath(String path) {
 | 
			
		||||
        int i = path.indexOf("/");
 | 
			
		||||
        if(i == -1) {
 | 
			
		||||
            if(s_logger.isInfoEnabled())
 | 
			
		||||
                s_logger.info("Invalid resource path: can not start at resource root");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(path.contains("..")) {
 | 
			
		||||
            if(s_logger.isInfoEnabled())
 | 
			
		||||
                s_logger.info("Invalid resource path: contains relative up-level navigation");
 | 
			
		||||
            
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return isValidResourceFolder(path.substring(0, i));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static boolean isValidResourceFolder(String name) {
 | 
			
		||||
        return s_validResourceFolders.containsKey(name); 
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,145 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.io.ByteArrayInputStream;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.InetSocketAddress;
 | 
			
		||||
import java.security.KeyStore;
 | 
			
		||||
 | 
			
		||||
import javax.net.ssl.KeyManagerFactory;
 | 
			
		||||
import javax.net.ssl.SSLContext;
 | 
			
		||||
import javax.net.ssl.SSLParameters;
 | 
			
		||||
import javax.net.ssl.SSLServerSocket;
 | 
			
		||||
import javax.net.ssl.SSLServerSocketFactory;
 | 
			
		||||
import javax.net.ssl.TrustManagerFactory;
 | 
			
		||||
 | 
			
		||||
import org.apache.log4j.Logger;
 | 
			
		||||
 | 
			
		||||
import com.sun.net.httpserver.HttpServer;
 | 
			
		||||
import com.sun.net.httpserver.HttpsConfigurator;
 | 
			
		||||
import com.sun.net.httpserver.HttpsParameters;
 | 
			
		||||
import com.sun.net.httpserver.HttpsServer;
 | 
			
		||||
 | 
			
		||||
public class ConsoleProxySecureServerFactoryImpl implements ConsoleProxyServerFactory  {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxySecureServerFactoryImpl.class);
 | 
			
		||||
    
 | 
			
		||||
    private SSLContext sslContext = null;
 | 
			
		||||
    
 | 
			
		||||
    public ConsoleProxySecureServerFactoryImpl() {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void init(byte[] ksBits, String ksPassword) {
 | 
			
		||||
        s_logger.info("Start initializing SSL");
 | 
			
		||||
 | 
			
		||||
        if(ksBits == null) {
 | 
			
		||||
            try {
 | 
			
		||||
                s_logger.info("Initializing SSL from built-in default certificate");
 | 
			
		||||
                
 | 
			
		||||
                char[] passphrase = "vmops.com".toCharArray();
 | 
			
		||||
                KeyStore ks = KeyStore.getInstance("JKS");
 | 
			
		||||
                
 | 
			
		||||
                ks.load(new FileInputStream("certs/realhostip.keystore"), passphrase);
 | 
			
		||||
                // ks.load(ConsoleProxy.class.getResourceAsStream("/realhostip.keystore"), passphrase);
 | 
			
		||||
                
 | 
			
		||||
                s_logger.info("SSL certificate loaded");
 | 
			
		||||
                
 | 
			
		||||
                KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
 | 
			
		||||
                kmf.init(ks, passphrase);
 | 
			
		||||
                s_logger.info("Key manager factory is initialized");
 | 
			
		||||
 | 
			
		||||
                TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
 | 
			
		||||
                tmf.init(ks);
 | 
			
		||||
                s_logger.info("Trust manager factory is initialized");
 | 
			
		||||
 | 
			
		||||
                sslContext = SSLContext.getInstance("TLS");
 | 
			
		||||
                sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 | 
			
		||||
                s_logger.info("SSL context is initialized");
 | 
			
		||||
            } catch (Exception ioe) {
 | 
			
		||||
                s_logger.error(ioe.toString(), ioe);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
        } else {
 | 
			
		||||
            char[] passphrase = ksPassword != null ? ksPassword.toCharArray() : null;
 | 
			
		||||
            try {
 | 
			
		||||
                s_logger.info("Initializing SSL from passed-in certificate");
 | 
			
		||||
                
 | 
			
		||||
                KeyStore ks = KeyStore.getInstance("JKS");
 | 
			
		||||
                ks.load(new ByteArrayInputStream(ksBits), passphrase);
 | 
			
		||||
                
 | 
			
		||||
                KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
 | 
			
		||||
                kmf.init(ks, passphrase);
 | 
			
		||||
                s_logger.info("Key manager factory is initialized");
 | 
			
		||||
        
 | 
			
		||||
                TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
 | 
			
		||||
                tmf.init(ks);
 | 
			
		||||
                s_logger.info("Trust manager factory is initialized");
 | 
			
		||||
        
 | 
			
		||||
                sslContext = SSLContext.getInstance("TLS");
 | 
			
		||||
                sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 | 
			
		||||
                s_logger.info("SSL context is initialized");
 | 
			
		||||
            } catch(Exception e) {
 | 
			
		||||
                s_logger.error("Unable to init factory due to exception ", e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public HttpServer createHttpServerInstance(int port) throws IOException {
 | 
			
		||||
        try {
 | 
			
		||||
            HttpsServer server = HttpsServer.create(new InetSocketAddress(port), 5);
 | 
			
		||||
            server.setHttpsConfigurator (new HttpsConfigurator(sslContext) {
 | 
			
		||||
                @Override
 | 
			
		||||
                public void configure (HttpsParameters params) {
 | 
			
		||||
 | 
			
		||||
                // get the remote address if needed
 | 
			
		||||
                InetSocketAddress remote = params.getClientAddress();
 | 
			
		||||
                SSLContext c = getSSLContext();
 | 
			
		||||
 | 
			
		||||
                // get the default parameters
 | 
			
		||||
                SSLParameters sslparams = c.getDefaultSSLParameters();
 | 
			
		||||
 | 
			
		||||
                params.setSSLParameters(sslparams);
 | 
			
		||||
                // statement above could throw IAE if any params invalid.
 | 
			
		||||
                // eg. if app has a UI and parameters supplied by a user.
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            s_logger.info("create HTTPS server instance on port: " + port);
 | 
			
		||||
            return server;
 | 
			
		||||
        } catch (Exception ioe) {
 | 
			
		||||
            s_logger.error(ioe.toString(), ioe);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public SSLServerSocket createSSLServerSocket(int port) throws IOException {
 | 
			
		||||
        try {
 | 
			
		||||
            SSLServerSocket srvSock = null;
 | 
			
		||||
            SSLServerSocketFactory ssf = sslContext.getServerSocketFactory();
 | 
			
		||||
            srvSock = (SSLServerSocket) ssf.createServerSocket(port);
 | 
			
		||||
            
 | 
			
		||||
            s_logger.info("create SSL server socket on port: " + port);
 | 
			
		||||
            return srvSock;
 | 
			
		||||
        } catch (Exception ioe) {
 | 
			
		||||
            s_logger.error(ioe.toString(), ioe);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,29 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
import javax.net.ssl.SSLServerSocket;
 | 
			
		||||
 | 
			
		||||
import com.sun.net.httpserver.HttpServer;
 | 
			
		||||
 | 
			
		||||
public interface ConsoleProxyServerFactory {
 | 
			
		||||
    void init(byte[] ksBits, String ksPassword);
 | 
			
		||||
    HttpServer createHttpServerInstance(int port) throws IOException;
 | 
			
		||||
    SSLServerSocket createSSLServerSocket(int port) throws IOException;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,212 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.awt.Color;
 | 
			
		||||
import java.awt.Font;
 | 
			
		||||
import java.awt.FontMetrics;
 | 
			
		||||
import java.awt.Graphics2D;
 | 
			
		||||
import java.awt.Image;
 | 
			
		||||
import java.awt.image.BufferedImage;
 | 
			
		||||
import java.io.ByteArrayOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
import com.sun.net.httpserver.Headers;
 | 
			
		||||
import com.sun.net.httpserver.HttpExchange;
 | 
			
		||||
import com.sun.net.httpserver.HttpHandler;
 | 
			
		||||
 | 
			
		||||
public class ConsoleProxyThumbnailHandler implements HttpHandler {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxyThumbnailHandler.class);
 | 
			
		||||
    
 | 
			
		||||
    public ConsoleProxyThumbnailHandler() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void handle(HttpExchange t) throws IOException {
 | 
			
		||||
        try {
 | 
			
		||||
            Thread.currentThread().setName("JPG Thread " + 
 | 
			
		||||
                    Thread.currentThread().getId() + " " + t.getRemoteAddress());
 | 
			
		||||
            
 | 
			
		||||
            if(s_logger.isDebugEnabled())
 | 
			
		||||
                s_logger.debug("ScreenHandler " + t.getRequestURI());
 | 
			
		||||
            
 | 
			
		||||
            long startTick = System.currentTimeMillis();
 | 
			
		||||
            doHandle(t);
 | 
			
		||||
            
 | 
			
		||||
            if(s_logger.isDebugEnabled())
 | 
			
		||||
                s_logger.debug(t.getRequestURI() + "Process time " + (System.currentTimeMillis() - startTick) + " ms");
 | 
			
		||||
        } catch (IllegalArgumentException e) {
 | 
			
		||||
            String response = "Bad query string";
 | 
			
		||||
            s_logger.error(response + ", request URI : " + t.getRequestURI());
 | 
			
		||||
            t.sendResponseHeaders(200, response.length());
 | 
			
		||||
            OutputStream os = t.getResponseBody();
 | 
			
		||||
            os.write(response.getBytes());
 | 
			
		||||
            os.close();
 | 
			
		||||
        } catch(OutOfMemoryError e) {
 | 
			
		||||
            s_logger.error("Unrecoverable OutOfMemory Error, exit and let it be re-launched");
 | 
			
		||||
            System.exit(1);
 | 
			
		||||
        } catch (Throwable e) {
 | 
			
		||||
            s_logger.error("Unexpected exception while handing thumbnail request, ", e);
 | 
			
		||||
            
 | 
			
		||||
            String queries = t.getRequestURI().getQuery();
 | 
			
		||||
            Map<String, String> queryMap = getQueryMap(queries);
 | 
			
		||||
            int width = 0;
 | 
			
		||||
            int height = 0;
 | 
			
		||||
            String ws = queryMap.get("w");
 | 
			
		||||
            String hs = queryMap.get("h");
 | 
			
		||||
            try {
 | 
			
		||||
                width = Integer.parseInt(ws);
 | 
			
		||||
                height = Integer.parseInt(hs);
 | 
			
		||||
            } catch (NumberFormatException ex) {
 | 
			
		||||
            }
 | 
			
		||||
            width = Math.min(width, 800);
 | 
			
		||||
            height = Math.min(height, 600);
 | 
			
		||||
            
 | 
			
		||||
            BufferedImage img = generateTextImage(width, height, "Cannot Connect");
 | 
			
		||||
            ByteArrayOutputStream bos = new ByteArrayOutputStream(8196);
 | 
			
		||||
            javax.imageio.ImageIO.write(img, "jpg", bos);
 | 
			
		||||
            byte[] bs = bos.toByteArray();
 | 
			
		||||
            Headers hds = t.getResponseHeaders();
 | 
			
		||||
            hds.set("Content-Type", "image/jpeg");
 | 
			
		||||
            hds.set("Cache-Control", "no-cache");
 | 
			
		||||
            hds.set("Cache-Control", "no-store");
 | 
			
		||||
            t.sendResponseHeaders(200, bs.length);
 | 
			
		||||
            OutputStream os = t.getResponseBody();
 | 
			
		||||
            os.write(bs);
 | 
			
		||||
            os.close();
 | 
			
		||||
            s_logger.error("Cannot get console, sent error JPG response for " + t.getRequestURI());
 | 
			
		||||
            return;
 | 
			
		||||
        } finally {
 | 
			
		||||
            t.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void doHandle(HttpExchange t) throws Exception, IllegalArgumentException {
 | 
			
		||||
        String queries = t.getRequestURI().getQuery();
 | 
			
		||||
        Map<String, String> queryMap = getQueryMap(queries);
 | 
			
		||||
        int width = 0;
 | 
			
		||||
        int height = 0;
 | 
			
		||||
        int port = 0;
 | 
			
		||||
        String ws = queryMap.get("w");
 | 
			
		||||
        String hs = queryMap.get("h");
 | 
			
		||||
        String host = queryMap.get("host");
 | 
			
		||||
        String portStr = queryMap.get("port");
 | 
			
		||||
        String sid = queryMap.get("sid");
 | 
			
		||||
        String tag = queryMap.get("tag");
 | 
			
		||||
        String ticket = queryMap.get("ticket");
 | 
			
		||||
        String console_url = queryMap.get("consoleurl");
 | 
			
		||||
        String console_host_session = queryMap.get("sessionref");
 | 
			
		||||
 | 
			
		||||
        if(tag == null)
 | 
			
		||||
            tag = "";
 | 
			
		||||
        
 | 
			
		||||
        if (ws == null || hs == null || host == null || portStr == null || sid == null ) {
 | 
			
		||||
            throw new IllegalArgumentException();
 | 
			
		||||
        }
 | 
			
		||||
        try {
 | 
			
		||||
            width = Integer.parseInt(ws);
 | 
			
		||||
            height = Integer.parseInt(hs);
 | 
			
		||||
            port = Integer.parseInt(portStr);
 | 
			
		||||
        } catch (NumberFormatException e) {
 | 
			
		||||
            throw new IllegalArgumentException(e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ConsoleProxyClientParam param = new ConsoleProxyClientParam();
 | 
			
		||||
        param.setClientHostAddress(host);
 | 
			
		||||
        param.setClientHostPort(port);
 | 
			
		||||
        param.setClientHostPassword(sid);
 | 
			
		||||
        param.setClientTag(tag);
 | 
			
		||||
        param.setTicket(ticket);
 | 
			
		||||
        param.setClientTunnelUrl(console_url);
 | 
			
		||||
        param.setClientTunnelSession(console_host_session);
 | 
			
		||||
        
 | 
			
		||||
        ConsoleProxyClient viewer = ConsoleProxy.getVncViewer(param);
 | 
			
		||||
        
 | 
			
		||||
        if (!viewer.isHostConnected()) {
 | 
			
		||||
            // use generated image instead of static
 | 
			
		||||
            BufferedImage img = generateTextImage(width, height, "Connecting");
 | 
			
		||||
            ByteArrayOutputStream bos = new ByteArrayOutputStream(8196);
 | 
			
		||||
            javax.imageio.ImageIO.write(img, "jpg", bos);
 | 
			
		||||
            byte[] bs = bos.toByteArray();
 | 
			
		||||
            Headers hds = t.getResponseHeaders();
 | 
			
		||||
            hds.set("Content-Type", "image/jpeg");
 | 
			
		||||
            hds.set("Cache-Control", "no-cache");
 | 
			
		||||
            hds.set("Cache-Control", "no-store");
 | 
			
		||||
            t.sendResponseHeaders(200, bs.length);
 | 
			
		||||
            OutputStream os = t.getResponseBody();
 | 
			
		||||
            os.write(bs);
 | 
			
		||||
            os.close();
 | 
			
		||||
            
 | 
			
		||||
            if(s_logger.isInfoEnabled())
 | 
			
		||||
                s_logger.info("Console not ready, sent dummy JPG response");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        {
 | 
			
		||||
            Image scaledImage = viewer.getClientScaledImage(width, height);
 | 
			
		||||
            BufferedImage bufferedImage = new BufferedImage(width, height,
 | 
			
		||||
                    BufferedImage.TYPE_3BYTE_BGR);
 | 
			
		||||
            Graphics2D bufImageGraphics = bufferedImage.createGraphics();
 | 
			
		||||
            bufImageGraphics.drawImage(scaledImage, 0, 0, null);
 | 
			
		||||
            ByteArrayOutputStream bos = new ByteArrayOutputStream(8196);
 | 
			
		||||
            javax.imageio.ImageIO.write(bufferedImage, "jpg", bos);
 | 
			
		||||
            byte[] bs = bos.toByteArray();
 | 
			
		||||
            Headers hds = t.getResponseHeaders();
 | 
			
		||||
            hds.set("Content-Type", "image/jpeg");
 | 
			
		||||
            hds.set("Cache-Control", "no-cache");
 | 
			
		||||
            hds.set("Cache-Control", "no-store");
 | 
			
		||||
            t.sendResponseHeaders(200, bs.length);
 | 
			
		||||
            OutputStream os = t.getResponseBody();
 | 
			
		||||
            os.write(bs);
 | 
			
		||||
            os.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static BufferedImage generateTextImage(int w, int h, String text) {
 | 
			
		||||
        BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);
 | 
			
		||||
        Graphics2D g = img.createGraphics();
 | 
			
		||||
        g.setColor(Color.BLACK);
 | 
			
		||||
        g.fillRect(0, 0, w, h);
 | 
			
		||||
        g.setColor(Color.WHITE);
 | 
			
		||||
        try {
 | 
			
		||||
            g.setFont(new Font(null, Font.PLAIN, 12));
 | 
			
		||||
            FontMetrics fm = g.getFontMetrics();
 | 
			
		||||
            int textWidth = fm.stringWidth(text);
 | 
			
		||||
            int startx = (w-textWidth) / 2;
 | 
			
		||||
            if(startx < 0)
 | 
			
		||||
                startx = 0;
 | 
			
		||||
            g.drawString(text, startx, h/2);
 | 
			
		||||
        } catch (Throwable e) {
 | 
			
		||||
            s_logger.warn("Problem in generating text to thumnail image, return blank image");
 | 
			
		||||
        }
 | 
			
		||||
        return img;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Map<String, String> getQueryMap(String query) {
 | 
			
		||||
        String[] params = query.split("&");
 | 
			
		||||
        Map<String, String> map = new HashMap<String, String>();
 | 
			
		||||
        for (String param : params) {
 | 
			
		||||
            String name = param.split("=")[0];
 | 
			
		||||
            String value = param.split("=")[1];
 | 
			
		||||
            map.put(name, value);
 | 
			
		||||
        }
 | 
			
		||||
        return map;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,235 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.URI;
 | 
			
		||||
import java.net.UnknownHostException;
 | 
			
		||||
 | 
			
		||||
import org.apache.log4j.Logger;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.vnc.FrameBufferCanvas;
 | 
			
		||||
import com.cloud.consoleproxy.vnc.RfbConstants;
 | 
			
		||||
import com.cloud.consoleproxy.vnc.VncClient;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * ConsoleProxyVncClient bridges a VNC engine with the front-end AJAX viewer
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
public class ConsoleProxyVncClient extends ConsoleProxyClientBase {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(ConsoleProxyVncClient.class);
 | 
			
		||||
 | 
			
		||||
    private static final int SHIFT_KEY_MASK = 64;
 | 
			
		||||
    private static final int CTRL_KEY_MASK = 128;
 | 
			
		||||
    private static final int META_KEY_MASK = 256;
 | 
			
		||||
    private static final int ALT_KEY_MASK = 512;
 | 
			
		||||
    
 | 
			
		||||
    private static final int X11_KEY_SHIFT = 0xffe1;
 | 
			
		||||
    private static final int X11_KEY_CTRL = 0xffe3;
 | 
			
		||||
    private static final int X11_KEY_ALT = 0xffe9;
 | 
			
		||||
    private static final int X11_KEY_META = 0xffe7;
 | 
			
		||||
    
 | 
			
		||||
    private VncClient client;
 | 
			
		||||
    private Thread worker;
 | 
			
		||||
    private boolean workerDone = false;
 | 
			
		||||
    
 | 
			
		||||
    private int lastModifierStates = 0;
 | 
			
		||||
    private int lastPointerMask = 0;
 | 
			
		||||
    
 | 
			
		||||
    public ConsoleProxyVncClient() {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public boolean isHostConnected() {
 | 
			
		||||
        if(client != null)
 | 
			
		||||
            return client.isHostConnected();
 | 
			
		||||
        
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isFrontEndAlive() {
 | 
			
		||||
        if(workerDone || System.currentTimeMillis() - getClientLastFrontEndActivityTime() > ConsoleProxy.VIEWER_LINGER_SECONDS*1000) {
 | 
			
		||||
            s_logger.info("Front end has been idle for too long");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void initClient(ConsoleProxyClientParam param) {
 | 
			
		||||
        setClientParam(param);
 | 
			
		||||
        
 | 
			
		||||
        client = new VncClient(this);
 | 
			
		||||
        worker = new Thread(new Runnable() {
 | 
			
		||||
            public void run() {
 | 
			
		||||
                String tunnelUrl = getClientParam().getClientTunnelUrl();
 | 
			
		||||
                String tunnelSession = getClientParam().getClientTunnelSession();
 | 
			
		||||
                
 | 
			
		||||
                for(int i = 0; i < 15; i++) {
 | 
			
		||||
                    try {
 | 
			
		||||
                        if(tunnelUrl != null && !tunnelUrl.isEmpty() && tunnelSession != null && !tunnelSession.isEmpty()) {
 | 
			
		||||
                            URI uri = new URI(tunnelUrl);
 | 
			
		||||
                            s_logger.info("Connect to VNC server via tunnel. url: " + tunnelUrl + ", session: " + tunnelSession);
 | 
			
		||||
                            
 | 
			
		||||
                            ConsoleProxy.ensureRoute(uri.getHost());
 | 
			
		||||
                            client.connectTo(
 | 
			
		||||
                                uri.getHost(), uri.getPort(), 
 | 
			
		||||
                                uri.getPath() + "?" + uri.getQuery(), 
 | 
			
		||||
                                tunnelSession, "https".equalsIgnoreCase(uri.getScheme()),
 | 
			
		||||
                                getClientHostPassword());
 | 
			
		||||
                        } else {
 | 
			
		||||
                            s_logger.info("Connect to VNC server directly. host: " + getClientHostAddress() + ", port: " + getClientHostPort());
 | 
			
		||||
                            ConsoleProxy.ensureRoute(getClientHostAddress());
 | 
			
		||||
                            client.connectTo(getClientHostAddress(), getClientHostPort(), getClientHostPassword());
 | 
			
		||||
                        }
 | 
			
		||||
                    } catch (UnknownHostException e) {
 | 
			
		||||
                        s_logger.error("Unexpected exception (will retry until timeout)", e);
 | 
			
		||||
                    } catch (IOException e) {
 | 
			
		||||
                        s_logger.error("Unexpected exception (will retry until timeout) ", e);
 | 
			
		||||
                    } catch (Throwable e) {
 | 
			
		||||
                        s_logger.error("Unexpected exception (will retry until timeout) ", e);
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    try {
 | 
			
		||||
                        Thread.sleep(1000);
 | 
			
		||||
                    } catch (InterruptedException e) {
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if(tunnelUrl != null && !tunnelUrl.isEmpty() && tunnelSession != null && !tunnelSession.isEmpty()) {
 | 
			
		||||
                        ConsoleProxyAuthenticationResult authResult = ConsoleProxy.reAuthenticationExternally(getClientParam());
 | 
			
		||||
                        if(authResult != null && authResult.isSuccess()) {
 | 
			
		||||
                            if(authResult.getTunnelUrl() != null && !authResult.getTunnelUrl().isEmpty() && 
 | 
			
		||||
                                authResult.getTunnelSession() != null && !authResult.getTunnelSession().isEmpty()) {
 | 
			
		||||
                                tunnelUrl = authResult.getTunnelUrl();
 | 
			
		||||
                                tunnelSession = authResult.getTunnelSession();
 | 
			
		||||
                                
 | 
			
		||||
                                s_logger.info("Reset XAPI session. url: " + tunnelUrl + ", session: " + tunnelSession);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                s_logger.info("Receiver thread stopped.");
 | 
			
		||||
                workerDone = true;
 | 
			
		||||
                client.getClientListener().onClientClose();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        worker.setDaemon(true);
 | 
			
		||||
        worker.start();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void closeClient() {
 | 
			
		||||
        if(client != null)
 | 
			
		||||
            client.shutdown();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onClientConnected() {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void onClientClose() {
 | 
			
		||||
        s_logger.info("Received client close indication. remove viewer from map.");
 | 
			
		||||
        
 | 
			
		||||
        ConsoleProxy.removeViewer(this);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onFramebufferUpdate(int x, int y, int w, int h) {
 | 
			
		||||
        super.onFramebufferUpdate(x, y, w, h);
 | 
			
		||||
        client.requestUpdate(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void sendClientRawKeyboardEvent(InputEventType event, int code, int modifiers) {
 | 
			
		||||
        if(client == null)
 | 
			
		||||
            return;
 | 
			
		||||
        
 | 
			
		||||
        updateFrontEndActivityTime();
 | 
			
		||||
        
 | 
			
		||||
        switch(event) {
 | 
			
		||||
        case KEY_DOWN :
 | 
			
		||||
            sendModifierEvents(modifiers);
 | 
			
		||||
            client.sendClientKeyboardEvent(RfbConstants.KEY_DOWN, code, 0);
 | 
			
		||||
            break;
 | 
			
		||||
            
 | 
			
		||||
        case KEY_UP :
 | 
			
		||||
            client.sendClientKeyboardEvent(RfbConstants.KEY_UP, code, 0);
 | 
			
		||||
            sendModifierEvents(0);
 | 
			
		||||
            break;
 | 
			
		||||
            
 | 
			
		||||
        case KEY_PRESS :
 | 
			
		||||
            break;
 | 
			
		||||
            
 | 
			
		||||
        default :
 | 
			
		||||
            assert(false);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void sendClientMouseEvent(InputEventType event, int x, int y, int code, int modifiers) {
 | 
			
		||||
        if(client == null)
 | 
			
		||||
            return;
 | 
			
		||||
        
 | 
			
		||||
        updateFrontEndActivityTime();
 | 
			
		||||
 | 
			
		||||
        if (event == InputEventType.MOUSE_DOWN) {
 | 
			
		||||
            if (code == 2) {
 | 
			
		||||
                lastPointerMask |= 4;
 | 
			
		||||
            } else if (code == 0) {
 | 
			
		||||
                lastPointerMask |= 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if (event == InputEventType.MOUSE_UP) {
 | 
			
		||||
            if (code == 2) {
 | 
			
		||||
                lastPointerMask ^= 4;
 | 
			
		||||
            } else if (code == 0) {
 | 
			
		||||
                lastPointerMask ^= 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
            
 | 
			
		||||
        sendModifierEvents(modifiers);
 | 
			
		||||
        client.sendClientMouseEvent(lastPointerMask, x, y, code, modifiers);
 | 
			
		||||
        if(lastPointerMask == 0)
 | 
			
		||||
            sendModifierEvents(0);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    protected FrameBufferCanvas getFrameBufferCavas() {
 | 
			
		||||
        if(client != null)
 | 
			
		||||
            return client.getFrameBufferCanvas();
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void sendModifierEvents(int modifiers) {
 | 
			
		||||
        if((modifiers & SHIFT_KEY_MASK) != (lastModifierStates & SHIFT_KEY_MASK))
 | 
			
		||||
            client.sendClientKeyboardEvent((modifiers & SHIFT_KEY_MASK) != 0 ? RfbConstants.KEY_DOWN : RfbConstants.KEY_UP, X11_KEY_SHIFT, 0);
 | 
			
		||||
            
 | 
			
		||||
        if((modifiers & CTRL_KEY_MASK) != (lastModifierStates & CTRL_KEY_MASK))
 | 
			
		||||
            client.sendClientKeyboardEvent((modifiers & CTRL_KEY_MASK) != 0 ? RfbConstants.KEY_DOWN : RfbConstants.KEY_UP, X11_KEY_CTRL, 0);
 | 
			
		||||
 | 
			
		||||
        if((modifiers & META_KEY_MASK) != (lastModifierStates & META_KEY_MASK))
 | 
			
		||||
            client.sendClientKeyboardEvent((modifiers & META_KEY_MASK) != 0 ? RfbConstants.KEY_DOWN : RfbConstants.KEY_UP, X11_KEY_META, 0);
 | 
			
		||||
        
 | 
			
		||||
        if((modifiers & ALT_KEY_MASK) != (lastModifierStates & ALT_KEY_MASK))
 | 
			
		||||
            client.sendClientKeyboardEvent((modifiers & ALT_KEY_MASK) != 0 ? RfbConstants.KEY_DOWN : RfbConstants.KEY_UP, X11_KEY_ALT, 0);
 | 
			
		||||
        
 | 
			
		||||
        lastModifierStates = modifiers;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,58 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy;
 | 
			
		||||
 | 
			
		||||
public enum InputEventType {
 | 
			
		||||
    MOUSE_MOVE(1),
 | 
			
		||||
    MOUSE_DOWN(2),
 | 
			
		||||
    MOUSE_UP(3),
 | 
			
		||||
    KEY_PRESS(4),
 | 
			
		||||
    KEY_DOWN(5),
 | 
			
		||||
    KEY_UP(6),
 | 
			
		||||
    MOUSE_DBLCLICK(8);
 | 
			
		||||
    
 | 
			
		||||
    int eventCode;
 | 
			
		||||
    private InputEventType(int eventCode) {
 | 
			
		||||
        this.eventCode = eventCode;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public int getEventCode() { 
 | 
			
		||||
        return eventCode; 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static InputEventType fromEventCode(int eventCode) {
 | 
			
		||||
        switch(eventCode) {
 | 
			
		||||
        case 1 :
 | 
			
		||||
            return MOUSE_MOVE;
 | 
			
		||||
        case 2 :
 | 
			
		||||
            return MOUSE_DOWN;
 | 
			
		||||
        case 3 :
 | 
			
		||||
            return MOUSE_UP;
 | 
			
		||||
        case 4 :
 | 
			
		||||
            return KEY_PRESS;
 | 
			
		||||
        case 5 :
 | 
			
		||||
            return KEY_DOWN;
 | 
			
		||||
        case 6 :
 | 
			
		||||
            return KEY_UP;
 | 
			
		||||
        case 8 :
 | 
			
		||||
            return MOUSE_DBLCLICK;
 | 
			
		||||
        default :
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        throw new IllegalArgumentException("Unsupport event code: " + eventCode);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,25 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.util;
 | 
			
		||||
 | 
			
		||||
import java.awt.Rectangle;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public interface ITileScanListener {
 | 
			
		||||
    boolean onTileChange(Rectangle rowMergedRect, int row, int col);
 | 
			
		||||
    void onRegionChange(List<Region> regionList);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,32 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.util;
 | 
			
		||||
 | 
			
		||||
import java.awt.image.BufferedImage;
 | 
			
		||||
import java.io.ByteArrayOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
public class ImageHelper {
 | 
			
		||||
    public static byte[] jpegFromImage(BufferedImage image) throws IOException {
 | 
			
		||||
        ByteArrayOutputStream bos = new ByteArrayOutputStream(128000);
 | 
			
		||||
        javax.imageio.ImageIO.write(image, "jpg", bos);
 | 
			
		||||
        
 | 
			
		||||
        byte[] jpegBits = bos.toByteArray();
 | 
			
		||||
        bos.close();
 | 
			
		||||
        return jpegBits;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,223 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.util;
 | 
			
		||||
 | 
			
		||||
// logger facility for dynamic switch between console logger used in Applet and log4j based logger
 | 
			
		||||
public class Logger {
 | 
			
		||||
    private static LoggerFactory factory = null;
 | 
			
		||||
    
 | 
			
		||||
    public static final int LEVEL_TRACE = 1;
 | 
			
		||||
    public static final int LEVEL_DEBUG = 2;
 | 
			
		||||
    public static final int LEVEL_INFO = 3;
 | 
			
		||||
    public static final int LEVEL_WARN = 4;
 | 
			
		||||
    public static final int LEVEL_ERROR = 5;
 | 
			
		||||
    
 | 
			
		||||
    private Class<?> clazz;
 | 
			
		||||
    private Logger logger;
 | 
			
		||||
    
 | 
			
		||||
    private static int level = LEVEL_INFO;
 | 
			
		||||
    
 | 
			
		||||
    public static Logger getLogger(Class<?> clazz) {
 | 
			
		||||
        return new Logger(clazz);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static void setFactory(LoggerFactory f) {
 | 
			
		||||
        factory = f;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static void setLevel(int l) {
 | 
			
		||||
        level = l;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public Logger(Class<?> clazz) {
 | 
			
		||||
        this.clazz = clazz;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    protected Logger() {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public boolean isTraceEnabled() {
 | 
			
		||||
        if(factory != null) {
 | 
			
		||||
            if(logger == null)
 | 
			
		||||
                logger = factory.getLogger(clazz);
 | 
			
		||||
            
 | 
			
		||||
            return logger.isTraceEnabled();
 | 
			
		||||
        }
 | 
			
		||||
        return level <= LEVEL_TRACE;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public boolean isDebugEnabled() {
 | 
			
		||||
        if(factory != null) {
 | 
			
		||||
            if(logger == null)
 | 
			
		||||
                logger = factory.getLogger(clazz);
 | 
			
		||||
            
 | 
			
		||||
            return logger.isDebugEnabled();
 | 
			
		||||
        }
 | 
			
		||||
        return level <= LEVEL_DEBUG;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public boolean isInfoEnabled() {
 | 
			
		||||
        if(factory != null) {
 | 
			
		||||
            if(logger == null)
 | 
			
		||||
                logger = factory.getLogger(clazz);
 | 
			
		||||
            
 | 
			
		||||
            return logger.isInfoEnabled();
 | 
			
		||||
        }
 | 
			
		||||
        return level <= LEVEL_INFO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void trace(Object message) {
 | 
			
		||||
        
 | 
			
		||||
        if(factory != null) {
 | 
			
		||||
            if(logger == null)
 | 
			
		||||
                logger = factory.getLogger(clazz);
 | 
			
		||||
            
 | 
			
		||||
            logger.trace(message);
 | 
			
		||||
        } else {
 | 
			
		||||
            if(level <= LEVEL_TRACE)
 | 
			
		||||
                System.out.println(message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void trace(Object message, Throwable exception) {
 | 
			
		||||
        if(factory != null) {
 | 
			
		||||
            if(logger == null)
 | 
			
		||||
                logger = factory.getLogger(clazz);
 | 
			
		||||
            
 | 
			
		||||
            logger.trace(message, exception);
 | 
			
		||||
        } else {
 | 
			
		||||
            if(level <= LEVEL_TRACE) {
 | 
			
		||||
                System.out.println(message);
 | 
			
		||||
                if (exception != null) {
 | 
			
		||||
                    exception.printStackTrace(System.out);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void info(Object message) {
 | 
			
		||||
        if(factory != null) {
 | 
			
		||||
            if(logger == null)
 | 
			
		||||
                logger = factory.getLogger(clazz);
 | 
			
		||||
            
 | 
			
		||||
            logger.info(message);
 | 
			
		||||
        } else {
 | 
			
		||||
            if(level <= LEVEL_INFO)
 | 
			
		||||
                System.out.println(message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void info(Object message, Throwable exception) {
 | 
			
		||||
        if(factory != null) {
 | 
			
		||||
            if(logger == null)
 | 
			
		||||
                logger = factory.getLogger(clazz);
 | 
			
		||||
            
 | 
			
		||||
            logger.info(message, exception);
 | 
			
		||||
        } else {        
 | 
			
		||||
            if(level <= LEVEL_INFO) {
 | 
			
		||||
                System.out.println(message);
 | 
			
		||||
                if (exception != null) {
 | 
			
		||||
                    exception.printStackTrace(System.out);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void debug(Object message) {
 | 
			
		||||
        if(factory != null) {
 | 
			
		||||
            if(logger == null)
 | 
			
		||||
                logger = factory.getLogger(clazz);
 | 
			
		||||
            
 | 
			
		||||
            logger.debug(message);
 | 
			
		||||
        } else {
 | 
			
		||||
            if(level <= LEVEL_DEBUG)
 | 
			
		||||
                System.out.println(message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void debug(Object message, Throwable exception) {
 | 
			
		||||
        if(factory != null) {
 | 
			
		||||
            if(logger == null)
 | 
			
		||||
                logger = factory.getLogger(clazz);
 | 
			
		||||
            
 | 
			
		||||
            logger.debug(message, exception);
 | 
			
		||||
        } else {
 | 
			
		||||
            if(level <= LEVEL_DEBUG) {
 | 
			
		||||
                System.out.println(message);
 | 
			
		||||
                if (exception != null) {
 | 
			
		||||
                    exception.printStackTrace(System.out);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void warn(Object message) {
 | 
			
		||||
        if(factory != null) {
 | 
			
		||||
            if(logger == null)
 | 
			
		||||
                logger = factory.getLogger(clazz);
 | 
			
		||||
            
 | 
			
		||||
            logger.warn(message);
 | 
			
		||||
        } else {
 | 
			
		||||
            if(level <= LEVEL_WARN)
 | 
			
		||||
                System.out.println(message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void warn(Object message, Throwable exception) {
 | 
			
		||||
        if(factory != null) {
 | 
			
		||||
            if(logger == null)
 | 
			
		||||
                logger = factory.getLogger(clazz);
 | 
			
		||||
            
 | 
			
		||||
            logger.warn(message, exception);
 | 
			
		||||
        } else {
 | 
			
		||||
            if(level <= LEVEL_WARN) {
 | 
			
		||||
                System.out.println(message);
 | 
			
		||||
                if (exception != null) {
 | 
			
		||||
                    exception.printStackTrace(System.out);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void error(Object message) {
 | 
			
		||||
        if(factory != null) {
 | 
			
		||||
            if(logger == null)
 | 
			
		||||
                logger = factory.getLogger(clazz);
 | 
			
		||||
            
 | 
			
		||||
            logger.error(message);
 | 
			
		||||
        } else {
 | 
			
		||||
            if(level <= LEVEL_ERROR)
 | 
			
		||||
                System.out.println(message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void error(Object message, Throwable exception) {
 | 
			
		||||
        if(factory != null) {
 | 
			
		||||
            if(logger == null)
 | 
			
		||||
                logger = factory.getLogger(clazz);
 | 
			
		||||
            
 | 
			
		||||
            logger.error(message, exception);
 | 
			
		||||
        } else {
 | 
			
		||||
            if(level <= LEVEL_ERROR) {
 | 
			
		||||
                System.out.println(message);
 | 
			
		||||
                if (exception != null) {
 | 
			
		||||
                    exception.printStackTrace(System.out);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,21 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.util;
 | 
			
		||||
 | 
			
		||||
public interface LoggerFactory {
 | 
			
		||||
    Logger getLogger(Class<?> clazz);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,249 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.util;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.net.Socket;
 | 
			
		||||
import java.security.KeyManagementException;
 | 
			
		||||
import java.security.NoSuchAlgorithmException;
 | 
			
		||||
import java.security.NoSuchProviderException;
 | 
			
		||||
import java.security.SecureRandom;
 | 
			
		||||
import java.security.cert.X509Certificate;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.regex.Matcher;
 | 
			
		||||
import java.util.regex.Pattern;
 | 
			
		||||
 | 
			
		||||
import javax.net.SocketFactory;
 | 
			
		||||
import javax.net.ssl.SSLContext;
 | 
			
		||||
import javax.net.ssl.SSLSocket;
 | 
			
		||||
import javax.net.ssl.TrustManager;
 | 
			
		||||
import javax.net.ssl.X509TrustManager;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// This file is originally from XenConsole with modifications 
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Send an HTTP CONNECT or PUT request to a XenAPI host with a Session ID,
 | 
			
		||||
 * return the connected socket and the Task ID. Used for tunnelling VNC
 | 
			
		||||
 * connections and import/export operations.
 | 
			
		||||
 */
 | 
			
		||||
public final class RawHTTP {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(RawHTTP.class);
 | 
			
		||||
 | 
			
		||||
    private static final Pattern END_PATTERN = Pattern.compile("^\r\n$");
 | 
			
		||||
    private static final Pattern HEADER_PATTERN = Pattern
 | 
			
		||||
            .compile("^([A-Z_a-z0-9-]+):\\s*(.*)\r\n$");
 | 
			
		||||
    private static final Pattern HTTP_PATTERN = Pattern
 | 
			
		||||
            .compile("^HTTP/\\d+\\.\\d+ (\\d*) (.*)\r\n$");
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @uml.property  name="command"
 | 
			
		||||
     */
 | 
			
		||||
    private final String command;
 | 
			
		||||
    /**
 | 
			
		||||
     * @uml.property  name="host"
 | 
			
		||||
     */
 | 
			
		||||
    private final String host;
 | 
			
		||||
    /**
 | 
			
		||||
     * @uml.property  name="port"
 | 
			
		||||
     */
 | 
			
		||||
    private final int port;
 | 
			
		||||
    /**
 | 
			
		||||
     * @uml.property  name="path"
 | 
			
		||||
     */
 | 
			
		||||
    private final String path;
 | 
			
		||||
    /**
 | 
			
		||||
     * @uml.property  name="session"
 | 
			
		||||
     */
 | 
			
		||||
    private final String session;
 | 
			
		||||
    /**
 | 
			
		||||
     * @uml.property  name="useSSL"
 | 
			
		||||
     */
 | 
			
		||||
    private final boolean useSSL;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @uml.property  name="responseHeaders"
 | 
			
		||||
     * @uml.associationEnd  qualifier="group:java.lang.String java.lang.String"
 | 
			
		||||
     */
 | 
			
		||||
    private final Map<String, String> responseHeaders = new HashMap<String, String>();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @uml.property  name="ic"
 | 
			
		||||
     */
 | 
			
		||||
    private InputStream ic;
 | 
			
		||||
    /**
 | 
			
		||||
     * @uml.property  name="oc"
 | 
			
		||||
     */
 | 
			
		||||
    private OutputStream oc;
 | 
			
		||||
    /**
 | 
			
		||||
     * @uml.property  name="s"
 | 
			
		||||
     */
 | 
			
		||||
    private Socket s;
 | 
			
		||||
 | 
			
		||||
    public InputStream getInputStream() {
 | 
			
		||||
        return ic;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public OutputStream getOutputStream() {
 | 
			
		||||
        return oc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Socket getSocket() {
 | 
			
		||||
        return s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public RawHTTP(String command, String host, int port, String path,
 | 
			
		||||
            String session, boolean useSSL) {
 | 
			
		||||
        this.command = command;
 | 
			
		||||
        this.host = host;
 | 
			
		||||
        this.port = port;
 | 
			
		||||
        this.path = path;
 | 
			
		||||
        this.session = session;
 | 
			
		||||
        this.useSSL = useSSL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static final TrustManager[] trustAllCerts = new TrustManager[] { 
 | 
			
		||||
        new X509TrustManager() {
 | 
			
		||||
            public X509Certificate[] getAcceptedIssuers() {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
 | 
			
		||||
            }
 | 
			
		||||
        } 
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private Socket _getSocket() throws IOException {
 | 
			
		||||
        if (useSSL) {
 | 
			
		||||
            SSLContext context = getClientSSLContext();
 | 
			
		||||
            if(context == null)
 | 
			
		||||
                throw new IOException("Unable to setup SSL context");
 | 
			
		||||
            
 | 
			
		||||
            SSLSocket ssl = null;
 | 
			
		||||
            try {
 | 
			
		||||
                context.init(null, trustAllCerts, new SecureRandom());
 | 
			
		||||
                SocketFactory factory = context.getSocketFactory();
 | 
			
		||||
                ssl = (SSLSocket) factory.createSocket(host, port);
 | 
			
		||||
                /* ssl.setSSLParameters(context.getDefaultSSLParameters()); */
 | 
			
		||||
            } catch (IOException e) {
 | 
			
		||||
                s_logger.error("IOException: " + e.getMessage(), e);
 | 
			
		||||
                throw e;
 | 
			
		||||
            } catch (KeyManagementException e) {
 | 
			
		||||
                s_logger.error("KeyManagementException: " + e.getMessage(), e);
 | 
			
		||||
            }
 | 
			
		||||
            return ssl;
 | 
			
		||||
        } else {
 | 
			
		||||
            return new Socket(host, port);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Socket connect() throws IOException {
 | 
			
		||||
        String[] headers = makeHeaders();
 | 
			
		||||
        s = _getSocket();
 | 
			
		||||
        try {
 | 
			
		||||
            oc = s.getOutputStream();
 | 
			
		||||
            for (String header : headers) {
 | 
			
		||||
                oc.write(header.getBytes());
 | 
			
		||||
                oc.write("\r\n".getBytes());
 | 
			
		||||
            }
 | 
			
		||||
            oc.flush();
 | 
			
		||||
            ic = s.getInputStream();
 | 
			
		||||
            while (true) {
 | 
			
		||||
                String line = readline(ic);
 | 
			
		||||
 | 
			
		||||
                Matcher m = END_PATTERN.matcher(line);
 | 
			
		||||
                if (m.matches()) {
 | 
			
		||||
                    return s;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                m = HEADER_PATTERN.matcher(line);
 | 
			
		||||
                if (m.matches()) {
 | 
			
		||||
                    responseHeaders.put(m.group(1), m.group(2));
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                m = HTTP_PATTERN.matcher(line);
 | 
			
		||||
                if (m.matches()) {
 | 
			
		||||
                    String status_code = m.group(1);
 | 
			
		||||
                    String reason_phrase = m.group(2);
 | 
			
		||||
                    if (!"200".equals(status_code)) {
 | 
			
		||||
                        throw new IOException("HTTP status " + status_code
 | 
			
		||||
                                + " " + reason_phrase);
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    throw new IOException("Unknown HTTP line " + line);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IOException exn) {
 | 
			
		||||
            s.close();
 | 
			
		||||
            throw exn;
 | 
			
		||||
        } catch (RuntimeException exn) {
 | 
			
		||||
            s.close();
 | 
			
		||||
            throw exn;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Map<String, String> getResponseHeaders() {
 | 
			
		||||
        return responseHeaders;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String[] makeHeaders() {
 | 
			
		||||
        String[] headers = { String.format("%s %s HTTP/1.0", command, path),
 | 
			
		||||
                String.format("Host: %s", host),
 | 
			
		||||
                String.format("Cookie: session_id=%s", session), "" };
 | 
			
		||||
        return headers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String readline(InputStream ic) throws IOException {
 | 
			
		||||
        String result = "";
 | 
			
		||||
        while (true) {
 | 
			
		||||
            try {
 | 
			
		||||
                int c = ic.read();
 | 
			
		||||
 | 
			
		||||
                if (c == -1) {
 | 
			
		||||
                    return result;
 | 
			
		||||
                }
 | 
			
		||||
                result = result + (char) c;
 | 
			
		||||
                if (c == 0x0a /* LF */) {
 | 
			
		||||
                    return result;
 | 
			
		||||
                }
 | 
			
		||||
            } catch (IOException e) {
 | 
			
		||||
                ic.close();
 | 
			
		||||
                throw e;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private SSLContext getClientSSLContext() {
 | 
			
		||||
        SSLContext sslContext = null;
 | 
			
		||||
        try {
 | 
			
		||||
            sslContext = SSLContext.getInstance("SSL", "SunJSSE");
 | 
			
		||||
        } catch (NoSuchAlgorithmException e) {
 | 
			
		||||
            s_logger.error("Unexpected exception ", e);
 | 
			
		||||
        } catch (NoSuchProviderException e) {
 | 
			
		||||
            s_logger.error("Unexpected exception ", e);
 | 
			
		||||
        }
 | 
			
		||||
        return sslContext;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,90 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.util;
 | 
			
		||||
 | 
			
		||||
import java.awt.Rectangle;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class Region {
 | 
			
		||||
    private Rectangle bound;
 | 
			
		||||
    private List<Rectangle> rectList;
 | 
			
		||||
 | 
			
		||||
    public Region() {
 | 
			
		||||
        bound = new Rectangle(0, 0, 0, 0);
 | 
			
		||||
        rectList = new ArrayList<Rectangle>();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public Region(Rectangle rect) {
 | 
			
		||||
        bound = new Rectangle(rect.x, rect.y, rect.width, rect.height);
 | 
			
		||||
        rectList = new ArrayList<Rectangle>();
 | 
			
		||||
        rectList.add(rect);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public Rectangle getBound() {
 | 
			
		||||
        return bound;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void clearBound() {
 | 
			
		||||
        assert(rectList.size() == 0);
 | 
			
		||||
        bound.x = bound.y = bound.width = bound.height = 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public List<Rectangle> getRectangles() {
 | 
			
		||||
        return rectList;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public boolean add(Rectangle rect) {
 | 
			
		||||
        if(bound.isEmpty()) {
 | 
			
		||||
            assert(rectList.size() == 0);
 | 
			
		||||
            bound.x = rect.x;
 | 
			
		||||
            bound.y = rect.y;
 | 
			
		||||
            bound.width = rect.width;
 | 
			
		||||
            bound.height = rect.height;
 | 
			
		||||
            
 | 
			
		||||
            rectList.add(rect);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        Rectangle rcInflated = new Rectangle(rect.x - 1, rect.y- 1, rect.width + 2, rect.height + 2);
 | 
			
		||||
        if(!bound.intersects(rcInflated))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        for(Rectangle r : rectList) {
 | 
			
		||||
            if(r.intersects(rcInflated)) {
 | 
			
		||||
                if(!r.contains(rect)) {
 | 
			
		||||
                    enlargeBound(rect);
 | 
			
		||||
                    rectList.add(rect);
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void enlargeBound(Rectangle rect) {
 | 
			
		||||
        int boundLeft = Math.min(bound.x, rect.x);
 | 
			
		||||
        int boundTop = Math.min(bound.y, rect.y);
 | 
			
		||||
        int boundRight = Math.max(bound.x + bound.width, rect.x + rect.width);
 | 
			
		||||
        int boundBottom = Math.max(bound.y + bound.height, rect.y + rect.height);
 | 
			
		||||
        
 | 
			
		||||
        bound.x = boundLeft;
 | 
			
		||||
        bound.y = boundTop;
 | 
			
		||||
        bound.width = boundRight - boundLeft;
 | 
			
		||||
        bound.height = boundBottom - boundTop;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,58 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.util;
 | 
			
		||||
 | 
			
		||||
import java.awt.Rectangle;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class RegionClassifier {
 | 
			
		||||
    private List<Region> regionList;
 | 
			
		||||
    
 | 
			
		||||
    public RegionClassifier() {
 | 
			
		||||
        regionList = new ArrayList<Region>();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void add(Rectangle rect) {
 | 
			
		||||
        boolean newRegion = true;
 | 
			
		||||
        Rectangle rcInflated = new Rectangle(rect.x - 1, rect.y - 1, rect.width + 2, rect.height + 2);
 | 
			
		||||
        for(Region region : regionList) {
 | 
			
		||||
            if(region.getBound().intersects(rcInflated)) {
 | 
			
		||||
                newRegion = false;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(newRegion) {
 | 
			
		||||
            regionList.add(new Region(rect));
 | 
			
		||||
        } else {
 | 
			
		||||
            for(Region region : regionList) {
 | 
			
		||||
                if(region.add(rect))
 | 
			
		||||
                    return;
 | 
			
		||||
            }
 | 
			
		||||
            regionList.add(new Region(rect));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public List<Region> getRegionList() {
 | 
			
		||||
        return regionList;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void clear() {
 | 
			
		||||
        regionList.clear();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,55 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.util;
 | 
			
		||||
 | 
			
		||||
import java.awt.Rectangle;
 | 
			
		||||
 | 
			
		||||
public class TileInfo {
 | 
			
		||||
    private int row;
 | 
			
		||||
    private int col;
 | 
			
		||||
    private Rectangle tileRect;
 | 
			
		||||
 | 
			
		||||
    public TileInfo(int row, int col, Rectangle tileRect) {
 | 
			
		||||
        this.row = row;
 | 
			
		||||
        this.col = col;
 | 
			
		||||
        this.tileRect = tileRect;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public int getRow() {
 | 
			
		||||
        return row;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void setRow(int row) {
 | 
			
		||||
        this.row = row;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public int getCol() {
 | 
			
		||||
        return col;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void setCol(int col) {
 | 
			
		||||
        this.col = col;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public Rectangle getTileRect() {
 | 
			
		||||
        return tileRect;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void setTileRect(Rectangle tileRect) {
 | 
			
		||||
        this.tileRect = tileRect;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,269 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.util;
 | 
			
		||||
 | 
			
		||||
import java.awt.Rectangle;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class TileTracker {
 | 
			
		||||
    
 | 
			
		||||
    // 2 dimension tile status snapshot, a true value means the corresponding tile has been invalidated
 | 
			
		||||
    private boolean[][] snapshot;
 | 
			
		||||
    
 | 
			
		||||
    private int tileWidth = 0;
 | 
			
		||||
    private int tileHeight = 0;
 | 
			
		||||
    private int trackWidth = 0;
 | 
			
		||||
    private int trackHeight = 0;
 | 
			
		||||
    
 | 
			
		||||
    public TileTracker() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getTileWidth() {
 | 
			
		||||
        return tileWidth;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTileWidth(int tileWidth) {
 | 
			
		||||
        this.tileWidth = tileWidth;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getTileHeight() {
 | 
			
		||||
        return tileHeight;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTileHeight(int tileHeight) {
 | 
			
		||||
        this.tileHeight = tileHeight;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getTrackWidth() {
 | 
			
		||||
        return trackWidth;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTrackWidth(int trackWidth) {
 | 
			
		||||
        this.trackWidth = trackWidth;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getTrackHeight() {
 | 
			
		||||
        return trackHeight;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTrackHeight(int trackHeight) {
 | 
			
		||||
        this.trackHeight = trackHeight;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void initTracking(int tileWidth, int tileHeight, int trackWidth, int trackHeight) {
 | 
			
		||||
        assert(tileWidth > 0);
 | 
			
		||||
        assert(tileHeight > 0);
 | 
			
		||||
        assert(trackWidth > 0);
 | 
			
		||||
        assert(trackHeight > 0);
 | 
			
		||||
        assert(tileWidth <= trackWidth);
 | 
			
		||||
        assert(tileHeight <= trackHeight);
 | 
			
		||||
        
 | 
			
		||||
        this.tileWidth = tileWidth;
 | 
			
		||||
        this.tileHeight = tileHeight;
 | 
			
		||||
        this.trackWidth = trackWidth;
 | 
			
		||||
        this.trackHeight = trackHeight;
 | 
			
		||||
        
 | 
			
		||||
        int cols = getTileCols();
 | 
			
		||||
        int rows = getTileRows();
 | 
			
		||||
        snapshot = new boolean[rows][cols];
 | 
			
		||||
        for(int i = 0; i < rows; i++)
 | 
			
		||||
            for(int j = 0; j < cols; j++)
 | 
			
		||||
                snapshot[i][j] = false;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public synchronized void resize(int trackWidth, int trackHeight) {
 | 
			
		||||
        assert(tileWidth > 0);
 | 
			
		||||
        assert(tileHeight > 0);
 | 
			
		||||
        assert(trackWidth > 0);
 | 
			
		||||
        assert(trackHeight > 0);
 | 
			
		||||
        
 | 
			
		||||
        this.trackWidth = trackWidth;
 | 
			
		||||
        this.trackHeight = trackHeight;
 | 
			
		||||
        
 | 
			
		||||
        int cols = getTileCols();
 | 
			
		||||
        int rows = getTileRows();
 | 
			
		||||
        snapshot = new boolean[rows][cols];
 | 
			
		||||
        for(int i = 0; i < rows; i++)
 | 
			
		||||
            for(int j = 0; j < cols; j++)
 | 
			
		||||
                snapshot[i][j] = true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void invalidate(Rectangle rect) {
 | 
			
		||||
        setTileFlag(rect, true);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void validate(Rectangle rect) {
 | 
			
		||||
        setTileFlag(rect, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<TileInfo> scan(boolean init) {
 | 
			
		||||
        List<TileInfo> l = new ArrayList<TileInfo>();
 | 
			
		||||
        
 | 
			
		||||
        synchronized(this) {
 | 
			
		||||
            for(int i = 0; i < getTileRows(); i++) {
 | 
			
		||||
                for(int j = 0; j < getTileCols(); j++) {
 | 
			
		||||
                    if(init || snapshot[i][j]) {
 | 
			
		||||
                        Rectangle rect = new Rectangle();
 | 
			
		||||
                        rect.y = i*tileHeight;
 | 
			
		||||
                        rect.x = j*tileWidth;
 | 
			
		||||
                        rect.width = Math.min(trackWidth - rect.x, tileWidth);
 | 
			
		||||
                        rect.height = Math.min(trackHeight - rect.y, tileHeight);
 | 
			
		||||
                        
 | 
			
		||||
                        l.add(new TileInfo(i, j, rect));
 | 
			
		||||
                        snapshot[i][j] = false;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            return l;
 | 
			
		||||
        }    
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public boolean hasFullCoverage() {
 | 
			
		||||
        synchronized(this) {
 | 
			
		||||
            for(int i = 0; i < getTileRows(); i++) {
 | 
			
		||||
                for(int j = 0; j < getTileCols(); j++) {
 | 
			
		||||
                    if(!snapshot[i][j])
 | 
			
		||||
                        return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }    
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    public void initCoverageTest() {
 | 
			
		||||
        synchronized(this) {
 | 
			
		||||
            for(int i = 0; i < getTileRows(); i++) {
 | 
			
		||||
                for(int j = 0; j < getTileCols(); j++) {
 | 
			
		||||
                    snapshot[i][j] = false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }    
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // listener will be called while holding the object lock, use it
 | 
			
		||||
    // with care to avoid deadlock condition being formed
 | 
			
		||||
    public synchronized void scan(int nStartRow, int nStartCol, ITileScanListener listener) {
 | 
			
		||||
        assert(listener != null);
 | 
			
		||||
        
 | 
			
		||||
        int cols = getTileCols();
 | 
			
		||||
        int rows = getTileRows();
 | 
			
		||||
        
 | 
			
		||||
        nStartRow = nStartRow % rows;
 | 
			
		||||
        nStartCol = nStartCol % cols;
 | 
			
		||||
        
 | 
			
		||||
        int nPos = nStartRow*cols + nStartCol;
 | 
			
		||||
        int nUnits = rows*cols;
 | 
			
		||||
        int nStartPos = nPos;
 | 
			
		||||
        int nRow;
 | 
			
		||||
        int nCol;
 | 
			
		||||
        do {
 | 
			
		||||
            nRow = nPos / cols;
 | 
			
		||||
            nCol = nPos % cols;
 | 
			
		||||
            
 | 
			
		||||
            if(snapshot[nRow][nCol]) {
 | 
			
		||||
                int nEndCol = nCol;
 | 
			
		||||
                for(; nEndCol < cols && snapshot[nRow][nEndCol]; nEndCol++) {
 | 
			
		||||
                    snapshot[nRow][nEndCol] = false;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                Rectangle rect = new Rectangle();
 | 
			
		||||
                rect.y = nRow*tileHeight;
 | 
			
		||||
                rect.height = tileHeight;
 | 
			
		||||
                rect.x = nCol*tileWidth;
 | 
			
		||||
                rect.width = (nEndCol - nCol)*tileWidth;
 | 
			
		||||
                
 | 
			
		||||
                if(!listener.onTileChange(rect, nRow, nEndCol))
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            nPos = (nPos + 1) % nUnits;
 | 
			
		||||
        } while(nPos != nStartPos);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void capture(ITileScanListener listener) {
 | 
			
		||||
        assert(listener != null);
 | 
			
		||||
        
 | 
			
		||||
        int cols = getTileCols();
 | 
			
		||||
        int rows = getTileRows();
 | 
			
		||||
        
 | 
			
		||||
        RegionClassifier classifier = new RegionClassifier();
 | 
			
		||||
        int left, top, right, bottom;
 | 
			
		||||
        
 | 
			
		||||
        synchronized(this) {
 | 
			
		||||
            for(int i = 0; i < rows; i++) {
 | 
			
		||||
                top = i*tileHeight;
 | 
			
		||||
                bottom = Math.min(top + tileHeight, trackHeight); 
 | 
			
		||||
                for(int j = 0; j < cols; j++) {
 | 
			
		||||
                    left = j*tileWidth;
 | 
			
		||||
                    right = Math.min(left + tileWidth, trackWidth);
 | 
			
		||||
                    
 | 
			
		||||
                    if(snapshot[i][j]) {
 | 
			
		||||
                        snapshot[i][j] = false;
 | 
			
		||||
                        classifier.add(new Rectangle(left, top, right - left, bottom - top));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        listener.onRegionChange(classifier.getRegionList());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private synchronized void setTileFlag(Rectangle rect, boolean flag) {
 | 
			
		||||
        int nStartTileRow;
 | 
			
		||||
        int nStartTileCol;
 | 
			
		||||
        int nEndTileRow;
 | 
			
		||||
        int nEndTileCol;
 | 
			
		||||
        
 | 
			
		||||
        int cols = getTileCols();
 | 
			
		||||
        int rows = getTileRows();
 | 
			
		||||
        
 | 
			
		||||
        if(rect != null) {
 | 
			
		||||
            nStartTileRow = Math.min(getTileYPos(rect.y), rows - 1);
 | 
			
		||||
            nStartTileCol = Math.min(getTileXPos(rect.x), cols - 1);
 | 
			
		||||
            nEndTileRow = Math.min(getTileYPos(rect.y + rect.height - 1), rows -1);
 | 
			
		||||
            nEndTileCol = Math.min(getTileXPos(rect.x + rect.width - 1), cols -1);
 | 
			
		||||
        } else {
 | 
			
		||||
            nStartTileRow = 0;
 | 
			
		||||
            nStartTileCol = 0;
 | 
			
		||||
            nEndTileRow = rows - 1;
 | 
			
		||||
            nEndTileCol = cols - 1;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for(int i = nStartTileRow; i <= nEndTileRow; i++)
 | 
			
		||||
            for(int j = nStartTileCol; j <= nEndTileCol; j++)
 | 
			
		||||
                snapshot[i][j] = flag;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private int getTileRows() {
 | 
			
		||||
        return (trackHeight + tileHeight - 1) / tileHeight;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private int getTileCols() {
 | 
			
		||||
        return (trackWidth + tileWidth - 1) / tileWidth;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private int getTileXPos(int x) {
 | 
			
		||||
        return x / tileWidth;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public int getTileYPos(int y) {
 | 
			
		||||
        return y / tileHeight;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,150 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.vnc;
 | 
			
		||||
 | 
			
		||||
import java.awt.Canvas;
 | 
			
		||||
import java.awt.Color;
 | 
			
		||||
import java.awt.Graphics;
 | 
			
		||||
import java.awt.Graphics2D;
 | 
			
		||||
import java.awt.Image;
 | 
			
		||||
import java.awt.Rectangle;
 | 
			
		||||
import java.awt.image.BufferedImage;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.ImageHelper;
 | 
			
		||||
import com.cloud.consoleproxy.util.TileInfo;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A <code>BuffereImageCanvas</code> component represents frame buffer image on
 | 
			
		||||
 * the screen. It also notifies its subscribers when screen is repainted.
 | 
			
		||||
 */
 | 
			
		||||
public class BufferedImageCanvas extends Canvas implements FrameBufferCanvas {
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    // Offline screen buffer
 | 
			
		||||
    private BufferedImage offlineImage;
 | 
			
		||||
 | 
			
		||||
    // Cached Graphics2D object for offline screen buffer
 | 
			
		||||
    private Graphics2D graphics;
 | 
			
		||||
 | 
			
		||||
    private PaintNotificationListener listener;
 | 
			
		||||
 | 
			
		||||
    public BufferedImageCanvas(PaintNotificationListener listener, int width, int height) {
 | 
			
		||||
        super();
 | 
			
		||||
        this.listener = listener;
 | 
			
		||||
 | 
			
		||||
        setBackground(Color.black);
 | 
			
		||||
 | 
			
		||||
        setFocusable(true);
 | 
			
		||||
 | 
			
		||||
        // Don't intercept TAB key
 | 
			
		||||
        setFocusTraversalKeysEnabled(false);
 | 
			
		||||
 | 
			
		||||
        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() {
 | 
			
		||||
        return offlineImage;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Graphics2D getOfflineGraphics() {
 | 
			
		||||
        return graphics;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void copyTile(Graphics2D g, int x, int y, Rectangle rc) {
 | 
			
		||||
        synchronized (offlineImage) {
 | 
			
		||||
            g.drawImage(offlineImage, x, y, x + rc.width, y + rc.height, rc.x, rc.y, rc.x + rc.width, rc.y + rc.height, null);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Image getFrameBufferScaledImage(int width, int height) {
 | 
			
		||||
        if (offlineImage != null)
 | 
			
		||||
            return offlineImage.getScaledInstance(width, height, Image.SCALE_DEFAULT);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public byte[] getFrameBufferJpeg() {
 | 
			
		||||
        int width = 800;
 | 
			
		||||
        int height = 600;
 | 
			
		||||
 | 
			
		||||
        width = offlineImage.getWidth();
 | 
			
		||||
        height = offlineImage.getHeight();
 | 
			
		||||
 | 
			
		||||
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
 | 
			
		||||
        Graphics2D g = bufferedImage.createGraphics();
 | 
			
		||||
        synchronized (offlineImage) {
 | 
			
		||||
            g.drawImage(offlineImage, 0, 0, width, height, 0, 0, width, height, null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,30 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.vnc;
 | 
			
		||||
 | 
			
		||||
import java.awt.Image;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.TileInfo;
 | 
			
		||||
 | 
			
		||||
public interface FrameBufferCanvas {
 | 
			
		||||
    Image getFrameBufferScaledImage(int width, int height);
 | 
			
		||||
 | 
			
		||||
    public byte[] getFrameBufferJpeg();
 | 
			
		||||
 | 
			
		||||
    public byte[] getTilesMergedJpeg(List<TileInfo> tileList, int tileWidth, int tileHeight);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,26 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.vnc;
 | 
			
		||||
 | 
			
		||||
public interface FrameBufferUpdateListener {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Notify listener, that frame buffer update packet is received, so client
 | 
			
		||||
     * is permitted (but not obligated) to ask server to send another update.
 | 
			
		||||
     */
 | 
			
		||||
    void frameBufferPacketReceived();
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,27 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.vnc;
 | 
			
		||||
 | 
			
		||||
public interface PaintNotificationListener {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Notify subscriber that screen is updated, so client can send another
 | 
			
		||||
     * frame buffer update request to server.
 | 
			
		||||
     */
 | 
			
		||||
    void imagePaintedOnScreen();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,82 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.vnc;
 | 
			
		||||
 | 
			
		||||
import java.nio.charset.Charset;
 | 
			
		||||
 | 
			
		||||
public interface RfbConstants {
 | 
			
		||||
 | 
			
		||||
    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 RFB_PROTOCOL_VERSION = RFB_PROTOCOL_VERSION_MAJOR + VNC_PROTOCOL_VERSION_MINOR;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Server message types.
 | 
			
		||||
     */
 | 
			
		||||
    final static int SERVER_FRAMEBUFFER_UPDATE = 0, SERVER_SET_COLOURMAP_ENTRIES = 1, SERVER_BELL = 2, SERVER_CUT_TEXT = 3;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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, CLIENT_KEYBOARD_EVENT = 4,
 | 
			
		||||
            CLIENT_POINTER_EVENT = 5, CLIENT_CUT_TEXT = 6;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Server authorization type
 | 
			
		||||
     */
 | 
			
		||||
    public final static int CONNECTION_FAILED = 0, NO_AUTH = 1, VNC_AUTH = 2;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Server authorization reply.
 | 
			
		||||
     */
 | 
			
		||||
    public final static int VNC_AUTH_OK = 0, VNC_AUTH_FAILED = 1, VNC_AUTH_TOO_MANY = 2;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Pseudo-encodings.
 | 
			
		||||
     */
 | 
			
		||||
    public final static int ENCODING_CURSOR = -239 /* 0xFFFFFF11 */, ENCODING_DESKTOP_SIZE = -223 /* 0xFFFFFF21 */;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Encodings, which we support.
 | 
			
		||||
     */
 | 
			
		||||
    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.
 | 
			
		||||
     */
 | 
			
		||||
    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 LITTLE_ENDIAN = 0, BIG_ENDIAN = 1;
 | 
			
		||||
 | 
			
		||||
    public static final int EXCLUSIVE_ACCESS = 0, SHARED_ACCESS = 1;
 | 
			
		||||
 | 
			
		||||
    public static final int PALETTE = 0, TRUE_COLOR = 1;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default charset to use when communicating with server.
 | 
			
		||||
     */
 | 
			
		||||
    public static final Charset CHARSET = Charset.availableCharsets().get("US-ASCII");
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,451 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.vnc;
 | 
			
		||||
 | 
			
		||||
import java.awt.Frame;
 | 
			
		||||
import java.awt.ScrollPane;
 | 
			
		||||
import java.awt.event.WindowAdapter;
 | 
			
		||||
import java.awt.event.WindowEvent;
 | 
			
		||||
import java.io.DataInputStream;
 | 
			
		||||
import java.io.DataOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.Socket;
 | 
			
		||||
import java.net.UnknownHostException;
 | 
			
		||||
import java.security.spec.KeySpec;
 | 
			
		||||
 | 
			
		||||
import javax.crypto.Cipher;
 | 
			
		||||
import javax.crypto.SecretKey;
 | 
			
		||||
import javax.crypto.SecretKeyFactory;
 | 
			
		||||
import javax.crypto.spec.DESKeySpec;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.ConsoleProxyClientListener;
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
import com.cloud.consoleproxy.util.RawHTTP;
 | 
			
		||||
import com.cloud.consoleproxy.vnc.packet.client.KeyboardEventPacket;
 | 
			
		||||
import com.cloud.consoleproxy.vnc.packet.client.MouseEventPacket;
 | 
			
		||||
 | 
			
		||||
public class VncClient {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(VncClient.class);
 | 
			
		||||
 | 
			
		||||
    private Socket socket;
 | 
			
		||||
    private DataInputStream is;
 | 
			
		||||
    private DataOutputStream os;
 | 
			
		||||
 | 
			
		||||
    private VncScreenDescription screen = new VncScreenDescription();
 | 
			
		||||
 | 
			
		||||
    private VncClientPacketSender sender;
 | 
			
		||||
    private VncServerPacketReceiver receiver;
 | 
			
		||||
 | 
			
		||||
    private boolean noUI = false;
 | 
			
		||||
    private ConsoleProxyClientListener clientListener = null;
 | 
			
		||||
 | 
			
		||||
    public static void main(String args[]) {
 | 
			
		||||
        if (args.length < 3) {
 | 
			
		||||
            printHelpMessage();
 | 
			
		||||
            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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
        String ourProtocolString = RfbConstants.RFB_PROTOCOL_VERSION + "\n";
 | 
			
		||||
        os.write(ourProtocolString.getBytes());
 | 
			
		||||
        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: {
 | 
			
		||||
            // 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 + ".");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
        os.write(response);
 | 
			
		||||
        os.flush();
 | 
			
		||||
 | 
			
		||||
        // Read security result
 | 
			
		||||
        int authResult = is.readInt();
 | 
			
		||||
 | 
			
		||||
        switch (authResult) {
 | 
			
		||||
        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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,258 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.vnc;
 | 
			
		||||
 | 
			
		||||
import java.awt.event.KeyEvent;
 | 
			
		||||
import java.awt.event.KeyListener;
 | 
			
		||||
import java.awt.event.MouseEvent;
 | 
			
		||||
import java.awt.event.MouseListener;
 | 
			
		||||
import java.awt.event.MouseMotionListener;
 | 
			
		||||
import java.io.DataOutputStream;
 | 
			
		||||
import java.util.concurrent.ArrayBlockingQueue;
 | 
			
		||||
import java.util.concurrent.BlockingQueue;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
import com.cloud.consoleproxy.vnc.packet.client.ClientPacket;
 | 
			
		||||
import com.cloud.consoleproxy.vnc.packet.client.FramebufferUpdateRequestPacket;
 | 
			
		||||
import com.cloud.consoleproxy.vnc.packet.client.KeyboardEventPacket;
 | 
			
		||||
import com.cloud.consoleproxy.vnc.packet.client.MouseEventPacket;
 | 
			
		||||
import com.cloud.consoleproxy.vnc.packet.client.SetEncodingsPacket;
 | 
			
		||||
import com.cloud.consoleproxy.vnc.packet.client.SetPixelFormatPacket;
 | 
			
		||||
 | 
			
		||||
public class VncClientPacketSender implements Runnable, PaintNotificationListener, KeyListener, MouseListener, MouseMotionListener, FrameBufferUpdateListener {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(VncClientPacketSender.class);
 | 
			
		||||
 | 
			
		||||
    // Queue for outgoing packets
 | 
			
		||||
    private final BlockingQueue<ClientPacket> queue = new ArrayBlockingQueue<ClientPacket>(30);
 | 
			
		||||
 | 
			
		||||
    private final DataOutputStream os;
 | 
			
		||||
    private final VncScreenDescription screen;
 | 
			
		||||
    private final VncClient vncConnection;
 | 
			
		||||
 | 
			
		||||
    private boolean connectionAlive = true;
 | 
			
		||||
 | 
			
		||||
    // Don't send update request again until we receive next frame buffer update
 | 
			
		||||
    private boolean updateRequestSent = false;
 | 
			
		||||
 | 
			
		||||
    public VncClientPacketSender(DataOutputStream os, VncScreenDescription screen, VncClient vncConnection) {
 | 
			
		||||
        this.os = os;
 | 
			
		||||
        this.screen = screen;
 | 
			
		||||
        this.vncConnection = vncConnection;
 | 
			
		||||
 | 
			
		||||
        sendSetPixelFormat();
 | 
			
		||||
        sendSetEncodings();
 | 
			
		||||
        requestFullScreenUpdate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void sendClientPacket(ClientPacket packet) {
 | 
			
		||||
        queue.add(packet);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void run() {
 | 
			
		||||
        try {
 | 
			
		||||
            while (connectionAlive) {
 | 
			
		||||
                ClientPacket packet = queue.poll(1, TimeUnit.SECONDS);
 | 
			
		||||
                if (packet != null) {
 | 
			
		||||
                    packet.write(os);
 | 
			
		||||
                    os.flush();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } 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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,89 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.vnc;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * VncScreenDescription - contains information about remote VNC screen.
 | 
			
		||||
 */
 | 
			
		||||
public class VncScreenDescription {
 | 
			
		||||
 | 
			
		||||
    // Frame buffer size
 | 
			
		||||
    private int framebufferWidth = -1;
 | 
			
		||||
    private int framebufferHeight = -1;
 | 
			
		||||
 | 
			
		||||
    // Desktop name
 | 
			
		||||
    private String desktopName;
 | 
			
		||||
 | 
			
		||||
    // Bytes per pixel
 | 
			
		||||
    private int bytesPerPixel;
 | 
			
		||||
 | 
			
		||||
    // Indicates that screen uses format which we want to use:
 | 
			
		||||
    // RGB 24bit packed into 32bit little-endian int.
 | 
			
		||||
    private boolean rgb888_32_le = false;
 | 
			
		||||
 | 
			
		||||
    public VncScreenDescription() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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, int greenShift, int blueShift) {
 | 
			
		||||
 | 
			
		||||
        bytesPerPixel = (bitsPerPixel + 7) / 8;
 | 
			
		||||
 | 
			
		||||
        rgb888_32_le = (depth == 24 && bitsPerPixel == 32 && redShift == 16 && greenShift == 8 && blueShift == 0 && redMax == 255 && greenMax == 255 && blueMax == 255
 | 
			
		||||
                && bigEndianFlag == RfbConstants.LITTLE_ENDIAN && trueColorFlag == RfbConstants.TRUE_COLOR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Store information about server screen size.
 | 
			
		||||
     */
 | 
			
		||||
    public void setFramebufferSize(int framebufferWidth, int framebufferHeight) {
 | 
			
		||||
        this.framebufferWidth = framebufferWidth;
 | 
			
		||||
        this.framebufferHeight = framebufferHeight;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Store server desktop name.
 | 
			
		||||
     */
 | 
			
		||||
    public void setDesktopName(String desktopName) {
 | 
			
		||||
        this.desktopName = desktopName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Getters for variables, as usual
 | 
			
		||||
 | 
			
		||||
    public String getDesktopName() {
 | 
			
		||||
        return desktopName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getBytesPerPixel() {
 | 
			
		||||
        return bytesPerPixel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getFramebufferHeight() {
 | 
			
		||||
        return framebufferHeight;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getFramebufferWidth() {
 | 
			
		||||
        return framebufferWidth;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isRGB888_32_LE() {
 | 
			
		||||
        return rgb888_32_le;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,123 @@
 | 
			
		||||
// Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
// or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
// distributed with this work for additional information
 | 
			
		||||
// regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
// to you under the Apache License, Version 2.0 (the
 | 
			
		||||
// "License"); you may not use this file except in compliance
 | 
			
		||||
// with the License.  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing,
 | 
			
		||||
// software distributed under the License is distributed on an
 | 
			
		||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
			
		||||
// KIND, either express or implied.  See the License for the
 | 
			
		||||
// specific language governing permissions and limitations
 | 
			
		||||
// under the License.
 | 
			
		||||
package com.cloud.consoleproxy.vnc;
 | 
			
		||||
 | 
			
		||||
import java.awt.Toolkit;
 | 
			
		||||
import java.awt.datatransfer.StringSelection;
 | 
			
		||||
import java.io.DataInputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
import com.cloud.consoleproxy.ConsoleProxyClientListener;
 | 
			
		||||
import com.cloud.consoleproxy.util.Logger;
 | 
			
		||||
import com.cloud.consoleproxy.vnc.packet.server.FramebufferUpdatePacket;
 | 
			
		||||
import com.cloud.consoleproxy.vnc.packet.server.ServerCutText;
 | 
			
		||||
 | 
			
		||||
public class VncServerPacketReceiver implements Runnable {
 | 
			
		||||
    private static final Logger s_logger = Logger.getLogger(VncServerPacketReceiver.class);
 | 
			
		||||
 | 
			
		||||
    private final VncScreenDescription screen;
 | 
			
		||||
    private BufferedImageCanvas canvas;
 | 
			
		||||
    private DataInputStream is;
 | 
			
		||||
 | 
			
		||||
    private boolean connectionAlive = true;
 | 
			
		||||
    private VncClient vncConnection;
 | 
			
		||||
    private final FrameBufferUpdateListener fburListener;
 | 
			
		||||
    private final ConsoleProxyClientListener clientListener;
 | 
			
		||||
 | 
			
		||||
    public VncServerPacketReceiver(DataInputStream is, BufferedImageCanvas canvas, VncScreenDescription screen, VncClient vncConnection, FrameBufferUpdateListener fburListener,
 | 
			
		||||
            ConsoleProxyClientListener clientListener) {
 | 
			
		||||
        this.screen = screen;
 | 
			
		||||
        this.canvas = canvas;
 | 
			
		||||
        this.is = is;
 | 
			
		||||
        this.vncConnection = vncConnection;
 | 
			
		||||
        this.fburListener = fburListener;
 | 
			
		||||
        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() {
 | 
			
		||||
        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());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||