This commit is contained in:
Pranav Saxena 2012-09-08 12:10:36 +05:30
commit 1b6a934446
119 changed files with 5512 additions and 5634 deletions

View File

@ -250,7 +250,7 @@ Within the awsapi directory
Within the console-proxy/js directory
licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows)
Copyright © 2011, John Resig
Copyright © 2009, John Resig
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

365
NOTICE
View File

@ -30,6 +30,181 @@
with venue lying in Santa Clara County, California.
For
cloud-javax.persistence-2.0.0.jar
EclipseLink 2.0.0
Dec 10th, 2009
About
The EclipseLink project's goal is to provide a complete persistence framework
that is both comprehensive and universal. It will run in any Java environment
and read and write objects to virtually any type of data source, including
relational databases, and XML. EclipseLink will focus on providing leading edge
support, including advanced feature extensions, for the dominant persistence
standards for each target data source; Java Persistence API (JPA) for relational
databases, Java API for XML Binding (JAXB) for XML, Service Data Objects (SDO),
and Database Web services (DBWS).
For tips on getting started with EclipseLink, please see the following
resources:
EclipseLink 2.0.0 Release Notes Documentation Examples and How To License
The Eclipse Foundation makes available all content in this plug-in ("Content").
Unless otherwise indicated below, the Content is provided to you under the terms
and conditions of the Eclipse Public License Version 1.0 ("EPL") and Eclipse
Distribution License Version 1.0 ("EDL"). A copy of the EPL is available at
http://www.eclipse.org/legal/epl-v10.html and a copy of the EDL is available at
http://www.eclipse.org/org/documents/edl-v10.php. For purposes of the EPL,
"Program" will mean the Content.
If you did not receive this Content directly from the Eclipse Foundation, the
Content is being redistributed by another party ("Redistributor") and different
terms and conditions may apply to your use of any object code in the Content.
Check the Redistributor's license that was provided with the Content. If no such
license exists, contact the Redistributor. Unless otherwise indicated below, the
terms and conditions of the EPL and EDL still apply to any source code in the
Content and such source code may be obtained at http://www.eclipse.org.
Third Party Content
The Content includes items that have been sourced from third parties as set out
below. If you did not receive this Content directly from the Eclipse Foundation,
the following is provided for informational purposes only, and you should look
to the Redistributor's license for terms and conditions of use.
Foundation Dependencies ASM EclipseLink JPA ANTLR Java Persistence API (JPA) 1.0
- EJB 3.0 Java Persistence API (JPA) 2.0 EARLY ACCESS EclipseLink MOXy Java
Architecture for XML Binding (JAXB) Java Mail Java Activation Framework
Streaming API for XML (StAX) EclipseLink SDO Service Data Objects (SDO)
Utilities Java Connector Xerces WSDL4J 1.6.2 ASM v1.5.3
The EclipseLink Project includes ASM for the purpose of byte code weaving. The
AMS library is re-packaged within the source of the project
(org.persistence.eclipse.internal.libraries.asm.*) to avoid version collisions
with other usage of ASM. A custom patch has been added to the ASM 1.5.3 source
to handle an issue with other usages. This fix has also been contributed back to
the ASM project for inclusion in later projects.
The source code is available within the project's subversion repository. The
binaries are distributed within the eclipselink.jar and in the
org.eclipse.persistence.asm_2.0.0.v*.jar bundle.
http://asm.objectweb.org/license.html
Copyright (c) 2000-2005 INRIA, France Telecom, All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. Redistributions in binary form must
reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the
distribution. Neither the name of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY
THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THEIMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSEARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BELIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, ORCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OFSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER INCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OFTHE POSSIBILITY OF SUCH DAMAGE.
ANTLR v3.0
The ANTLR library (license) is included within EclipseLink Project to enable
parsing of the Java Persistence Query language (JP QL). The ANTLR library is re-
packaged within the project in the
org.eclipse.persistence.internal.libraries.antlr.* packages.
The source is available with the project's subversion repository. The binaries
are distributed within the eclipselink.jar and in the
org.eclipse.persistence.antlr_2.0.0.v*.jar bundle.
Java Architecture for XML Binding (JAXB) v2.0.5
The JAXB libraries distributed under CDDL v1.0 are included within the
EclipseLink Project to enable the MOXY component's implementation of JAXB.
JAXB Libraries:
/jlib/moxy/javax.xml.bind_2.1.12.v20090708-1500.jar /jlib/moxy/jaxb-impl.jar
/jlib/moxy/jaxb.xjc.jar Java Persistence (JPA) 1.0 - EJB 3.0
The Java Persistence API, included with EJB 3.0, is available for download from
the ejb-api directory in the glassfish CVS repository.It is distributed under
CDDLv1.0 . The jar is being shipped as an OSGi bundle and is required for
compilation of some container based fuctionality.
Java Persistence (JPA) 2.0.
EclipseLink is the Java Persistence (JPA) 2.0 Reference Implementation (JSR
317). The JPA 2.0 specification API is included in EclipseLink under the EPL and
EDL licenses.
Java Mail v1.4
The Java Mail library (mail.jar) is distributed with the JAXB v2.0.5 under CDDL
v1.0 and is included within the EclipseLink Project distribution to support Web
Services attachment handling in the MOXy component. It is only required when
using Java SE 5 (Java Mail is included in Java SE 6).
Java Activation Framework v1.1
The Java Activation Framework (activation.jar) is distributed with the JAXB
v2.0.5 under CDDL v1.0 and is included within the EclipseLink Project
distribution to support Web Services attachment handling in the MOXy component.
It is only required when using Java SE 5 (The Java Activation Framework is
included in Java SE 6).
Streaming API for XML (StAX) v1.0
The Streaming API for XML (StAX) library (jsr173_1.0_api.jar) is distributed
with the JAXB v2.0.5 under CDDL v1.0 and is included within the EclipseLink
Project distribution as an optional XML processing approach in the MOXy
component.
Service Data Objects (SDO) v2.1.1
The Service Data Objects (SDO) API is distributed under a CDDLv1.0 and custom
license. It provides the standard API implemented by the EclipseLink Project's
SDO component.
Java Connector v1.5
The JCA 1.5 API is available for download from the connector-api directory in
the glassfish CVS repository. It is distributed under CDDLv1.0 .
This jar is being shipped and required by the Workbench only. When using
EclipseLink in a container where JCA integration is required that container will
provide the necessary API libraries.
Xerces v2.9.0
Xerces 2.9.0 is available from the Xerces home page. It is distributed under
Apache 2.0.
This jar is shipped for the Workbench's use only in the reading and writing of
XML configuration files.
WSDL4j v1.6.2
WSDL4J 1.6.2 is available for download from the wsdl4j project. It distributed
under CPLv1.0 .
This jar is being shipped as a OSGi bundle and is only required for the DBWS
Builder utility.
For
cloud-commons-logging-1.1.1.jar
commons-logging-1.1.1.jar
@ -255,6 +430,21 @@
THE SOFTWARE.
For
jquery.js
jQuery JavaScript Library v1.3.2
http://jquery.com/
Copyright (c) 2009 John Resig
Dual licensed under the MIT and GPL licenses.
http://docs.jquery.com/License
Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
Revision: 6246
For
axis2-1.5.1.jar
axis2-adb-1.5.1.jar
@ -320,181 +510,6 @@
- software copyright (c) 2000 World Wide Web Consortium, http://www.w3.org
For
cloud-javax.persistence-2.0.0.jar
EclipseLink 2.0.0
Dec 10th, 2009
About
The EclipseLink project's goal is to provide a complete persistence framework
that is both comprehensive and universal. It will run in any Java environment
and read and write objects to virtually any type of data source, including
relational databases, and XML. EclipseLink will focus on providing leading edge
support, including advanced feature extensions, for the dominant persistence
standards for each target data source; Java Persistence API (JPA) for relational
databases, Java API for XML Binding (JAXB) for XML, Service Data Objects (SDO),
and Database Web services (DBWS).
For tips on getting started with EclipseLink, please see the following
resources:
EclipseLink 2.0.0 Release Notes Documentation Examples and How To License
The Eclipse Foundation makes available all content in this plug-in ("Content").
Unless otherwise indicated below, the Content is provided to you under the terms
and conditions of the Eclipse Public License Version 1.0 ("EPL") and Eclipse
Distribution License Version 1.0 (“EDL”). A copy of the EPL is available at
http://www.eclipse.org/legal/epl-v10.html and a copy of the EDL is available at
http://www.eclipse.org/org/documents/edl-v10.php. For purposes of the EPL,
"Program" will mean the Content.
If you did not receive this Content directly from the Eclipse Foundation, the
Content is being redistributed by another party ("Redistributor") and different
terms and conditions may apply to your use of any object code in the Content.
Check the Redistributors license that was provided with the Content. If no such
license exists, contact the Redistributor. Unless otherwise indicated below, the
terms and conditions of the EPL and EDL still apply to any source code in the
Content and such source code may be obtained at http://www.eclipse.org.
Third Party Content
The Content includes items that have been sourced from third parties as set out
below. If you did not receive this Content directly from the Eclipse Foundation,
the following is provided for informational purposes only, and you should look
to the Redistributors license for terms and conditions of use.
Foundation Dependencies ASM EclipseLink JPA ANTLR Java Persistence API (JPA) 1.0
- EJB 3.0 Java Persistence API (JPA) 2.0 EARLY ACCESS EclipseLink MOXy Java
Architecture for XML Binding (JAXB) Java Mail Java Activation Framework
Streaming API for XML (StAX) EclipseLink SDO Service Data Objects (SDO)
Utilities Java Connector Xerces WSDL4J 1.6.2 ASM v1.5.3
The EclipseLink Project includes ASM for the purpose of byte code weaving. The
AMS library is re-packaged within the source of the project
(org.persistence.eclipse.internal.libraries.asm.*) to avoid version collisions
with other usage of ASM. A custom patch has been added to the ASM 1.5.3 source
to handle an issue with other usages. This fix has also been contributed back to
the ASM project for inclusion in later projects.
The source code is available within the project's subversion repository. The
binaries are distributed within the eclipselink.jar and in the
org.eclipse.persistence.asm_2.0.0.v*.jar bundle.
http://asm.objectweb.org/license.html
Copyright (c) 2000-2005 INRIA, France Telecom, All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. Redistributions in binary form must
reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the
distribution. Neither the name of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY
THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THEIMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSEARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BELIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, ORCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OFSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER INCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OFTHE POSSIBILITY OF SUCH DAMAGE.
ANTLR v3.0
The ANTLR library (license) is included within EclipseLink Project to enable
parsing of the Java Persistence Query language (JP QL). The ANTLR library is re-
packaged within the project in the
org.eclipse.persistence.internal.libraries.antlr.* packages.
The source is available with the project's subversion repository. The binaries
are distributed within the eclipselink.jar and in the
org.eclipse.persistence.antlr_2.0.0.v*.jar bundle.
Java Architecture for XML Binding (JAXB) v2.0.5
The JAXB libraries distributed under CDDL v1.0 are included within the
EclipseLink Project to enable the MOXY component's implementation of JAXB.
JAXB Libraries:
/jlib/moxy/javax.xml.bind_2.1.12.v20090708-1500.jar /jlib/moxy/jaxb-impl.jar
/jlib/moxy/jaxb.xjc.jar Java Persistence (JPA) 1.0 - EJB 3.0
The Java Persistence API, included with EJB 3.0, is available for download from
the ejb-api directory in the glassfish CVS repository.It is distributed under
CDDLv1.0 . The jar is being shipped as an OSGi bundle and is required for
compilation of some container based fuctionality.
Java Persistence (JPA) 2.0.
EclipseLink is the Java Persistence (JPA) 2.0 Reference Implementation (JSR
317). The JPA 2.0 specification API is included in EclipseLink under the EPL and
EDL licenses.
Java Mail v1.4
The Java Mail library (mail.jar) is distributed with the JAXB v2.0.5 under CDDL
v1.0 and is included within the EclipseLink Project distribution to support Web
Services attachment handling in the MOXy component. It is only required when
using Java SE 5 (Java Mail is included in Java SE 6).
Java Activation Framework v1.1
The Java Activation Framework (activation.jar) is distributed with the JAXB
v2.0.5 under CDDL v1.0 and is included within the EclipseLink Project
distribution to support Web Services attachment handling in the MOXy component.
It is only required when using Java SE 5 (The Java Activation Framework is
included in Java SE 6).
Streaming API for XML (StAX) v1.0
The Streaming API for XML (StAX) library (jsr173_1.0_api.jar) is distributed
with the JAXB v2.0.5 under CDDL v1.0 and is included within the EclipseLink
Project distribution as an optional XML processing approach in the MOXy
component.
Service Data Objects (SDO) v2.1.1
The Service Data Objects (SDO) API is distributed under a CDDLv1.0 and custom
license. It provides the standard API implemented by the EclipseLink Project's
SDO component.
Java Connector v1.5
The JCA 1.5 API is available for download from the connector-api directory in
the glassfish CVS repository. It is distributed under CDDLv1.0 .
This jar is being shipped and required by the Workbench only. When using
EclipseLink in a container where JCA integration is required that container will
provide the necessary API libraries.
Xerces v2.9.0
Xerces 2.9.0 is available from the Xerces home page. It is distributed under
Apache 2.0.
This jar is shipped for the Workbench's use only in the reading and writing of
XML configuration files.
WSDL4j v1.6.2
WSDL4J 1.6.2 is available for download from the wsdl4j project. It distributed
under CPLv1.0 .
This jar is being shipped as a OSGi bundle and is only required for the DBWS
Builder utility.
For
cloud-commons-codec-1.5.jar
commons-codec-1.4.jar

View File

@ -1,153 +0,0 @@
#!/usr/bin/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 os
import logging
import sys
import socket
import subprocess
import time
from cloudutils.cloudException import CloudRuntimeException, CloudInternalException
from cloudutils.utilities import initLoging, bash
from cloudutils.configFileOps import configFileOps
from cloudutils.globalEnv import globalEnv
from cloudutils.networkConfig import networkConfig
from cloudutils.syscfg import sysConfigFactory
from optparse import OptionParser
url="http://rightscale-cloudstack.s3.amazonaws.com/kvm/centos/5.4/RightImage_CentOS_5.4_x64_v5.6.34.qcow2.bz2"
destFolder="/mnt/template/tmpl/1/4/"
metaFile="template.properties"
def getUserInputs():
print "Welcome to myCloud Setup:"
mgtSvr = "myagent.cloud.com"
cfo = configFileOps("/etc/cloud/agent/agent.properties")
oldToken = cfo.getEntry("zone")
if oldToken == "default":
oldToken = ""
zoneToken = raw_input("Please input the Zone Token:[%s]"%oldToken)
if zoneToken == "":
if oldToken == "":
print "Please input a valid zone token"
exit(1)
zoneToken = oldToken
try:
defaultNic = networkConfig.getDefaultNetwork()
except:
print "Failed to get default route. Please configure your network to add a default route"
exit(1)
network = defaultNic.name
return [mgtSvr, zoneToken, network]
def downloadTemplate():
if not os.path.exists(destFolder):
os.makedirs(destFolder)
oldName =url.split("/")[-1]
templateFile=url.split("/")[-1].replace(".bz2","")
templateFullPath = destFolder + templateFile
metaFullPath = destFolder + metaFile
if os.path.exists(templateFullPath):
if os.path.exists(metaFullPath):
return True
os.remove(templateFullPath)
print "Need to download myCloud template into your local disk, from " + url + " to " + destFolder + " :"
try:
proc = subprocess.Popen(["/bin/bash", "-c", "wget -O - " + url + " | bunzip2 > " + destFolder + templateFile])
proc.communicate()
ret = proc.poll()
if ret is None or ret < 0:
raise CloudRuntimeException("Failed to download template")
except KeyboardInterrupt:
if os.path.exists(templateFullPath):
os.remove(templateFullPath)
raise CloudRuntimeException("Downloading process is interrupted")
file = open(metaFullPath, "w")
physicalSize = os.stat(templateFullPath).st_size
virtualSize = bash("qemu-img info " + templateFullPath + " |grep virtual").getStdout().split("(")[1].split(" ")[0]
cfo = configFileOps(metaFullPath)
cfo.addEntry("filename", templateFile)
cfo.addEntry("id", "4")
cfo.addEntry("qcow2.size", str(physicalSize))
cfo.addEntry("public", "true")
cfo.addEntry("uniquename", "Rightscale CentOS 5.4")
cfo.addEntry("qcow2.virtualsize", virtualSize)
cfo.addEntry("virtualsize", virtualSize)
cfo.addEntry("hvm", "true")
cfo.addEntry("description", "Rightscale CentOS 5.4")
cfo.addEntry("qcow2", "true")
cfo.addEntry("qcow2.filename", templateFile)
cfo.addEntry("size", str(physicalSize))
cfo.save()
if __name__ == '__main__':
initLoging("/var/log/cloud/setupAgent.log")
glbEnv = globalEnv()
glbEnv.mode = "Agent"
glbEnv.agentMode = "myCloud"
parser = OptionParser()
parser.add_option("-z", "--zone-token", dest="zone", help="zone token")
(options, args) = parser.parse_args()
if options.zone is None:
userInputs = getUserInputs()
glbEnv.mgtSvr = userInputs[0]
glbEnv.zone = userInputs[1]
glbEnv.defaultNic = userInputs[2]
else:
glbEnv.zone = options.zone
try:
defaultNic = networkConfig.getDefaultNetwork()
glbEnv.defaultNic = defaultNic.name
except:
print "Failed to get default route. Please configure your network to have a default route"
sys.exit(2)
#generate UUID
glbEnv.uuid = configFileOps("/etc/cloud/agent/agent.properties").getEntry("guid")
if glbEnv.uuid == "":
glbEnv.uuid = bash("uuidgen").getStdout()
print "Starting to configure your system:"
syscfg = sysConfigFactory.getSysConfigFactory(glbEnv)
try:
syscfg.config()
downloadTemplate()
syscfg.svo.stopService("cloud-agent")
syscfg.svo.enableService("cloud-agent")
print "myCloud setup is Done!"
except (CloudRuntimeException,CloudInternalException), e:
print e
print "Try to restore your system:"
try:
syscfg.restore()
except:
pass

View File

@ -1,247 +0,0 @@
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.
0. Contents
===========
../sbin/vnetd: userspace daemon that runs the vnet
../module/2.6.18/vnet_module.ko: kernel module (alternative to vnetd)
../vnetd.sh: init script for vnet
../vn: helper script to create vnets
../id_rsa: the private key used to ssh to the routing domain
createvm.sh: clones a vm image from a given template
mountvm.sh: script to mount a remote (nfs) image directory
runvm.sh: script to run a vm
rundomr.sh: script to run a routing domain (domR) for a given vnet
listvmdisk.sh: lists disks belonging to a vm
createtmplt.sh: installs a template
listvmdisksize.sh: lists actuala and total usage per disk
../ipassoc.sh: associate / de-associate a public ip with an instance
../firewall.sh: add or remove firewall rules
stopvm.sh: stop the vm and remove the entry from xend
../delvm.sh: delete the vm image from zfs
../listclones.sh: list all filesystems that are clones under a parent fs
1. Install
==========
On the hosts that run the customer vms as well as the domR
a) Copy vn to /usr/sbin on dom0
b) Copy module/2.6.18/vnet_module.ko to /lib/modules/`uname -r`/kernel
c) Run repos/vmdev/xen/xen-3.3.0/tools/vnet/examples/vnet-insert
Ensure that all iptables rules are flushed from domO before starting any domains
(use iptables -F)
d) Ensure that the ISCSI initiator is installed (yum install iscsi*)
2. Creating /deleting a vm image on Solaris ZFS
================
The template image consists of a filesystem to hold kernel and ramdisk (linux)
or the pygrub file (linux) or nothing (windows). Contained within the template
filesystem (but not visible using 'ls') is the root volume.
Use the createvm script to clone a template snapshot. For example:
./createvm.sh -t tank/volumes/demo/template/public/os/centos52-x86_64 -d /tank/volumes/demo/template/public/datadisk/ext3-8g -i /tank/demo/vm/chiradeep/i0007 -u /tank/demo/vm/chiradeep
-t: the template fs snapshot
-i: the target clone fs
-u: the user's fs under which the clone will be created. If the user fs does not exist, it will be created.
-d: the disk fs to be cloned under the image dir specified by -i
Once this is created, use the listvmdisk.sh to list the disks:
listvmdisk.sh -i tank/demo/vm/chiradeep/i0007 -r (for the root disk)
listvmdisk.sh -i tank/demo/vm/chiradeep/i0007 -w (for the data disk)
listvmdisk.sh -i tank/demo/vm/chiradeep/i0007 -d <n> (for the data disks)
This outputs the local target name (zfs name) and the ISCSI target name
separated by a comma:
tank/demo/vm/chiradeep/i0007/datadisk1-ext3-8g,iqn.1986-03.com.sun:02:0b6c18c9-7a13-e7c9-ce78-91af20023bb3
The local target name can be used to list total (-t)and actual(-a) disk usage:
./listvmdisksize.sh -d tank/demo/vm/chiradeep/i0007/datadisk1-ext3-8g -t
8589934592
Use the delvm.sh script to delete an instance. For example:
./delvm.sh -u tank/demo/vm/chiradeep -i tank/demo/vm/chiradeep/i0007
-i: the instance fs to delete
-u: the user fs to delete
Either -i or -u or both can be supplied.
Use the listclones.sh script to list all clones under a parent fs:
./listclones.sh -p tank/demo/vm
3. Mounting an image
==================
The image directory resides on the NFS server, you can mount it with the
mountvm.sh script. For example:
./mountvm.sh -m -h 192.168.1.248 -t iqn.1986-03.com.sun:02:bf65dcfd-42b5-6e0e-e08e-99ae311b39ba -l /images/chiradeep/i0005 -n centos52 -r tank/demo/vm/chiradeep/i0005 -1 iqn.1986-03.com.sun:02:6d505eee-bf64-6729-e362-bab6c148bbc8
-h : the nfs/iscsi server host
-l : the local directory
-r : the remote directory
-n : the vm name (the same name used in runvm or rundomr)
-r : the iscsi target name for the root volume (see listvmdisk above)
-w : the iscsi target name for the swap volume (see listvmdisk above)
-1 : the iscsi target name for the datadisk volume (see listvmdisk above)
[-m | -u] : mount or unmount
4. Routing Domain (domR)
=======================
The routing domain for a customer needs to be started before any other VM in that vnet can start. To start a routing domain, for example:
./rundomr.sh -v 0008 -m 128 -i 192.168.1.33 -g 65.37.141.1 -a aa:00:00:05:00:33 -l "domR-vnet0008" -A 06:01:02:03:04:05 -p 02:01:02:03:04:05 -n 255.255.255.0 -I 65.37.141.33 -N 255.255.255.128 -b eth1 -d "dns1=192.168.1.254 dns2=207.69.188.186 domain=vmops.org" /images/chiradeep/router
-v : the is the 16-bit vnet-id specified in 4 hex characters
-m : the ram size for the domain in megabytes (128 is usually sufficient)
-a : the mac address of the eth0 of the domR
-A : the mac address of the eth1 of the domR
-p : the mac address of the eth2 of the domR
-i : the eth1 ip address in the datacenter LAN (e.g., 192.168.1.33)
-n : the netmask of eth1
-I : the eth2 ip address in the public LAN (e.g., 65.37.141.33)
-N : the netmask of eth2 (e.g., 65.37.141.128)
-b : the Xen bridge (typ.eth1) that eth2 has to be enslaved to (public LAN)
-g : the default gateway in the public subnet (e.g., 65.37.141.1)
-l : the vm name for the doMR
-d : nameserver information in the format shown in the example
Note: -d option requires template tank/demo/template/public/t100001@12_16_2008
or later
5. Starting a vm
================
The VM files are assumed to exist in a single image directory with the following conventions:
a) The kernel file begins with vmlinuz (e.g. vmlinuz-2.6.18.8-xen) (Linux)
b) The root volume begins with vmi-root (e.g.,vmi-root-centos52-x86_64-pv)
c) The data partition begins with datadisk1 (e.g., datadisk1-ext3-8g)
d) The swap partition contains "swap" (e.g., fedora-swap) (Linux only)
If booting Linux using pygrub, only the root and data files are needed. An
empty file called 'pygrub' must be placed in the image directory
To run the vm, see the following example
/runvm.sh -v 0005 -i 10.1.1.56 -m 256 -g 192.168.1.33 -a 02:00:00:05:00:56 -l "centos5-2" -c 11 -n 2 -u 66 /images/chiradeep/i0007
-v : the is the 16-bit vnet-id specified in 4 hex characters
-i : this is the host ip address in the 10.x.y.z subnet (cannot be 10.1.1.1)
-m : the ram size for the domain in megabytes
-g : the eth1 ip address of the routing domain
-a : the mac address of the eth0 of the vm
-l : the vm name. This is also the hostname, ensure it is is a legal hostname
-c : the VNC console id
-w : the VNC password. If not specified, defaults to 'password'
-n : the number of VCPUs (eq to number of cores) to allocate (default all)
-u : the percentage of one VCPU to allocate (integer) (default no cap)
<image dir>: the absolute path of the directory holding the VM files/volumes
The vncviewer can connect to the eth0 ip of dom0 and the specified vnc console number (e.g., 192.168.1.125:11).
The 'n' and 'u' parameters depends on the physical CPU of the host and the
number of compute units requested. For example, lets say 1 compute unit = 1Ghz
and the physical CPU is a quad-core CPU running at 3.0 Ghz. To request 2 cores
running 1 compute unit each, n = 2 and u= 2 x (1/3)*100
6. Associate a public Ip with a domR (source NAT)
===========================================
The example below shows how to associate the public ip 65.37.141.33 the
routing domain. This has to be run on the dom0 of the host hosting the
routing domain.
ipassoc.sh -A -r domR-vnet0007 -i 192.168.1.32 -l 65.37.141.33 -a 06:01:02:03:06:05
-A|-D: create or delete an association
-r: the name (label) of the routing domain
-i: the eth1 ip of the routing domain
-a: the mac address of eth2 in the routing domain (not required for -D)
-l: the public ip to be used for source NAT
7. Firewall rules
=================
Each instance can have firewall rules associated to allow
some ports through. By default, when created, an instance has all ports and
protocols blocked. In the following example, the 10.1.1.155 instance gets ssh
traffic and icmp pings opened up:
firewall.sh -A -i 192.168.1.133 -P tcp -p 22 -r 10.1.1.155 -l 65.37.141.33 -d
22
firewall.sh -A -i 192.168.1.133 -P icmp -t echo-request -r 10.1.1.155 -l
65.37.141.33
-A|-D: add or delete a rule
-i: the eth1 ip of the routing domain
-r: the local eth0 ip of the target instance
-l: the public ip
-P: the protocol (tcp, udp, icmp)
-t: (for icmp) the icmp type
-p: (for tcp and udp) the port (port range in the form of a:b)
-d: (for tcp and udp) the target port (port range in the form of a:b)
8. Stopping and restarting a VM
===============================
You can use 'xm reboot vmname' to reboot the VM.
To stop it (and delete it from Xend's internal database), use
stopvm.sh -l <vmname>
This will not remove the vnet however.
The stopvm script will NOT attempt to umount the root and data disks as well
To explicitly unmount the root disk data disks from the NFS server, run
this on dom0:
mountvm.sh -u -l /images/u00000002/i0003
-u: (no arguments)
-l: the local directory on the compute server
9. Vnet cleanup
===============
When you kill the vnet task, all vnif* interfaces will disappear but the
bridges will linger.
You can use vnetcleanup.sh to clean up the vnet
vnetcleanup.sh -a will clean up all vnets
vnetcleanup.sh -v 0005 will only cleanup vnet0005.
10. VM Image Cleanup
===================
On ZFS, run delvm.sh, for example:
./delvm.sh -u tank/demo/vm/u00000003 -i tank/demo/vm/u00000003/i0001
-u: the user fs (optional)
-i: the instance fs (optional)
11. Template installation
=========================
Template installation involves copying the image file of the rootdisk to a
iscsi volume. For example:
createtmplt.sh -t rpool/volumes/demo/template/public/os/ubuntu8 -f
/rpool/volumes/demo/template/public/download/ubuntu8/ubuntu8.0.img -n ubuntu8 -s 12G
-t: the filesystem (created if non-existent) where the volume will be mounted
-f: the absolute path to the file containing the root disk image
-n: the name of the template. The create volume will be vmi-root-$name
-s: the size in gigabytes for the volume
-h: if a hvm image
12. Mapping iscsi target names to VM names
==========================================
The mapiscsi.sh script maps iscsi names of targets logged in to by the routing
host/compute host:
[root@r-1-1-1 iscsi]# ./mapiscsi.sh
iqn.1986-03.com.sun:02:ef4942ec-9f7e-4d71-e994-bb670867053e r-870-TEST-0186-root
iqn.1986-03.com.sun:02:599f5cc5-2f90-c1c3-9c5e-fef252345e64 r-870-TEST-0186-swap
iqn.1986-03.com.sun:02:0e893b01-fa32-682e-976d-d15781cf1a44 r-872-TEST-0187-root
iqn.1986-03.com.sun:02:21225d22-479c-4a35-dca0-ad56e60aa6f4 r-872-TEST-0187-swap
iqn.1986-03.com.sun:02:55b1a6d4-d202-e565-ffe1-ee63e4a48210 r-875-TEST-0188-root
iqn.1986-03.com.sun:02:4fac467c-7b63-6ffb-c207-aa35ccecfcd5 r-875-TEST-0188-swap
If no VM name can be found, the second field is blank
13. OpenVZ patch workarounds
============================
The openvz patch eliminates kernel oops related to bride reconfiguration.
However this requires an extra tickle to the bridge to make it actually send
packets to member port. The member port needs to be taken down (ifconfig down)
and up (ifconfig up).
This is done in
a) rundomr.sh -- on creation of vnet bridge, the vnif is taken down and up
b) runvm.sh -- ditto
c) /etc/xen/qemu-ifup -- the interface (tapX.0) is taken down and then up
after the interface is added to the bridge.

View File

@ -1,211 +0,0 @@
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.
0. Contents
===========
sbin/vnetd: userspace daemon that runs the vnet
module/2.6.18/vnet_module.ko: kernel module (alternative to vnetd)
vnetd.sh: init script for vnet
vn: helper script to create vnets
id_rsa: the private key used to ssh to the routing domain
createvm.sh: clones a vm image from a given template
mountvm.sh: script to mount a remote (nfs) image directory
runvm.sh: script to run a vm
rundomr.sh: script to run a routing domain (domR) for a given vnet
ipassoc.sh: associate / de-associate a public ip with an instance
firewall.sh: add or remove firewall rules
stopvm.sh: stop the vm and remove the entry from xend
delvm.sh: delete the vm image from zfs
loadbalancer.sh: configure the loadbalancer
listclones.sh: list all filesystems that are clones under a parent fs
1. Install
==========
On the hosts that run the customer vms as well as the domR
a) Copy vn to /usr/sbin on dom0
Either (vnetd):
1) Copy sbin/vnetd to /usr/sbin on dom0
2) Copy vnetd.sh to /etc/init.d/vnetd on dom0
3) run chkconfig vnetd on
OR
1) Copy module/2.6.18/vnet_module.ko to /lib/modules/`uname -r`/kernel
2) Run repos/vmdev/xen/xen-3.3.0/tools/vnet/examples/vnet-insert
Ensure that all iptables rules are flushed from domO before starting any domains
(use iptables -F)
2. Creating /deleting a vm image on Solaris ZFS
================
Use the createvm script to clone a template snapshot. For example:
createvm.sh -t tank/template/public/t100001@12_3_2008 -i tank/demo/vm/u00000002/i0001 -u tank/demo/vm/u00000002 -d /tank/demo/template/public/datadisk/ext3-8g
-t: the template fs snapshot
-i: the target clone fs
-u: the user's fs under which the clone will be created. If the user fs does not exist, it will be created.
-d: the disk fs to be cloned under the image dir specified by -i
Once this is created, use the listvmdisk.sh to list the disks:
listvmdisk.sh -i tank/demo/vm/u00000002/i0001 -r (for the root disk)
listvmdisk.sh -i tank/demo/vm/u00000002/i0001 -d <n> (for the data disks)
Use the delvm.sh script to delete an instance. For example:
./delvm.sh -u tank/demo/vm/u00000003 -i tank/demo/vm/u00000003/i0001
-i: the instance fs to delete
-u: the user fs to delete
Either -i or -u or both can be supplied.
Use the listclones.sh script to list all clones under a parent fs:
./listclones.sh -p tank/demo/vm
3. Mounting an image
==================
If the image directory resides on the NFS server, you can mount it with the
mountvm.sh script. For example:
./mountvm.sh -h sol10-1.lab.vmops.com -l /images/u00000002/i0001 -r
/tank/vm/demo/u00000002/i0001 -m
-h : the nfs server host
-l : the local directory
-r : the remote directory
[-m | -u] : mount or unmount
4. Routing Domain (domR)
=======================
The routing domain for a customer needs to be started before any other VM in that vnet can start. To start a routing domain, for example:
./rundomr.sh -v 0008 -m 128 -i 192.168.1.33 -g 65.37.141.1 -a aa:00:00:05:00:33 -l "domR-vnet0008" -A 06:01:02:03:04:05 -p 02:01:02:03:04:05 -n 255.255.255.0 -I 65.37.141.33 -N 255.255.255.128 -b eth1 -d "dns1=192.168.1.254 dns2=207.69.188.186 domain=vmops.org" /images/templates/t100001
-v : the is the 16-bit vnet-id specified in 4 hex characters
-m : the ram size for the domain in megabytes (128 is usually sufficient)
-a : the mac address of the eth0 of the domR
-A : the mac address of the eth1 of the domR
-p : the mac address of the eth2 of the domR
-i : the eth1 ip address in the datacenter LAN (e.g., 192.168.1.33)
-n : the netmask of eth1
-I : the eth2 ip address in the public LAN (e.g., 65.37.141.33)
-N : the netmask of eth2 (e.g., 65.37.141.128)
-b : the Xen bridge (typ.eth1) that eth2 has to be enslaved to (public LAN)
-g : the default gateway in the public subnet (e.g., 65.37.141.1)
-l : the vm name for the doMR
-d : nameserver information in the format shown in the example
Note: -d option requires template tank/demo/template/public/t100001@12_16_2008
or later
5. Starting a vm
================
The VM files are assumed to exist in a single image directory with the following conventions:
a) The kernel file begins with vmlinuz (e.g. vmlinuz-2.6.18.8-xen) (Linux)
b) The root filesystem begins with vmi-root (e.g., vmi-root-centos.5-2.64.img)
c) The data partition begins with vmi-data1 (e.g., vmi-data1.img)
d) The swap partition ends with ".swap" (e.g., centos64.swap) (Linux only)
If booting Linux using pygrub, only the root and data files are needed. An
empty file called 'pygrub' must be placed in the image directory
To run the vm, see the following example
/runvm.sh -v 0005 -i 10.1.1.122 -m 256 -g 192.168.1.108 -a 02:00:00:05:00:22 -l "centos.5-2.64" -c 11 -n 2 -u 66 /images/u00000002/i0003
-v : the is the 16-bit vnet-id specified in 4 hex characters
-i : this is the host ip address in the 10.x.y.z subnet (cannot be 10.1.1.1)
-m : the ram size for the domain in megabytes
-g : the eth1 ip address of the routing domain
-a : the mac address of the eth0 of the vm
-l : the vm name. This is also the hostname, ensure it is is a legal hostname
-c : the VNC console id
-w : the VNC password. If not specified, defaults to 'password'
-n : the number of VCPUs (eq to number of cores) to allocate (default all)
-u : the percentage of one VCPU to allocate (integer) (default no cap)
<image dir>: the absolute path of the directory holding the VM files
The vncviewer can connect to the eth0 ip of dom0 and the specified vnc console number (e.g., 192.168.1.125:11).
The 'n' and 'u' parameters depends on the physical CPU of the host and the
number of compute units requested. For example, lets say 1 compute unit = 1Ghz
and the physical CPU is a quad-core CPU running at 3.0 Ghz. To request 2 cores
running 1 compute unit each, n = 2 and u= 2 x (1/3)*100
6. Associate a public Ip with a domR (source NAT)
===========================================
The example below shows how to associate the public ip 65.37.141.33 the
routing domain. This has to be run on the dom0 of the host hosting the
routing domain.
ipassoc.sh -A -r domR-vnet0007 -i 192.168.1.32 -l 65.37.141.33 -a 06:01:02:03:06:05
-A|-D: create or delete an association
-r: the name (label) of the routing domain
-i: the eth1 ip of the routing domain
-a: the mac address of eth2 in the routing domain (not required for -D)
-l: the public ip to be used for source NAT
7. Firewall rules
=================
Each instance can have firewall rules associated to allow
some ports through. By default, when created, an instance has all ports and
protocols blocked. In the following example, the 10.1.1.155 instance gets ssh
traffic and icmp pings opened up:
firewall.sh -A -i 192.168.1.133 -P tcp -p 22 -r 10.1.1.155 -l 65.37.141.33 -d
22
firewall.sh -A -i 192.168.1.133 -P icmp -t echo-request -r 10.1.1.155 -l
65.37.141.33
-A|-D: add or delete a rule
-i: the eth1 ip of the routing domain
-r: the local eth0 ip of the target instance
-l: the public ip
-P: the protocol (tcp, udp, icmp)
-t: (for icmp) the icmp type
-p: (for tcp and udp) the port (port range in the form of a:b)
-d: (for tcp and udp) the target port (port range in the form of a:b)
7.5 Loadbalancer rules
=====================
Loadbalancing is provided by HAProxy running within the routing domain. Because the rules are large and consist of many components, it is expected that the entire HAProxy configuration file is provided to the script. This is copied over to the routing domain and the haproxy process is restarted.
loadbalancer.sh -A -i 192.168.1.35 -l 65.37.141.30 -d 80 -f /tmp/haproxy.cfg
New haproxy instance successfully loaded, stopping previous one.
-A|-D: add or delete a rule
-i: the eth1 ip of the routing domain
-l: the public ip
-d: the target port
-f: the haproxy configuration file
8. Stopping and restarting a VM
===============================
You can use 'xm reboot vmname' to reboot the VM.
To stop it (and delete it from Xend's internal database), use
stopvm.sh -l <vmname>
This will not remove the vnet however.
The stopvm script will attempt to umount the root and data disks as well
To explicitly unmount the root disk data disks from the NFS server, run
this on dom0:
mountvm.sh -u -l /images/u00000002/i0003
-u: (no arguments)
-l: the local directory on the compute server
9. Vnet cleanup
===============
When you kill the vnet task, all vnif* interfaces will disappear but the
bridges will linger.
You can use vnetcleanup.sh to clean up the vnet
vnetcleanup.sh -a will clean up all vnets
vnetcleanup.sh -v 0005 will only cleanup vnet0005.
10. VM Image Cleanup
===================
On ZFS, run delvm.sh, for example:
./delvm.sh -u tank/demo/vm/u00000003 -i tank/demo/vm/u00000003/i0001
-u: the user fs (optional)
-i: the instance fs (optional)
10. TODO
=======
5. Automatic install instead of manual steps of (1)

View File

@ -14,67 +14,67 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.agent.resource.consoleproxy;
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;
}
}
package com.cloud.agent.resource.consoleproxy;
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;
}
}

View File

@ -1,3 +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.
package com.cloud.bridge.model;
import javax.persistence.Column;

View File

@ -1,3 +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.
package com.cloud.bridge.model;
import javax.persistence.Column;

View File

@ -1,3 +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.
package com.cloud.bridge.model;
import javax.persistence.Column;

View File

@ -1,3 +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.
package com.cloud.bridge.model;
import javax.persistence.Column;

View File

@ -1,3 +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.
package com.cloud.bridge.model;
import java.util.Date;

View File

@ -1,3 +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.
package com.cloud.bridge.model;
import java.util.Date;

View File

@ -1,3 +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.
package com.cloud.bridge.model;
import javax.persistence.Column;

View File

@ -1,3 +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.
package com.cloud.bridge.model;
import javax.persistence.Column;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import com.cloud.bridge.model.BucketPolicyVO;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import com.cloud.bridge.model.CloudStackAccountVO;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import javax.ejb.Local;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import com.cloud.bridge.model.CloudStackConfigurationVO;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import java.sql.Connection;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import com.cloud.bridge.model.CloudStackServiceOfferingVO;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import com.cloud.bridge.model.MHostVO;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import com.cloud.bridge.model.MHostMountVO;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import java.util.List;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import java.util.List;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import java.util.List;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import java.util.ArrayList;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import java.util.List;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import java.util.List;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import com.cloud.bridge.model.OfferingBundleVO;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import java.util.List;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import java.util.List;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import com.cloud.bridge.model.SHostVO;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import java.util.List;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import java.util.List;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import java.util.List;

View File

@ -1,3 +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.
package com.cloud.bridge.persist.dao;
import com.cloud.bridge.model.UserCredentialsVO;

View File

@ -78,6 +78,7 @@
<property name="build.log" location="${target.dir}/ant_verbose.txt" />
<property name="deps.dir" location="${base.dir}/deps" />
<property name="xenapi.dir" location="${deps.dir}/XenServerJava" />
<!-- directories for client compilation-->
<property name="client.dir" location="${base.dir}/client" />
@ -129,6 +130,7 @@
<property name="agent.jar" value="cloud-agent.jar" />
<property name="console-proxy.jar" value="cloud-console-proxy.jar" />
<property name="api.jar" value="cloud-api.jar"/>
<property name="xenapi.jar" value="cloud-xenapi.jar" />
<property name="vmware-base.jar" value="cloud-vmware-base.jar" />
<property name="vmware.jar" value="cloud-vmware.jar" />
@ -215,12 +217,20 @@
<target name="compile-vmware-base" depends="-init, compile-utils" description="Compile the VMware support library">
<compile-java jar.name="${vmware-base.jar}" top.dir="${vmware-base.dir}" classpath="vmware-base.classpath" />
</target>
<path id="xenapi.classpath">
<path refid="deps.classpath" />
<path refid="dist.classpath" />
</path>
<target name="compile-xenapi" depends="-init" description="Compile XenServer java sdk.">
<compile-java jar.name="${xenapi.jar}" top.dir="${xenapi.dir}" classpath="xenapi.classpath" />
</target>
<path id="server.classpath">
<path refid="deps.classpath" />
<path refid="dist.classpath" />
</path>
<target name="compile-server" depends="-init, compile-utils, compile-core, compile-agent" description="Compile the management server.">
<target name="compile-server" depends="-init, compile-utils, compile-xenapi, compile-core, compile-agent" description="Compile the management server.">
<compile-java jar.name="${server.jar}" top.dir="${server.dir}" classpath="server.classpath" />
</target>

View File

@ -182,12 +182,11 @@
</condition>
<antcall target="unzip" inheritAll="true"/>
<unwar overwrite="true" src="${deploy.work.dir}/client/client.war" dest="${server.deploy.to.dir}/webapps/client"/>
<!-- <copy todir="${server.deploy.to.dir}/lib">
<fileset dir="${deploy.work.dir}/client/lib/">
<copy todir="${server.deploy.to.dir}/lib">
<fileset dir="${deps.dir}/">
<include name="*.jar"/>
</fileset>
</copy>
-->
<touch file="${server.deploy.to.dir}/webapps/client/WEB-INF/lib/scripts/vm/hypervisor/xenserver/version"/>
<echo file="${server.deploy.to.dir}/webapps/client/WEB-INF/lib/scripts/vm/hypervisor/xenserver/version" append="false" message="${version}.${build.number}"/>
<copy overwrite="true" todir="${server.deploy.to.dir}/conf">
@ -399,21 +398,17 @@
<target name="build-apidocs" description="Generate api documentation" depends="build-all">
<property name="commands.file" location="${dist.dir}/client/conf/commands.properties" />
<property name="commands.ext.file" location="${dist.dir}/client/conf/commands-ext.properties" />
<property name="commands.f5.file" location="${dist.dir}/client/conf/f5bigip_commands.properties" />
<property name="commands.juniper.file" location="${dist.dir}/client/conf/junipersrx_commands.properties" />
<property name="commands.cisco.file" location="${dist.dir}/client/conf/cisconexusvsm_commands.properties" />
<property name="commands.netscaler.file" location="${dist.dir}/client/conf/netscalerloadbalancer_commands.properties" />
<property name="commands.vr.file" location="${dist.dir}/client/conf/virtualrouter_commands.properties" />
<property name="commands.file" location="${dist.dir}/client/conf/commands.properties" />
<property name="commands.ext.file" location="${dist.dir}/client/conf/commands-ext.properties" />
<property name="commands.vr.file" location="${dist.dir}/client/conf/virtualrouter_commands.properties" />
<echo message="build-apidocs" />
<echo message="build-apidocs" />
<exec dir="${apidoc.scripts.dir}" executable="bash" failonerror="true">
<arg value="build-apidoc.sh" />
<arg value="${target.dir}/jar" />
<arg value="${deps.dir}" />
<arg value="${dist.dir}" />
<arg value="-f ${commands.cisco.file},${commands.file},${commands.ext.file},${commands.f5.file},${commands.juniper.file},${commands.netscaler.file},${commands.vr.file}" />
<arg value="-f ${commands.file},${commands.ext.file},${commands.vr.file}" />
</exec>
<echo message="Result locates at ${dist.dir}/commands.xml" />

View File

@ -200,26 +200,23 @@
<zip destfile="${dist.dir}/systemvm.zip" duplicate="preserve" update="true">
<!-- Console proxy now includes an agent shell, therefore we need to package agent related distribution -->
<zipfileset dir="${deps.dir}">
<include name="cloud-xmlrpc-client-3.1.3.jar" />
<include name="cloud-xmlrpc-common-3.1.3.jar" />
<include name="cloud-ws-commons-util-1.0.2.jar" />
<include name="cloud-log4j.jar" />
<include name="cloud-apache-log4j-extras-1.0.jar" />
<include name="cloud-google-gson-1.7.1.jar" />
<include name="cloud-commons-httpclient-3.1.jar" />
<include name="cloud-commons-logging-1.1.1.jar" />
<include name="cloud-commons-collections-3.2.1.jar" />
<include name="cloud-commons-codec-1.5.jar" />
<include name="cloud-commons-pool-1.5.6.jar" />
<include name="cloud-cglib.jar" />
<include name="cloud-axis.jar" />
<include name="cloud-commons-discovery.jar" />
<include name="cloud-wsdl4j.jar" />
<include name="vmware-apputils.jar" />
<include name="vmware-vim.jar" />
<include name="vmware-lib-jaxrpc.jar" />
<include name="vmware-vim25.jar" />
<include name="cloud-ejb-api-3.0.jar" />
<include name="xmlrpc-client-3.1.3.jar" />
<include name="xmlrpc-common-3.1.3.jar" />
<include name="ws-commons-util-1.0.2.jar" />
<include name="log4j*.jar" />
<include name="asm-3.1.jar" />
<include name="apache-log4j-extras-1.1.jar" />
<include name="gson-1.7.1.jar" />
<include name="commons-httpclient-3.1.jar" />
<include name="commons-logging-1.1.1.jar" />
<include name="commons-collections-3.1.jar" />
<include name="commons-codec-1.6.jar" />
<include name="commons-pool-1.6.jar" />
<include name="cglib-*.jar" />
<include name="axis-*.jar" />
<include name="discovery-*.jar" />
<include name="wsdl4j-*.jar" />
<include name="ejb-api-3.0.jar" />
</zipfileset>
<zipfileset dir="${jar.dir}">
<include name="${agent.jar}" />

View File

@ -1,4 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--
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.
-->
<launchConfiguration type="org.eclipse.m2e.Maven2LaunchConfigurationType">
<booleanAttribute key="M2_DEBUG_OUTPUT" value="false"/>
<stringAttribute key="M2_GOALS" value="jetty:run"/>

View File

@ -20,15 +20,7 @@ generateUsageRecords=com.cloud.api.commands.GenerateUsageRecordsCmd;1
listUsageRecords=com.cloud.api.commands.GetUsageRecordsCmd;1
listUsageTypes=com.cloud.api.commands.ListUsageTypesCmd;1
#### external firewall commands
addExternalFirewall=com.cloud.api.commands.AddExternalFirewallCmd;1
deleteExternalFirewall=com.cloud.api.commands.DeleteExternalFirewallCmd;1
listExternalFirewalls=com.cloud.api.commands.ListExternalFirewallsCmd;1
#### external loadbalancer commands
addExternalLoadBalancer=com.cloud.api.commands.AddExternalLoadBalancerCmd;1
deleteExternalLoadBalancer=com.cloud.api.commands.DeleteExternalLoadBalancerCmd;1
listExternalLoadBalancers=com.cloud.api.commands.ListExternalLoadBalancersCmd;1
### Network Devices commands
addNetworkDevice=com.cloud.api.commands.AddNetworkDeviceCmd;1
@ -40,16 +32,4 @@ addTrafficMonitor=com.cloud.api.commands.AddTrafficMonitorCmd;1
deleteTrafficMonitor=com.cloud.api.commands.DeleteTrafficMonitorCmd;1
listTrafficMonitors=com.cloud.api.commands.ListTrafficMonitorsCmd;1
####Netapp integration commands
createVolumeOnFiler=com.cloud.api.commands.netapp.CreateVolumeOnFilerCmd;15
destroyVolumeOnFiler=com.cloud.api.commands.netapp.DestroyVolumeOnFilerCmd;15
listVolumesOnFiler=com.cloud.api.commands.netapp.ListVolumesOnFilerCmd;15
createLunOnFiler=com.cloud.api.commands.netapp.CreateLunCmd;15
destroyLunOnFiler=com.cloud.api.commands.netapp.DestroyLunCmd;15
listLunsOnFiler=com.cloud.api.commands.netapp.ListLunsCmd;15
associateLun=com.cloud.api.commands.netapp.AssociateLunCmd;15
dissociateLun=com.cloud.api.commands.netapp.DissociateLunCmd;15
createPool=com.cloud.api.commands.netapp.CreateVolumePoolCmd;15
deletePool=com.cloud.api.commands.netapp.DeleteVolumePoolCmd;15
modifyPool=com.cloud.api.commands.netapp.ModifyVolumePoolCmd;15
listPools=com.cloud.api.commands.netapp.ListVolumePoolsCmd;15

View File

@ -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.
### bitmap of permissions at the end of each classname, 1 = ADMIN, 2 = RESOURCE_DOMAIN_ADMIN, 4 = DOMAIN_ADMIN, 8 = USER
### Please standardize naming conventions to camel-case (even for acronyms).
####Netapp integration commands
createVolumeOnFiler=com.cloud.api.commands.netapp.CreateVolumeOnFilerCmd;15
destroyVolumeOnFiler=com.cloud.api.commands.netapp.DestroyVolumeOnFilerCmd;15
listVolumesOnFiler=com.cloud.api.commands.netapp.ListVolumesOnFilerCmd;15
createLunOnFiler=com.cloud.api.commands.netapp.CreateLunCmd;15
destroyLunOnFiler=com.cloud.api.commands.netapp.DestroyLunCmd;15
listLunsOnFiler=com.cloud.api.commands.netapp.ListLunsCmd;15
associateLun=com.cloud.api.commands.netapp.AssociateLunCmd;15
dissociateLun=com.cloud.api.commands.netapp.DissociateLunCmd;15
createPool=com.cloud.api.commands.netapp.CreateVolumePoolCmd;15
deletePool=com.cloud.api.commands.netapp.DeleteVolumePoolCmd;15
modifyPool=com.cloud.api.commands.netapp.ModifyVolumePoolCmd;15
listPools=com.cloud.api.commands.netapp.ListVolumePoolsCmd;15

View File

@ -475,6 +475,7 @@ fi
%{_javadir}/asm-3.1.jar
%{_javadir}/xapi-5.6.100-1-SNAPSHOT.jar
%{_javadir}/log4j-*.jar
%{_javadir}/apache-log4j-extras-1.1.jar
%{_javadir}/trilead-ssh2-build213-svnkit-1.3-patch.jar
%{_javadir}/cglib-2.2.jar
%{_javadir}/xmlrpc-common-3.*.jar
@ -553,7 +554,6 @@ fi
%attr(0755,root,root) %{_initrddir}/%{name}-agent
%attr(0755,root,root) %{_bindir}/%{name}-setup-agent
%dir %attr(0770,root,root) %{_localstatedir}/log/%{name}/agent
%attr(0755,root,root) %{_bindir}/mycloud-setup-agent
%files cli
%{_bindir}/%{name}-tool

View File

@ -1,25 +1,25 @@
<?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.
-->
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/deps"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<?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.
-->
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/deps"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -1,41 +1,41 @@
<?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.
-->
<projectDescription>
<name>console-proxy</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
</natures>
</projectDescription>
<?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.
-->
<projectDescription>
<name>console-proxy</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
</natures>
</projectDescription>

View File

@ -1,46 +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
# 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

View File

@ -1,23 +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
# 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

View File

@ -1,19 +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
# 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

View File

@ -1,23 +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
# 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

View File

@ -1,144 +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;
}
/*
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;
}

File diff suppressed because it is too large Load Diff

View File

@ -17,56 +17,56 @@ 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);
}
//
// 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);
}

View File

@ -1,18 +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 %*
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 %*

View File

@ -14,53 +14,53 @@
// 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;
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;
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 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;

View File

@ -14,20 +14,20 @@
// 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);
}
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);
}
}

View File

@ -14,8 +14,8 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.consoleproxy;
package com.cloud.consoleproxy;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@ -30,377 +30,377 @@ 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();
}
}
}
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();
}
}
}

View File

@ -14,87 +14,87 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.consoleproxy;
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 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");
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(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);
key = Integer.parseInt(keyStr);
if(null != w)
width = Integer.parseInt(w);
@ -102,58 +102,58 @@ public class ConsoleProxyAjaxImageHandler implements HttpHandler {
height = Integer.parseInt(h);
} catch (NumberFormatException e) {
s_logger.warn("Invalid numeric parameter in query string: " + keyStr);
throw new IllegalArgumentException(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);
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);
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);
}
}
}
}
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);
}
}
}
}

View File

@ -14,68 +14,68 @@
// 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;
}
}
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;
}
}

View File

@ -14,8 +14,8 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.consoleproxy;
package com.cloud.consoleproxy;
import java.io.IOException;
import java.net.InetSocketAddress;
@ -23,26 +23,26 @@ 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;
}
}
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;
}
}

View File

@ -14,12 +14,12 @@
// 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();
}
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();
}

View File

@ -14,57 +14,57 @@
// 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;
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();
}
}
}
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();
}
}
}

View File

@ -14,61 +14,61 @@
// 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;
}
}
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;
}
}

View File

@ -14,76 +14,76 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.consoleproxy;
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);
}
}
}
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);
}
}
}

View File

@ -34,120 +34,120 @@ import com.cloud.consoleproxy.util.Logger;
// 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");
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();
}
}
_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();
}
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();
}
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();
}
}

View File

@ -14,168 +14,168 @@
// 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;
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);
}
}
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);
}
}

View File

@ -14,8 +14,8 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.consoleproxy;
package com.cloud.consoleproxy;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
@ -35,111 +35,111 @@ 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");
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");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
s_logger.info("Trust manager factory is initialized");
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");
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;
}
}
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;
}
}

View File

@ -14,16 +14,16 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.consoleproxy;
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;
}
void init(byte[] ksBits, String ksPassword);
HttpServer createHttpServerInstance(int port) throws IOException;
SSLServerSocket createSSLServerSocket(int port) throws IOException;
}

View File

@ -14,199 +14,199 @@
// 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;
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");
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
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);
}
public class ConsoleProxyThumbnailHandler implements HttpHandler {
private static final Logger s_logger = Logger.getLogger(ConsoleProxyThumbnailHandler.class);
public ConsoleProxyThumbnailHandler() {
}
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;
}
}
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;
}
}

View File

@ -14,45 +14,45 @@
// 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);
}
}
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);
}
}

View File

@ -14,12 +14,12 @@
// 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);
}
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);
}

View File

@ -14,19 +14,19 @@
// 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;
}
}
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;
}
}

View File

@ -14,210 +14,210 @@
// 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);
}
}
}
}
}
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);
}
}
}
}
}

View File

@ -14,8 +14,8 @@
// 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);
}
package com.cloud.consoleproxy.util;
public interface LoggerFactory {
Logger getLogger(Class<?> clazz);
}

View File

@ -14,236 +14,236 @@
// 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;
}
}
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;
}
}

View File

@ -14,77 +14,77 @@
// 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;
}
}
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;
}
}

View File

@ -14,45 +14,45 @@
// 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();
}
}
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();
}
}

View File

@ -14,42 +14,42 @@
// 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;
}
}
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;
}
}

View File

@ -14,256 +14,256 @@
// 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;
}
}
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;
}
}

View File

@ -30,125 +30,121 @@ 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.
* 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;
private static final long serialVersionUID = 1L;
// Offline screen buffer
private BufferedImage offlineImage;
// Cached Graphics2D object for offline screen buffer
private Graphics2D graphics;
// Offline screen buffer
private BufferedImage offlineImage;
private PaintNotificationListener listener;
// Cached Graphics2D object for offline screen buffer
private Graphics2D graphics;
public BufferedImageCanvas(PaintNotificationListener listener, int width, int height) {
super();
this.listener = listener;
private PaintNotificationListener listener;
setBackground(Color.black);
setFocusable(true);
public BufferedImageCanvas(PaintNotificationListener listener, int width, int height) {
super();
this.listener = listener;
// Don't intercept TAB key
setFocusTraversalKeysEnabled(false);
setBackground(Color.black);
setCanvasSize(width, height);
}
setFocusable(true);
public void setCanvasSize(int width, int height) {
this.offlineImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
graphics = offlineImage.createGraphics();
// Don't intercept TAB key
setFocusTraversalKeysEnabled(false);
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);
setCanvasSize(width, height);
}
// Notify server that update is painted on screen
listener.imagePaintedOnScreen();
}
public BufferedImage getOfflineImage() {
return offlineImage;
}
public void setCanvasSize(int width, int height) {
this.offlineImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
graphics = offlineImage.createGraphics();
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;
}
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;
}
}

View File

@ -14,15 +14,17 @@
// 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);
}
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);
}

View File

@ -18,9 +18,9 @@ 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();
/**
* 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();
}

View File

@ -18,10 +18,10 @@ 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();
/**
* Notify subscriber that screen is updated, so client can send another
* frame buffer update request to server.
*/
void imagePaintedOnScreen();
}

View File

@ -20,62 +20,63 @@ 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;
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;
/**
* 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;
/**
* 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 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;
/**
* 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;
/**
* 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*/;
/**
* 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 };
/**
* 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;
/**
* 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 KEY_UP = 0, KEY_DOWN = 1;
public static final int LITTLE_ENDIAN = 0, BIG_ENDIAN = 1;
public static final int LITTLE_ENDIAN = 0, BIG_ENDIAN = 1;
public static final int EXCLUSIVE_ACCESS = 0, SHARED_ACCESS = 1;
public static final int EXCLUSIVE_ACCESS = 0, SHARED_ACCESS = 1;
public static final int PALETTE = 0, TRUE_COLOR = 1;
public static final int PALETTE = 0, TRUE_COLOR = 1;
/**
* Default charset to use when communicating with server.
*/
public static final Charset CHARSET = Charset.availableCharsets().get("US-ASCII");
/**
* Default charset to use when communicating with server.
*/
public static final Charset CHARSET = Charset.availableCharsets().get("US-ASCII");
}

View File

@ -39,414 +39,413 @@ 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 static final Logger s_logger = Logger.getLogger(VncClient.class);
private Socket socket;
private DataInputStream is;
private DataOutputStream os;
private Socket socket;
private DataInputStream is;
private DataOutputStream os;
private VncScreenDescription screen = new VncScreenDescription();
private VncScreenDescription screen = new VncScreenDescription();
private VncClientPacketSender sender;
private VncServerPacketReceiver receiver;
private boolean noUI = false;
private ConsoleProxyClientListener clientListener = null;
private VncClientPacketSender sender;
private VncServerPacketReceiver receiver;
public static void main(String args[]) {
if (args.length < 3) {
printHelpMessage();
System.exit(1);
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);
}
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 + "\".");
private static void printHelpMessage() {
/* LOG */s_logger.info("Usage: HOST PORT PASSWORD.");
}
// 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);
public VncClient(ConsoleProxyClientListener clientListener) {
this.noUI = true;
this.clientListener = clientListener;
}
case RfbConstants.NO_AUTH: {
// Client can connect without authorization. Nothing to do.
break;
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);
}
case RfbConstants.VNC_AUTH: {
s_logger.info("VNC server requires password authentication");
doVncAuth(password);
break;
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) {
}
}
}
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());
public ConsoleProxyClientListener getClientListener() {
return clientListener;
}
// Send encoded challenge
os.write(response);
os.flush();
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;
}
// Read security result
int authResult = is.readInt();
switch (authResult) {
case RfbConstants.VNC_AUTH_OK: {
// Nothing to do
break;
RawHTTP tunnel = new RawHTTP("CONNECT", host, port, path, session, useSSL);
this.socket = tunnel.connect();
doConnect(sid);
}
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]);
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);
}
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);
private void doConnect(String password) throws IOException {
is = new DataInputStream(socket.getInputStream());
os = new DataOutputStream(socket.getOutputStream());
byte[] response = cipher.doFinal(challenge);
return response;
}
// Initialize connection
handshake();
authenticate(password);
initialize();
/**
* 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;
}
s_logger.info("Connecting to VNC server succeeded, start session");
private void initialize() throws IOException {
// Send client initialization message
{
// Send shared flag
os.writeByte(RfbConstants.EXCLUSIVE_ACCESS);
os.flush();
// 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();
}
}
// 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);
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;
}
// Read pixel format
{
int bitsPerPixel = is.readUnsignedByte();
int depth = is.readUnsignedByte();
/**
* Handshake with VNC server.
*/
private void handshake() throws IOException {
int bigEndianFlag = is.readUnsignedByte();
int trueColorFlag = is.readUnsignedByte();
// Read protocol version
byte[] buf = new byte[12];
is.readFully(buf);
String rfbProtocol = new String(buf);
int redMax = is.readUnsignedShort();
int greenMax = is.readUnsignedShort();
int blueMax = is.readUnsignedShort();
// 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 + "\".");
}
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);
// Send response: we support RFB 3.3 only
String ourProtocolString = RfbConstants.RFB_PROTOCOL_VERSION + "\n";
os.write(ourProtocolString.getBytes());
os.flush();
}
// 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);
/**
* 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();
}
}
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();
}
}

View File

@ -35,226 +35,224 @@ 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);
private static final Logger s_logger = Logger.getLogger(VncClientPacketSender.class);
// Queue for outgoing packets
private final BlockingQueue<ClientPacket> queue = new ArrayBlockingQueue<ClientPacket>(30);
// 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 final DataOutputStream os;
private final VncScreenDescription screen;
private final VncClient vncConnection;
private boolean connectionAlive = true;
private boolean connectionAlive = true;
// Don't send update request again until we receive next frame buffer update
private boolean updateRequestSent = false;
// 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;
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);
}
sendSetPixelFormat();
sendSetEncodings();
requestFullScreenUpdate();
}
@Override
public void run() {
try {
while (connectionAlive) {
ClientPacket packet = queue.poll(1, TimeUnit.SECONDS);
if (packet != null) {
packet.write(os);
os.flush();
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();
}
}
}
} catch (Throwable e) {
s_logger.error("Unexpected exception: ", e);
if (connectionAlive) {
closeConnection();
vncConnection.shutdown();
}
}
}
private void sendSetEncodings() {
queue.add(new SetEncodingsPacket(RfbConstants.SUPPORTED_ENCODINGS_ARRAY));
}
private void sendSetPixelFormat() {
if (!screen.isRGB888_32_LE()) {
queue.add(new SetPixelFormatPacket(screen, 32, 24, RfbConstants.LITTLE_ENDIAN, RfbConstants.TRUE_COLOR, 255, 255, 255, 16, 8, 0));
}
}
public void closeConnection() {
connectionAlive = false;
}
public void requestFullScreenUpdate() {
queue.add(new FramebufferUpdateRequestPacket(RfbConstants.FRAMEBUFFER_FULL_UPDATE_REQUEST, 0, 0, screen.getFramebufferWidth(), screen
.getFramebufferHeight()));
updateRequestSent = true;
}
@Override
public void imagePaintedOnScreen() {
if (!updateRequestSent) {
queue.add(new FramebufferUpdateRequestPacket(RfbConstants.FRAMEBUFFER_INCREMENTAL_UPDATE_REQUEST, 0, 0, screen.getFramebufferWidth(), screen
.getFramebufferHeight()));
updateRequestSent = true;
}
}
@Override
public void frameBufferPacketReceived() {
updateRequestSent = false;
}
@Override
public void mouseDragged(MouseEvent e) {
queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY()));
}
@Override
public void mouseMoved(MouseEvent e) {
queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY()));
}
@Override
public void mouseClicked(MouseEvent e) {
// Nothing to do
}
@Override
public void mousePressed(MouseEvent e) {
queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY()));
}
@Override
public void mouseReleased(MouseEvent e) {
queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY()));
}
@Override
public void mouseEntered(MouseEvent e) {
// Nothing to do
}
@Override
public void mouseExited(MouseEvent e) {
// Nothing to do
}
/**
* Current state of buttons 1 to 8 are represented by bits 0 to 7 of
* button-mask respectively, 0 meaning up, 1 meaning down (pressed). On a
* conventional mouse, buttons 1, 2 and 3 correspond to the left, middle and
* right buttons on the mouse. On a wheel mouse, each step of the wheel
* upwards is represented by a press and release of button 4, and each step
* downwards is represented by a press and release of button 5.
*
* @param modifiers
* extended modifiers from AWT mouse event
* @return VNC mouse button mask
*/
public static int mapAwtModifiersToVncButtonMask(int modifiers) {
int mask = (((modifiers & MouseEvent.BUTTON1_DOWN_MASK) != 0) ? 0x1 : 0) | (((modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0) ? 0x2 : 0)
| (((modifiers & MouseEvent.BUTTON3_DOWN_MASK) != 0) ? 0x4 : 0);
return mask;
}
@Override
public void keyTyped(KeyEvent e) {
// Do nothing
}
@Override
public void keyPressed(KeyEvent e) {
ClientPacket request = new KeyboardEventPacket(RfbConstants.KEY_DOWN, mapAwtKeyToVncKey(e.getKeyCode()));
queue.add(request);
}
@Override
public void keyReleased(KeyEvent e) {
ClientPacket request = new KeyboardEventPacket(RfbConstants.KEY_UP, mapAwtKeyToVncKey(e.getKeyCode()));
queue.add(request);
}
private int mapAwtKeyToVncKey(int key) {
switch (key) {
case KeyEvent.VK_BACK_SPACE:
return 0xff08;
case KeyEvent.VK_TAB:
return 0xff09;
case KeyEvent.VK_ENTER:
return 0xff0d;
case KeyEvent.VK_ESCAPE:
return 0xff1b;
case KeyEvent.VK_INSERT:
return 0xff63;
case KeyEvent.VK_DELETE:
return 0xffff;
case KeyEvent.VK_HOME:
return 0xff50;
case KeyEvent.VK_END:
return 0xff57;
case KeyEvent.VK_PAGE_UP:
return 0xff55;
case KeyEvent.VK_PAGE_DOWN:
return 0xff56;
case KeyEvent.VK_LEFT:
return 0xff51;
case KeyEvent.VK_UP:
return 0xff52;
case KeyEvent.VK_RIGHT:
return 0xff53;
case KeyEvent.VK_DOWN:
return 0xff54;
case KeyEvent.VK_F1:
return 0xffbe;
case KeyEvent.VK_F2:
return 0xffbf;
case KeyEvent.VK_F3:
return 0xffc0;
case KeyEvent.VK_F4:
return 0xffc1;
case KeyEvent.VK_F5:
return 0xffc2;
case KeyEvent.VK_F6:
return 0xffc3;
case KeyEvent.VK_F7:
return 0xffc4;
case KeyEvent.VK_F8:
return 0xffc5;
case KeyEvent.VK_F9:
return 0xffc6;
case KeyEvent.VK_F10:
return 0xffc7;
case KeyEvent.VK_F11:
return 0xffc8;
case KeyEvent.VK_F12:
return 0xffc9;
case KeyEvent.VK_SHIFT:
return 0xffe1;
case KeyEvent.VK_CONTROL:
return 0xffe3;
case KeyEvent.VK_META:
return 0xffe7;
case KeyEvent.VK_ALT:
return 0xffe9;
case KeyEvent.VK_ALT_GRAPH:
return 0xffea;
case KeyEvent.VK_BACK_QUOTE:
return 0x0060;
}
return key;
}
private void sendSetEncodings() {
queue.add(new SetEncodingsPacket(RfbConstants.SUPPORTED_ENCODINGS_ARRAY));
}
private void sendSetPixelFormat() {
if (!screen.isRGB888_32_LE()) {
queue.add(new SetPixelFormatPacket(screen, 32, 24, RfbConstants.LITTLE_ENDIAN, RfbConstants.TRUE_COLOR, 255, 255, 255, 16, 8, 0));
}
}
public void closeConnection() {
connectionAlive = false;
}
public void requestFullScreenUpdate() {
queue.add(new FramebufferUpdateRequestPacket(RfbConstants.FRAMEBUFFER_FULL_UPDATE_REQUEST, 0, 0, screen.getFramebufferWidth(), screen.getFramebufferHeight()));
updateRequestSent = true;
}
@Override
public void imagePaintedOnScreen() {
if (!updateRequestSent) {
queue.add(new FramebufferUpdateRequestPacket(RfbConstants.FRAMEBUFFER_INCREMENTAL_UPDATE_REQUEST, 0, 0, screen.getFramebufferWidth(), screen.getFramebufferHeight()));
updateRequestSent = true;
}
}
@Override
public void frameBufferPacketReceived() {
updateRequestSent = false;
}
@Override
public void mouseDragged(MouseEvent e) {
queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY()));
}
@Override
public void mouseMoved(MouseEvent e) {
queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY()));
}
@Override
public void mouseClicked(MouseEvent e) {
// Nothing to do
}
@Override
public void mousePressed(MouseEvent e) {
queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY()));
}
@Override
public void mouseReleased(MouseEvent e) {
queue.add(new MouseEventPacket(mapAwtModifiersToVncButtonMask(e.getModifiersEx()), e.getX(), e.getY()));
}
@Override
public void mouseEntered(MouseEvent e) {
// Nothing to do
}
@Override
public void mouseExited(MouseEvent e) {
// Nothing to do
}
/**
* Current state of buttons 1 to 8 are represented by bits 0 to 7 of
* button-mask respectively, 0 meaning up, 1 meaning down (pressed). On a
* conventional mouse, buttons 1, 2 and 3 correspond to the left, middle and
* right buttons on the mouse. On a wheel mouse, each step of the wheel
* upwards is represented by a press and release of button 4, and each step
* downwards is represented by a press and release of button 5.
*
* @param modifiers
* extended modifiers from AWT mouse event
* @return VNC mouse button mask
*/
public static int mapAwtModifiersToVncButtonMask(int modifiers) {
int mask = (((modifiers & MouseEvent.BUTTON1_DOWN_MASK) != 0) ? 0x1 : 0) | (((modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0) ? 0x2 : 0)
| (((modifiers & MouseEvent.BUTTON3_DOWN_MASK) != 0) ? 0x4 : 0);
return mask;
}
@Override
public void keyTyped(KeyEvent e) {
// Do nothing
}
@Override
public void keyPressed(KeyEvent e) {
ClientPacket request = new KeyboardEventPacket(RfbConstants.KEY_DOWN, mapAwtKeyToVncKey(e.getKeyCode()));
queue.add(request);
}
@Override
public void keyReleased(KeyEvent e) {
ClientPacket request = new KeyboardEventPacket(RfbConstants.KEY_UP, mapAwtKeyToVncKey(e.getKeyCode()));
queue.add(request);
}
private int mapAwtKeyToVncKey(int key) {
switch (key) {
case KeyEvent.VK_BACK_SPACE:
return 0xff08;
case KeyEvent.VK_TAB:
return 0xff09;
case KeyEvent.VK_ENTER:
return 0xff0d;
case KeyEvent.VK_ESCAPE:
return 0xff1b;
case KeyEvent.VK_INSERT:
return 0xff63;
case KeyEvent.VK_DELETE:
return 0xffff;
case KeyEvent.VK_HOME:
return 0xff50;
case KeyEvent.VK_END:
return 0xff57;
case KeyEvent.VK_PAGE_UP:
return 0xff55;
case KeyEvent.VK_PAGE_DOWN:
return 0xff56;
case KeyEvent.VK_LEFT:
return 0xff51;
case KeyEvent.VK_UP:
return 0xff52;
case KeyEvent.VK_RIGHT:
return 0xff53;
case KeyEvent.VK_DOWN:
return 0xff54;
case KeyEvent.VK_F1:
return 0xffbe;
case KeyEvent.VK_F2:
return 0xffbf;
case KeyEvent.VK_F3:
return 0xffc0;
case KeyEvent.VK_F4:
return 0xffc1;
case KeyEvent.VK_F5:
return 0xffc2;
case KeyEvent.VK_F6:
return 0xffc3;
case KeyEvent.VK_F7:
return 0xffc4;
case KeyEvent.VK_F8:
return 0xffc5;
case KeyEvent.VK_F9:
return 0xffc6;
case KeyEvent.VK_F10:
return 0xffc7;
case KeyEvent.VK_F11:
return 0xffc8;
case KeyEvent.VK_F12:
return 0xffc9;
case KeyEvent.VK_SHIFT:
return 0xffe1;
case KeyEvent.VK_CONTROL:
return 0xffe3;
case KeyEvent.VK_META:
return 0xffe7;
case KeyEvent.VK_ALT:
return 0xffe9;
case KeyEvent.VK_ALT_GRAPH:
return 0xffea;
case KeyEvent.VK_BACK_QUOTE:
return 0x0060;
}
return key;
}
}

View File

@ -21,70 +21,69 @@ package com.cloud.consoleproxy.vnc;
*/
public class VncScreenDescription {
// Frame buffer size
private int framebufferWidth = -1;
private int framebufferHeight = -1;
// Frame buffer size
private int framebufferWidth = -1;
private int framebufferHeight = -1;
// Desktop name
private String desktopName;
// Desktop name
private String desktopName;
// Bytes per pixel
private int bytesPerPixel;
// 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;
// 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() {
}
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) {
/**
* 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;
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);
}
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 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;
}
/**
* Store server desktop name.
*/
public void setDesktopName(String desktopName) {
this.desktopName = desktopName;
}
// Getters for variables, as usual
// Getters for variables, as usual
public String getDesktopName() {
return desktopName;
}
public String getDesktopName() {
return desktopName;
}
public int getBytesPerPixel() {
return bytesPerPixel;
}
public int getBytesPerPixel() {
return bytesPerPixel;
}
public int getFramebufferHeight() {
return framebufferHeight;
}
public int getFramebufferHeight() {
return framebufferHeight;
}
public int getFramebufferWidth() {
return framebufferWidth;
}
public int getFramebufferWidth() {
return framebufferWidth;
}
public boolean isRGB888_32_LE() {
return rgb888_32_le;
}
public boolean isRGB888_32_LE() {
return rgb888_32_le;
}
}

View File

@ -27,97 +27,97 @@ 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 static final Logger s_logger = Logger.getLogger(VncServerPacketReceiver.class);
private final VncScreenDescription screen;
private BufferedImageCanvas canvas;
private DataInputStream is;
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;
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 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 void closeConnection() {
connectionAlive = false;
}
public boolean isConnectionAlive() {
return connectionAlive;
}
public BufferedImageCanvas getCanvas() {
return canvas;
}
/**
* Handle server bell packet.
*/
private void serverBell() {
Toolkit.getDefaultToolkit().beep();
}
@Override
public void run() {
try {
while (connectionAlive) {
/**
* 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());
}
// 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());
}
}

View File

@ -21,6 +21,6 @@ import java.io.IOException;
public interface ClientPacket {
void write(DataOutputStream os) throws IOException;
void write(DataOutputStream os) throws IOException;
}

View File

@ -28,27 +28,26 @@ import com.cloud.consoleproxy.vnc.RfbConstants;
*/
public class FramebufferUpdateRequestPacket implements ClientPacket {
private final int incremental;
private final int x, y, width, height;
private final int incremental;
private final int x, y, width, height;
public FramebufferUpdateRequestPacket(int incremental, int x, int y, int width, int height) {
this.incremental = incremental;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public FramebufferUpdateRequestPacket(int incremental, int x, int y, int width, int height) {
this.incremental = incremental;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
@Override
public void write(DataOutputStream os) throws IOException {
os.writeByte(RfbConstants.CLIENT_FRAMEBUFFER_UPDATE_REQUEST);
@Override
public void write(DataOutputStream os) throws IOException {
os.writeByte(RfbConstants.CLIENT_FRAMEBUFFER_UPDATE_REQUEST);
os.writeByte(incremental);
os.writeShort(x);
os.writeShort(y);
os.writeShort(width);
os.writeShort(height);
}
os.writeByte(incremental);
os.writeShort(x);
os.writeShort(y);
os.writeShort(width);
os.writeShort(height);
}
}

View File

@ -23,20 +23,20 @@ import com.cloud.consoleproxy.vnc.RfbConstants;
public class KeyboardEventPacket implements ClientPacket {
private final int downFlag, key;
public KeyboardEventPacket(int downFlag, int key) {
this.downFlag = downFlag;
this.key = key;
}
private final int downFlag, key;
@Override
public void write(DataOutputStream os) throws IOException {
os.writeByte(RfbConstants.CLIENT_KEYBOARD_EVENT);
public KeyboardEventPacket(int downFlag, int key) {
this.downFlag = downFlag;
this.key = key;
}
os.writeByte(downFlag);
os.writeShort(0); // padding
os.writeInt(key);
}
@Override
public void write(DataOutputStream os) throws IOException {
os.writeByte(RfbConstants.CLIENT_KEYBOARD_EVENT);
os.writeByte(downFlag);
os.writeShort(0); // padding
os.writeInt(key);
}
}

View File

@ -23,21 +23,21 @@ import com.cloud.consoleproxy.vnc.RfbConstants;
public class MouseEventPacket implements ClientPacket {
private final int buttonMask, x, y;
private final int buttonMask, x, y;
public MouseEventPacket(int buttonMask, int x, int y) {
this.buttonMask = buttonMask;
this.x = x;
this.y = y;
}
public MouseEventPacket(int buttonMask, int x, int y) {
this.buttonMask = buttonMask;
this.x = x;
this.y = y;
}
@Override
public void write(DataOutputStream os) throws IOException {
os.writeByte(RfbConstants.CLIENT_POINTER_EVENT);
@Override
public void write(DataOutputStream os) throws IOException {
os.writeByte(RfbConstants.CLIENT_POINTER_EVENT);
os.writeByte(buttonMask);
os.writeShort(x);
os.writeShort(y);
}
os.writeByte(buttonMask);
os.writeShort(x);
os.writeShort(y);
}
}

View File

@ -23,26 +23,23 @@ import com.cloud.consoleproxy.vnc.RfbConstants;
public class SetEncodingsPacket implements ClientPacket {
private final int[] encodings;
private final int[] encodings;
public SetEncodingsPacket(int[] encodings)
{
this.encodings = encodings;
}
@Override
public void write(DataOutputStream os) throws IOException
{
os.writeByte(RfbConstants.CLIENT_SET_ENCODINGS);
os.writeByte(0);//padding
os.writeShort(encodings.length);
for(int i=0;i<encodings.length;i++)
{
os.writeInt(encodings[i]);
public SetEncodingsPacket(int[] encodings) {
this.encodings = encodings;
}
@Override
public void write(DataOutputStream os) throws IOException {
os.writeByte(RfbConstants.CLIENT_SET_ENCODINGS);
os.writeByte(0);// padding
os.writeShort(encodings.length);
for (int i = 0; i < encodings.length; i++) {
os.writeInt(encodings[i]);
}
}
}
}

View File

@ -24,52 +24,52 @@ import com.cloud.consoleproxy.vnc.VncScreenDescription;
public class SetPixelFormatPacket implements ClientPacket {
private final int bitsPerPixel, depth, bigEndianFlag, trueColourFlag, redMax, greenMax, blueMax, redShift, greenShift, blueShift;
private final VncScreenDescription screen;
private final int bitsPerPixel, depth, bigEndianFlag, trueColourFlag, redMax, greenMax, blueMax, redShift, greenShift, blueShift;
public SetPixelFormatPacket(VncScreenDescription screen, int bitsPerPixel, int depth, int bigEndianFlag, int trueColorFlag, int redMax, int greenMax,
int blueMax, int redShift, int greenShift, int blueShift) {
this.screen = screen;
this.bitsPerPixel = bitsPerPixel;
this.depth = depth;
this.bigEndianFlag = bigEndianFlag;
this.trueColourFlag = trueColorFlag;
this.redMax = redMax;
this.greenMax = greenMax;
this.blueMax = blueMax;
this.redShift = redShift;
this.greenShift = greenShift;
this.blueShift = blueShift;
}
private final VncScreenDescription screen;
@Override
public void write(DataOutputStream os) throws IOException {
os.writeByte(RfbConstants.CLIENT_SET_PIXEL_FORMAT);
public SetPixelFormatPacket(VncScreenDescription screen, int bitsPerPixel, int depth, int bigEndianFlag, int trueColorFlag, int redMax, int greenMax, int blueMax, int redShift, int greenShift,
int blueShift) {
this.screen = screen;
this.bitsPerPixel = bitsPerPixel;
this.depth = depth;
this.bigEndianFlag = bigEndianFlag;
this.trueColourFlag = trueColorFlag;
this.redMax = redMax;
this.greenMax = greenMax;
this.blueMax = blueMax;
this.redShift = redShift;
this.greenShift = greenShift;
this.blueShift = blueShift;
}
// Padding
os.writeByte(0);
os.writeByte(0);
os.writeByte(0);
@Override
public void write(DataOutputStream os) throws IOException {
os.writeByte(RfbConstants.CLIENT_SET_PIXEL_FORMAT);
// Send pixel format
os.writeByte(bitsPerPixel);
os.writeByte(depth);
os.writeByte(bigEndianFlag);
os.writeByte(trueColourFlag);
os.writeShort(redMax);
os.writeShort(greenMax);
os.writeShort(blueMax);
os.writeByte(redShift);
os.writeByte(greenShift);
os.writeByte(blueShift);
// Padding
os.writeByte(0);
os.writeByte(0);
os.writeByte(0);
// Padding
os.writeByte(0);
os.writeByte(0);
os.writeByte(0);
// Send pixel format
os.writeByte(bitsPerPixel);
os.writeByte(depth);
os.writeByte(bigEndianFlag);
os.writeByte(trueColourFlag);
os.writeShort(redMax);
os.writeShort(greenMax);
os.writeShort(blueMax);
os.writeByte(redShift);
os.writeByte(greenShift);
os.writeByte(blueShift);
screen.setPixelFormat(bitsPerPixel, depth, bigEndianFlag, trueColourFlag, redMax, greenMax, blueMax, redShift, greenShift, blueShift);
}
// Padding
os.writeByte(0);
os.writeByte(0);
os.writeByte(0);
screen.setPixelFormat(bitsPerPixel, depth, bigEndianFlag, trueColourFlag, redMax, greenMax, blueMax, redShift, greenShift, blueShift);
}
}

View File

@ -18,36 +18,36 @@ package com.cloud.consoleproxy.vnc.packet.server;
public abstract class AbstractRect implements Rect {
protected final int x;
protected final int y;
protected final int width;
protected final int height;
protected final int x;
protected final int y;
protected final int width;
protected final int height;
public AbstractRect(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public AbstractRect(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
@Override
public int getX() {
return x;
}
@Override
public int getX() {
return x;
}
@Override
public int getY() {
return y;
}
@Override
public int getY() {
return y;
}
@Override
public int getWidth() {
return width;
}
@Override
public int getWidth() {
return width;
}
@Override
public int getHeight() {
return height;
}
@Override
public int getHeight() {
return height;
}
}

View File

@ -23,17 +23,17 @@ import java.io.IOException;
public class CopyRect extends AbstractRect {
private final int srcX, srcY;
private final int srcX, srcY;
public CopyRect(int x, int y, int width, int height, DataInputStream is) throws IOException {
super(x, y, width, height);
public CopyRect(int x, int y, int width, int height, DataInputStream is) throws IOException {
super(x, y, width, height);
srcX = is.readUnsignedShort();
srcY = is.readUnsignedShort();
}
srcX = is.readUnsignedShort();
srcY = is.readUnsignedShort();
}
@Override
public void paint(BufferedImage image, Graphics2D graphics) {
graphics.copyArea(srcX, srcY, width, height, x - srcX, y - srcY);
}
@Override
public void paint(BufferedImage image, Graphics2D graphics) {
graphics.copyArea(srcX, srcY, width, height, x - srcX, y - srcY);
}
}

View File

@ -22,18 +22,18 @@ import java.awt.image.BufferedImage;
import com.cloud.consoleproxy.vnc.BufferedImageCanvas;
public class FrameBufferSizeChangeRequest extends AbstractRect {
private final BufferedImageCanvas canvas;
public FrameBufferSizeChangeRequest(BufferedImageCanvas canvas, int width, int height) {
super(0, 0, width, height);
this.canvas = canvas;
canvas.setCanvasSize(width, height);
}
private final BufferedImageCanvas canvas;
@Override
public void paint(BufferedImage offlineImage, Graphics2D graphics) {
canvas.setCanvasSize(width, height);
}
public FrameBufferSizeChangeRequest(BufferedImageCanvas canvas, int width, int height) {
super(0, 0, width, height);
this.canvas = canvas;
canvas.setCanvasSize(width, height);
}
@Override
public void paint(BufferedImage offlineImage, Graphics2D graphics) {
canvas.setCanvasSize(width, height);
}
}

View File

@ -29,75 +29,74 @@ import com.cloud.consoleproxy.vnc.packet.server.Rect;
public class FramebufferUpdatePacket {
private final VncScreenDescription screen;
private final BufferedImageCanvas canvas;
private final ConsoleProxyClientListener clientListener;
private final VncScreenDescription screen;
private final BufferedImageCanvas canvas;
private final ConsoleProxyClientListener clientListener;
public FramebufferUpdatePacket(BufferedImageCanvas canvas, VncScreenDescription screen, DataInputStream is,
ConsoleProxyClientListener clientListener) throws IOException {
this.screen = screen;
this.canvas = canvas;
this.clientListener = clientListener;
readPacketData(is);
}
public FramebufferUpdatePacket(BufferedImageCanvas canvas, VncScreenDescription screen, DataInputStream is, ConsoleProxyClientListener clientListener) throws IOException {
private void readPacketData(DataInputStream is) throws IOException {
is.skipBytes(1);// Skip padding
// Read number of rectangles
int numberOfRectangles = is.readUnsignedShort();
// For all rectangles
for (int i = 0; i < numberOfRectangles; i++) {
// Read coordinate of rectangle
int x = is.readUnsignedShort();
int y = is.readUnsignedShort();
int width = is.readUnsignedShort();
int height = is.readUnsignedShort();
int encodingType = is.readInt();
// Process rectangle
Rect rect;
switch (encodingType) {
case RfbConstants.ENCODING_RAW: {
rect = new RawRect(screen, x, y, width, height, is);
break;
}
case RfbConstants.ENCODING_COPY_RECT: {
rect = new CopyRect(x, y, width, height, is);
break;
}
case RfbConstants.ENCODING_DESKTOP_SIZE: {
rect = new FrameBufferSizeChangeRequest(canvas, width, height);
if(this.clientListener != null)
this.clientListener.onFramebufferSizeChange(width, height);
break;
}
default:
throw new RuntimeException("Unsupported ecnoding: " + encodingType);
}
paint(rect, canvas);
if(this.clientListener != null)
this.clientListener.onFramebufferUpdate(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
this.screen = screen;
this.canvas = canvas;
this.clientListener = clientListener;
readPacketData(is);
}
}
private void readPacketData(DataInputStream is) throws IOException {
is.skipBytes(1);// Skip padding
public void paint(Rect rect, BufferedImageCanvas canvas) {
// Draw rectangle on offline buffer
rect.paint(canvas.getOfflineImage(), canvas.getOfflineGraphics());
// Request update of repainted area
canvas.repaint(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
// Read number of rectangles
int numberOfRectangles = is.readUnsignedShort();
// For all rectangles
for (int i = 0; i < numberOfRectangles; i++) {
// Read coordinate of rectangle
int x = is.readUnsignedShort();
int y = is.readUnsignedShort();
int width = is.readUnsignedShort();
int height = is.readUnsignedShort();
int encodingType = is.readInt();
// Process rectangle
Rect rect;
switch (encodingType) {
case RfbConstants.ENCODING_RAW: {
rect = new RawRect(screen, x, y, width, height, is);
break;
}
case RfbConstants.ENCODING_COPY_RECT: {
rect = new CopyRect(x, y, width, height, is);
break;
}
case RfbConstants.ENCODING_DESKTOP_SIZE: {
rect = new FrameBufferSizeChangeRequest(canvas, width, height);
if (this.clientListener != null)
this.clientListener.onFramebufferSizeChange(width, height);
break;
}
default:
throw new RuntimeException("Unsupported ecnoding: " + encodingType);
}
paint(rect, canvas);
if (this.clientListener != null)
this.clientListener.onFramebufferUpdate(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
}
public void paint(Rect rect, BufferedImageCanvas canvas) {
// Draw rectangle on offline buffer
rect.paint(canvas.getOfflineImage(), canvas.getOfflineGraphics());
// Request update of repainted area
canvas.repaint(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
}

View File

@ -26,51 +26,50 @@ import java.io.IOException;
import com.cloud.consoleproxy.vnc.VncScreenDescription;
public class RawRect extends AbstractRect {
private final int[] buf;
private final int[] buf;
public RawRect(VncScreenDescription screen, int x, int y, int width, int height, DataInputStream is) throws IOException {
super(x, y, width, height);
public RawRect(VncScreenDescription screen, int x, int y, int width, int height, DataInputStream is) throws IOException {
super(x, y, width, height);
byte[] bbuf = new byte[width * height * screen.getBytesPerPixel()];
is.readFully(bbuf);
byte[] bbuf = new byte[width * height * screen.getBytesPerPixel()];
is.readFully(bbuf);
// Convert array of bytes to array of int
int size = width * height;
buf = new int[size];
for (int i = 0, j = 0; i < size; i++, j += 4) {
buf[i] = (bbuf[j + 0] & 0xFF) | ((bbuf[j + 1] & 0xFF) << 8) | ((bbuf[j + 2] & 0xFF) << 16) | ((bbuf[j + 3] & 0xFF) << 24);
}
}
@Override
public void paint(BufferedImage image, Graphics2D graphics) {
DataBuffer dataBuf = image.getRaster().getDataBuffer();
switch (dataBuf.getDataType()) {
case DataBuffer.TYPE_INT: {
// We chose RGB888 model, so Raster will use DataBufferInt type
DataBufferInt dataBuffer = (DataBufferInt) dataBuf;
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
// Paint rectangle directly on buffer, line by line
int[] imageBuffer = dataBuffer.getData();
for (int srcLine = 0, dstLine = y; srcLine < height && dstLine < imageHeight; srcLine++, dstLine++) {
try {
System.arraycopy(buf, srcLine * width, imageBuffer, x + dstLine * imageWidth, width);
} catch (IndexOutOfBoundsException e) {
// Convert array of bytes to array of int
int size = width * height;
buf = new int[size];
for (int i = 0, j = 0; i < size; i++, j += 4) {
buf[i] = (bbuf[j + 0] & 0xFF) | ((bbuf[j + 1] & 0xFF) << 8) | ((bbuf[j + 2] & 0xFF) << 16) | ((bbuf[j + 3] & 0xFF) << 24);
}
}
break;
}
default:
throw new RuntimeException("Unsupported data buffer in buffered image: expected data buffer of type int (DataBufferInt). Actual data buffer type: "
+ dataBuf.getClass().getSimpleName());
@Override
public void paint(BufferedImage image, Graphics2D graphics) {
DataBuffer dataBuf = image.getRaster().getDataBuffer();
switch (dataBuf.getDataType()) {
case DataBuffer.TYPE_INT: {
// We chose RGB888 model, so Raster will use DataBufferInt type
DataBufferInt dataBuffer = (DataBufferInt) dataBuf;
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
// Paint rectangle directly on buffer, line by line
int[] imageBuffer = dataBuffer.getData();
for (int srcLine = 0, dstLine = y; srcLine < height && dstLine < imageHeight; srcLine++, dstLine++) {
try {
System.arraycopy(buf, srcLine * width, imageBuffer, x + dstLine * imageWidth, width);
} catch (IndexOutOfBoundsException e) {
}
}
break;
}
default:
throw new RuntimeException("Unsupported data buffer in buffered image: expected data buffer of type int (DataBufferInt). Actual data buffer type: " + dataBuf.getClass().getSimpleName());
}
}
}
}

View File

@ -20,11 +20,14 @@ import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
public interface Rect {
void paint(BufferedImage offlineImage, Graphics2D graphics);
int getX();
int getY();
int getWidth();
int getHeight();
void paint(BufferedImage offlineImage, Graphics2D graphics);
int getX();
int getY();
int getWidth();
int getHeight();
}

View File

@ -23,27 +23,27 @@ import com.cloud.consoleproxy.util.Logger;
import com.cloud.consoleproxy.vnc.RfbConstants;
public class ServerCutText {
private static final Logger s_logger = Logger.getLogger(ServerCutText.class);
private static final Logger s_logger = Logger.getLogger(ServerCutText.class);
private String content;
private String content;
public String getContent() {
return content;
}
public String getContent() {
return content;
}
public ServerCutText(DataInputStream is) throws IOException {
readPacketData(is);
}
public ServerCutText(DataInputStream is) throws IOException {
readPacketData(is);
}
private void readPacketData(DataInputStream is) throws IOException {
is.skipBytes(3);// Skip padding
int length = is.readInt();
byte buf[] = new byte[length];
is.readFully(buf);
private void readPacketData(DataInputStream is) throws IOException {
is.skipBytes(3);// Skip padding
int length = is.readInt();
byte buf[] = new byte[length];
is.readFully(buf);
content = new String(buf, RfbConstants.CHARSET);
content = new String(buf, RfbConstants.CHARSET);
/* LOG */s_logger.info("Clippboard content: " + content);
}
/* LOG */s_logger.info("Clippboard content: " + content);
}
}

Some files were not shown because too many files have changed in this diff Show More