Compare commits
4 Commits
feature/KA
...
relativemo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
551164b425 | ||
|
|
1518575982 | ||
|
|
fda877dd72 | ||
|
|
c0f107a83e |
@@ -1,33 +1,16 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
is_kasmvnc() {
|
|
||||||
local package="$1";
|
|
||||||
|
|
||||||
echo "$package" | grep -q 'kasmvncserver_'
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepare_upload_filename() {
|
function prepare_upload_filename() {
|
||||||
local package="$1";
|
local package="$1";
|
||||||
|
|
||||||
if ! is_kasmvnc "$package"; then
|
|
||||||
export upload_filename="$package"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
.ci/detect_os_arch_package_format "$package" > /tmp/os_arch_package_format;
|
.ci/detect_os_arch_package_format "$package" > /tmp/os_arch_package_format;
|
||||||
source /tmp/os_arch_package_format;
|
source /tmp/os_arch_package_format;
|
||||||
detect_release_branch
|
detect_release_branch
|
||||||
|
|
||||||
detect_revision "$package" "$OS_ARCH"
|
|
||||||
if [ -n "$REVISION" ]; then
|
|
||||||
REVISION="_${REVISION}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$RELEASE_BRANCH" ]; then
|
if [ -n "$RELEASE_BRANCH" ]; then
|
||||||
export upload_filename="kasmvncserver_${PACKAGE_OS}_${RELEASE_VERSION}${REVISION}_${OS_ARCH}.${PACKAGE_FORMAT}";
|
export upload_filename="kasmvncserver_${PACKAGE_OS}_${RELEASE_VERSION}_${OS_ARCH}.${PACKAGE_FORMAT}";
|
||||||
else
|
else
|
||||||
export SANITIZED_BRANCH="$(echo $CI_COMMIT_REF_NAME | sed 's/\//_/g')";
|
export SANITIZED_BRANCH="$(echo $CI_COMMIT_REF_NAME | sed 's/\//_/g')";
|
||||||
export upload_filename="kasmvncserver_${PACKAGE_OS}_${RELEASE_VERSION}_${SANITIZED_BRANCH}_${CI_COMMIT_SHA:0:6}${REVISION}_${OS_ARCH}.${PACKAGE_FORMAT}";
|
export upload_filename="kasmvncserver_${PACKAGE_OS}_${RELEASE_VERSION}_${SANITIZED_BRANCH}_${CI_COMMIT_SHA:0:6}_${OS_ARCH}.${PACKAGE_FORMAT}";
|
||||||
fi
|
fi
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,7 +25,6 @@ function upload_to_s3() {
|
|||||||
export BUILD_STATUS="{\"key\":\"doc\", \"state\":\"SUCCESSFUL\", \"name\":\"${upload_filename}\", \"url\":\"${S3_URL}\"}";
|
export BUILD_STATUS="{\"key\":\"doc\", \"state\":\"SUCCESSFUL\", \"name\":\"${upload_filename}\", \"url\":\"${S3_URL}\"}";
|
||||||
curl --request POST --header "PRIVATE-TOKEN:${GITLAB_API_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/statuses/${CI_COMMIT_SHA}?state=success&name=build-url&target_url=${S3_URL}";
|
curl --request POST --header "PRIVATE-TOKEN:${GITLAB_API_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/statuses/${CI_COMMIT_SHA}?state=success&name=build-url&target_url=${S3_URL}";
|
||||||
};
|
};
|
||||||
|
|
||||||
function prepare_to_run_scripts_and_s3_uploads() {
|
function prepare_to_run_scripts_and_s3_uploads() {
|
||||||
export DEBIAN_FRONTEND=noninteractive;
|
export DEBIAN_FRONTEND=noninteractive;
|
||||||
apt-get update;
|
apt-get update;
|
||||||
@@ -56,16 +38,3 @@ detect_release_branch() {
|
|||||||
export RELEASE_BRANCH=1;
|
export RELEASE_BRANCH=1;
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
detect_revision() {
|
|
||||||
local package="$1"
|
|
||||||
local arch="$2"
|
|
||||||
|
|
||||||
REVISION=
|
|
||||||
|
|
||||||
if ! echo "$package" | grep -q '+'; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
REVISION=$(echo "$package" | sed "s/_${arch}.\+//" | sed 's/.\++//')
|
|
||||||
}
|
|
||||||
|
|||||||
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
builder/build
|
||||||
138
.gitlab-ci.yml
138
.gitlab-ci.yml
@@ -8,114 +8,36 @@ variables:
|
|||||||
GIT_FETCH_EXTRA_FLAGS: --tags
|
GIT_FETCH_EXTRA_FLAGS: --tags
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- www
|
|
||||||
- build
|
- build
|
||||||
- upload
|
- upload
|
||||||
|
|
||||||
.prepare_build: &prepare_build
|
.prepare_build: &prepare_build
|
||||||
|
- ls -l
|
||||||
- pwd
|
- pwd
|
||||||
- apk add bash
|
- apk add bash
|
||||||
- mkdir -p "$GITLAB_SHARED_DIND_DIR" && chmod 777 "$GITLAB_SHARED_DIND_DIR"
|
- mkdir -p "$GITLAB_SHARED_DIND_DIR" && chmod 777 "$GITLAB_SHARED_DIND_DIR"
|
||||||
|
|
||||||
.prepare_www: &prepare_www
|
|
||||||
- tar -zxf output/www/kasm_www.tar.gz -C builder/
|
|
||||||
|
|
||||||
.prepare_artfacts: &prepare_artfacts
|
.prepare_artfacts: &prepare_artfacts
|
||||||
|
- mkdir output
|
||||||
- cp -r builder/build/* output/
|
- cp -r builder/build/* output/
|
||||||
- rm output/*.tar.gz
|
- rm output/*.tar.gz
|
||||||
|
|
||||||
build_www:
|
|
||||||
stage: www
|
|
||||||
allow_failure: false
|
|
||||||
before_script:
|
|
||||||
- *prepare_build
|
|
||||||
script:
|
|
||||||
- webpacked_www=$PWD/builder/www
|
|
||||||
- src_www=kasmweb
|
|
||||||
- docker build -t kasmweb/www -f builder/dockerfile.www.build .
|
|
||||||
- docker run --rm -v $PWD/builder/www:/build kasmweb/www:latest
|
|
||||||
- mkdir -p output/www
|
|
||||||
- cd builder
|
|
||||||
- tar -zcvf ../output/www/kasm_www.tar.gz www
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- output/
|
|
||||||
|
|
||||||
build_ubuntu_bionic:
|
build_ubuntu_bionic:
|
||||||
stage: build
|
stage: build
|
||||||
allow_failure: true
|
|
||||||
before_script:
|
before_script:
|
||||||
- *prepare_build
|
- *prepare_build
|
||||||
- *prepare_www
|
|
||||||
after_script:
|
after_script:
|
||||||
- *prepare_artfacts
|
- *prepare_artfacts
|
||||||
script:
|
script:
|
||||||
- bash builder/build-package ubuntu bionic
|
- bash builder/build-package ubuntu bionic
|
||||||
only:
|
|
||||||
variables:
|
|
||||||
- $CI_COMMIT_MESSAGE =~ /\[full [Cc][Ii]\]/
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- output/
|
|
||||||
|
|
||||||
build_ubuntu_bionic_arm:
|
|
||||||
stage: build
|
|
||||||
allow_failure: false
|
|
||||||
tags:
|
|
||||||
- arm
|
|
||||||
before_script:
|
|
||||||
- *prepare_build
|
|
||||||
- *prepare_www
|
|
||||||
after_script:
|
|
||||||
- *prepare_artfacts
|
|
||||||
script:
|
|
||||||
- bash builder/build-package ubuntu bionic
|
|
||||||
only:
|
|
||||||
variables:
|
|
||||||
- $CI_COMMIT_MESSAGE =~ /\[full [Cc][Ii]\]/
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- output/
|
|
||||||
|
|
||||||
build_ubuntu_bionic_libjpeg_turbo:
|
|
||||||
stage: build
|
|
||||||
allow_failure: false
|
|
||||||
before_script:
|
|
||||||
- *prepare_build
|
|
||||||
- *prepare_www
|
|
||||||
after_script:
|
|
||||||
- *prepare_artfacts
|
|
||||||
script:
|
|
||||||
- bash builder/build-package ubuntu focal +libjpeg-turbo_latest
|
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- output/
|
- output/
|
||||||
|
|
||||||
build_ubuntu_focal:
|
build_ubuntu_focal:
|
||||||
stage: build
|
stage: build
|
||||||
allow_failure: true
|
|
||||||
before_script:
|
before_script:
|
||||||
- *prepare_build
|
- *prepare_build
|
||||||
- *prepare_www
|
|
||||||
after_script:
|
|
||||||
- *prepare_artfacts
|
|
||||||
script:
|
|
||||||
- bash builder/build-package ubuntu focal;
|
|
||||||
only:
|
|
||||||
variables:
|
|
||||||
- $CI_COMMIT_MESSAGE =~ /\[full [Cc][Ii]\]/
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- output/
|
|
||||||
|
|
||||||
build_ubuntu_focal_arm:
|
|
||||||
stage: build
|
|
||||||
allow_failure: true
|
|
||||||
tags:
|
|
||||||
- arm
|
|
||||||
before_script:
|
|
||||||
- *prepare_build
|
|
||||||
- *prepare_www
|
|
||||||
after_script:
|
after_script:
|
||||||
- *prepare_artfacts
|
- *prepare_artfacts
|
||||||
script:
|
script:
|
||||||
@@ -126,82 +48,32 @@ build_ubuntu_focal_arm:
|
|||||||
|
|
||||||
build_debian_buster:
|
build_debian_buster:
|
||||||
stage: build
|
stage: build
|
||||||
allow_failure: true
|
|
||||||
before_script:
|
before_script:
|
||||||
- *prepare_build
|
- *prepare_build
|
||||||
- *prepare_www
|
|
||||||
after_script:
|
after_script:
|
||||||
- *prepare_artfacts
|
- *prepare_artfacts
|
||||||
script:
|
script:
|
||||||
- bash builder/build-package debian buster;
|
- bash builder/build-package debian buster;
|
||||||
only:
|
|
||||||
variables:
|
|
||||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- output/
|
|
||||||
|
|
||||||
build_debian_buster_arm:
|
|
||||||
stage: build
|
|
||||||
allow_failure: true
|
|
||||||
tags:
|
|
||||||
- arm
|
|
||||||
before_script:
|
|
||||||
- *prepare_build
|
|
||||||
- *prepare_www
|
|
||||||
after_script:
|
|
||||||
- *prepare_artfacts
|
|
||||||
script:
|
|
||||||
- bash builder/build-package debian buster;
|
|
||||||
only:
|
|
||||||
variables:
|
|
||||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/
|
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- output/
|
- output/
|
||||||
|
|
||||||
build_debian_bullseye:
|
build_debian_bullseye:
|
||||||
stage: build
|
stage: build
|
||||||
allow_failure: true
|
|
||||||
before_script:
|
before_script:
|
||||||
- *prepare_build
|
- *prepare_build
|
||||||
- *prepare_www
|
|
||||||
after_script:
|
after_script:
|
||||||
- *prepare_artfacts
|
- *prepare_artfacts
|
||||||
script:
|
script:
|
||||||
- bash builder/build-package debian bullseye;
|
- bash builder/build-package debian bullseye;
|
||||||
only:
|
|
||||||
variables:
|
|
||||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- output/
|
|
||||||
|
|
||||||
build_debian_bullseye_arm:
|
|
||||||
stage: build
|
|
||||||
allow_failure: true
|
|
||||||
tags:
|
|
||||||
- arm
|
|
||||||
before_script:
|
|
||||||
- *prepare_build
|
|
||||||
- *prepare_www
|
|
||||||
after_script:
|
|
||||||
- *prepare_artfacts
|
|
||||||
script:
|
|
||||||
- bash builder/build-package debian bullseye;
|
|
||||||
only:
|
|
||||||
variables:
|
|
||||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/
|
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- output/
|
- output/
|
||||||
|
|
||||||
build_kali_rolling:
|
build_kali_rolling:
|
||||||
stage: build
|
stage: build
|
||||||
allow_failure: true
|
|
||||||
before_script:
|
before_script:
|
||||||
- *prepare_build
|
- *prepare_build
|
||||||
- *prepare_www
|
|
||||||
after_script:
|
after_script:
|
||||||
- *prepare_artfacts
|
- *prepare_artfacts
|
||||||
script:
|
script:
|
||||||
@@ -212,10 +84,8 @@ build_kali_rolling:
|
|||||||
|
|
||||||
build_centos7:
|
build_centos7:
|
||||||
stage: build
|
stage: build
|
||||||
allow_failure: true
|
|
||||||
before_script:
|
before_script:
|
||||||
- *prepare_build
|
- *prepare_build
|
||||||
- *prepare_www
|
|
||||||
after_script:
|
after_script:
|
||||||
- *prepare_artfacts
|
- *prepare_artfacts
|
||||||
script:
|
script:
|
||||||
@@ -233,11 +103,9 @@ upload:
|
|||||||
- export S3_BUILD_DIRECTORY="kasmvnc/${CI_COMMIT_SHA}"
|
- export S3_BUILD_DIRECTORY="kasmvnc/${CI_COMMIT_SHA}"
|
||||||
- prepare_to_run_scripts_and_s3_uploads
|
- prepare_to_run_scripts_and_s3_uploads
|
||||||
- export RELEASE_VERSION=$(.ci/next_release_version "$CI_COMMIT_REF_NAME")
|
- export RELEASE_VERSION=$(.ci/next_release_version "$CI_COMMIT_REF_NAME")
|
||||||
- for package in `find output/ -type f -name '*.deb' -or -name '*.rpm'`; do
|
- for package in `find output/ -type f -name 'kasmvncserver_*.deb' -or -name '*.rpm'`; do
|
||||||
prepare_upload_filename "$package";
|
prepare_upload_filename "$package";
|
||||||
echo;
|
echo;
|
||||||
echo "File to upload $upload_filename";
|
echo "File to upload $upload_filename";
|
||||||
upload_to_s3 "$package" "$upload_filename";
|
upload_to_s3 "$package" "$upload_filename";
|
||||||
UPLOAD_NAME=$(echo $upload_filename | sed 's#kasmvncserver_##' | sed -r 's#_([0-9]{1,3}\.){2}[0-9]{1,2}_\S+?([a-f0-9]{6})##' | sed -r 's#\.(deb|rpm)##');
|
|
||||||
curl --request POST --header "PRIVATE-TOKEN:${GITLAB_API_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/statuses/${CI_COMMIT_SHA}?state=success&name=${UPLOAD_NAME}&target_url=${S3_URL}";
|
|
||||||
done
|
done
|
||||||
|
|||||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,4 +1,4 @@
|
|||||||
[submodule "kasmweb"]
|
[submodule "kasmweb"]
|
||||||
path = kasmweb
|
path = kasmweb
|
||||||
url = https://github.com/kasmtech/noVNC.git
|
url = https://github.com/kasmtech/noVNC.git
|
||||||
branch = master
|
branch = pointer_lock_api
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ include(CheckLibraryExists)
|
|||||||
include(CheckTypeSize)
|
include(CheckTypeSize)
|
||||||
include(CheckCSourceCompiles)
|
include(CheckCSourceCompiles)
|
||||||
include(CheckCXXSourceCompiles)
|
include(CheckCXXSourceCompiles)
|
||||||
include(CheckCXXCompilerFlag)
|
|
||||||
include(CheckCSourceRuns)
|
include(CheckCSourceRuns)
|
||||||
|
|
||||||
include(CMakeMacroLibtoolFile)
|
include(CMakeMacroLibtoolFile)
|
||||||
@@ -209,9 +208,6 @@ if(ENABLE_PAM)
|
|||||||
endif()
|
endif()
|
||||||
set(HAVE_PAM ${ENABLE_PAM})
|
set(HAVE_PAM ${ENABLE_PAM})
|
||||||
|
|
||||||
# Check for SSE2
|
|
||||||
check_cxx_compiler_flag(-msse2 COMPILER_SUPPORTS_SSE2)
|
|
||||||
|
|
||||||
# Generate config.h and make sure the source finds it
|
# Generate config.h and make sure the source finds it
|
||||||
configure_file(config.h.in config.h)
|
configure_file(config.h.in config.h)
|
||||||
add_definitions(-DHAVE_CONFIG_H)
|
add_definitions(-DHAVE_CONFIG_H)
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -1,11 +1,11 @@
|
|||||||
# KasmVNC - Linux Web Remote Desktop
|
# KasmVNC - Linux Web Remote Desktop
|
||||||
|
|
||||||
<a href="https://kasmweb.com"><img src="https://kasm-static-content.s3.amazonaws.com/logo_kasm.png" width="300"><a/>
|
[](https://kasmweb.com)
|
||||||
|
|
||||||
[Kasm Technologies](https://www.kasmweb.com) developed Kasm Workspaces, the Containerized Streaming Platform. Kasm has open-sourced the Workspace docker images, which include containerized [full desktops and apps](https://github.com/kasmtech/workspaces-images) and [base images](https://github.com/kasmtech/workspaces-core-images) intended for developers to create custimized streaming containers. These containers can be used standalone or within the [Kasm Workspaces Platform](https://www.kasmweb.com) which provides a full Enterprise feature set. KasmVNC is used as the streaming tech for our container images, however, you can use KasmVNC for individual servers. While the term VNC is in the name, KasmVNC is not intended to remain compliant with the RFB spec and has different goals than other VNC projects:
|
[Kasm Technologies LLC](https://www.kasmweb.com) developed Kasm Server, a Containerized Desktop Infrastructure (CDI) solution. Kasm started with TigerVNC and eventually forked it to create KasmVNC. KasmVNC is used within the overal Kasm CDI infrastructure, however, you can use KasmVNC for individual servers. KasmVNC has different goals than TigerVNC:
|
||||||
|
|
||||||
- Web-based - KasmVNC is designed to provide a web accessible remote desktop. It comes with a web server and websocket server built in. There is no need to install other components. Simply run and navigate to your desktop's URL on the port you specify. While you can still tun on the legacy VNC port, it is disabled by default.
|
- Web-based - KasmVNC is designed to provide a web accessible remote desktop. It comes with a web server and websocket server built in. There is no need to install other components. Simply run and navigate to your desktop's URL on the port you specify. While you can still tun on the legacy VNC port, it is disabled by default.
|
||||||
- Security - The RFB specification (VNC) limits the password field to 8 characters, so while the client may take a longer password, only the first 8 characters are sent. KasmVNC defaults to HTTPS with HTTP Basic Auth and disables the legacy VNC authentication method which is not sufficiently secure for internet accessible systems.
|
- Security - KasmVNC defaults to HTTPS and allows for HTTP Basic Auth. VNC Password authentication is limited by specification to 8 characters and is not suffecient for use on an internet accessible remote desktop. Our goal is to create a by default secure, web based experience.
|
||||||
- Simplicity - KasmVNC aims at being simple to deploy and configure.
|
- Simplicity - KasmVNC aims at being simple to deploy and configure.
|
||||||
|
|
||||||
# New Features!
|
# New Features!
|
||||||
@@ -42,9 +42,9 @@ Future Goals:
|
|||||||
#### Debian-based
|
#### Debian-based
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
wget https://github.com/kasmtech/KasmVNC/releases/download/v0.9.2-beta/kasmvncserver_ubuntu_bionic_0.9.2_amd64.deb
|
wget -qO- https://github.com/kasmtech/KasmVNC/releases/download/v0.9.1-beta/kasmvncserver_0.9.1~beta-1_amd64.deb
|
||||||
|
|
||||||
sudo dpkg -i kasmvncserver_*.deb
|
sudo dpkg -i kasmvncserver_0.9.1~beta-1_amd64.deb
|
||||||
sudo apt-get -f install
|
sudo apt-get -f install
|
||||||
|
|
||||||
# We provide an example script to run KasmVNC at #
|
# We provide an example script to run KasmVNC at #
|
||||||
@@ -91,13 +91,11 @@ The options for vncserver:
|
|||||||
| interface | Which interface to bind the web server to. |
|
| interface | Which interface to bind the web server to. |
|
||||||
|
|
||||||
### Development
|
### Development
|
||||||
Would you like to contribute to KasmVNC? Please reachout to us at info@kasmweb.com. We have investigated or are working on the following, if you have experience in these fields and would like to help please let us know.
|
Would you like to contribute to KasmVNC? Please reachout to us at info@kasmweb.com
|
||||||
|
|
||||||
Real-time H264 encoding using NVIDIA and Intel encoding technology.
|
We need help, especially in packaging KasmVNC for various operating systems. We would love to have standard debian or RMP packages and host our own repo, however, that all requires a lot of experience, proper testing, and pipeline development for automated builds.
|
||||||
|
|
||||||
Windows version of KasmVNC. We have been able to get it to compile for Windows and increased the performance, but still not releasable. Experienced Windows developers with a background in cross compiling would help.
|
We also need help with Windows, which is not currently supported. While KasmVNC can technically be built for Windows 10, it is unusably slow, due to all the changes that occured in Windows since the original Windows support was added in the chain of VNC forked projects.
|
||||||
|
|
||||||
ARM version of KasmVNC, we have had requests for this and at one point we did have an ARM build of KasmVNC but it takes dev cycles to mainain and bring it back to life.
|
|
||||||
|
|
||||||
### Compiling From Source
|
### Compiling From Source
|
||||||
See the [builder/README.md](https://github.com/kasmtech/KasmVNC/blob/master/builder/README.md). We containerize our build systems to ensure highly repeatable builds.
|
See the [builder/README.md](https://github.com/kasmtech/KasmVNC/blob/master/builder/README.md). We containerize our build systems to ensure highly repeatable builds.
|
||||||
|
|||||||
@@ -3,17 +3,8 @@ Docker CE
|
|||||||
|
|
||||||
# Build a deb/rpm package
|
# Build a deb/rpm package
|
||||||
```
|
```
|
||||||
# builder/build-package <os> <os_codename> <build_tag>
|
# builder/build-package <os> <os_codename>
|
||||||
# os_codename is what "lsb_release -c" outputs, e.g. buster, focal.
|
# os_codename is what "lsb_release -c" outputs, e.g. buster, focal.
|
||||||
#
|
|
||||||
# build_tag allows building multiple versions of deb package (rpm not supported)
|
|
||||||
# targeting a single distro release (e.g. Ubuntu Bionic). If build_tag is given,
|
|
||||||
# the package name will include build_tag as part of Debian revision. For
|
|
||||||
# example:
|
|
||||||
# * with build_tag: kasmvncserver_0.9.1~beta-1+libjpeg-turbo-latest_amd64.deb
|
|
||||||
# * without build_tag: kasmvncserver_0.9.1~beta-1_amd64.deb
|
|
||||||
# You need to have .build and .deb.build for the build_tag.
|
|
||||||
#
|
|
||||||
# Packages will be placed under builder/build/
|
# Packages will be placed under builder/build/
|
||||||
|
|
||||||
builder/build-package ubuntu bionic
|
builder/build-package ubuntu bionic
|
||||||
@@ -79,63 +70,3 @@ packages installed with XFCE.
|
|||||||
```
|
```
|
||||||
builder/test-deb-barebones ubuntu focal
|
builder/test-deb-barebones ubuntu focal
|
||||||
```
|
```
|
||||||
|
|
||||||
# Preparing a release
|
|
||||||
|
|
||||||
Deb and rpm packages need their versions bumped to the new release version. It
|
|
||||||
can be done with:
|
|
||||||
|
|
||||||
```
|
|
||||||
builder/bump-package-version 0.9.4-beta
|
|
||||||
```
|
|
||||||
|
|
||||||
This will update corresponding package files, use `git diff` to see changes.
|
|
||||||
|
|
||||||
If you've ran the command and curious about Debian version specifics, here's an
|
|
||||||
explanation:
|
|
||||||
Deb version will be `0.9.4~beta-1`. `~` (and not `-`) is required by packaging
|
|
||||||
guidelines, and `-1` is Debian package revision for `0.9.4` upstream release. If
|
|
||||||
a Debian-specific patch was later added on top of `0.9.4`, it'd be `-2` for the
|
|
||||||
next Debian version. Rpm has a corresponding revision in its .spec file.
|
|
||||||
|
|
||||||
# CI development
|
|
||||||
|
|
||||||
S3 upload code is extracted to various files in `.ci`. It's possible to iterate
|
|
||||||
locally by doing stuff like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
bash -c '
|
|
||||||
. .ci/upload.sh;
|
|
||||||
prepare_upload_filename "bionic/kasmvncserver_0.9.1~beta-1+libjpeg-turbo-latest_amd64.deb";
|
|
||||||
echo $upload_filename;'
|
|
||||||
```
|
|
||||||
|
|
||||||
# ARM
|
|
||||||
|
|
||||||
KasmVNC is supported on ARM, however, the build process needs to be broken into two parts with one occuring on a x64 system and the other on an ARM system. All our testing and official builds are done on AWS Graviton instances.
|
|
||||||
|
|
||||||
### Build www code on x86 System
|
|
||||||
The www code is webpacked for performance and thus requires building. There are NPM packages, phantomjs, which do not have an ARM build. Therefore, this must be built on x86 and then copied over to the ARM system for final packaging.
|
|
||||||
|
|
||||||
```
|
|
||||||
cd ~/KasmVNC
|
|
||||||
mkdir builder/www
|
|
||||||
sudo docker build -t kasmweb/www -f builder/dockerfile.www.build .
|
|
||||||
sudo docker run --rm -v $PWD/builder/www:/build kasmweb/www:latest
|
|
||||||
cd builder
|
|
||||||
tar -zcvf /tmp/kasm_www.tar.gz www
|
|
||||||
```
|
|
||||||
|
|
||||||
Now transfer ```kasm_www.tar.gz``` to the ARM system.
|
|
||||||
|
|
||||||
### Build KasmVNC ARM
|
|
||||||
These instructions assume KasmVNC has been cloned at $HOME and ```kasm_www.tar.gz``` has been placed at $HOME as well, adjust for your environment.
|
|
||||||
|
|
||||||
```
|
|
||||||
cd ~
|
|
||||||
tar -zxf kasm_www.tar.gz -C KasmVNC/builder/
|
|
||||||
cd KasmVNC
|
|
||||||
sudo builder/build-package ubuntu bionic
|
|
||||||
```
|
|
||||||
The resulting deb package can be found under ~/KasmVNC/builder/build/bionic
|
|
||||||
Replace ```bionic``` with ```focal``` to build for Ubuntu 20.04LTS. At this time, only Ubuntu Bionic has been tested, however, other Debian based builds we support should also work.
|
|
||||||
|
|||||||
@@ -5,17 +5,12 @@ set -e
|
|||||||
cd "$(dirname "$0")/.."
|
cd "$(dirname "$0")/.."
|
||||||
. builder/os_ver_cli.sh
|
. builder/os_ver_cli.sh
|
||||||
|
|
||||||
L_UID=$(id -u) #Ubuntu already has UID env var, but this should work on all Linix systems
|
docker build -t debbuilder_${os}:${os_codename} -f \
|
||||||
L_GID=$(id -g)
|
builder/dockerfile.${os}_${os_codename}.deb.build .
|
||||||
|
|
||||||
builder_image=debbuilder_${os}:${os_codename}${build_tag_for_images}
|
|
||||||
docker build --build-arg KASMVNC_PACKAGE_DIR="builder/build/${os_codename}" \
|
|
||||||
--build-arg L_UID="$L_UID" \
|
|
||||||
-t "$builder_image" -f \
|
|
||||||
builder/dockerfile.${os}_${os_codename}${build_tag}.deb.build .
|
|
||||||
|
|
||||||
deb_output_dir=$(cd .. && echo $PWD)
|
deb_output_dir=$(cd .. && echo $PWD)
|
||||||
docker run --rm -v "$deb_output_dir":/src -e BUILD_TAG="$build_tag" \
|
L_UID=$(id -u) #Ubuntu already has UID env var, but this should work on all Linix systems
|
||||||
--user "$L_UID:$L_GID" \
|
L_GID=$(id -g)
|
||||||
"$builder_image" /bin/bash -c \
|
docker run --rm -v "$deb_output_dir":/src --user $L_UID:$L_GID \
|
||||||
|
debbuilder_${os}:${os_codename} /bin/bash -c \
|
||||||
'/src/*/builder/build-deb-inside-docker'
|
'/src/*/builder/build-deb-inside-docker'
|
||||||
|
|||||||
@@ -2,31 +2,12 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
prepare_docker_copy_of_debian_dir_and_cd_to_id() {
|
cd "$(dirname "$0")/.."
|
||||||
cd "$(dirname "$0")/.."
|
|
||||||
|
|
||||||
local mounted_src_dir="$PWD"
|
|
||||||
local docker_src_dir="$HOME/src"
|
|
||||||
|
|
||||||
mkdir "$docker_src_dir"
|
|
||||||
cd "$docker_src_dir"
|
|
||||||
cp -a "$mounted_src_dir/debian/" .
|
|
||||||
ln -s "$mounted_src_dir/builder" .
|
|
||||||
}
|
|
||||||
|
|
||||||
prepare_docker_copy_of_debian_dir_and_cd_to_id
|
|
||||||
|
|
||||||
os=$(lsb_release -is | tr '[:upper:]' '[:lower:]')
|
os=$(lsb_release -is | tr '[:upper:]' '[:lower:]')
|
||||||
os_codename=$(lsb_release -cs)
|
os_codename=$(lsb_release -cs)
|
||||||
os_dir="builder/build/${os_codename}"
|
os_dir="builder/build/${os_codename}"
|
||||||
|
|
||||||
if [ "$BUILD_TAG" = "+libjpeg-turbo_latest" ]; then
|
|
||||||
echo 'libjpeg 62 libjpeg-turbo (>= 2.1.1)' > debian/shlibs.local
|
|
||||||
|
|
||||||
debian_revision="$(echo $BUILD_TAG | tr _ -)"
|
|
||||||
sed -i -e "1 s/)/$debian_revision)/" debian/changelog
|
|
||||||
fi
|
|
||||||
|
|
||||||
dpkg-buildpackage -us -uc -b
|
dpkg-buildpackage -us -uc -b
|
||||||
mkdir -p "$os_dir"
|
mkdir -p "$os_dir"
|
||||||
cp ../*.deb "$os_dir"
|
cp ../*.deb "$os_dir"
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ set -e
|
|||||||
|
|
||||||
os="$1"
|
os="$1"
|
||||||
codename="$2"
|
codename="$2"
|
||||||
build_tag="$3"
|
|
||||||
|
|
||||||
detect_package_format() {
|
detect_package_format() {
|
||||||
package_format=rpm
|
package_format=rpm
|
||||||
@@ -13,17 +12,8 @@ detect_package_format() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
warn_build_tag_not_supported_for_rpm_and_exit() {
|
|
||||||
if [[ "$build_tag" && "$package_format" = "rpm" ]]; then
|
|
||||||
echo >&2 "<build_tag> isn't supported for rpm"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
cd "$(dirname "$0")/.."
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
detect_package_format
|
detect_package_format
|
||||||
warn_build_tag_not_supported_for_rpm_and_exit
|
builder/build-tarball "$os" "$codename"
|
||||||
|
builder/build-${package_format} "$os" "$codename"
|
||||||
builder/build-tarball "$os" "$codename" "$build_tag"
|
|
||||||
builder/build-${package_format} "$os" "$codename" "$build_tag"
|
|
||||||
|
|||||||
@@ -2,18 +2,8 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
warn_build_tag_not_supported_for_rpm_and_exit() {
|
|
||||||
local build_tag="$1"
|
|
||||||
|
|
||||||
if [[ -n "$build_tag" ]]; then
|
|
||||||
echo >&2 "<build_tag> isn't supported for rpm"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
cd "$(dirname "$0")/.."
|
cd "$(dirname "$0")/.."
|
||||||
. builder/os_ver_cli.sh
|
. builder/os_ver_cli.sh
|
||||||
warn_build_tag_not_supported_for_rpm_and_exit "$build_tag"
|
|
||||||
|
|
||||||
docker build -t kasmvnc_rpmbuilder_${os}:${os_codename} -f \
|
docker build -t kasmvnc_rpmbuilder_${os}:${os_codename} -f \
|
||||||
builder/dockerfile.${os}_${os_codename}.rpm.build .
|
builder/dockerfile.${os}_${os_codename}.rpm.build .
|
||||||
|
|||||||
@@ -12,13 +12,6 @@ build_www_dir() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
move_libjpeg_turbo_to_os_specific_dir() {
|
|
||||||
chown $L_UID:$L_GID $shared_with_docker_dir/${os_codename}/*
|
|
||||||
mkdir -p $PWD/builder/build/${os_codename}/
|
|
||||||
mv $shared_with_docker_dir/${os_codename}/libjpeg-turbo*.deb \
|
|
||||||
$PWD/builder/build/${os_codename}/
|
|
||||||
}
|
|
||||||
|
|
||||||
shared_with_docker_dir=${GITLAB_SHARED_DIND_DIR:-/tmp}
|
shared_with_docker_dir=${GITLAB_SHARED_DIND_DIR:-/tmp}
|
||||||
|
|
||||||
cd "$(dirname "$0")/.."
|
cd "$(dirname "$0")/.."
|
||||||
@@ -26,21 +19,13 @@ cd "$(dirname "$0")/.."
|
|||||||
|
|
||||||
build_www_dir
|
build_www_dir
|
||||||
|
|
||||||
builder_image=kasmvncbuilder:$os_codename${build_tag_for_images}
|
docker build -t kasmvncbuilder:$os_codename \
|
||||||
docker build -t "$builder_image" \
|
-f builder/dockerfile.${os}_${os_codename}.build .
|
||||||
-f builder/dockerfile.${os}_${os_codename}${build_tag}.build .
|
|
||||||
mkdir -p builder/build
|
mkdir -p builder/build
|
||||||
docker run -v $shared_with_docker_dir:/build -e BUILD_TAG="$build_tag" \
|
docker run -v $shared_with_docker_dir:/build --rm kasmvncbuilder:$os_codename
|
||||||
--rm "$builder_image"
|
|
||||||
|
|
||||||
L_GID=$(id -g)
|
L_GID=$(id -g)
|
||||||
L_UID=$(id -u)
|
L_UID=$(id -u)
|
||||||
tarball_name="kasmvnc.${os}_${os_codename}.tar.gz"
|
tarball_name="kasmvnc.${os}_${os_codename}.tar.gz"
|
||||||
tarball_name_with_build_tag="kasmvnc.${os}_${os_codename}${build_tag}.tar.gz"
|
|
||||||
chown $L_UID:$L_GID $shared_with_docker_dir/$tarball_name
|
chown $L_UID:$L_GID $shared_with_docker_dir/$tarball_name
|
||||||
mv $shared_with_docker_dir/$tarball_name \
|
mv $shared_with_docker_dir/$tarball_name $PWD/builder/build/
|
||||||
$PWD/builder/build/"$tarball_name_with_build_tag"
|
|
||||||
|
|
||||||
if [ "$build_tag" = "+libjpeg-turbo_latest" ]; then
|
|
||||||
move_libjpeg_turbo_to_os_specific_dir
|
|
||||||
fi
|
|
||||||
|
|||||||
@@ -30,19 +30,16 @@ sed -i -e '/find_package(FLTK/s@^@#@' \
|
|||||||
-e '/add_subdirectory(tests/s@^@#@' \
|
-e '/add_subdirectory(tests/s@^@#@' \
|
||||||
CMakeLists.txt
|
CMakeLists.txt
|
||||||
|
|
||||||
cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo . -DBUILD_VIEWER:BOOL=OFF
|
cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo .
|
||||||
make -j5
|
make -j5
|
||||||
|
|
||||||
tar -C unix/xserver -xf /tmp/xorg-server-${XORG_VER}.tar.bz2 --strip-components=1
|
tar -C unix/xserver -xvf /tmp/xorg-server-${XORG_VER}.tar.bz2 --strip-components=1
|
||||||
|
|
||||||
cd unix/xserver
|
cd unix/xserver
|
||||||
patch -Np1 -i ../xserver${XORG_PATCH}.patch
|
patch -Np1 -i ../xserver${XORG_PATCH}.patch
|
||||||
case "$XORG_VER" in
|
if [[ $XORG_VER =~ ^1\.20\..*$ ]]; then
|
||||||
1.20.*)
|
|
||||||
if [ -f ../xserver120.7.patch ]; then
|
|
||||||
patch -Np1 -i ../xserver120.7.patch
|
patch -Np1 -i ../xserver120.7.patch
|
||||||
fi ;;
|
fi
|
||||||
esac
|
|
||||||
|
|
||||||
autoreconf -i
|
autoreconf -i
|
||||||
# Configuring Xorg is long and has many distro-specific paths.
|
# Configuring Xorg is long and has many distro-specific paths.
|
||||||
@@ -75,8 +72,6 @@ mkdir lib
|
|||||||
cd lib
|
cd lib
|
||||||
if [ -d /usr/lib/x86_64-linux-gnu/dri ]; then
|
if [ -d /usr/lib/x86_64-linux-gnu/dri ]; then
|
||||||
ln -s /usr/lib/x86_64-linux-gnu/dri dri
|
ln -s /usr/lib/x86_64-linux-gnu/dri dri
|
||||||
elif [ -d /usr/lib/aarch64-linux-gnu/dri ]; then
|
|
||||||
ln -s /usr/lib/aarch64-linux-gnu/dri dri
|
|
||||||
else
|
else
|
||||||
ln -s /usr/lib64/dri dri
|
ln -s /usr/lib64/dri dri
|
||||||
fi
|
fi
|
||||||
@@ -89,7 +84,3 @@ fi
|
|||||||
make servertarball
|
make servertarball
|
||||||
|
|
||||||
cp kasmvnc*.tar.gz /build/kasmvnc.${KASMVNC_BUILD_OS}_${KASMVNC_BUILD_OS_CODENAME}.tar.gz
|
cp kasmvnc*.tar.gz /build/kasmvnc.${KASMVNC_BUILD_OS}_${KASMVNC_BUILD_OS_CODENAME}.tar.gz
|
||||||
if [ "$BUILD_TAG" = "+libjpeg-turbo_latest" ]; then
|
|
||||||
mkdir -p /build/${KASMVNC_BUILD_OS_CODENAME}/
|
|
||||||
cp /libjpeg-turbo/libjpeg*.deb /build/${KASMVNC_BUILD_OS_CODENAME}/
|
|
||||||
fi
|
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -eo pipefail
|
|
||||||
|
|
||||||
update_version_to_meet_packaging_standards() {
|
|
||||||
new_version=$(echo "$new_version" |
|
|
||||||
sed -e 's/\([0-9]\)-\([a-zA-Z]\)/\1~\2/')
|
|
||||||
}
|
|
||||||
|
|
||||||
add_debian_revision_to_new_version() {
|
|
||||||
echo "$new_version-1"
|
|
||||||
}
|
|
||||||
|
|
||||||
bump_rpm() {
|
|
||||||
sed -i "s/^Version:.\+/Version: $new_version/" centos/kasmvncserver.spec
|
|
||||||
}
|
|
||||||
|
|
||||||
bump_deb() {
|
|
||||||
local image="debbump_package_version:dev"
|
|
||||||
local L_UID=$(id -u)
|
|
||||||
local L_GID=$(id -g)
|
|
||||||
local debian_version=$(add_debian_revision_to_new_version)
|
|
||||||
|
|
||||||
docker build -t "$image" -f builder/dockerfile.bump-package-version .
|
|
||||||
docker run --rm -v "$PWD":/src --user "$L_UID:$L_GID" \
|
|
||||||
"$image" /bin/bash -c \
|
|
||||||
"cd /src && builder/bump-package-version-inside-docker-deb $debian_version"
|
|
||||||
}
|
|
||||||
|
|
||||||
new_version="$1"
|
|
||||||
|
|
||||||
if [[ -z "$new_version" ]]; then
|
|
||||||
echo >&2 "Usage: $(basename "$0") <new_version>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$(dirname "$0")/.."
|
|
||||||
|
|
||||||
update_version_to_meet_packaging_standards
|
|
||||||
bump_rpm
|
|
||||||
bump_deb
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
new_version="$1"
|
|
||||||
|
|
||||||
update_version() {
|
|
||||||
dch --newversion $new_version 'New upstream release.'
|
|
||||||
}
|
|
||||||
|
|
||||||
mark_as_released() {
|
|
||||||
dch --release ""
|
|
||||||
}
|
|
||||||
|
|
||||||
update_version
|
|
||||||
mark_as_released
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
FROM debian:buster
|
|
||||||
|
|
||||||
ENV DEBEMAIL="Kasm Technologies LLC <info@kasmweb.com>"
|
|
||||||
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get -y install vim devscripts
|
|
||||||
@@ -3,7 +3,6 @@ FROM centos:centos7
|
|||||||
ENV KASMVNC_BUILD_OS centos
|
ENV KASMVNC_BUILD_OS centos
|
||||||
ENV KASMVNC_BUILD_OS_CODENAME core
|
ENV KASMVNC_BUILD_OS_CODENAME core
|
||||||
|
|
||||||
RUN yum update -y ca-certificates
|
|
||||||
RUN yum install -y build-dep xorg-server libxfont-dev sudo
|
RUN yum install -y build-dep xorg-server libxfont-dev sudo
|
||||||
RUN yum install -y gcc cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver
|
RUN yum install -y gcc cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver
|
||||||
RUN yum install -y libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev openssl-devel
|
RUN yum install -y libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev openssl-devel
|
||||||
@@ -16,14 +15,15 @@ RUN yum install -y mesa-dri-drivers
|
|||||||
|
|
||||||
# Additions for webp
|
# Additions for webp
|
||||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||||
RUN cd /tmp/libwebp-1.0.2 && \
|
RUN cd /tmp/libwebp-1.0.2 && \
|
||||||
./configure --enable-static --disable-shared && \
|
./configure --enable-static --disable-shared && \
|
||||||
make && make install
|
make && make install
|
||||||
|
|
||||||
RUN useradd -m docker && echo "docker:docker" | chpasswd
|
RUN useradd -m docker && echo "docker:docker" | chpasswd
|
||||||
|
|
||||||
COPY --chown=docker:docker . /src/
|
COPY . /src
|
||||||
|
RUN chown -R docker:docker /src
|
||||||
|
|
||||||
USER docker
|
USER docker
|
||||||
ENTRYPOINT ["/src/builder/build.sh"]
|
ENTRYPOINT ["/src/builder/build.sh"]
|
||||||
|
|||||||
@@ -17,14 +17,15 @@ RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libg
|
|||||||
|
|
||||||
# Additions for webp
|
# Additions for webp
|
||||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||||
RUN cd /tmp/libwebp-1.0.2 && \
|
RUN cd /tmp/libwebp-1.0.2 && \
|
||||||
./configure --enable-static --disable-shared && \
|
./configure --enable-static --disable-shared && \
|
||||||
make && make install
|
make && make install
|
||||||
|
|
||||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||||
|
|
||||||
COPY --chown=docker:docker . /src/
|
COPY . /src
|
||||||
|
RUN chown -R docker:docker /src
|
||||||
|
|
||||||
USER docker
|
USER docker
|
||||||
ENTRYPOINT ["/src/builder/build.sh"]
|
ENTRYPOINT ["/src/builder/build.sh"]
|
||||||
|
|||||||
@@ -9,11 +9,4 @@ RUN apt-get update && \
|
|||||||
COPY ./debian/control /tmp
|
COPY ./debian/control /tmp
|
||||||
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
||||||
|
|
||||||
ARG L_UID
|
USER 1000
|
||||||
RUN if [ "$L_UID" -eq 0 ]; then \
|
|
||||||
useradd -m docker; \
|
|
||||||
else \
|
|
||||||
useradd -m docker -u $L_UID;\
|
|
||||||
fi
|
|
||||||
|
|
||||||
USER docker
|
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ COPY startup/ $STARTUPDIR
|
|||||||
### START CUSTOM STUFF ####
|
### START CUSTOM STUFF ####
|
||||||
|
|
||||||
ARG KASMVNC_PACKAGE_DIR
|
ARG KASMVNC_PACKAGE_DIR
|
||||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
|
RUN dpkg -i /tmp/*.deb; apt-get -yf install
|
||||||
|
|
||||||
### END CUSTOM STUFF ###
|
### END CUSTOM STUFF ###
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
FROM debian:buster-slim
|
FROM debian:buster-slim
|
||||||
|
|
||||||
ARG KASMVNC_PACKAGE_DIR
|
ARG KASMVNC_PACKAGE_DIR
|
||||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; apt-get update && dpkg -i /tmp/*.deb; apt-get -yf install
|
RUN apt-get update && dpkg -i /tmp/*.deb; apt-get -yf install
|
||||||
RUN apt-get update && apt-get -y install xterm
|
RUN apt-get update && apt-get -y install xterm
|
||||||
|
|
||||||
COPY startup/deb/kasmvncserver-easy-start /usr/local/bin
|
COPY startup/deb/kasmvncserver-easy-start /usr/local/bin
|
||||||
|
|||||||
@@ -17,14 +17,15 @@ RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libg
|
|||||||
|
|
||||||
# Additions for webp
|
# Additions for webp
|
||||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||||
RUN cd /tmp/libwebp-1.0.2 && \
|
RUN cd /tmp/libwebp-1.0.2 && \
|
||||||
./configure --enable-static --disable-shared && \
|
./configure --enable-static --disable-shared && \
|
||||||
make && make install
|
make && make install
|
||||||
|
|
||||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||||
|
|
||||||
COPY --chown=docker:docker . /src/
|
COPY . /src
|
||||||
|
RUN chown -R docker:docker /src
|
||||||
|
|
||||||
USER docker
|
USER docker
|
||||||
ENTRYPOINT ["/src/builder/build.sh"]
|
ENTRYPOINT ["/src/builder/build.sh"]
|
||||||
|
|||||||
@@ -9,11 +9,4 @@ RUN apt-get update && \
|
|||||||
COPY ./debian/control /tmp
|
COPY ./debian/control /tmp
|
||||||
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
||||||
|
|
||||||
ARG L_UID
|
USER 1000
|
||||||
RUN if [ "$L_UID" -eq 0 ]; then \
|
|
||||||
useradd -m docker; \
|
|
||||||
else \
|
|
||||||
useradd -m docker -u $L_UID;\
|
|
||||||
fi
|
|
||||||
|
|
||||||
USER docker
|
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ COPY startup/ $STARTUPDIR
|
|||||||
### START CUSTOM STUFF ####
|
### START CUSTOM STUFF ####
|
||||||
|
|
||||||
ARG KASMVNC_PACKAGE_DIR
|
ARG KASMVNC_PACKAGE_DIR
|
||||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
|
RUN dpkg -i /tmp/*.deb; apt-get -yf install
|
||||||
|
|
||||||
### END CUSTOM STUFF ###
|
### END CUSTOM STUFF ###
|
||||||
|
|
||||||
|
|||||||
@@ -24,14 +24,15 @@ RUN dnf install -y bzip2 redhat-lsb-core
|
|||||||
|
|
||||||
# Additions for webp
|
# Additions for webp
|
||||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||||
RUN cd /tmp/libwebp-1.0.2 && \
|
RUN cd /tmp/libwebp-1.0.2 && \
|
||||||
./configure --enable-static --disable-shared && \
|
./configure --enable-static --disable-shared && \
|
||||||
make && make install
|
make && make install
|
||||||
|
|
||||||
RUN useradd -m docker && echo "docker:docker" | chpasswd
|
RUN useradd -m docker && echo "docker:docker" | chpasswd
|
||||||
|
|
||||||
COPY --chown=docker:docker . /src/
|
COPY . /src
|
||||||
|
RUN chown -R docker:docker /src
|
||||||
|
|
||||||
USER docker
|
USER docker
|
||||||
ENTRYPOINT ["/src/builder/build.sh"]
|
ENTRYPOINT ["/src/builder/build.sh"]
|
||||||
|
|||||||
@@ -17,14 +17,15 @@ RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libg
|
|||||||
|
|
||||||
# Additions for webp
|
# Additions for webp
|
||||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||||
RUN cd /tmp/libwebp-1.0.2 && \
|
RUN cd /tmp/libwebp-1.0.2 && \
|
||||||
./configure --enable-static --disable-shared && \
|
./configure --enable-static --disable-shared && \
|
||||||
make && make install
|
make && make install
|
||||||
|
|
||||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||||
|
|
||||||
COPY --chown=docker:docker . /src/
|
COPY . /src
|
||||||
|
RUN chown -R docker:docker /src
|
||||||
|
|
||||||
USER docker
|
USER docker
|
||||||
ENTRYPOINT ["/src/builder/build.sh"]
|
ENTRYPOINT ["/src/builder/build.sh"]
|
||||||
|
|||||||
@@ -9,11 +9,4 @@ RUN apt-get update && \
|
|||||||
COPY ./debian/control /tmp
|
COPY ./debian/control /tmp
|
||||||
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
||||||
|
|
||||||
ARG L_UID
|
USER 1000
|
||||||
RUN if [ "$L_UID" -eq 0 ]; then \
|
|
||||||
useradd -m docker; \
|
|
||||||
else \
|
|
||||||
useradd -m docker -u $L_UID;\
|
|
||||||
fi
|
|
||||||
|
|
||||||
USER docker
|
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ COPY startup/ $STARTUPDIR
|
|||||||
### START CUSTOM STUFF ####
|
### START CUSTOM STUFF ####
|
||||||
|
|
||||||
ARG KASMVNC_PACKAGE_DIR
|
ARG KASMVNC_PACKAGE_DIR
|
||||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
|
RUN dpkg -i /tmp/*.deb; apt-get -yf install
|
||||||
|
|
||||||
### END CUSTOM STUFF ###
|
### END CUSTOM STUFF ###
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ RUN cd /tmp/libwebp-1.0.2 && ./configure && make && make install
|
|||||||
|
|
||||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||||
|
|
||||||
COPY --chown=docker:docker . /src/
|
COPY . /src
|
||||||
|
RUN chown -R docker:docker /src
|
||||||
|
|
||||||
|
|
||||||
USER docker
|
USER docker
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libg
|
|||||||
|
|
||||||
# Additions for webp
|
# Additions for webp
|
||||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||||
RUN cd /tmp/libwebp-1.0.2 && \
|
RUN cd /tmp/libwebp-1.0.2 && \
|
||||||
./configure --enable-static --disable-shared && \
|
./configure --enable-static --disable-shared && \
|
||||||
make && make install
|
make && make install
|
||||||
@@ -28,7 +28,8 @@ RUN cd /tmp/libwebp-1.0.2 && \
|
|||||||
|
|
||||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||||
|
|
||||||
COPY --chown=docker:docker . /src/
|
COPY . /src
|
||||||
|
RUN chown -R docker:docker /src
|
||||||
|
|
||||||
USER docker
|
USER docker
|
||||||
ENTRYPOINT ["/src/builder/build.sh"]
|
ENTRYPOINT ["/src/builder/build.sh"]
|
||||||
|
|||||||
@@ -7,11 +7,4 @@ RUN apt-get update && \
|
|||||||
COPY ./debian/control /tmp
|
COPY ./debian/control /tmp
|
||||||
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
||||||
|
|
||||||
ARG L_UID
|
USER 1000
|
||||||
RUN if [ "$L_UID" -eq 0 ]; then \
|
|
||||||
useradd -m docker; \
|
|
||||||
else \
|
|
||||||
useradd -m docker -u $L_UID;\
|
|
||||||
fi
|
|
||||||
|
|
||||||
USER docker
|
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ COPY startup/ $STARTUPDIR
|
|||||||
### START CUSTOM STUFF ####
|
### START CUSTOM STUFF ####
|
||||||
|
|
||||||
ARG KASMVNC_PACKAGE_DIR
|
ARG KASMVNC_PACKAGE_DIR
|
||||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
|
RUN dpkg -i /tmp/*.deb; apt-get -yf install
|
||||||
|
|
||||||
### END CUSTOM STUFF ###
|
### END CUSTOM STUFF ###
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
FROM ubuntu:20.04
|
|
||||||
|
|
||||||
ENV KASMVNC_BUILD_OS ubuntu
|
|
||||||
ENV KASMVNC_BUILD_OS_CODENAME focal
|
|
||||||
ENV XORG_VER 1.20.8
|
|
||||||
|
|
||||||
RUN sed -i 's$# deb-src$deb-src$' /etc/apt/sources.list
|
|
||||||
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get -y install sudo
|
|
||||||
|
|
||||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata
|
|
||||||
RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev
|
|
||||||
RUN apt-get update && apt-get -y install cmake git libgnutls28-dev vim wget tightvncserver
|
|
||||||
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y cmake nasm gcc
|
|
||||||
RUN git clone https://github.com/libjpeg-turbo/libjpeg-turbo.git
|
|
||||||
RUN export MAKEFLAGS=-j`nproc`; cd libjpeg-turbo && cmake -G"Unix Makefiles" && make deb
|
|
||||||
RUN export MAKEFLAGS=-j`nproc`; cd libjpeg-turbo && cmake -DCMAKE_INSTALL_PREFIX=/usr/local -G"Unix Makefiles" && make && make install
|
|
||||||
|
|
||||||
# Additions for webp
|
|
||||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
|
||||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
|
||||||
RUN cd /tmp/libwebp-1.0.2 && \
|
|
||||||
./configure --enable-static --disable-shared && \
|
|
||||||
make && make install
|
|
||||||
|
|
||||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
|
||||||
|
|
||||||
COPY --chown=docker:docker . /src
|
|
||||||
|
|
||||||
USER docker
|
|
||||||
ENTRYPOINT ["/src/builder/build.sh"]
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
FROM ubuntu:20.04
|
|
||||||
|
|
||||||
RUN apt-get update && \
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get -y install vim build-essential devscripts equivs
|
|
||||||
|
|
||||||
ARG KASMVNC_PACKAGE_DIR
|
|
||||||
COPY $KASMVNC_PACKAGE_DIR/libjpeg-turbo*deb /tmp
|
|
||||||
RUN apt-get install /tmp/libjpeg-turbo*deb
|
|
||||||
|
|
||||||
# Install build-deps for the package.
|
|
||||||
COPY ./debian/control /tmp
|
|
||||||
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
|
||||||
|
|
||||||
ENV LD_LIBRARY_PATH="/opt/libjpeg-turbo/lib64/:$LD_LIBRARY_PATH"
|
|
||||||
|
|
||||||
ARG L_UID
|
|
||||||
RUN if [ "$L_UID" -eq 0 ]; then \
|
|
||||||
useradd -m docker; \
|
|
||||||
else \
|
|
||||||
useradd -m docker -u $L_UID;\
|
|
||||||
fi
|
|
||||||
|
|
||||||
USER docker
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
FROM ubuntu:20.04
|
|
||||||
|
|
||||||
ENV DISPLAY=:1 \
|
|
||||||
VNC_PORT=8443 \
|
|
||||||
VNC_RESOLUTION=1280x720 \
|
|
||||||
MAX_FRAME_RATE=24 \
|
|
||||||
VNCOPTIONS="-PreferBandwidth -DynamicQualityMin=4 -DynamicQualityMax=7" \
|
|
||||||
HOME=/home/user \
|
|
||||||
TERM=xterm \
|
|
||||||
STARTUPDIR=/dockerstartup \
|
|
||||||
INST_SCRIPTS=/dockerstartup/install \
|
|
||||||
KASM_RX_HOME=/dockerstartup/kasmrx \
|
|
||||||
DEBIAN_FRONTEND=noninteractive \
|
|
||||||
VNC_COL_DEPTH=24 \
|
|
||||||
VNC_RESOLUTION=1280x1024 \
|
|
||||||
VNC_PW=vncpassword \
|
|
||||||
VNC_USER=user \
|
|
||||||
VNC_VIEW_ONLY_PW=vncviewonlypassword \
|
|
||||||
LD_LIBRARY_PATH=/opt/libjpeg-turbo/lib64/:/usr/local/lib/ \
|
|
||||||
OMP_WAIT_POLICY=PASSIVE \
|
|
||||||
SHELL=/bin/bash \
|
|
||||||
SINGLE_APPLICATION=0 \
|
|
||||||
KASMVNC_BUILD_OS=ubuntu \
|
|
||||||
KASMVNC_BUILD_OS_CODENAME=bionic
|
|
||||||
|
|
||||||
EXPOSE $VNC_PORT
|
|
||||||
|
|
||||||
WORKDIR $HOME
|
|
||||||
|
|
||||||
### REQUIRED STUFF ###
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y supervisor xfce4 xfce4-terminal xterm libnss-wrapper gettext wget
|
|
||||||
RUN apt-get purge -y pm-utils xscreensaver*
|
|
||||||
RUN apt-get update && apt-get install -y vim less
|
|
||||||
RUN apt-get update && apt-get -y install lsb-release
|
|
||||||
|
|
||||||
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
|
|
||||||
|
|
||||||
RUN mkdir -p $STARTUPDIR
|
|
||||||
COPY startup/ $STARTUPDIR
|
|
||||||
|
|
||||||
### START CUSTOM STUFF ####
|
|
||||||
|
|
||||||
ARG KASMVNC_PACKAGE_DIR
|
|
||||||
COPY $KASMVNC_PACKAGE_DIR/libjpeg-turbo_*.deb /tmp
|
|
||||||
RUN apt-get install /tmp/libjpeg-turbo*deb
|
|
||||||
|
|
||||||
ARG BUILD_DEBIAN_REVISION
|
|
||||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*$BUILD_DEBIAN_REVISION*.deb /tmp
|
|
||||||
RUN dpkg -i /tmp/*.deb; apt-get -yf install
|
|
||||||
|
|
||||||
### END CUSTOM STUFF ###
|
|
||||||
|
|
||||||
RUN chown -R 1000:0 $HOME
|
|
||||||
USER 1000:ssl-cert
|
|
||||||
WORKDIR $HOME
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/dockerstartup/vnc_startup.sh" ]
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
FROM ubuntu:focal
|
FROM ubuntu:focal
|
||||||
|
|
||||||
ARG KASMVNC_PACKAGE_DIR
|
ARG KASMVNC_PACKAGE_DIR
|
||||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; apt-get update && dpkg -i /tmp/*.deb; apt-get -yf install
|
RUN apt-get update && dpkg -i /tmp/*.deb; apt-get -yf install
|
||||||
RUN apt-get update && apt-get -y install xterm lsb-release
|
RUN apt-get update && apt-get -y install xterm lsb-release
|
||||||
|
|
||||||
RUN useradd -m foo && addgroup foo ssl-cert
|
RUN useradd -m foo && addgroup foo ssl-cert
|
||||||
|
|||||||
@@ -17,14 +17,15 @@ RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libg
|
|||||||
|
|
||||||
# Additions for webp
|
# Additions for webp
|
||||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||||
RUN cd /tmp/libwebp-1.0.2 && \
|
RUN cd /tmp/libwebp-1.0.2 && \
|
||||||
./configure --enable-static --disable-shared && \
|
./configure --enable-static --disable-shared && \
|
||||||
make && make install
|
make && make install
|
||||||
|
|
||||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||||
|
|
||||||
COPY --chown=docker:docker . /src/
|
COPY . /src
|
||||||
|
RUN chown -R docker:docker /src
|
||||||
|
|
||||||
USER docker
|
USER docker
|
||||||
ENTRYPOINT ["/src/builder/build.sh"]
|
ENTRYPOINT ["/src/builder/build.sh"]
|
||||||
|
|||||||
@@ -9,11 +9,4 @@ RUN apt-get update && \
|
|||||||
COPY ./debian/control /tmp
|
COPY ./debian/control /tmp
|
||||||
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
||||||
|
|
||||||
ARG L_UID
|
USER 1000
|
||||||
RUN if [ "$L_UID" -eq 0 ]; then \
|
|
||||||
useradd -m docker; \
|
|
||||||
else \
|
|
||||||
useradd -m docker -u $L_UID;\
|
|
||||||
fi
|
|
||||||
|
|
||||||
USER docker
|
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ COPY startup/ $STARTUPDIR
|
|||||||
### START CUSTOM STUFF ####
|
### START CUSTOM STUFF ####
|
||||||
|
|
||||||
ARG KASMVNC_PACKAGE_DIR
|
ARG KASMVNC_PACKAGE_DIR
|
||||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
|
RUN dpkg -i /tmp/*.deb; apt-get -yf install
|
||||||
|
|
||||||
RUN mkdir ~/.vnc && echo '/usr/bin/xfce4-session &' >> ~/.vnc/xstartup && \
|
RUN mkdir ~/.vnc && echo '/usr/bin/xfce4-session &' >> ~/.vnc/xstartup && \
|
||||||
chmod +x ~/.vnc/xstartup
|
chmod +x ~/.vnc/xstartup
|
||||||
|
|||||||
@@ -3,11 +3,6 @@ default_os_codename=bionic
|
|||||||
|
|
||||||
os=${1:-$default_os}
|
os=${1:-$default_os}
|
||||||
os_codename=${2:-$default_os_codename}
|
os_codename=${2:-$default_os_codename}
|
||||||
build_tag="${3:-}"
|
|
||||||
if [[ -n "$build_tag" ]]; then
|
|
||||||
build_tag_for_images="_${build_tag#+}"
|
|
||||||
build_debian_revision="$(echo $build_tag | tr _ -)"
|
|
||||||
fi
|
|
||||||
os_image="$os:$os_codename"
|
os_image="$os:$os_codename"
|
||||||
|
|
||||||
echo "Building for $os_image"
|
echo "Building for $os_image"
|
||||||
|
|||||||
@@ -5,12 +5,10 @@ set -e
|
|||||||
cd "$(dirname "$0")"
|
cd "$(dirname "$0")"
|
||||||
. ./os_ver_cli.sh
|
. ./os_ver_cli.sh
|
||||||
|
|
||||||
tester_image=kasmvnctester_${os}:$os_codename${build_tag_for_images}
|
|
||||||
docker build --build-arg KASMVNC_PACKAGE_DIR="build/${os_codename}" \
|
docker build --build-arg KASMVNC_PACKAGE_DIR="build/${os_codename}" \
|
||||||
--build-arg BUILD_DEBIAN_REVISION="$build_debian_revision" \
|
-t kasmvnctester_${os}:$os_codename \
|
||||||
-t "$tester_image" \
|
-f dockerfile.${os}_${os_codename}.deb.test .
|
||||||
-f dockerfile.${os}_${os_codename}${build_tag}.deb.test .
|
|
||||||
docker run -it -p 443:8443 --rm \
|
docker run -it -p 443:8443 --rm \
|
||||||
-e KASMVNC_VERBOSE_LOGGING=$KASMVNC_VERBOSE_LOGGING \
|
-e KASMVNC_VERBOSE_LOGGING=$KASMVNC_VERBOSE_LOGGING \
|
||||||
-e "VNC_USER=foo" -e "VNC_PW=foobar" \
|
-e "VNC_USER=foo" -e "VNC_PW=foobar" \
|
||||||
"$tester_image"
|
kasmvnctester_${os}:$os_codename
|
||||||
|
|||||||
@@ -24,8 +24,6 @@
|
|||||||
#include <rfb/PixelBuffer.h>
|
#include <rfb/PixelBuffer.h>
|
||||||
#include <rfb/PixelFormat.h>
|
#include <rfb/PixelFormat.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace network {
|
namespace network {
|
||||||
@@ -36,17 +34,6 @@ namespace network {
|
|||||||
|
|
||||||
// from main thread
|
// from main thread
|
||||||
void mainUpdateScreen(rfb::PixelBuffer *pb);
|
void mainUpdateScreen(rfb::PixelBuffer *pb);
|
||||||
void mainUpdateBottleneckStats(const char userid[], const char stats[]);
|
|
||||||
void mainClearBottleneckStats(const char userid[]);
|
|
||||||
void mainUpdateServerFrameStats(uint8_t changedPerc, uint32_t all,
|
|
||||||
uint32_t jpeg, uint32_t webp, uint32_t analysis,
|
|
||||||
uint32_t jpegarea, uint32_t webparea,
|
|
||||||
uint16_t njpeg, uint16_t nwebp,
|
|
||||||
uint16_t enc, uint16_t scale, uint16_t shot,
|
|
||||||
uint16_t w, uint16_t h);
|
|
||||||
void mainUpdateClientFrameStats(const char userid[], uint32_t render, uint32_t all,
|
|
||||||
uint32_t ping);
|
|
||||||
void mainUpdateUserInfo(const uint8_t ownerConn, const uint8_t numUsers);
|
|
||||||
|
|
||||||
// from network threads
|
// from network threads
|
||||||
uint8_t *netGetScreenshot(uint16_t w, uint16_t h,
|
uint8_t *netGetScreenshot(uint16_t w, uint16_t h,
|
||||||
@@ -55,25 +42,13 @@ namespace network {
|
|||||||
uint8_t netAddUser(const char name[], const char pw[], const bool write);
|
uint8_t netAddUser(const char name[], const char pw[], const bool write);
|
||||||
uint8_t netRemoveUser(const char name[]);
|
uint8_t netRemoveUser(const char name[]);
|
||||||
uint8_t netGiveControlTo(const char name[]);
|
uint8_t netGiveControlTo(const char name[]);
|
||||||
void netGetBottleneckStats(char *buf, uint32_t len);
|
|
||||||
void netGetFrameStats(char *buf, uint32_t len);
|
|
||||||
uint8_t netServerFrameStatsReady();
|
|
||||||
|
|
||||||
enum USER_ACTION {
|
enum USER_ACTION {
|
||||||
//USER_ADD, - handled locally for interactivity
|
//USER_ADD, - handled locally for interactivity
|
||||||
USER_REMOVE,
|
USER_REMOVE,
|
||||||
USER_GIVE_CONTROL,
|
USER_GIVE_CONTROL,
|
||||||
WANT_FRAME_STATS_SERVERONLY,
|
|
||||||
WANT_FRAME_STATS_ALL,
|
|
||||||
WANT_FRAME_STATS_OWNER,
|
|
||||||
WANT_FRAME_STATS_SPECIFIC,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t netRequestFrameStats(USER_ACTION what, const char *client);
|
|
||||||
uint8_t netOwnerConnected();
|
|
||||||
uint8_t netNumActiveUsers();
|
|
||||||
uint8_t netGetClientFrameStatsNum();
|
|
||||||
|
|
||||||
struct action_data {
|
struct action_data {
|
||||||
enum USER_ACTION action;
|
enum USER_ACTION action;
|
||||||
kasmpasswd_entry_t data;
|
kasmpasswd_entry_t data;
|
||||||
@@ -93,40 +68,6 @@ namespace network {
|
|||||||
std::vector<uint8_t> cachedJpeg;
|
std::vector<uint8_t> cachedJpeg;
|
||||||
uint16_t cachedW, cachedH;
|
uint16_t cachedW, cachedH;
|
||||||
uint8_t cachedQ;
|
uint8_t cachedQ;
|
||||||
|
|
||||||
std::map<std::string, std::string> bottleneckStats;
|
|
||||||
pthread_mutex_t statMutex;
|
|
||||||
|
|
||||||
struct clientFrameStats_t {
|
|
||||||
uint32_t render;
|
|
||||||
uint32_t all;
|
|
||||||
uint32_t ping;
|
|
||||||
};
|
|
||||||
struct serverFrameStats_t {
|
|
||||||
uint32_t all;
|
|
||||||
uint32_t jpeg;
|
|
||||||
uint32_t webp;
|
|
||||||
uint32_t analysis;
|
|
||||||
uint32_t jpegarea;
|
|
||||||
uint32_t webparea;
|
|
||||||
uint16_t njpeg;
|
|
||||||
uint16_t nwebp;
|
|
||||||
uint16_t enc;
|
|
||||||
uint16_t scale;
|
|
||||||
uint16_t shot;
|
|
||||||
uint16_t w;
|
|
||||||
uint16_t h;
|
|
||||||
uint8_t changedPerc;
|
|
||||||
|
|
||||||
uint8_t inprogress;
|
|
||||||
};
|
|
||||||
std::map<std::string, clientFrameStats_t> clientFrameStats;
|
|
||||||
serverFrameStats_t serverFrameStats;
|
|
||||||
pthread_mutex_t frameStatMutex;
|
|
||||||
|
|
||||||
uint8_t ownerConnected;
|
|
||||||
uint8_t activeUsers;
|
|
||||||
pthread_mutex_t userInfoMutex;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <network/GetAPI.h>
|
#include <network/GetAPI.h>
|
||||||
#include <rfb/ConnParams.h>
|
#include <rfb/ConnParams.h>
|
||||||
#include <rfb/EncodeManager.h>
|
|
||||||
#include <rfb/LogWriter.h>
|
#include <rfb/LogWriter.h>
|
||||||
#include <rfb/JpegCompressor.h>
|
#include <rfb/JpegCompressor.h>
|
||||||
#include <rfb/xxhash.h>
|
#include <rfb/xxhash.h>
|
||||||
@@ -33,6 +32,10 @@ using namespace rfb;
|
|||||||
|
|
||||||
static LogWriter vlog("GetAPIMessager");
|
static LogWriter vlog("GetAPIMessager");
|
||||||
|
|
||||||
|
PixelBuffer *progressiveBilinearScale(const PixelBuffer *pb,
|
||||||
|
const uint16_t tgtw, const uint16_t tgth,
|
||||||
|
const float tgtdiff);
|
||||||
|
|
||||||
struct TightJPEGConfiguration {
|
struct TightJPEGConfiguration {
|
||||||
int quality;
|
int quality;
|
||||||
int subsampling;
|
int subsampling;
|
||||||
@@ -53,16 +56,10 @@ static const struct TightJPEGConfiguration conf[10] = {
|
|||||||
|
|
||||||
GetAPIMessager::GetAPIMessager(const char *passwdfile_): passwdfile(passwdfile_),
|
GetAPIMessager::GetAPIMessager(const char *passwdfile_): passwdfile(passwdfile_),
|
||||||
screenW(0), screenH(0), screenHash(0),
|
screenW(0), screenH(0), screenHash(0),
|
||||||
cachedW(0), cachedH(0), cachedQ(0),
|
cachedW(0), cachedH(0), cachedQ(0) {
|
||||||
ownerConnected(0), activeUsers(0) {
|
|
||||||
|
|
||||||
pthread_mutex_init(&screenMutex, NULL);
|
pthread_mutex_init(&screenMutex, NULL);
|
||||||
pthread_mutex_init(&userMutex, NULL);
|
pthread_mutex_init(&userMutex, NULL);
|
||||||
pthread_mutex_init(&statMutex, NULL);
|
|
||||||
pthread_mutex_init(&frameStatMutex, NULL);
|
|
||||||
pthread_mutex_init(&userInfoMutex, NULL);
|
|
||||||
|
|
||||||
serverFrameStats.inprogress = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// from main thread
|
// from main thread
|
||||||
@@ -98,78 +95,6 @@ void GetAPIMessager::mainUpdateScreen(rfb::PixelBuffer *pb) {
|
|||||||
pthread_mutex_unlock(&screenMutex);
|
pthread_mutex_unlock(&screenMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetAPIMessager::mainUpdateBottleneckStats(const char userid[], const char stats[]) {
|
|
||||||
if (pthread_mutex_trylock(&statMutex))
|
|
||||||
return;
|
|
||||||
|
|
||||||
bottleneckStats[userid] = stats;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&statMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetAPIMessager::mainClearBottleneckStats(const char userid[]) {
|
|
||||||
if (pthread_mutex_lock(&statMutex))
|
|
||||||
return;
|
|
||||||
|
|
||||||
bottleneckStats.erase(userid);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&statMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetAPIMessager::mainUpdateServerFrameStats(uint8_t changedPerc,
|
|
||||||
uint32_t all, uint32_t jpeg, uint32_t webp, uint32_t analysis,
|
|
||||||
uint32_t jpegarea, uint32_t webparea,
|
|
||||||
uint16_t njpeg, uint16_t nwebp,
|
|
||||||
uint16_t enc, uint16_t scale, uint16_t shot,
|
|
||||||
uint16_t w, uint16_t h) {
|
|
||||||
|
|
||||||
if (pthread_mutex_lock(&frameStatMutex))
|
|
||||||
return;
|
|
||||||
|
|
||||||
serverFrameStats.changedPerc = changedPerc;
|
|
||||||
serverFrameStats.all = all;
|
|
||||||
serverFrameStats.jpeg = jpeg;
|
|
||||||
serverFrameStats.webp = webp;
|
|
||||||
serverFrameStats.analysis = analysis;
|
|
||||||
serverFrameStats.jpegarea = jpegarea;
|
|
||||||
serverFrameStats.webparea = webparea;
|
|
||||||
serverFrameStats.njpeg = njpeg;
|
|
||||||
serverFrameStats.nwebp = nwebp;
|
|
||||||
serverFrameStats.enc = enc;
|
|
||||||
serverFrameStats.scale = scale;
|
|
||||||
serverFrameStats.shot = shot;
|
|
||||||
serverFrameStats.w = w;
|
|
||||||
serverFrameStats.h = h;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&frameStatMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetAPIMessager::mainUpdateClientFrameStats(const char userid[], uint32_t render,
|
|
||||||
uint32_t all, uint32_t ping) {
|
|
||||||
|
|
||||||
if (pthread_mutex_lock(&frameStatMutex))
|
|
||||||
return;
|
|
||||||
|
|
||||||
clientFrameStats_t s;
|
|
||||||
s.render = render;
|
|
||||||
s.all = all;
|
|
||||||
s.ping = ping;
|
|
||||||
|
|
||||||
clientFrameStats[userid] = s;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&frameStatMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetAPIMessager::mainUpdateUserInfo(const uint8_t ownerConn, const uint8_t numUsers) {
|
|
||||||
if (pthread_mutex_lock(&userInfoMutex))
|
|
||||||
return;
|
|
||||||
|
|
||||||
ownerConnected = ownerConn;
|
|
||||||
activeUsers = numUsers;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&userInfoMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// from network threads
|
// from network threads
|
||||||
uint8_t *GetAPIMessager::netGetScreenshot(uint16_t w, uint16_t h,
|
uint8_t *GetAPIMessager::netGetScreenshot(uint16_t w, uint16_t h,
|
||||||
const uint8_t q, const bool dedup,
|
const uint8_t q, const bool dedup,
|
||||||
@@ -361,271 +286,3 @@ uint8_t GetAPIMessager::netGiveControlTo(const char name[]) {
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetAPIMessager::netGetBottleneckStats(char *buf, uint32_t len) {
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
"username.1": {
|
|
||||||
"192.168.100.2:14908": [ 100, 100, 100, 100 ],
|
|
||||||
"192.168.100.3:14918": [ 100, 100, 100, 100 ]
|
|
||||||
},
|
|
||||||
"username.2": {
|
|
||||||
"192.168.100.5:14904": [ 100, 100, 100, 100 ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
std::map<std::string, std::string>::const_iterator it;
|
|
||||||
const char *prev = NULL;
|
|
||||||
FILE *f;
|
|
||||||
|
|
||||||
if (pthread_mutex_lock(&statMutex)) {
|
|
||||||
buf[0] = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conservative estimate
|
|
||||||
if (len < bottleneckStats.size() * 60) {
|
|
||||||
buf[0] = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
f = fmemopen(buf, len, "w");
|
|
||||||
|
|
||||||
fprintf(f, "{\n");
|
|
||||||
|
|
||||||
for (it = bottleneckStats.begin(); it != bottleneckStats.end(); it++) {
|
|
||||||
// user@127.0.0.1_1627311208.791752::websocket
|
|
||||||
const char *id = it->first.c_str();
|
|
||||||
const char *data = it->second.c_str();
|
|
||||||
|
|
||||||
const char *at = strchr(id, '@');
|
|
||||||
if (!at)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const unsigned userlen = at - id;
|
|
||||||
if (prev && !strncmp(prev, id, userlen)) {
|
|
||||||
// Same user
|
|
||||||
fprintf(f, ",\n\t\t\"%s\": %s", at + 1, data);
|
|
||||||
} else {
|
|
||||||
// New one
|
|
||||||
if (prev) {
|
|
||||||
fprintf(f, "\n\t},\n");
|
|
||||||
}
|
|
||||||
fprintf(f, "\t\"%.*s\": {\n", userlen, id);
|
|
||||||
fprintf(f, "\t\t\"%s\": %s", at + 1, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
prev = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bottleneckStats.size())
|
|
||||||
fprintf(f, "}\n");
|
|
||||||
else
|
|
||||||
fprintf(f, "\n\t}\n}\n");
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
out:
|
|
||||||
pthread_mutex_unlock(&statMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetAPIMessager::netGetFrameStats(char *buf, uint32_t len) {
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
"frame" : {
|
|
||||||
"resx": 1024,
|
|
||||||
"resy": 1280,
|
|
||||||
"changed": 75,
|
|
||||||
"server_time": 23
|
|
||||||
},
|
|
||||||
"server_side" : [
|
|
||||||
{ "process_name": "Analysis", "time": 20 },
|
|
||||||
{ "process_name": "TightWEBPEncoder", "time": 20, "count": 64, "area": 12 },
|
|
||||||
{ "process_name": "TightJPEGEncoder", "time": 20, "count": 64, "area": 12 }
|
|
||||||
],
|
|
||||||
"client_side" : [
|
|
||||||
{
|
|
||||||
"client": "123.1.2.1:1211",
|
|
||||||
"client_time": 20,
|
|
||||||
"ping": 20,
|
|
||||||
"processes" : [
|
|
||||||
{ "process_name": "scanRenderQ", "time": 20 }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
std::map<std::string, clientFrameStats_t>::const_iterator it;
|
|
||||||
unsigned i = 0;
|
|
||||||
FILE *f;
|
|
||||||
|
|
||||||
if (pthread_mutex_lock(&frameStatMutex)) {
|
|
||||||
buf[0] = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned num = clientFrameStats.size();
|
|
||||||
|
|
||||||
// Conservative estimate
|
|
||||||
if (len < 1024) {
|
|
||||||
buf[0] = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
f = fmemopen(buf, len, "w");
|
|
||||||
|
|
||||||
fprintf(f, "{\n");
|
|
||||||
|
|
||||||
fprintf(f, "\t\"frame\" : {\n"
|
|
||||||
"\t\t\"resx\": %u,\n"
|
|
||||||
"\t\t\"resy\": %u,\n"
|
|
||||||
"\t\t\"changed\": %u,\n"
|
|
||||||
"\t\t\"server_time\": %u\n"
|
|
||||||
"\t},\n",
|
|
||||||
serverFrameStats.w,
|
|
||||||
serverFrameStats.h,
|
|
||||||
serverFrameStats.changedPerc,
|
|
||||||
serverFrameStats.all);
|
|
||||||
|
|
||||||
fprintf(f, "\t\"server_side\" : [\n"
|
|
||||||
"\t\t{ \"process_name\": \"Analysis\", \"time\": %u },\n"
|
|
||||||
"\t\t{ \"process_name\": \"Screenshot\", \"time\": %u },\n"
|
|
||||||
"\t\t{ \"process_name\": \"Encoding_total\", \"time\": %u, \"videoscaling\": %u },\n"
|
|
||||||
"\t\t{ \"process_name\": \"TightJPEGEncoder\", \"time\": %u, \"count\": %u, \"area\": %u },\n"
|
|
||||||
"\t\t{ \"process_name\": \"TightWEBPEncoder\", \"time\": %u, \"count\": %u, \"area\": %u }\n"
|
|
||||||
"\t],\n",
|
|
||||||
serverFrameStats.analysis,
|
|
||||||
serverFrameStats.shot,
|
|
||||||
serverFrameStats.enc,
|
|
||||||
serverFrameStats.scale,
|
|
||||||
serverFrameStats.jpeg,
|
|
||||||
serverFrameStats.njpeg,
|
|
||||||
serverFrameStats.jpegarea,
|
|
||||||
serverFrameStats.webp,
|
|
||||||
serverFrameStats.nwebp,
|
|
||||||
serverFrameStats.webparea);
|
|
||||||
|
|
||||||
fprintf(f, "\t\"client_side\" : [\n");
|
|
||||||
|
|
||||||
for (it = clientFrameStats.begin(); it != clientFrameStats.end(); it++, i++) {
|
|
||||||
const char *id = it->first.c_str();
|
|
||||||
const clientFrameStats_t &s = it->second;
|
|
||||||
|
|
||||||
fprintf(f, "\t\t\{\n"
|
|
||||||
"\t\t\t\"client\": \"%s\",\n"
|
|
||||||
"\t\t\t\"client_time\": %u,\n"
|
|
||||||
"\t\t\t\"ping\": %u,\n"
|
|
||||||
"\t\t\t\"processes\" : [\n"
|
|
||||||
"\t\t\t\t{ \"process_name\": \"scanRenderQ\", \"time\": %u }\n"
|
|
||||||
"\t\t\t]\n"
|
|
||||||
"\t\t}",
|
|
||||||
id,
|
|
||||||
s.all,
|
|
||||||
s.ping,
|
|
||||||
s.render);
|
|
||||||
|
|
||||||
if (i == num - 1)
|
|
||||||
fprintf(f, "\n");
|
|
||||||
else
|
|
||||||
fprintf(f, ",\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(f, "\t]\n}\n");
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
serverFrameStats.inprogress = 0;
|
|
||||||
|
|
||||||
out:
|
|
||||||
pthread_mutex_unlock(&frameStatMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t GetAPIMessager::netRequestFrameStats(USER_ACTION what, const char *client) {
|
|
||||||
// Return 1 for success
|
|
||||||
action_data act;
|
|
||||||
act.action = what;
|
|
||||||
if (client) {
|
|
||||||
strncpy(act.data.password, client, PASSWORD_LEN);
|
|
||||||
act.data.password[PASSWORD_LEN - 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// In progress already?
|
|
||||||
bool fail = false;
|
|
||||||
if (pthread_mutex_lock(&frameStatMutex))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (serverFrameStats.inprogress) {
|
|
||||||
fail = true;
|
|
||||||
vlog.error("Frame stats request already in progress, refusing another");
|
|
||||||
} else {
|
|
||||||
clientFrameStats.clear();
|
|
||||||
memset(&serverFrameStats, 0, sizeof(serverFrameStats_t));
|
|
||||||
serverFrameStats.inprogress = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&frameStatMutex);
|
|
||||||
if (fail)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Send it in
|
|
||||||
if (pthread_mutex_lock(&userMutex))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
actionQueue.push_back(act);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&userMutex);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t GetAPIMessager::netOwnerConnected() {
|
|
||||||
uint8_t ret;
|
|
||||||
|
|
||||||
if (pthread_mutex_lock(&userInfoMutex))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ret = ownerConnected;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&userInfoMutex);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t GetAPIMessager::netNumActiveUsers() {
|
|
||||||
uint8_t ret;
|
|
||||||
|
|
||||||
if (pthread_mutex_lock(&userInfoMutex))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ret = activeUsers;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&userInfoMutex);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t GetAPIMessager::netGetClientFrameStatsNum() {
|
|
||||||
uint8_t ret;
|
|
||||||
|
|
||||||
if (pthread_mutex_lock(&frameStatMutex))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ret = clientFrameStats.size();
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&frameStatMutex);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t GetAPIMessager::netServerFrameStatsReady() {
|
|
||||||
uint8_t ret;
|
|
||||||
|
|
||||||
if (pthread_mutex_lock(&frameStatMutex))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ret = serverFrameStats.w != 0;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&frameStatMutex);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -40,8 +40,6 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <wordexp.h>
|
#include <wordexp.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include "websocket.h"
|
#include "websocket.h"
|
||||||
|
|
||||||
#include <network/GetAPI.h>
|
#include <network/GetAPI.h>
|
||||||
@@ -461,67 +459,6 @@ static uint8_t givecontrolCb(void *messager, const char name[])
|
|||||||
return msgr->netGiveControlTo(name);
|
return msgr->netGiveControlTo(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bottleneckStatsCb(void *messager, char *buf, uint32_t len)
|
|
||||||
{
|
|
||||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
|
||||||
msgr->netGetBottleneckStats(buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void frameStatsCb(void *messager, char *buf, uint32_t len)
|
|
||||||
{
|
|
||||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
|
||||||
msgr->netGetFrameStats(buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t requestFrameStatsNoneCb(void *messager)
|
|
||||||
{
|
|
||||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
|
||||||
return msgr->netRequestFrameStats(GetAPIMessager::WANT_FRAME_STATS_SERVERONLY, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t requestFrameStatsOwnerCb(void *messager)
|
|
||||||
{
|
|
||||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
|
||||||
return msgr->netRequestFrameStats(GetAPIMessager::WANT_FRAME_STATS_OWNER, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t requestFrameStatsAllCb(void *messager)
|
|
||||||
{
|
|
||||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
|
||||||
return msgr->netRequestFrameStats(GetAPIMessager::WANT_FRAME_STATS_ALL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t requestFrameStatsOneCb(void *messager, const char *client)
|
|
||||||
{
|
|
||||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
|
||||||
return msgr->netRequestFrameStats(GetAPIMessager::WANT_FRAME_STATS_SPECIFIC, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t ownerConnectedCb(void *messager)
|
|
||||||
{
|
|
||||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
|
||||||
return msgr->netOwnerConnected();
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t numActiveUsersCb(void *messager)
|
|
||||||
{
|
|
||||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
|
||||||
return msgr->netNumActiveUsers();
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t getClientFrameStatsNumCb(void *messager)
|
|
||||||
{
|
|
||||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
|
||||||
return msgr->netGetClientFrameStatsNum();
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t serverFrameStatsReadyCb(void *messager)
|
|
||||||
{
|
|
||||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
|
||||||
return msgr->netServerFrameStatsReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
WebsocketListener::WebsocketListener(const struct sockaddr *listenaddr,
|
WebsocketListener::WebsocketListener(const struct sockaddr *listenaddr,
|
||||||
socklen_t listenaddrlen,
|
socklen_t listenaddrlen,
|
||||||
bool sslonly, const char *cert, const char *certkey,
|
bool sslonly, const char *cert, const char *certkey,
|
||||||
@@ -566,7 +503,7 @@ WebsocketListener::WebsocketListener(const struct sockaddr *listenaddr,
|
|||||||
if (bind(sock, &sa.u.sa, listenaddrlen) == -1) {
|
if (bind(sock, &sa.u.sa, listenaddrlen) == -1) {
|
||||||
int e = errorNumber;
|
int e = errorNumber;
|
||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
throw SocketException("failed to bind socket, is someone else on our -websocketPort?", e);
|
throw SocketException("failed to bind socket", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
listen(sock); // sets the internal fd
|
listen(sock); // sets the internal fd
|
||||||
@@ -576,16 +513,13 @@ WebsocketListener::WebsocketListener(const struct sockaddr *listenaddr,
|
|||||||
//
|
//
|
||||||
internalSocket = socket(AF_UNIX, SOCK_STREAM, 0);
|
internalSocket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
|
||||||
char sockname[32];
|
|
||||||
sprintf(sockname, ".KasmVNCSock%u", getpid());
|
|
||||||
|
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
strcpy(addr.sun_path, sockname);
|
strcpy(addr.sun_path, ".KasmVNCSock");
|
||||||
addr.sun_path[0] = '\0';
|
addr.sun_path[0] = '\0';
|
||||||
|
|
||||||
if (bind(internalSocket, (struct sockaddr *) &addr,
|
if (bind(internalSocket, (struct sockaddr *) &addr,
|
||||||
sizeof(sa_family_t) + strlen(sockname))) {
|
sizeof(sa_family_t) + sizeof(".KasmVNCSock"))) {
|
||||||
throw SocketException("failed to bind socket", errorNumber);
|
throw SocketException("failed to bind socket", errorNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,18 +548,6 @@ WebsocketListener::WebsocketListener(const struct sockaddr *listenaddr,
|
|||||||
settings.adduserCb = adduserCb;
|
settings.adduserCb = adduserCb;
|
||||||
settings.removeCb = removeCb;
|
settings.removeCb = removeCb;
|
||||||
settings.givecontrolCb = givecontrolCb;
|
settings.givecontrolCb = givecontrolCb;
|
||||||
settings.bottleneckStatsCb = bottleneckStatsCb;
|
|
||||||
settings.frameStatsCb = frameStatsCb;
|
|
||||||
|
|
||||||
settings.requestFrameStatsNoneCb = requestFrameStatsNoneCb;
|
|
||||||
settings.requestFrameStatsOwnerCb = requestFrameStatsOwnerCb;
|
|
||||||
settings.requestFrameStatsAllCb = requestFrameStatsAllCb;
|
|
||||||
settings.requestFrameStatsOneCb = requestFrameStatsOneCb;
|
|
||||||
|
|
||||||
settings.ownerConnectedCb = ownerConnectedCb;
|
|
||||||
settings.numActiveUsersCb = numActiveUsersCb;
|
|
||||||
settings.getClientFrameStatsNumCb = getClientFrameStatsNumCb;
|
|
||||||
settings.serverFrameStatsReadyCb = serverFrameStatsReadyCb;
|
|
||||||
|
|
||||||
pthread_t tid;
|
pthread_t tid;
|
||||||
pthread_create(&tid, NULL, start_server, NULL);
|
pthread_create(&tid, NULL, start_server, NULL);
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ static const char *parse_get(const char * const in, const char * const opt, unsi
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void percent_decode(const char *src, char *dst, const uint8_t filter) {
|
static void percent_decode(const char *src, char *dst) {
|
||||||
while (1) {
|
while (1) {
|
||||||
if (!*src)
|
if (!*src)
|
||||||
break;
|
break;
|
||||||
@@ -127,32 +127,7 @@ static void percent_decode(const char *src, char *dst, const uint8_t filter) {
|
|||||||
hex[2] = '\0';
|
hex[2] = '\0';
|
||||||
|
|
||||||
src += 2;
|
src += 2;
|
||||||
*dst = strtol(hex, NULL, 16);
|
*dst++ = strtol(hex, NULL, 16);
|
||||||
|
|
||||||
if (filter) {
|
|
||||||
// Avoid directory traversal
|
|
||||||
if (*dst == '/')
|
|
||||||
*dst = '_';
|
|
||||||
}
|
|
||||||
|
|
||||||
dst++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*dst = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static void percent_encode(const char *src, char *dst) {
|
|
||||||
while (1) {
|
|
||||||
if (!*src)
|
|
||||||
break;
|
|
||||||
if (isalnum(*src) || *src == '.' || *src == ',') {
|
|
||||||
*dst++ = *src++;
|
|
||||||
} else {
|
|
||||||
*dst++ = '%';
|
|
||||||
sprintf(dst, "%02X", *src);
|
|
||||||
dst += 2;
|
|
||||||
src++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -591,7 +566,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
|
|||||||
headers->key3[0] = '\0';
|
headers->key3[0] = '\0';
|
||||||
|
|
||||||
if ((strlen(handshake) < 92) || (bcmp(handshake, "GET ", 4) != 0) ||
|
if ((strlen(handshake) < 92) || (bcmp(handshake, "GET ", 4) != 0) ||
|
||||||
(!strcasestr(handshake, "Upgrade: websocket"))) {
|
(!strstr(handshake, "Upgrade: websocket"))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
start = handshake+4;
|
start = handshake+4;
|
||||||
@@ -608,11 +583,11 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
|
|||||||
headers->host[end-start] = '\0';
|
headers->host[end-start] = '\0';
|
||||||
|
|
||||||
headers->origin[0] = '\0';
|
headers->origin[0] = '\0';
|
||||||
start = strcasestr(handshake, "\r\nOrigin: ");
|
start = strstr(handshake, "\r\nOrigin: ");
|
||||||
if (start) {
|
if (start) {
|
||||||
start += 10;
|
start += 10;
|
||||||
} else {
|
} else {
|
||||||
start = strcasestr(handshake, "\r\nSec-WebSocket-Origin: ");
|
start = strstr(handshake, "\r\nSec-WebSocket-Origin: ");
|
||||||
if (!start) { return 0; }
|
if (!start) { return 0; }
|
||||||
start += 24;
|
start += 24;
|
||||||
}
|
}
|
||||||
@@ -620,7 +595,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
|
|||||||
strncpy(headers->origin, start, end-start);
|
strncpy(headers->origin, start, end-start);
|
||||||
headers->origin[end-start] = '\0';
|
headers->origin[end-start] = '\0';
|
||||||
|
|
||||||
start = strcasestr(handshake, "\r\nSec-WebSocket-Version: ");
|
start = strstr(handshake, "\r\nSec-WebSocket-Version: ");
|
||||||
if (start) {
|
if (start) {
|
||||||
// HyBi/RFC 6455
|
// HyBi/RFC 6455
|
||||||
start += 25;
|
start += 25;
|
||||||
@@ -630,7 +605,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
|
|||||||
ws_ctx->hixie = 0;
|
ws_ctx->hixie = 0;
|
||||||
ws_ctx->hybi = strtol(headers->version, NULL, 10);
|
ws_ctx->hybi = strtol(headers->version, NULL, 10);
|
||||||
|
|
||||||
start = strcasestr(handshake, "\r\nSec-WebSocket-Key: ");
|
start = strstr(handshake, "\r\nSec-WebSocket-Key: ");
|
||||||
if (!start) { return 0; }
|
if (!start) { return 0; }
|
||||||
start += 21;
|
start += 21;
|
||||||
end = strstr(start, "\r\n");
|
end = strstr(start, "\r\n");
|
||||||
@@ -644,7 +619,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
|
|||||||
strncpy(headers->connection, start, end-start);
|
strncpy(headers->connection, start, end-start);
|
||||||
headers->connection[end-start] = '\0';
|
headers->connection[end-start] = '\0';
|
||||||
|
|
||||||
start = strcasestr(handshake, "\r\nSec-WebSocket-Protocol: ");
|
start = strstr(handshake, "\r\nSec-WebSocket-Protocol: ");
|
||||||
if (!start) { return 0; }
|
if (!start) { return 0; }
|
||||||
start += 26;
|
start += 26;
|
||||||
end = strstr(start, "\r\n");
|
end = strstr(start, "\r\n");
|
||||||
@@ -662,14 +637,14 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
|
|||||||
strncpy(headers->key3, start, 8);
|
strncpy(headers->key3, start, 8);
|
||||||
headers->key3[8] = '\0';
|
headers->key3[8] = '\0';
|
||||||
|
|
||||||
start = strcasestr(handshake, "\r\nSec-WebSocket-Key1: ");
|
start = strstr(handshake, "\r\nSec-WebSocket-Key1: ");
|
||||||
if (!start) { return 0; }
|
if (!start) { return 0; }
|
||||||
start += 22;
|
start += 22;
|
||||||
end = strstr(start, "\r\n");
|
end = strstr(start, "\r\n");
|
||||||
strncpy(headers->key1, start, end-start);
|
strncpy(headers->key1, start, end-start);
|
||||||
headers->key1[end-start] = '\0';
|
headers->key1[end-start] = '\0';
|
||||||
|
|
||||||
start = strcasestr(handshake, "\r\nSec-WebSocket-Key2: ");
|
start = strstr(handshake, "\r\nSec-WebSocket-Key2: ");
|
||||||
if (!start) { return 0; }
|
if (!start) { return 0; }
|
||||||
start += 22;
|
start += 22;
|
||||||
end = strstr(start, "\r\n");
|
end = strstr(start, "\r\n");
|
||||||
@@ -771,7 +746,6 @@ def:
|
|||||||
|
|
||||||
static void dirlisting(ws_ctx_t *ws_ctx, const char fullpath[], const char path[]) {
|
static void dirlisting(ws_ctx_t *ws_ctx, const char fullpath[], const char path[]) {
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
char enc[PATH_MAX * 3 + 1];
|
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
// Redirect?
|
// Redirect?
|
||||||
@@ -805,13 +779,11 @@ static void dirlisting(ws_ctx_t *ws_ctx, const char fullpath[], const char path[
|
|||||||
if (!strcmp(names[i]->d_name, ".") || !strcmp(names[i]->d_name, ".."))
|
if (!strcmp(names[i]->d_name, ".") || !strcmp(names[i]->d_name, ".."))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
percent_encode(names[i]->d_name, enc);
|
|
||||||
|
|
||||||
if (names[i]->d_type == DT_DIR)
|
if (names[i]->d_type == DT_DIR)
|
||||||
sprintf(buf, "<li><a href=\"%s/\">%s/</a></li>", enc,
|
sprintf(buf, "<li><a href=\"%s/\">%s/</a></li>", names[i]->d_name,
|
||||||
names[i]->d_name);
|
names[i]->d_name);
|
||||||
else
|
else
|
||||||
sprintf(buf, "<li><a href=\"%s\">%s</a></li>", enc,
|
sprintf(buf, "<li><a href=\"%s\">%s</a></li>", names[i]->d_name,
|
||||||
names[i]->d_name);
|
names[i]->d_name);
|
||||||
|
|
||||||
ws_send(ws_ctx, buf, strlen(buf));
|
ws_send(ws_ctx, buf, strlen(buf));
|
||||||
@@ -850,15 +822,13 @@ static void servefile(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
len = strlen(path);
|
len = strlen(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
percent_decode(path, buf, 1);
|
wserr("Requested file '%s'\n", path);
|
||||||
|
sprintf(fullpath, "%s/%s", settings.httpdir, path);
|
||||||
wserr("Requested file '%s'\n", buf);
|
|
||||||
sprintf(fullpath, "%s/%s", settings.httpdir, buf);
|
|
||||||
|
|
||||||
DIR *dir = opendir(fullpath);
|
DIR *dir = opendir(fullpath);
|
||||||
if (dir) {
|
if (dir) {
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
dirlisting(ws_ctx, fullpath, buf);
|
dirlisting(ws_ctx, fullpath, path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1006,14 +976,14 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
if (len) {
|
if (len) {
|
||||||
memcpy(buf, param, len);
|
memcpy(buf, param, len);
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
percent_decode(buf, decname, 0);
|
percent_decode(buf, decname);
|
||||||
}
|
}
|
||||||
|
|
||||||
param = parse_get(args, "password", &len);
|
param = parse_get(args, "password", &len);
|
||||||
if (len) {
|
if (len) {
|
||||||
memcpy(buf, param, len);
|
memcpy(buf, param, len);
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
percent_decode(buf, decpw, 0);
|
percent_decode(buf, decpw);
|
||||||
|
|
||||||
struct crypt_data cdata;
|
struct crypt_data cdata;
|
||||||
cdata.initialized = 0;
|
cdata.initialized = 0;
|
||||||
@@ -1053,7 +1023,7 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
if (len) {
|
if (len) {
|
||||||
memcpy(buf, param, len);
|
memcpy(buf, param, len);
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
percent_decode(buf, decname, 0);
|
percent_decode(buf, decname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!decname[0])
|
if (!decname[0])
|
||||||
@@ -1082,7 +1052,7 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
if (len) {
|
if (len) {
|
||||||
memcpy(buf, param, len);
|
memcpy(buf, param, len);
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
percent_decode(buf, decname, 0);
|
percent_decode(buf, decname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!decname[0])
|
if (!decname[0])
|
||||||
@@ -1104,89 +1074,6 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
|
|
||||||
wserr("Passed give_control request to main thread\n");
|
wserr("Passed give_control request to main thread\n");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else entry("/api/get_bottleneck_stats") {
|
|
||||||
char statbuf[4096];
|
|
||||||
settings.bottleneckStatsCb(settings.messager, statbuf, 4096);
|
|
||||||
|
|
||||||
sprintf(buf, "HTTP/1.1 200 OK\r\n"
|
|
||||||
"Server: KasmVNC/4.0\r\n"
|
|
||||||
"Connection: close\r\n"
|
|
||||||
"Content-type: text/plain\r\n"
|
|
||||||
"Content-length: %lu\r\n"
|
|
||||||
"\r\n", strlen(statbuf));
|
|
||||||
ws_send(ws_ctx, buf, strlen(buf));
|
|
||||||
ws_send(ws_ctx, statbuf, strlen(statbuf));
|
|
||||||
|
|
||||||
wserr("Sent bottleneck stats to API caller\n");
|
|
||||||
ret = 1;
|
|
||||||
} else entry("/api/get_frame_stats") {
|
|
||||||
char statbuf[4096], decname[1024];
|
|
||||||
unsigned waitfor;
|
|
||||||
|
|
||||||
param = parse_get(args, "client", &len);
|
|
||||||
if (len) {
|
|
||||||
memcpy(buf, param, len);
|
|
||||||
buf[len] = '\0';
|
|
||||||
percent_decode(buf, decname, 0);
|
|
||||||
} else {
|
|
||||||
wserr("client param required\n");
|
|
||||||
goto nope;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!decname[0])
|
|
||||||
goto nope;
|
|
||||||
|
|
||||||
if (!strcmp(decname, "none")) {
|
|
||||||
waitfor = 0;
|
|
||||||
if (!settings.requestFrameStatsNoneCb(settings.messager))
|
|
||||||
goto nope;
|
|
||||||
} else if (!strcmp(decname, "auto")) {
|
|
||||||
waitfor = settings.ownerConnectedCb(settings.messager);
|
|
||||||
if (!waitfor) {
|
|
||||||
if (!settings.requestFrameStatsNoneCb(settings.messager))
|
|
||||||
goto nope;
|
|
||||||
} else {
|
|
||||||
if (!settings.requestFrameStatsOwnerCb(settings.messager))
|
|
||||||
goto nope;
|
|
||||||
}
|
|
||||||
} else if (!strcmp(decname, "all")) {
|
|
||||||
waitfor = settings.numActiveUsersCb(settings.messager);
|
|
||||||
if (!settings.requestFrameStatsAllCb(settings.messager))
|
|
||||||
goto nope;
|
|
||||||
} else {
|
|
||||||
waitfor = 1;
|
|
||||||
if (!settings.requestFrameStatsOneCb(settings.messager, decname))
|
|
||||||
goto nope;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
usleep(10 * 1000);
|
|
||||||
if (settings.serverFrameStatsReadyCb(settings.messager))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waitfor) {
|
|
||||||
unsigned waits;
|
|
||||||
for (waits = 0; waits < 20; waits++) { // wait up to 2s
|
|
||||||
if (settings.getClientFrameStatsNumCb(settings.messager) >= waitfor)
|
|
||||||
break;
|
|
||||||
usleep(100 * 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.frameStatsCb(settings.messager, statbuf, 4096);
|
|
||||||
|
|
||||||
sprintf(buf, "HTTP/1.1 200 OK\r\n"
|
|
||||||
"Server: KasmVNC/4.0\r\n"
|
|
||||||
"Connection: close\r\n"
|
|
||||||
"Content-type: text/plain\r\n"
|
|
||||||
"Content-length: %lu\r\n"
|
|
||||||
"\r\n", strlen(statbuf));
|
|
||||||
ws_send(ws_ctx, buf, strlen(buf));
|
|
||||||
ws_send(ws_ctx, statbuf, strlen(statbuf));
|
|
||||||
|
|
||||||
wserr("Sent frame stats to API caller\n");
|
|
||||||
ret = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef entry
|
#undef entry
|
||||||
@@ -1350,8 +1237,6 @@ ws_ctx_t *do_handshake(int sock) {
|
|||||||
} else {
|
} else {
|
||||||
// Client tried an empty password, just fail them
|
// Client tried an empty password, just fail them
|
||||||
response[0] = '\0';
|
response[0] = '\0';
|
||||||
authbuf[0] = 'a';
|
|
||||||
authbuf[1] = '\0';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,18 +84,6 @@ typedef struct {
|
|||||||
const uint8_t write);
|
const uint8_t write);
|
||||||
uint8_t (*removeCb)(void *messager, const char name[]);
|
uint8_t (*removeCb)(void *messager, const char name[]);
|
||||||
uint8_t (*givecontrolCb)(void *messager, const char name[]);
|
uint8_t (*givecontrolCb)(void *messager, const char name[]);
|
||||||
void (*bottleneckStatsCb)(void *messager, char *buf, uint32_t len);
|
|
||||||
void (*frameStatsCb)(void *messager, char *buf, uint32_t len);
|
|
||||||
|
|
||||||
uint8_t (*requestFrameStatsNoneCb)(void *messager);
|
|
||||||
uint8_t (*requestFrameStatsOwnerCb)(void *messager);
|
|
||||||
uint8_t (*requestFrameStatsAllCb)(void *messager);
|
|
||||||
uint8_t (*requestFrameStatsOneCb)(void *messager, const char *client);
|
|
||||||
|
|
||||||
uint8_t (*ownerConnectedCb)(void *messager);
|
|
||||||
uint8_t (*numActiveUsersCb)(void *messager);
|
|
||||||
uint8_t (*getClientFrameStatsNumCb)(void *messager);
|
|
||||||
uint8_t (*serverFrameStatsReadyCb)(void *messager);
|
|
||||||
} settings_t;
|
} settings_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -20,8 +20,6 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include "websocket.h"
|
#include "websocket.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -44,11 +42,11 @@ static void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
|||||||
int maxfd, client = ws_ctx->sockfd;
|
int maxfd, client = ws_ctx->sockfd;
|
||||||
unsigned int opcode, left, ret;
|
unsigned int opcode, left, ret;
|
||||||
unsigned int tout_start, tout_end, cout_start, cout_end;
|
unsigned int tout_start, tout_end, cout_start, cout_end;
|
||||||
unsigned int tin_end;
|
unsigned int tin_start, tin_end;
|
||||||
ssize_t len, bytes;
|
ssize_t len, bytes;
|
||||||
|
|
||||||
tout_start = tout_end = cout_start = cout_end =
|
tout_start = tout_end = cout_start = cout_end =
|
||||||
tin_end = 0;
|
tin_start = tin_end = 0;
|
||||||
maxfd = client > target ? client+1 : target+1;
|
maxfd = client > target ? client+1 : target+1;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -165,7 +163,7 @@ static void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(client, &rlist)) {
|
if (FD_ISSET(client, &rlist)) {
|
||||||
bytes = ws_recv(ws_ctx, ws_ctx->tin_buf + tin_end, BUFSIZE-1-tin_end);
|
bytes = ws_recv(ws_ctx, ws_ctx->tin_buf + tin_end, BUFSIZE-1);
|
||||||
if (pipe_error) { break; }
|
if (pipe_error) { break; }
|
||||||
if (bytes <= 0) {
|
if (bytes <= 0) {
|
||||||
handler_emsg("client closed connection\n");
|
handler_emsg("client closed connection\n");
|
||||||
@@ -180,13 +178,13 @@ static void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
*/
|
*/
|
||||||
if (ws_ctx->hybi) {
|
if (ws_ctx->hybi) {
|
||||||
len = decode_hybi(ws_ctx->tin_buf,
|
len = decode_hybi(ws_ctx->tin_buf + tin_start,
|
||||||
tin_end,
|
tin_end-tin_start,
|
||||||
ws_ctx->tout_buf, BUFSIZE-1,
|
ws_ctx->tout_buf, BUFSIZE-1,
|
||||||
&opcode, &left);
|
&opcode, &left);
|
||||||
} else {
|
} else {
|
||||||
len = decode_hixie(ws_ctx->tin_buf,
|
len = decode_hixie(ws_ctx->tin_buf + tin_start,
|
||||||
tin_end,
|
tin_end-tin_start,
|
||||||
ws_ctx->tout_buf, BUFSIZE-1,
|
ws_ctx->tout_buf, BUFSIZE-1,
|
||||||
&opcode, &left);
|
&opcode, &left);
|
||||||
}
|
}
|
||||||
@@ -208,13 +206,10 @@ static void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (left) {
|
if (left) {
|
||||||
const unsigned tin_start = tin_end - left;
|
tin_start = tin_end - left;
|
||||||
//handler_emsg("partial frame from client, %u left, start %u end %u, lens %lu %lu\n",
|
//printf("partial frame from client");
|
||||||
// left, tin_start, tin_end, bytes, len);
|
|
||||||
memmove(ws_ctx->tin_buf, ws_ctx->tin_buf + tin_start, left);
|
|
||||||
tin_end = left;
|
|
||||||
} else {
|
} else {
|
||||||
//handler_emsg("handled %lu/%lu bytes\n", bytes, len);
|
tin_start = 0;
|
||||||
tin_end = 0;
|
tin_end = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,21 +222,14 @@ static void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
|||||||
|
|
||||||
void proxy_handler(ws_ctx_t *ws_ctx) {
|
void proxy_handler(ws_ctx_t *ws_ctx) {
|
||||||
|
|
||||||
char sockname[32];
|
|
||||||
sprintf(sockname, ".KasmVNCSock%u", getpid());
|
|
||||||
|
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
strcpy(addr.sun_path, sockname);
|
strcpy(addr.sun_path, ".KasmVNCSock");
|
||||||
addr.sun_path[0] = '\0';
|
addr.sun_path[0] = '\0';
|
||||||
|
|
||||||
struct timeval tv;
|
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
|
|
||||||
struct sockaddr_un myaddr;
|
struct sockaddr_un myaddr;
|
||||||
myaddr.sun_family = AF_UNIX;
|
myaddr.sun_family = AF_UNIX;
|
||||||
sprintf(myaddr.sun_path, ".%s@%s_%lu.%lu", ws_ctx->user, ws_ctx->ip,
|
sprintf(myaddr.sun_path, ".%s@%s", ws_ctx->user, ws_ctx->ip);
|
||||||
tv.tv_sec, tv.tv_usec);
|
|
||||||
myaddr.sun_path[0] = '\0';
|
myaddr.sun_path[0] = '\0';
|
||||||
|
|
||||||
int tsock = socket(AF_UNIX, SOCK_STREAM, 0);
|
int tsock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
@@ -250,7 +238,7 @@ void proxy_handler(ws_ctx_t *ws_ctx) {
|
|||||||
handler_msg("connecting to VNC target\n");
|
handler_msg("connecting to VNC target\n");
|
||||||
|
|
||||||
if (connect(tsock, (struct sockaddr *) &addr,
|
if (connect(tsock, (struct sockaddr *) &addr,
|
||||||
sizeof(sa_family_t) + strlen(sockname)) < 0) {
|
sizeof(sa_family_t) + sizeof(".KasmVNCSock")) < 0) {
|
||||||
|
|
||||||
handler_emsg("Could not connect to target: %s\n",
|
handler_emsg("Could not connect to target: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ set(RFB_SOURCES
|
|||||||
Security.cxx
|
Security.cxx
|
||||||
SecurityServer.cxx
|
SecurityServer.cxx
|
||||||
SecurityClient.cxx
|
SecurityClient.cxx
|
||||||
SelfBench.cxx
|
|
||||||
SSecurityPlain.cxx
|
SSecurityPlain.cxx
|
||||||
SSecurityStack.cxx
|
SSecurityStack.cxx
|
||||||
SSecurityVncAuth.cxx
|
SSecurityVncAuth.cxx
|
||||||
@@ -64,7 +63,6 @@ set(RFB_SOURCES
|
|||||||
VNCServerST.cxx
|
VNCServerST.cxx
|
||||||
ZRLEEncoder.cxx
|
ZRLEEncoder.cxx
|
||||||
ZRLEDecoder.cxx
|
ZRLEDecoder.cxx
|
||||||
cpuid.cxx
|
|
||||||
encodings.cxx
|
encodings.cxx
|
||||||
util.cxx
|
util.cxx
|
||||||
xxhash.c)
|
xxhash.c)
|
||||||
@@ -98,27 +96,6 @@ if(GNUTLS_FOUND)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# SSE2
|
|
||||||
|
|
||||||
set(SSE2_SOURCES
|
|
||||||
scale_sse2.cxx)
|
|
||||||
|
|
||||||
set(SCALE_DUMMY_SOURCES
|
|
||||||
scale_dummy.cxx)
|
|
||||||
|
|
||||||
if(COMPILER_SUPPORTS_SSE2)
|
|
||||||
set_source_files_properties(${SSE2_SOURCES} PROPERTIES COMPILE_FLAGS ${COMPILE_FLAGS} -msse2)
|
|
||||||
set(RFB_SOURCES
|
|
||||||
${RFB_SOURCES}
|
|
||||||
${SSE2_SOURCES}
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
set(RFB_SOURCES
|
|
||||||
${RFB_SOURCES}
|
|
||||||
${SCALE_DUMMY_SOURCES}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(rfb STATIC ${RFB_SOURCES})
|
add_library(rfb STATIC ${RFB_SOURCES})
|
||||||
|
|
||||||
target_link_libraries(rfb ${RFB_LIBRARIES})
|
target_link_libraries(rfb ${RFB_LIBRARIES})
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace rfb {
|
|||||||
int w, int h,
|
int w, int h,
|
||||||
const ScreenSet& layout);
|
const ScreenSet& layout);
|
||||||
virtual void setCursor(int width, int height, const Point& hotspot,
|
virtual void setCursor(int width, int height, const Point& hotspot,
|
||||||
const rdr::U8* data, const bool resizing = false) = 0;
|
const rdr::U8* data) = 0;
|
||||||
virtual void setPixelFormat(const PixelFormat& pf);
|
virtual void setPixelFormat(const PixelFormat& pf);
|
||||||
virtual void setName(const char* name);
|
virtual void setName(const char* name);
|
||||||
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
|
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
|
||||||
|
|||||||
@@ -695,8 +695,6 @@ bool ComparingUpdateTracker::compare(bool skipScrollDetection, const Region &ski
|
|||||||
std::vector<Rect> rects;
|
std::vector<Rect> rects;
|
||||||
std::vector<Rect>::iterator i;
|
std::vector<Rect>::iterator i;
|
||||||
|
|
||||||
changedPerc = 100;
|
|
||||||
|
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -751,13 +749,8 @@ bool ComparingUpdateTracker::compare(bool skipScrollDetection, const Region &ski
|
|||||||
for (i = rects.begin(); i != rects.end(); i++)
|
for (i = rects.begin(); i != rects.end(); i++)
|
||||||
totalPixels += i->area();
|
totalPixels += i->area();
|
||||||
newChanged.get_rects(&rects);
|
newChanged.get_rects(&rects);
|
||||||
unsigned newchangedarea = 0;
|
for (i = rects.begin(); i != rects.end(); i++)
|
||||||
for (i = rects.begin(); i != rects.end(); i++) {
|
|
||||||
missedPixels += i->area();
|
missedPixels += i->area();
|
||||||
newchangedarea += i->area();
|
|
||||||
}
|
|
||||||
|
|
||||||
changedPerc = newchangedarea * 100 / fb->area();
|
|
||||||
|
|
||||||
if (changed.equals(newChanged))
|
if (changed.equals(newChanged))
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -48,8 +48,6 @@ namespace rfb {
|
|||||||
virtual void getUpdateInfo(UpdateInfo* info, const Region& cliprgn);
|
virtual void getUpdateInfo(UpdateInfo* info, const Region& cliprgn);
|
||||||
virtual void clear();
|
virtual void clear();
|
||||||
|
|
||||||
rdr::U8 changedPerc;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void compareRect(const Rect& r, Region* newchanged, const Region &skipCursorArea);
|
void compareRect(const Rect& r, Region* newchanged, const Region &skipCursorArea);
|
||||||
PixelBuffer* fb;
|
PixelBuffer* fb;
|
||||||
|
|||||||
@@ -298,11 +298,6 @@ size_t Congestion::getBandwidth()
|
|||||||
return congWindow * 1000 / safeBaseRTT;
|
return congWindow * 1000 / safeBaseRTT;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned Congestion::getPingTime() const
|
|
||||||
{
|
|
||||||
return safeBaseRTT;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Congestion::debugTrace(const char* filename, int fd)
|
void Congestion::debugTrace(const char* filename, int fd)
|
||||||
{
|
{
|
||||||
#ifdef CONGESTION_TRACE
|
#ifdef CONGESTION_TRACE
|
||||||
|
|||||||
@@ -51,8 +51,6 @@ namespace rfb {
|
|||||||
// per second.
|
// per second.
|
||||||
size_t getBandwidth();
|
size_t getBandwidth();
|
||||||
|
|
||||||
unsigned getPingTime() const;
|
|
||||||
|
|
||||||
// debugTrace() writes the current congestion window, as well as the
|
// debugTrace() writes the current congestion window, as well as the
|
||||||
// congestion window of the underlying TCP layer, to the specified
|
// congestion window of the underlying TCP layer, to the specified
|
||||||
// file
|
// file
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ ConnParams::ConnParams()
|
|||||||
width(0), height(0), useCopyRect(false),
|
width(0), height(0), useCopyRect(false),
|
||||||
supportsLocalCursor(false), supportsLocalXCursor(false),
|
supportsLocalCursor(false), supportsLocalXCursor(false),
|
||||||
supportsLocalCursorWithAlpha(false),
|
supportsLocalCursorWithAlpha(false),
|
||||||
supportsVMWareCursor(false),
|
|
||||||
supportsCursorPosition(false),
|
supportsCursorPosition(false),
|
||||||
supportsDesktopResize(false), supportsExtendedDesktopSize(false),
|
supportsDesktopResize(false), supportsExtendedDesktopSize(false),
|
||||||
supportsDesktopRename(false), supportsLastRect(false),
|
supportsDesktopRename(false), supportsLastRect(false),
|
||||||
@@ -124,7 +123,6 @@ void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings)
|
|||||||
useCopyRect = false;
|
useCopyRect = false;
|
||||||
supportsLocalCursor = false;
|
supportsLocalCursor = false;
|
||||||
supportsLocalCursorWithAlpha = false;
|
supportsLocalCursorWithAlpha = false;
|
||||||
supportsVMWareCursor = false;
|
|
||||||
supportsDesktopResize = false;
|
supportsDesktopResize = false;
|
||||||
supportsExtendedDesktopSize = false;
|
supportsExtendedDesktopSize = false;
|
||||||
supportsLocalXCursor = false;
|
supportsLocalXCursor = false;
|
||||||
@@ -155,9 +153,6 @@ void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings)
|
|||||||
case pseudoEncodingCursorWithAlpha:
|
case pseudoEncodingCursorWithAlpha:
|
||||||
supportsLocalCursorWithAlpha = true;
|
supportsLocalCursorWithAlpha = true;
|
||||||
break;
|
break;
|
||||||
case pseudoEncodingVMwareCursor:
|
|
||||||
supportsVMWareCursor = true;
|
|
||||||
break;
|
|
||||||
case pseudoEncodingDesktopSize:
|
case pseudoEncodingDesktopSize:
|
||||||
supportsDesktopResize = true;
|
supportsDesktopResize = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -102,7 +102,6 @@ namespace rfb {
|
|||||||
bool supportsLocalCursor;
|
bool supportsLocalCursor;
|
||||||
bool supportsLocalXCursor;
|
bool supportsLocalXCursor;
|
||||||
bool supportsLocalCursorWithAlpha;
|
bool supportsLocalCursorWithAlpha;
|
||||||
bool supportsVMWareCursor;
|
|
||||||
bool supportsCursorPosition;
|
bool supportsCursorPosition;
|
||||||
bool supportsDesktopResize;
|
bool supportsDesktopResize;
|
||||||
bool supportsExtendedDesktopSize;
|
bool supportsExtendedDesktopSize;
|
||||||
|
|||||||
@@ -22,12 +22,10 @@
|
|||||||
#include <omp.h>
|
#include <omp.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <rfb/cpuid.h>
|
|
||||||
#include <rfb/EncCache.h>
|
#include <rfb/EncCache.h>
|
||||||
#include <rfb/EncodeManager.h>
|
#include <rfb/EncodeManager.h>
|
||||||
#include <rfb/Encoder.h>
|
#include <rfb/Encoder.h>
|
||||||
#include <rfb/Palette.h>
|
#include <rfb/Palette.h>
|
||||||
#include <rfb/scale_sse2.h>
|
|
||||||
#include <rfb/SConnection.h>
|
#include <rfb/SConnection.h>
|
||||||
#include <rfb/ServerCore.h>
|
#include <rfb/ServerCore.h>
|
||||||
#include <rfb/SMsgWriter.h>
|
#include <rfb/SMsgWriter.h>
|
||||||
@@ -361,8 +359,6 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,
|
|||||||
changed = changed_;
|
changed = changed_;
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
gettimeofday(&start, NULL);
|
||||||
memset(&jpegstats, 0, sizeof(codecstats_t));
|
|
||||||
memset(&webpstats, 0, sizeof(codecstats_t));
|
|
||||||
|
|
||||||
if (allowLossy && activeEncoders[encoderFullColour] == encoderTightWEBP) {
|
if (allowLossy && activeEncoders[encoderFullColour] == encoderTightWEBP) {
|
||||||
const unsigned rate = 1024 * 1000 / rfb::Server::frameRate;
|
const unsigned rate = 1024 * 1000 / rfb::Server::frameRate;
|
||||||
@@ -897,7 +893,7 @@ void EncodeManager::updateVideoStats(const std::vector<Rect> &rects, const Pixel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PixelBuffer *rfb::nearestScale(const PixelBuffer *pb, const uint16_t w, const uint16_t h,
|
static PixelBuffer *nearestScale(const PixelBuffer *pb, const uint16_t w, const uint16_t h,
|
||||||
const float diff)
|
const float diff)
|
||||||
{
|
{
|
||||||
ManagedPixelBuffer *newpb = new ManagedPixelBuffer(pb->getPF(), w, h);
|
ManagedPixelBuffer *newpb = new ManagedPixelBuffer(pb->getPF(), w, h);
|
||||||
@@ -922,7 +918,7 @@ PixelBuffer *rfb::nearestScale(const PixelBuffer *pb, const uint16_t w, const ui
|
|||||||
return newpb;
|
return newpb;
|
||||||
}
|
}
|
||||||
|
|
||||||
PixelBuffer *rfb::bilinearScale(const PixelBuffer *pb, const uint16_t w, const uint16_t h,
|
static PixelBuffer *bilinearScale(const PixelBuffer *pb, const uint16_t w, const uint16_t h,
|
||||||
const float diff)
|
const float diff)
|
||||||
{
|
{
|
||||||
ManagedPixelBuffer *newpb = new ManagedPixelBuffer(pb->getPF(), w, h);
|
ManagedPixelBuffer *newpb = new ManagedPixelBuffer(pb->getPF(), w, h);
|
||||||
@@ -970,68 +966,10 @@ PixelBuffer *rfb::bilinearScale(const PixelBuffer *pb, const uint16_t w, const u
|
|||||||
return newpb;
|
return newpb;
|
||||||
}
|
}
|
||||||
|
|
||||||
PixelBuffer *rfb::progressiveBilinearScale(const PixelBuffer *pb,
|
PixelBuffer *progressiveBilinearScale(const PixelBuffer *pb,
|
||||||
const uint16_t tgtw, const uint16_t tgth,
|
const uint16_t tgtw, const uint16_t tgth,
|
||||||
const float tgtdiff)
|
const float tgtdiff)
|
||||||
{
|
{
|
||||||
if (supportsSSE2()) {
|
|
||||||
if (tgtdiff >= 0.5f) {
|
|
||||||
ManagedPixelBuffer *newpb = new ManagedPixelBuffer(pb->getPF(), tgtw, tgth);
|
|
||||||
|
|
||||||
int oldstride, newstride;
|
|
||||||
const rdr::U8 *oldpx = pb->getBuffer(pb->getRect(), &oldstride);
|
|
||||||
rdr::U8 *newpx = newpb->getBufferRW(newpb->getRect(), &newstride);
|
|
||||||
|
|
||||||
SSE2_scale(oldpx, tgtw, tgth, newpx, oldstride, newstride, tgtdiff);
|
|
||||||
return newpb;
|
|
||||||
}
|
|
||||||
|
|
||||||
PixelBuffer *newpb;
|
|
||||||
uint16_t neww, newh, oldw, oldh;
|
|
||||||
bool del = false;
|
|
||||||
|
|
||||||
do {
|
|
||||||
oldw = pb->getRect().width();
|
|
||||||
oldh = pb->getRect().height();
|
|
||||||
neww = oldw / 2;
|
|
||||||
newh = oldh / 2;
|
|
||||||
|
|
||||||
newpb = new ManagedPixelBuffer(pb->getPF(), neww, newh);
|
|
||||||
|
|
||||||
int oldstride, newstride;
|
|
||||||
const rdr::U8 *oldpx = pb->getBuffer(pb->getRect(), &oldstride);
|
|
||||||
rdr::U8 *newpx = ((ManagedPixelBuffer *) newpb)->getBufferRW(newpb->getRect(),
|
|
||||||
&newstride);
|
|
||||||
|
|
||||||
SSE2_halve(oldpx, neww, newh, newpx, oldstride, newstride);
|
|
||||||
|
|
||||||
if (del)
|
|
||||||
delete pb;
|
|
||||||
del = true;
|
|
||||||
|
|
||||||
pb = newpb;
|
|
||||||
} while (tgtw * 2 < neww);
|
|
||||||
|
|
||||||
// Final, non-halving step
|
|
||||||
if (tgtw != neww || tgth != newh) {
|
|
||||||
oldw = pb->getRect().width();
|
|
||||||
oldh = pb->getRect().height();
|
|
||||||
|
|
||||||
newpb = new ManagedPixelBuffer(pb->getPF(), tgtw, tgth);
|
|
||||||
|
|
||||||
int oldstride, newstride;
|
|
||||||
const rdr::U8 *oldpx = pb->getBuffer(pb->getRect(), &oldstride);
|
|
||||||
rdr::U8 *newpx = ((ManagedPixelBuffer *) newpb)->getBufferRW(newpb->getRect(),
|
|
||||||
&newstride);
|
|
||||||
|
|
||||||
SSE2_scale(oldpx, tgtw, tgth, newpx, oldstride, newstride, tgtw / (float) oldw);
|
|
||||||
if (del)
|
|
||||||
delete pb;
|
|
||||||
}
|
|
||||||
|
|
||||||
return newpb;
|
|
||||||
} // SSE2
|
|
||||||
|
|
||||||
if (tgtdiff >= 0.5f)
|
if (tgtdiff >= 0.5f)
|
||||||
return bilinearScale(pb, tgtw, tgth, tgtdiff);
|
return bilinearScale(pb, tgtw, tgth, tgtdiff);
|
||||||
|
|
||||||
@@ -1076,7 +1014,6 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
|
|||||||
std::vector<uint8_t> isWebp, fromCache;
|
std::vector<uint8_t> isWebp, fromCache;
|
||||||
std::vector<Palette> palettes;
|
std::vector<Palette> palettes;
|
||||||
std::vector<std::vector<uint8_t> > compresseds;
|
std::vector<std::vector<uint8_t> > compresseds;
|
||||||
std::vector<uint32_t> ms;
|
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
if (rfb::Server::rectThreads > 0)
|
if (rfb::Server::rectThreads > 0)
|
||||||
@@ -1141,13 +1078,9 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
|
|||||||
palettes.resize(subrects.size());
|
palettes.resize(subrects.size());
|
||||||
compresseds.resize(subrects.size());
|
compresseds.resize(subrects.size());
|
||||||
scaledrects.resize(subrects.size());
|
scaledrects.resize(subrects.size());
|
||||||
ms.resize(subrects.size());
|
|
||||||
|
|
||||||
// In case the current resolution is above the max video res, and video was detected,
|
// In case the current resolution is above the max video res, and video was detected,
|
||||||
// scale to that res, keeping aspect ratio
|
// scale to that res, keeping aspect ratio
|
||||||
struct timeval scalestart;
|
|
||||||
gettimeofday(&scalestart, NULL);
|
|
||||||
|
|
||||||
const PixelBuffer *scaledpb = NULL;
|
const PixelBuffer *scaledpb = NULL;
|
||||||
if (videoDetected &&
|
if (videoDetected &&
|
||||||
(maxVideoX < pb->getRect().width() || maxVideoY < pb->getRect().height())) {
|
(maxVideoX < pb->getRect().width() || maxVideoY < pb->getRect().height())) {
|
||||||
@@ -1196,25 +1129,15 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scalingTime = msSince(&scalestart);
|
|
||||||
|
|
||||||
#pragma omp parallel for schedule(dynamic, 1)
|
#pragma omp parallel for schedule(dynamic, 1)
|
||||||
for (i = 0; i < subrects.size(); ++i) {
|
for (i = 0; i < subrects.size(); ++i) {
|
||||||
encoderTypes[i] = getEncoderType(subrects[i], pb, &palettes[i], compresseds[i],
|
encoderTypes[i] = getEncoderType(subrects[i], pb, &palettes[i], compresseds[i],
|
||||||
&isWebp[i], &fromCache[i],
|
&isWebp[i], &fromCache[i],
|
||||||
scaledpb, scaledrects[i], ms[i]);
|
scaledpb, scaledrects[i]);
|
||||||
checkWebpFallback(start);
|
checkWebpFallback(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < subrects.size(); ++i) {
|
|
||||||
if (encoderTypes[i] == encoderFullColour) {
|
|
||||||
if (isWebp[i])
|
|
||||||
webpstats.ms += ms[i];
|
|
||||||
else
|
|
||||||
jpegstats.ms += ms[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start) {
|
if (start) {
|
||||||
encodingTime = msSince(start);
|
encodingTime = msSince(start);
|
||||||
|
|
||||||
@@ -1255,8 +1178,7 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
|
|||||||
uint8_t EncodeManager::getEncoderType(const Rect& rect, const PixelBuffer *pb,
|
uint8_t EncodeManager::getEncoderType(const Rect& rect, const PixelBuffer *pb,
|
||||||
Palette *pal, std::vector<uint8_t> &compressed,
|
Palette *pal, std::vector<uint8_t> &compressed,
|
||||||
uint8_t *isWebp, uint8_t *fromCache,
|
uint8_t *isWebp, uint8_t *fromCache,
|
||||||
const PixelBuffer *scaledpb, const Rect& scaledrect,
|
const PixelBuffer *scaledpb, const Rect& scaledrect) const
|
||||||
uint32_t &ms) const
|
|
||||||
{
|
{
|
||||||
struct RectInfo info;
|
struct RectInfo info;
|
||||||
unsigned int maxColours = 256;
|
unsigned int maxColours = 256;
|
||||||
@@ -1309,12 +1231,9 @@ uint8_t EncodeManager::getEncoderType(const Rect& rect, const PixelBuffer *pb,
|
|||||||
|
|
||||||
*isWebp = 0;
|
*isWebp = 0;
|
||||||
*fromCache = 0;
|
*fromCache = 0;
|
||||||
ms = 0;
|
|
||||||
if (type == encoderFullColour) {
|
if (type == encoderFullColour) {
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
const void *data;
|
const void *data;
|
||||||
struct timeval start;
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
|
|
||||||
if (encCache->enabled &&
|
if (encCache->enabled &&
|
||||||
(data = encCache->get(activeEncoders[encoderFullColour],
|
(data = encCache->get(activeEncoders[encoderFullColour],
|
||||||
@@ -1355,8 +1274,6 @@ uint8_t EncodeManager::getEncoderType(const Rect& rect, const PixelBuffer *pb,
|
|||||||
compressed,
|
compressed,
|
||||||
videoDetected);
|
videoDetected);
|
||||||
}
|
}
|
||||||
|
|
||||||
ms = msSince(&start);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete ppb;
|
delete ppb;
|
||||||
@@ -1375,15 +1292,10 @@ void EncodeManager::writeSubRect(const Rect& rect, const PixelBuffer *pb,
|
|||||||
encoder = startRect(rect, type, compressed.size() == 0, isWebp);
|
encoder = startRect(rect, type, compressed.size() == 0, isWebp);
|
||||||
|
|
||||||
if (compressed.size()) {
|
if (compressed.size()) {
|
||||||
if (isWebp) {
|
if (isWebp)
|
||||||
((TightWEBPEncoder *) encoder)->writeOnly(compressed);
|
((TightWEBPEncoder *) encoder)->writeOnly(compressed);
|
||||||
webpstats.area += rect.area();
|
else
|
||||||
webpstats.rects++;
|
|
||||||
} else {
|
|
||||||
((TightJPEGEncoder *) encoder)->writeOnly(compressed);
|
((TightJPEGEncoder *) encoder)->writeOnly(compressed);
|
||||||
jpegstats.area += rect.area();
|
|
||||||
jpegstats.rects++;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (encoder->flags & EncoderUseNativePF) {
|
if (encoder->flags & EncoderUseNativePF) {
|
||||||
ppb = preparePixelBuffer(rect, pb, false);
|
ppb = preparePixelBuffer(rect, pb, false);
|
||||||
|
|||||||
@@ -68,24 +68,9 @@ namespace rfb {
|
|||||||
const RenderedCursor* renderedCursor,
|
const RenderedCursor* renderedCursor,
|
||||||
size_t maxUpdateSize);
|
size_t maxUpdateSize);
|
||||||
|
|
||||||
void clearEncodingTime() {
|
|
||||||
encodingTime = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned getEncodingTime() const {
|
unsigned getEncodingTime() const {
|
||||||
return encodingTime;
|
return encodingTime;
|
||||||
};
|
};
|
||||||
unsigned getScalingTime() const {
|
|
||||||
return scalingTime;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct codecstats_t {
|
|
||||||
uint32_t ms;
|
|
||||||
uint32_t area;
|
|
||||||
uint32_t rects;
|
|
||||||
};
|
|
||||||
|
|
||||||
codecstats_t jpegstats, webpstats;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void doUpdate(bool allowLossy, const Region& changed,
|
void doUpdate(bool allowLossy, const Region& changed,
|
||||||
@@ -120,8 +105,7 @@ namespace rfb {
|
|||||||
uint8_t getEncoderType(const Rect& rect, const PixelBuffer *pb, Palette *pal,
|
uint8_t getEncoderType(const Rect& rect, const PixelBuffer *pb, Palette *pal,
|
||||||
std::vector<uint8_t> &compressed, uint8_t *isWebp,
|
std::vector<uint8_t> &compressed, uint8_t *isWebp,
|
||||||
uint8_t *fromCache,
|
uint8_t *fromCache,
|
||||||
const PixelBuffer *scaledpb, const Rect& scaledrect,
|
const PixelBuffer *scaledpb, const Rect& scaledrect) const;
|
||||||
uint32_t &ms) const;
|
|
||||||
virtual bool handleTimeout(Timer* t);
|
virtual bool handleTimeout(Timer* t);
|
||||||
|
|
||||||
bool checkSolidTile(const Rect& r, const rdr::U8* colourValue,
|
bool checkSolidTile(const Rect& r, const rdr::U8* colourValue,
|
||||||
@@ -199,7 +183,6 @@ namespace rfb {
|
|||||||
bool webpTookTooLong;
|
bool webpTookTooLong;
|
||||||
unsigned encodingTime;
|
unsigned encodingTime;
|
||||||
unsigned maxEncodingTime, framesSinceEncPrint;
|
unsigned maxEncodingTime, framesSinceEncPrint;
|
||||||
unsigned scalingTime;
|
|
||||||
|
|
||||||
EncCache *encCache;
|
EncCache *encCache;
|
||||||
|
|
||||||
@@ -215,13 +198,6 @@ namespace rfb {
|
|||||||
virtual rdr::U8* getBufferRW(const Rect& r, int* stride);
|
virtual rdr::U8* getBufferRW(const Rect& r, int* stride);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
PixelBuffer *nearestScale(const PixelBuffer *pb, const uint16_t w, const uint16_t h,
|
|
||||||
const float diff);
|
|
||||||
PixelBuffer *bilinearScale(const PixelBuffer *pb, const uint16_t w, const uint16_t h,
|
|
||||||
const float diff);
|
|
||||||
PixelBuffer *progressiveBilinearScale(const PixelBuffer *pb, const uint16_t w, const uint16_t h,
|
|
||||||
const float diff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -36,11 +36,10 @@ namespace rfb {
|
|||||||
rdr::U32 __unused_attr keycode,
|
rdr::U32 __unused_attr keycode,
|
||||||
bool __unused_attr down) { }
|
bool __unused_attr down) { }
|
||||||
virtual void pointerEvent(const Point& __unused_attr pos,
|
virtual void pointerEvent(const Point& __unused_attr pos,
|
||||||
|
const Point& __unused_attr abspos,
|
||||||
int __unused_attr buttonMask,
|
int __unused_attr buttonMask,
|
||||||
const bool __unused_attr skipClick,
|
const bool __unused_attr skipClick,
|
||||||
const bool __unused_attr skipRelease,
|
const bool __unused_attr skipRelease) { }
|
||||||
int scrollX,
|
|
||||||
int scrollY) { }
|
|
||||||
virtual void clientCutText(const char* __unused_attr str,
|
virtual void clientCutText(const char* __unused_attr str,
|
||||||
int __unused_attr len) { }
|
int __unused_attr len) { }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -284,26 +284,74 @@ void SConnection::setEncodings(int nEncodings, const rdr::S32* encodings)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SMsgHandler::setEncodings(nEncodings, encodings);
|
SMsgHandler::setEncodings(nEncodings, encodings);
|
||||||
|
|
||||||
|
if (cp.supportsExtendedClipboard) {
|
||||||
|
rdr::U32 sizes[] = { 0 };
|
||||||
|
writer()->writeClipboardCaps(rfb::clipboardUTF8 |
|
||||||
|
rfb::clipboardRequest |
|
||||||
|
rfb::clipboardPeek |
|
||||||
|
rfb::clipboardNotify |
|
||||||
|
rfb::clipboardProvide,
|
||||||
|
sizes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConnection::clearBinaryClipboard()
|
void SConnection::clientCutText(const char* str, int len)
|
||||||
{
|
{
|
||||||
binaryClipboard.clear();
|
hasLocalClipboard = false;
|
||||||
|
|
||||||
|
strFree(clientClipboard);
|
||||||
|
clientClipboard = NULL;
|
||||||
|
|
||||||
|
clientClipboard = latin1ToUTF8(str);
|
||||||
|
|
||||||
|
handleClipboardAnnounce(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConnection::addBinaryClipboard(const char mime[], const rdr::U8 *data,
|
void SConnection::handleClipboardRequest(rdr::U32 flags)
|
||||||
const rdr::U32 len)
|
|
||||||
{
|
{
|
||||||
binaryClipboard_t bin;
|
if (!(flags & rfb::clipboardUTF8))
|
||||||
strncpy(bin.mime, mime, sizeof(bin.mime));
|
return;
|
||||||
bin.mime[sizeof(bin.mime) - 1] = '\0';
|
if (!hasLocalClipboard)
|
||||||
|
return;
|
||||||
bin.data.resize(len);
|
handleClipboardRequest();
|
||||||
memcpy(&bin.data[0], data, len);
|
|
||||||
|
|
||||||
binaryClipboard.push_back(bin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SConnection::handleClipboardPeek(rdr::U32 flags)
|
||||||
|
{
|
||||||
|
if (!hasLocalClipboard)
|
||||||
|
return;
|
||||||
|
if (cp.clipboardFlags() & rfb::clipboardNotify)
|
||||||
|
writer()->writeClipboardNotify(rfb::clipboardUTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SConnection::handleClipboardNotify(rdr::U32 flags)
|
||||||
|
{
|
||||||
|
strFree(clientClipboard);
|
||||||
|
clientClipboard = NULL;
|
||||||
|
|
||||||
|
if (flags & rfb::clipboardUTF8) {
|
||||||
|
handleClipboardAnnounce(true);
|
||||||
|
hasLocalClipboard = false;
|
||||||
|
} else {
|
||||||
|
handleClipboardAnnounce(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SConnection::handleClipboardProvide(rdr::U32 flags,
|
||||||
|
const size_t* lengths,
|
||||||
|
const rdr::U8* const* data)
|
||||||
|
{
|
||||||
|
if (!(flags & rfb::clipboardUTF8))
|
||||||
|
return;
|
||||||
|
|
||||||
|
strFree(clientClipboard);
|
||||||
|
clientClipboard = NULL;
|
||||||
|
|
||||||
|
clientClipboard = convertLF((const char*)data[0], lengths[0]);
|
||||||
|
|
||||||
|
handleClipboardData(clientClipboard, strlen(clientClipboard));
|
||||||
|
}
|
||||||
|
|
||||||
void SConnection::supportsQEMUKeyEvent()
|
void SConnection::supportsQEMUKeyEvent()
|
||||||
{
|
{
|
||||||
@@ -397,13 +445,56 @@ void SConnection::enableContinuousUpdates(bool enable,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SConnection::handleClipboardRequest()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void SConnection::handleClipboardAnnounce(bool available)
|
void SConnection::handleClipboardAnnounce(bool available)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SConnection::handleClipboardData(const char* data, int len)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SConnection::requestClipboard()
|
||||||
|
{
|
||||||
|
if (clientClipboard != NULL) {
|
||||||
|
handleClipboardData(clientClipboard, strlen(clientClipboard));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cp.supportsExtendedClipboard &&
|
||||||
|
(cp.clipboardFlags() & rfb::clipboardRequest))
|
||||||
|
writer()->writeClipboardRequest(rfb::clipboardUTF8);
|
||||||
|
}
|
||||||
|
|
||||||
void SConnection::announceClipboard(bool available)
|
void SConnection::announceClipboard(bool available)
|
||||||
{
|
{
|
||||||
hasLocalClipboard = available;
|
hasLocalClipboard = available;
|
||||||
|
|
||||||
|
if (cp.supportsExtendedClipboard &&
|
||||||
|
(cp.clipboardFlags() & rfb::clipboardNotify))
|
||||||
|
writer()->writeClipboardNotify(available ? rfb::clipboardUTF8 : 0);
|
||||||
|
else {
|
||||||
|
if (available)
|
||||||
|
handleClipboardRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SConnection::sendClipboardData(const char* data, int len)
|
||||||
|
{
|
||||||
|
if (cp.supportsExtendedClipboard &&
|
||||||
|
(cp.clipboardFlags() & rfb::clipboardProvide)) {
|
||||||
|
CharArray filtered(convertCRLF(data));
|
||||||
|
size_t sizes[1] = { strlen(filtered.buf) + 1 };
|
||||||
|
const rdr::U8* data[1] = { (const rdr::U8*)filtered.buf };
|
||||||
|
writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data);
|
||||||
|
} else {
|
||||||
|
CharArray latin1(utf8ToLatin1(data));
|
||||||
|
|
||||||
|
writer()->writeServerCutText(latin1.buf, strlen(latin1.buf));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConnection::writeFakeColourMap(void)
|
void SConnection::writeFakeColourMap(void)
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
#include <rdr/OutStream.h>
|
#include <rdr/OutStream.h>
|
||||||
#include <rfb/SMsgHandler.h>
|
#include <rfb/SMsgHandler.h>
|
||||||
#include <rfb/SecurityServer.h>
|
#include <rfb/SecurityServer.h>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace rfb {
|
namespace rfb {
|
||||||
|
|
||||||
@@ -74,9 +73,14 @@ namespace rfb {
|
|||||||
|
|
||||||
virtual void setEncodings(int nEncodings, const rdr::S32* encodings);
|
virtual void setEncodings(int nEncodings, const rdr::S32* encodings);
|
||||||
|
|
||||||
virtual void clearBinaryClipboard();
|
virtual void clientCutText(const char* str, int len);
|
||||||
virtual void addBinaryClipboard(const char mime[], const rdr::U8 *data,
|
|
||||||
const rdr::U32 len);
|
virtual void handleClipboardRequest(rdr::U32 flags);
|
||||||
|
virtual void handleClipboardPeek(rdr::U32 flags);
|
||||||
|
virtual void handleClipboardNotify(rdr::U32 flags);
|
||||||
|
virtual void handleClipboardProvide(rdr::U32 flags,
|
||||||
|
const size_t* lengths,
|
||||||
|
const rdr::U8* const* data);
|
||||||
|
|
||||||
virtual void supportsQEMUKeyEvent();
|
virtual void supportsQEMUKeyEvent();
|
||||||
|
|
||||||
@@ -123,11 +127,25 @@ namespace rfb {
|
|||||||
virtual void enableContinuousUpdates(bool enable,
|
virtual void enableContinuousUpdates(bool enable,
|
||||||
int x, int y, int w, int h);
|
int x, int y, int w, int h);
|
||||||
|
|
||||||
|
// handleClipboardRequest() is called whenever the client requests
|
||||||
|
// the server to send over its clipboard data. It will only be
|
||||||
|
// called after the server has first announced a clipboard change
|
||||||
|
// via announceClipboard().
|
||||||
|
virtual void handleClipboardRequest();
|
||||||
|
|
||||||
// handleClipboardAnnounce() is called to indicate a change in the
|
// handleClipboardAnnounce() is called to indicate a change in the
|
||||||
// clipboard on the client. Call requestClipboard() to access the
|
// clipboard on the client. Call requestClipboard() to access the
|
||||||
// actual data.
|
// actual data.
|
||||||
virtual void handleClipboardAnnounce(bool available);
|
virtual void handleClipboardAnnounce(bool available);
|
||||||
|
|
||||||
|
// handleClipboardData() is called when the client has sent over
|
||||||
|
// the clipboard data as a result of a previous call to
|
||||||
|
// requestClipboard(). Note that this function might never be
|
||||||
|
// called if the clipboard data was no longer available when the
|
||||||
|
// client received the request.
|
||||||
|
virtual void handleClipboardData(const char* data, int len);
|
||||||
|
|
||||||
|
|
||||||
virtual void add_changed_all() {}
|
virtual void add_changed_all() {}
|
||||||
|
|
||||||
// setAccessRights() allows a security package to limit the access rights
|
// setAccessRights() allows a security package to limit the access rights
|
||||||
@@ -148,11 +166,22 @@ namespace rfb {
|
|||||||
|
|
||||||
// Other methods
|
// Other methods
|
||||||
|
|
||||||
|
// requestClipboard() will result in a request to the client to
|
||||||
|
// transfer its clipboard data. A call to handleClipboardData()
|
||||||
|
// will be made once the data is available.
|
||||||
|
virtual void requestClipboard();
|
||||||
|
|
||||||
// announceClipboard() informs the client of changes to the
|
// announceClipboard() informs the client of changes to the
|
||||||
// clipboard on the server. The client may later request the
|
// clipboard on the server. The client may later request the
|
||||||
// clipboard data via handleClipboardRequest().
|
// clipboard data via handleClipboardRequest().
|
||||||
virtual void announceClipboard(bool available);
|
virtual void announceClipboard(bool available);
|
||||||
|
|
||||||
|
// sendClipboardData() transfers the clipboard data to the client
|
||||||
|
// and should be called whenever the client has requested the
|
||||||
|
// clipboard via handleClipboardRequest().
|
||||||
|
virtual void sendClipboardData(const char* data, int len);
|
||||||
|
|
||||||
|
|
||||||
// authenticated() returns true if the client has authenticated
|
// authenticated() returns true if the client has authenticated
|
||||||
// successfully.
|
// successfully.
|
||||||
bool authenticated() { return (state_ == RFBSTATE_INITIALISATION ||
|
bool authenticated() { return (state_ == RFBSTATE_INITIALISATION ||
|
||||||
@@ -192,19 +221,12 @@ namespace rfb {
|
|||||||
|
|
||||||
rdr::S32 getPreferredEncoding() { return preferredEncoding; }
|
rdr::S32 getPreferredEncoding() { return preferredEncoding; }
|
||||||
|
|
||||||
struct binaryClipboard_t {
|
|
||||||
char mime[32];
|
|
||||||
std::vector<unsigned char> data;
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setState(stateEnum s) { state_ = s; }
|
void setState(stateEnum s) { state_ = s; }
|
||||||
|
|
||||||
void setReader(SMsgReader *r) { reader_ = r; }
|
void setReader(SMsgReader *r) { reader_ = r; }
|
||||||
void setWriter(SMsgWriter *w) { writer_ = w; }
|
void setWriter(SMsgWriter *w) { writer_ = w; }
|
||||||
|
|
||||||
std::vector<binaryClipboard_t> binaryClipboard;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void writeFakeColourMap(void);
|
void writeFakeColourMap(void);
|
||||||
|
|
||||||
@@ -230,7 +252,4 @@ namespace rfb {
|
|||||||
bool hasLocalClipboard;
|
bool hasLocalClipboard;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#define WRITER_PERMS (AccessKeyEvents | AccessPtrEvents | AccessCutText | AccessSetDesktopSize)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -78,13 +78,23 @@ namespace rfb {
|
|||||||
// the relevant RFB protocol messages from clients.
|
// the relevant RFB protocol messages from clients.
|
||||||
// See InputHandler for method signatures.
|
// See InputHandler for method signatures.
|
||||||
|
|
||||||
|
// handleClipboardRequest() is called whenever a client requests
|
||||||
|
// the server to send over its clipboard data. It will only be
|
||||||
|
// called after the server has first announced a clipboard change
|
||||||
|
// via VNCServer::announceClipboard().
|
||||||
|
virtual void handleClipboardRequest() {}
|
||||||
|
|
||||||
// handleClipboardAnnounce() is called to indicate a change in the
|
// handleClipboardAnnounce() is called to indicate a change in the
|
||||||
// clipboard on a client. Call VNCServer::requestClipboard() to
|
// clipboard on a client. Call VNCServer::requestClipboard() to
|
||||||
// access the actual data.
|
// access the actual data.
|
||||||
virtual void handleClipboardAnnounce(bool __unused_attr available) {}
|
virtual void handleClipboardAnnounce(bool __unused_attr available) {}
|
||||||
|
|
||||||
virtual void handleClipboardAnnounceBinary(const unsigned __unused_attr num,
|
// handleClipboardData() is called when a client has sent over
|
||||||
const char __unused_attr mimes[][32]) {}
|
// the clipboard data as a result of a previous call to
|
||||||
|
// VNCServer::requestClipboard(). Note that this function might
|
||||||
|
// never be called if the clipboard data was no longer available
|
||||||
|
// when the client received the request.
|
||||||
|
virtual void handleClipboardData(const char* __unused_attr data, int len __unused_attr) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~SDesktop() {}
|
virtual ~SDesktop() {}
|
||||||
|
|||||||
@@ -64,16 +64,26 @@ void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings)
|
|||||||
supportsQEMUKeyEvent();
|
supportsQEMUKeyEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgHandler::handleClipboardAnnounceBinary(const unsigned, const char mimes[][32])
|
void SMsgHandler::handleClipboardCaps(rdr::U32 flags, const rdr::U32* lengths)
|
||||||
|
{
|
||||||
|
cp.setClipboardCaps(flags, lengths);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMsgHandler::handleClipboardRequest(rdr::U32 flags)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgHandler::clearBinaryClipboard()
|
void SMsgHandler::handleClipboardPeek(rdr::U32 flags)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgHandler::addBinaryClipboard(const char mime[], const rdr::U8 *data,
|
void SMsgHandler::handleClipboardNotify(rdr::U32 flags)
|
||||||
const rdr::U32 len)
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMsgHandler::handleClipboardProvide(rdr::U32 flags,
|
||||||
|
const size_t* lengths,
|
||||||
|
const rdr::U8* const* data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,13 +54,16 @@ namespace rfb {
|
|||||||
virtual void enableContinuousUpdates(bool enable,
|
virtual void enableContinuousUpdates(bool enable,
|
||||||
int x, int y, int w, int h) = 0;
|
int x, int y, int w, int h) = 0;
|
||||||
|
|
||||||
virtual void handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
|
virtual void handleClipboardCaps(rdr::U32 flags,
|
||||||
virtual void clearBinaryClipboard();
|
const rdr::U32* lengths);
|
||||||
virtual void addBinaryClipboard(const char mime[], const rdr::U8 *data,
|
virtual void handleClipboardRequest(rdr::U32 flags);
|
||||||
const rdr::U32 len);
|
virtual void handleClipboardPeek(rdr::U32 flags);
|
||||||
|
virtual void handleClipboardNotify(rdr::U32 flags);
|
||||||
|
virtual void handleClipboardProvide(rdr::U32 flags,
|
||||||
|
const size_t* lengths,
|
||||||
|
const rdr::U8* const* data);
|
||||||
|
|
||||||
virtual void sendStats(const bool toClient = true) = 0;
|
virtual void sendStats() = 0;
|
||||||
virtual void handleFrameStats(rdr::U32 all, rdr::U32 render) = 0;
|
|
||||||
|
|
||||||
virtual bool canChangeKasmSettings() const = 0;
|
virtual bool canChangeKasmSettings() const = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ using namespace rfb;
|
|||||||
|
|
||||||
static LogWriter vlog("SMsgReader");
|
static LogWriter vlog("SMsgReader");
|
||||||
|
|
||||||
|
static IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);
|
||||||
|
|
||||||
SMsgReader::SMsgReader(SMsgHandler* handler_, rdr::InStream* is_)
|
SMsgReader::SMsgReader(SMsgHandler* handler_, rdr::InStream* is_)
|
||||||
: handler(handler_), is(is_)
|
: handler(handler_), is(is_)
|
||||||
{
|
{
|
||||||
@@ -78,12 +80,6 @@ void SMsgReader::readMsg()
|
|||||||
case msgTypeRequestStats:
|
case msgTypeRequestStats:
|
||||||
readRequestStats();
|
readRequestStats();
|
||||||
break;
|
break;
|
||||||
case msgTypeFrameStats:
|
|
||||||
readFrameStats();
|
|
||||||
break;
|
|
||||||
case msgTypeBinaryClipboard:
|
|
||||||
readBinaryClipboard();
|
|
||||||
break;
|
|
||||||
case msgTypeKeyEvent:
|
case msgTypeKeyEvent:
|
||||||
readKeyEvent();
|
readKeyEvent();
|
||||||
break;
|
break;
|
||||||
@@ -224,9 +220,7 @@ void SMsgReader::readPointerEvent()
|
|||||||
int mask = is->readU8();
|
int mask = is->readU8();
|
||||||
int x = is->readU16();
|
int x = is->readU16();
|
||||||
int y = is->readU16();
|
int y = is->readU16();
|
||||||
int scrollX = is->readS16();
|
handler->pointerEvent(Point(x, y), Point(0, 0), mask, false, false);
|
||||||
int scrollY = is->readS16();
|
|
||||||
handler->pointerEvent(Point(x, y), mask, false, false, scrollX, scrollY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -241,54 +235,109 @@ void SMsgReader::readClientCutText()
|
|||||||
readExtendedClipboard(slen);
|
readExtendedClipboard(slen);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (len > (size_t)maxCutText) {
|
||||||
is->skip(len);
|
is->skip(len);
|
||||||
vlog.error("Client sent old cuttext msg, ignoring");
|
vlog.error("Cut text too long (%d bytes) - ignoring", len);
|
||||||
}
|
return;
|
||||||
|
|
||||||
void SMsgReader::readBinaryClipboard()
|
|
||||||
{
|
|
||||||
const rdr::U8 num = is->readU8();
|
|
||||||
rdr::U8 i, valid = 0;
|
|
||||||
char tmpmimes[num][32];
|
|
||||||
|
|
||||||
handler->clearBinaryClipboard();
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
const rdr::U8 mimelen = is->readU8();
|
|
||||||
if (mimelen > 32 - 1) {
|
|
||||||
vlog.error("Mime too long (%u)", mimelen);
|
|
||||||
}
|
}
|
||||||
|
CharArray ca(len+1);
|
||||||
char mime[mimelen + 1];
|
ca.buf[len] = 0;
|
||||||
mime[mimelen] = '\0';
|
|
||||||
is->readBytes(mime, mimelen);
|
|
||||||
|
|
||||||
strncpy(tmpmimes[valid], mime, 32);
|
|
||||||
tmpmimes[valid][31] = '\0';
|
|
||||||
|
|
||||||
const rdr::U32 len = is->readU32();
|
|
||||||
CharArray ca(len);
|
|
||||||
is->readBytes(ca.buf, len);
|
is->readBytes(ca.buf, len);
|
||||||
|
handler->clientCutText(ca.buf, len);
|
||||||
if (rfb::Server::DLP_ClipAcceptMax && len > (unsigned) rfb::Server::DLP_ClipAcceptMax) {
|
|
||||||
vlog.info("DLP: refused to receive binary clipboard, too large");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
vlog.debug("Received binary clipboard, type %s, %u bytes", mime, len);
|
|
||||||
|
|
||||||
handler->addBinaryClipboard(mime, (rdr::U8 *) ca.buf, len);
|
|
||||||
valid++;
|
|
||||||
}
|
|
||||||
|
|
||||||
handler->handleClipboardAnnounceBinary(valid, tmpmimes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgReader::readExtendedClipboard(rdr::S32 len)
|
void SMsgReader::readExtendedClipboard(rdr::S32 len)
|
||||||
{
|
{
|
||||||
|
rdr::U32 flags;
|
||||||
|
rdr::U32 action;
|
||||||
|
|
||||||
if (len < 4)
|
if (len < 4)
|
||||||
throw Exception("Invalid extended clipboard message");
|
throw Exception("Invalid extended clipboard message");
|
||||||
vlog.error("Client sent old cuttext msg, ignoring");
|
if (len > maxCutText) {
|
||||||
|
vlog.error("Extended clipboard message too long (%d bytes) - ignoring", len);
|
||||||
is->skip(len);
|
is->skip(len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = is->readU32();
|
||||||
|
action = flags & clipboardActionMask;
|
||||||
|
|
||||||
|
if (action & clipboardCaps) {
|
||||||
|
int i;
|
||||||
|
size_t num;
|
||||||
|
rdr::U32 lengths[16];
|
||||||
|
|
||||||
|
num = 0;
|
||||||
|
for (i = 0;i < 16;i++) {
|
||||||
|
if (flags & (1 << i))
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < (rdr::S32)(4 + 4*num))
|
||||||
|
throw Exception("Invalid extended clipboard message");
|
||||||
|
|
||||||
|
num = 0;
|
||||||
|
for (i = 0;i < 16;i++) {
|
||||||
|
if (flags & (1 << i))
|
||||||
|
lengths[num++] = is->readU32();
|
||||||
|
}
|
||||||
|
|
||||||
|
handler->handleClipboardCaps(flags, lengths);
|
||||||
|
} else if (action == clipboardProvide) {
|
||||||
|
rdr::ZlibInStream zis;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
size_t num;
|
||||||
|
size_t lengths[16];
|
||||||
|
rdr::U8* buffers[16];
|
||||||
|
|
||||||
|
zis.setUnderlying(is, len - 4);
|
||||||
|
|
||||||
|
num = 0;
|
||||||
|
for (i = 0;i < 16;i++) {
|
||||||
|
if (!(flags & 1 << i))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
lengths[num] = zis.readU32();
|
||||||
|
if (lengths[num] > (size_t)maxCutText) {
|
||||||
|
vlog.error("Extended clipboard data too long (%d bytes) - ignoring",
|
||||||
|
(unsigned)lengths[num]);
|
||||||
|
zis.skip(lengths[num]);
|
||||||
|
flags &= ~(1 << i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffers[num] = new rdr::U8[lengths[num]];
|
||||||
|
zis.readBytes(buffers[num], lengths[num]);
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
zis.flushUnderlying();
|
||||||
|
zis.setUnderlying(NULL, 0);
|
||||||
|
|
||||||
|
handler->handleClipboardProvide(flags, lengths, buffers);
|
||||||
|
|
||||||
|
num = 0;
|
||||||
|
for (i = 0;i < 16;i++) {
|
||||||
|
if (!(flags & 1 << i))
|
||||||
|
continue;
|
||||||
|
delete [] buffers[num++];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (action) {
|
||||||
|
case clipboardRequest:
|
||||||
|
handler->handleClipboardRequest(flags);
|
||||||
|
break;
|
||||||
|
case clipboardPeek:
|
||||||
|
handler->handleClipboardPeek(flags);
|
||||||
|
break;
|
||||||
|
case clipboardNotify:
|
||||||
|
handler->handleClipboardNotify(flags);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw Exception("Invalid extended clipboard action");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgReader::readRequestStats()
|
void SMsgReader::readRequestStats()
|
||||||
@@ -297,14 +346,6 @@ void SMsgReader::readRequestStats()
|
|||||||
handler->sendStats();
|
handler->sendStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgReader::readFrameStats()
|
|
||||||
{
|
|
||||||
is->skip(3);
|
|
||||||
rdr::U32 all = is->readU32();
|
|
||||||
rdr::U32 render = is->readU32();
|
|
||||||
handler->handleFrameStats(all, render);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMsgReader::readQEMUMessage()
|
void SMsgReader::readQEMUMessage()
|
||||||
{
|
{
|
||||||
int subType = is->readU8();
|
int subType = is->readU8();
|
||||||
|
|||||||
@@ -57,8 +57,6 @@ namespace rfb {
|
|||||||
void readClientCutText();
|
void readClientCutText();
|
||||||
void readExtendedClipboard(rdr::S32 len);
|
void readExtendedClipboard(rdr::S32 len);
|
||||||
void readRequestStats();
|
void readRequestStats();
|
||||||
void readFrameStats();
|
|
||||||
void readBinaryClipboard();
|
|
||||||
|
|
||||||
void readQEMUMessage();
|
void readQEMUMessage();
|
||||||
void readQEMUKeyEvent();
|
void readQEMUKeyEvent();
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
|
|||||||
needSetDesktopSize(false), needExtendedDesktopSize(false),
|
needSetDesktopSize(false), needExtendedDesktopSize(false),
|
||||||
needSetDesktopName(false), needSetCursor(false),
|
needSetDesktopName(false), needSetCursor(false),
|
||||||
needSetXCursor(false), needSetCursorWithAlpha(false),
|
needSetXCursor(false), needSetCursorWithAlpha(false),
|
||||||
needSetVMWareCursor(false),
|
|
||||||
needCursorPos(false),
|
needCursorPos(false),
|
||||||
needLEDState(false), needQEMUKeyEvent(false)
|
needLEDState(false), needQEMUKeyEvent(false)
|
||||||
{
|
{
|
||||||
@@ -85,21 +84,118 @@ void SMsgWriter::writeBell()
|
|||||||
endMsg();
|
endMsg();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgWriter::writeBinaryClipboard(const std::vector<SConnection::binaryClipboard_t> &b)
|
void SMsgWriter::writeServerCutText(const char* str, int len)
|
||||||
{
|
{
|
||||||
startMsg(msgTypeBinaryClipboard);
|
startMsg(msgTypeServerCutText);
|
||||||
|
os->pad(3);
|
||||||
|
os->writeU32(len);
|
||||||
|
os->writeBytes(str, len);
|
||||||
|
endMsg();
|
||||||
|
}
|
||||||
|
|
||||||
os->writeU8(b.size());
|
void SMsgWriter::writeClipboardCaps(rdr::U32 caps,
|
||||||
rdr::U8 i;
|
const rdr::U32* lengths)
|
||||||
for (i = 0; i < b.size(); i++) {
|
{
|
||||||
const rdr::U8 mimelen = strlen(b[i].mime);
|
size_t i, count;
|
||||||
os->writeU8(mimelen);
|
|
||||||
os->writeBytes(b[i].mime, mimelen);
|
|
||||||
|
|
||||||
os->writeU32(b[i].data.size());
|
if (!cp->supportsExtendedClipboard)
|
||||||
os->writeBytes(&b[i].data[0], b[i].data.size());
|
throw Exception("Client does not support extended clipboard");
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
for (i = 0;i < 16;i++) {
|
||||||
|
if (caps & (1 << i))
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startMsg(msgTypeServerCutText);
|
||||||
|
os->pad(3);
|
||||||
|
os->writeS32(-(4 + 4 * count));
|
||||||
|
|
||||||
|
os->writeU32(caps | clipboardCaps);
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
for (i = 0;i < 16;i++) {
|
||||||
|
if (caps & (1 << i))
|
||||||
|
os->writeU32(lengths[count++]);
|
||||||
|
}
|
||||||
|
|
||||||
|
endMsg();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMsgWriter::writeClipboardRequest(rdr::U32 flags)
|
||||||
|
{
|
||||||
|
if (!cp->supportsExtendedClipboard)
|
||||||
|
throw Exception("Client does not support extended clipboard");
|
||||||
|
if (!(cp->clipboardFlags() & clipboardRequest))
|
||||||
|
throw Exception("Client does not support clipboard \"request\" action");
|
||||||
|
|
||||||
|
startMsg(msgTypeServerCutText);
|
||||||
|
os->pad(3);
|
||||||
|
os->writeS32(-4);
|
||||||
|
os->writeU32(flags | clipboardRequest);
|
||||||
|
endMsg();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMsgWriter::writeClipboardPeek(rdr::U32 flags)
|
||||||
|
{
|
||||||
|
if (!cp->supportsExtendedClipboard)
|
||||||
|
throw Exception("Client does not support extended clipboard");
|
||||||
|
if (!(cp->clipboardFlags() & clipboardPeek))
|
||||||
|
throw Exception("Client does not support clipboard \"peek\" action");
|
||||||
|
|
||||||
|
startMsg(msgTypeServerCutText);
|
||||||
|
os->pad(3);
|
||||||
|
os->writeS32(-4);
|
||||||
|
os->writeU32(flags | clipboardPeek);
|
||||||
|
endMsg();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMsgWriter::writeClipboardNotify(rdr::U32 flags)
|
||||||
|
{
|
||||||
|
if (!cp->supportsExtendedClipboard)
|
||||||
|
throw Exception("Client does not support extended clipboard");
|
||||||
|
if (!(cp->clipboardFlags() & clipboardNotify))
|
||||||
|
throw Exception("Client does not support clipboard \"notify\" action");
|
||||||
|
|
||||||
|
startMsg(msgTypeServerCutText);
|
||||||
|
os->pad(3);
|
||||||
|
os->writeS32(-4);
|
||||||
|
os->writeU32(flags | clipboardNotify);
|
||||||
|
endMsg();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMsgWriter::writeClipboardProvide(rdr::U32 flags,
|
||||||
|
const size_t* lengths,
|
||||||
|
const rdr::U8* const* data)
|
||||||
|
{
|
||||||
|
rdr::MemOutStream mos;
|
||||||
|
rdr::ZlibOutStream zos;
|
||||||
|
|
||||||
|
int i, count;
|
||||||
|
|
||||||
|
if (!cp->supportsExtendedClipboard)
|
||||||
|
throw Exception("Client does not support extended clipboard");
|
||||||
|
if (!(cp->clipboardFlags() & clipboardProvide))
|
||||||
|
throw Exception("Client does not support clipboard \"provide\" action");
|
||||||
|
|
||||||
|
zos.setUnderlying(&mos);
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
for (i = 0;i < 16;i++) {
|
||||||
|
if (!(flags & (1 << i)))
|
||||||
|
continue;
|
||||||
|
zos.writeU32(lengths[count]);
|
||||||
|
zos.writeBytes(data[count], lengths[count]);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
zos.flush();
|
||||||
|
|
||||||
|
startMsg(msgTypeServerCutText);
|
||||||
|
os->pad(3);
|
||||||
|
os->writeS32(-(4 + mos.length()));
|
||||||
|
os->writeU32(flags | clipboardProvide);
|
||||||
|
os->writeBytes(mos.data(), mos.length());
|
||||||
endMsg();
|
endMsg();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,12 +208,6 @@ void SMsgWriter::writeStats(const char* str, int len)
|
|||||||
endMsg();
|
endMsg();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgWriter::writeRequestFrameStats()
|
|
||||||
{
|
|
||||||
startMsg(msgTypeRequestFrameStats);
|
|
||||||
endMsg();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
|
void SMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
|
||||||
{
|
{
|
||||||
if (!cp->supportsFence)
|
if (!cp->supportsFence)
|
||||||
@@ -225,16 +315,6 @@ bool SMsgWriter::writeSetCursorWithAlpha()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SMsgWriter::writeSetVMwareCursor()
|
|
||||||
{
|
|
||||||
if (!cp->supportsVMWareCursor)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
needSetVMWareCursor = true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMsgWriter::writeCursorPos()
|
void SMsgWriter::writeCursorPos()
|
||||||
{
|
{
|
||||||
if (!cp->supportsEncoding(pseudoEncodingVMwareCursorPosition))
|
if (!cp->supportsEncoding(pseudoEncodingVMwareCursorPosition))
|
||||||
@@ -269,7 +349,7 @@ bool SMsgWriter::needFakeUpdate()
|
|||||||
{
|
{
|
||||||
if (needSetDesktopName)
|
if (needSetDesktopName)
|
||||||
return true;
|
return true;
|
||||||
if (needSetCursor || needSetXCursor || needSetCursorWithAlpha || needSetVMWareCursor)
|
if (needSetCursor || needSetXCursor || needSetCursorWithAlpha)
|
||||||
return true;
|
return true;
|
||||||
if (needCursorPos)
|
if (needCursorPos)
|
||||||
return true;
|
return true;
|
||||||
@@ -325,8 +405,6 @@ void SMsgWriter::writeFramebufferUpdateStart(int nRects)
|
|||||||
nRects++;
|
nRects++;
|
||||||
if (needSetCursorWithAlpha)
|
if (needSetCursorWithAlpha)
|
||||||
nRects++;
|
nRects++;
|
||||||
if (needSetVMWareCursor)
|
|
||||||
nRects++;
|
|
||||||
if (needCursorPos)
|
if (needCursorPos)
|
||||||
nRects++;
|
nRects++;
|
||||||
if (needLEDState)
|
if (needLEDState)
|
||||||
@@ -444,15 +522,6 @@ void SMsgWriter::writePseudoRects()
|
|||||||
needSetCursorWithAlpha = false;
|
needSetCursorWithAlpha = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needSetVMWareCursor) {
|
|
||||||
const Cursor& cursor = cp->cursor();
|
|
||||||
|
|
||||||
writeSetVMwareCursorRect(cursor.width(), cursor.height(),
|
|
||||||
cursor.hotspot().x, cursor.hotspot().y,
|
|
||||||
cursor.getBuffer());
|
|
||||||
needSetVMWareCursor = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needCursorPos) {
|
if (needCursorPos) {
|
||||||
const Point& cursorPos = cp->cursorPos();
|
const Point& cursorPos = cp->cursorPos();
|
||||||
|
|
||||||
@@ -643,28 +712,6 @@ void SMsgWriter::writeSetCursorWithAlphaRect(int width, int height,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgWriter::writeSetVMwareCursorRect(int width, int height,
|
|
||||||
int hotspotX, int hotspotY,
|
|
||||||
const rdr::U8* data)
|
|
||||||
{
|
|
||||||
if (!cp->supportsVMWareCursor)
|
|
||||||
throw Exception("Client does not support local cursors");
|
|
||||||
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
|
|
||||||
throw Exception("SMsgWriter::writeSetVMwareCursorRect: nRects out of sync");
|
|
||||||
|
|
||||||
os->writeS16(hotspotX);
|
|
||||||
os->writeS16(hotspotY);
|
|
||||||
os->writeU16(width);
|
|
||||||
os->writeU16(height);
|
|
||||||
os->writeU32(pseudoEncodingVMwareCursor);
|
|
||||||
|
|
||||||
os->writeU8(1); // Alpha cursor
|
|
||||||
os->pad(1);
|
|
||||||
|
|
||||||
// FIXME: Should alpha be premultiplied?
|
|
||||||
os->writeBytes(data, width*height*4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMsgWriter::writeSetVMwareCursorPositionRect(int hotspotX, int hotspotY)
|
void SMsgWriter::writeSetVMwareCursorPositionRect(int hotspotX, int hotspotY)
|
||||||
{
|
{
|
||||||
if (!cp->supportsEncoding(pseudoEncodingVMwareCursorPosition))
|
if (!cp->supportsEncoding(pseudoEncodingVMwareCursorPosition))
|
||||||
|
|||||||
@@ -26,8 +26,6 @@
|
|||||||
#include <rdr/types.h>
|
#include <rdr/types.h>
|
||||||
#include <rfb/encodings.h>
|
#include <rfb/encodings.h>
|
||||||
#include <rfb/ScreenSet.h>
|
#include <rfb/ScreenSet.h>
|
||||||
#include <rfb/SConnection.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace rdr { class OutStream; }
|
namespace rdr { class OutStream; }
|
||||||
|
|
||||||
@@ -56,13 +54,17 @@ namespace rfb {
|
|||||||
|
|
||||||
// writeBell() and writeServerCutText() do the obvious thing.
|
// writeBell() and writeServerCutText() do the obvious thing.
|
||||||
void writeBell();
|
void writeBell();
|
||||||
|
void writeServerCutText(const char* str, int len);
|
||||||
|
|
||||||
void writeBinaryClipboard(const std::vector<SConnection::binaryClipboard_t> &b);
|
void writeClipboardCaps(rdr::U32 caps, const rdr::U32* lengths);
|
||||||
|
void writeClipboardRequest(rdr::U32 flags);
|
||||||
|
void writeClipboardPeek(rdr::U32 flags);
|
||||||
|
void writeClipboardNotify(rdr::U32 flags);
|
||||||
|
void writeClipboardProvide(rdr::U32 flags, const size_t* lengths,
|
||||||
|
const rdr::U8* const* data);
|
||||||
|
|
||||||
void writeStats(const char* str, int len);
|
void writeStats(const char* str, int len);
|
||||||
|
|
||||||
void writeRequestFrameStats();
|
|
||||||
|
|
||||||
// writeFence() sends a new fence request or response to the client.
|
// writeFence() sends a new fence request or response to the client.
|
||||||
void writeFence(rdr::U32 flags, unsigned len, const char data[]);
|
void writeFence(rdr::U32 flags, unsigned len, const char data[]);
|
||||||
|
|
||||||
@@ -88,7 +90,6 @@ namespace rfb {
|
|||||||
bool writeSetCursor();
|
bool writeSetCursor();
|
||||||
bool writeSetXCursor();
|
bool writeSetXCursor();
|
||||||
bool writeSetCursorWithAlpha();
|
bool writeSetCursorWithAlpha();
|
||||||
bool writeSetVMwareCursor();
|
|
||||||
|
|
||||||
// Notifies the client that the cursor pointer was moved by the server.
|
// Notifies the client that the cursor pointer was moved by the server.
|
||||||
void writeCursorPos();
|
void writeCursorPos();
|
||||||
@@ -148,9 +149,6 @@ namespace rfb {
|
|||||||
void writeSetCursorWithAlphaRect(int width, int height,
|
void writeSetCursorWithAlphaRect(int width, int height,
|
||||||
int hotspotX, int hotspotY,
|
int hotspotX, int hotspotY,
|
||||||
const rdr::U8* data);
|
const rdr::U8* data);
|
||||||
void writeSetVMwareCursorRect(int width, int height,
|
|
||||||
int hotspotX, int hotspotY,
|
|
||||||
const rdr::U8* data);
|
|
||||||
void writeSetVMwareCursorPositionRect(int hotspotX, int hotspotY);
|
void writeSetVMwareCursorPositionRect(int hotspotX, int hotspotY);
|
||||||
void writeLEDStateRect(rdr::U8 state);
|
void writeLEDStateRect(rdr::U8 state);
|
||||||
void writeQEMUKeyEventRect();
|
void writeQEMUKeyEventRect();
|
||||||
@@ -167,7 +165,6 @@ namespace rfb {
|
|||||||
bool needSetCursor;
|
bool needSetCursor;
|
||||||
bool needSetXCursor;
|
bool needSetXCursor;
|
||||||
bool needSetCursorWithAlpha;
|
bool needSetCursorWithAlpha;
|
||||||
bool needSetVMWareCursor;
|
|
||||||
bool needCursorPos;
|
bool needCursorPos;
|
||||||
bool needLEDState;
|
bool needLEDState;
|
||||||
bool needQEMUKeyEvent;
|
bool needQEMUKeyEvent;
|
||||||
|
|||||||
@@ -1,197 +0,0 @@
|
|||||||
/* Copyright (C) 2021 Kasm Web
|
|
||||||
*
|
|
||||||
* This is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this software; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
||||||
* USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <rfb/ComparingUpdateTracker.h>
|
|
||||||
#include <rfb/EncodeManager.h>
|
|
||||||
#include <rfb/LogWriter.h>
|
|
||||||
#include <rfb/SConnection.h>
|
|
||||||
#include <rfb/ServerCore.h>
|
|
||||||
#include <rfb/PixelBuffer.h>
|
|
||||||
#include <rfb/TightJPEGEncoder.h>
|
|
||||||
#include <rfb/TightWEBPEncoder.h>
|
|
||||||
#include <rfb/util.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
using namespace rfb;
|
|
||||||
static LogWriter vlog("SelfBench");
|
|
||||||
|
|
||||||
static const PixelFormat pfRGBX(32, 24, false, true, 255, 255, 255, 0, 8, 16);
|
|
||||||
|
|
||||||
#define RUNS 64
|
|
||||||
|
|
||||||
#define W 1600
|
|
||||||
#define H 1200
|
|
||||||
|
|
||||||
void SelfBench() {
|
|
||||||
|
|
||||||
unsigned i, runs;
|
|
||||||
struct timeval start;
|
|
||||||
|
|
||||||
ManagedPixelBuffer f1(pfRGBX, W, H);
|
|
||||||
ManagedPixelBuffer f2(pfRGBX, W, H);
|
|
||||||
ManagedPixelBuffer screen(pfRGBX, W, H);
|
|
||||||
|
|
||||||
int stride;
|
|
||||||
rdr::U8 *f1ptr = f1.getBufferRW(f1.getRect(), &stride);
|
|
||||||
rdr::U8 *f2ptr = f2.getBufferRW(f2.getRect(), &stride);
|
|
||||||
rdr::U8 * const screenptr = screen.getBufferRW(screen.getRect(), &stride);
|
|
||||||
|
|
||||||
rdr::U8 * const f1orig = f1ptr;
|
|
||||||
rdr::U8 * const f2orig = f2ptr;
|
|
||||||
|
|
||||||
for (i = 0; i < W * H * 4; i += 4) {
|
|
||||||
f1ptr[0] = rand();
|
|
||||||
f1ptr[1] = rand();
|
|
||||||
f1ptr[2] = rand();
|
|
||||||
|
|
||||||
f2ptr[0] = rand();
|
|
||||||
f2ptr[1] = rand();
|
|
||||||
f2ptr[2] = rand();
|
|
||||||
|
|
||||||
f1ptr += 4;
|
|
||||||
f2ptr += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
vlog.info("Running micro-benchmarks (single-threaded, runs depending on task)");
|
|
||||||
|
|
||||||
// Encoding
|
|
||||||
std::vector<uint8_t> vec;
|
|
||||||
|
|
||||||
TightJPEGEncoder jpeg(NULL);
|
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
runs = RUNS;
|
|
||||||
for (i = 0; i < runs; i++) {
|
|
||||||
jpeg.compressOnly(&f1, 8, vec, false);
|
|
||||||
}
|
|
||||||
vlog.info("Jpeg compression at quality 8 took %u ms (%u runs)", msSince(&start), runs);
|
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
runs = RUNS;
|
|
||||||
for (i = 0; i < runs; i++) {
|
|
||||||
jpeg.compressOnly(&f1, 4, vec, false);
|
|
||||||
}
|
|
||||||
vlog.info("Jpeg compression at quality 4 took %u ms (%u runs)", msSince(&start), runs);
|
|
||||||
|
|
||||||
|
|
||||||
TightWEBPEncoder webp(NULL);
|
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
runs = RUNS / 8;
|
|
||||||
for (i = 0; i < runs; i++) {
|
|
||||||
webp.compressOnly(&f1, 8, vec, false);
|
|
||||||
}
|
|
||||||
vlog.info("Webp compression at quality 8 took %u ms (%u runs)", msSince(&start), runs);
|
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
runs = RUNS / 4;
|
|
||||||
for (i = 0; i < runs; i++) {
|
|
||||||
webp.compressOnly(&f1, 4, vec, false);
|
|
||||||
}
|
|
||||||
vlog.info("Webp compression at quality 4 took %u ms (%u runs)", msSince(&start), runs);
|
|
||||||
|
|
||||||
// Scaling
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
runs = RUNS;
|
|
||||||
for (i = 0; i < runs; i++) {
|
|
||||||
PixelBuffer *pb = nearestScale(&f1, W * 0.8, H * 0.8, 0.8);
|
|
||||||
delete pb;
|
|
||||||
}
|
|
||||||
vlog.info("Nearest scaling to 80%% took %u ms (%u runs)", msSince(&start), runs);
|
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
runs = RUNS;
|
|
||||||
for (i = 0; i < runs; i++) {
|
|
||||||
PixelBuffer *pb = nearestScale(&f1, W * 0.4, H * 0.4, 0.4);
|
|
||||||
delete pb;
|
|
||||||
}
|
|
||||||
vlog.info("Nearest scaling to 40%% took %u ms (%u runs)", msSince(&start), runs);
|
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
runs = RUNS;
|
|
||||||
for (i = 0; i < runs; i++) {
|
|
||||||
PixelBuffer *pb = bilinearScale(&f1, W * 0.8, H * 0.8, 0.8);
|
|
||||||
delete pb;
|
|
||||||
}
|
|
||||||
vlog.info("Bilinear scaling to 80%% took %u ms (%u runs)", msSince(&start), runs);
|
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
runs = RUNS;
|
|
||||||
for (i = 0; i < runs; i++) {
|
|
||||||
PixelBuffer *pb = bilinearScale(&f1, W * 0.4, H * 0.4, 0.4);
|
|
||||||
delete pb;
|
|
||||||
}
|
|
||||||
vlog.info("Bilinear scaling to 40%% took %u ms (%u runs)", msSince(&start), runs);
|
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
runs = RUNS;
|
|
||||||
for (i = 0; i < runs; i++) {
|
|
||||||
PixelBuffer *pb = progressiveBilinearScale(&f1, W * 0.8, H * 0.8, 0.8);
|
|
||||||
delete pb;
|
|
||||||
}
|
|
||||||
vlog.info("Progressive bilinear scaling to 80%% took %u ms (%u runs)", msSince(&start), runs);
|
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
runs = RUNS;
|
|
||||||
for (i = 0; i < runs; i++) {
|
|
||||||
PixelBuffer *pb = progressiveBilinearScale(&f1, W * 0.4, H * 0.4, 0.4);
|
|
||||||
delete pb;
|
|
||||||
}
|
|
||||||
vlog.info("Progressive bilinear scaling to 40%% took %u ms (%u runs)", msSince(&start), runs);
|
|
||||||
|
|
||||||
// Analysis
|
|
||||||
ComparingUpdateTracker *comparer = new ComparingUpdateTracker(&screen);
|
|
||||||
Region cursorReg;
|
|
||||||
|
|
||||||
Server::detectScrolling.setParam(false);
|
|
||||||
Server::detectHorizontal.setParam(false);
|
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
runs = RUNS;
|
|
||||||
for (i = 0; i < runs; i++) {
|
|
||||||
memcpy(screenptr, i % 2 ? f1orig : f2orig, W * H * 4);
|
|
||||||
comparer->compare(true, cursorReg);
|
|
||||||
}
|
|
||||||
vlog.info("Analysis took %u ms (%u runs) (incl. memcpy overhead)", msSince(&start), runs);
|
|
||||||
|
|
||||||
Server::detectScrolling.setParam(true);
|
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
runs = RUNS;
|
|
||||||
for (i = 0; i < runs; i++) {
|
|
||||||
memcpy(screenptr, i % 2 ? f1orig : f2orig, W * H * 4);
|
|
||||||
comparer->compare(false, cursorReg);
|
|
||||||
}
|
|
||||||
vlog.info("Analysis w/ scroll detection took %u ms (%u runs) (incl. memcpy overhead)", msSince(&start), runs);
|
|
||||||
|
|
||||||
Server::detectHorizontal.setParam(true);
|
|
||||||
delete comparer;
|
|
||||||
comparer = new ComparingUpdateTracker(&screen);
|
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
runs = RUNS / 2;
|
|
||||||
for (i = 0; i < runs; i++) {
|
|
||||||
memcpy(screenptr, i % 2 ? f1orig : f2orig, W * H * 4);
|
|
||||||
comparer->compare(false, cursorReg);
|
|
||||||
}
|
|
||||||
vlog.info("Analysis w/ horizontal scroll detection took %u ms (%u runs) (incl. memcpy overhead)", msSince(&start), runs);
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
@@ -113,10 +113,6 @@ rfb::BoolParameter rfb::Server::ignoreClientSettingsKasm
|
|||||||
("IgnoreClientSettingsKasm",
|
("IgnoreClientSettingsKasm",
|
||||||
"Ignore the additional client settings exposed in Kasm.",
|
"Ignore the additional client settings exposed in Kasm.",
|
||||||
false);
|
false);
|
||||||
rfb::BoolParameter rfb::Server::selfBench
|
|
||||||
("SelfBench",
|
|
||||||
"Run self-benchmarks and exit.",
|
|
||||||
false);
|
|
||||||
rfb::IntParameter rfb::Server::dynamicQualityMin
|
rfb::IntParameter rfb::Server::dynamicQualityMin
|
||||||
("DynamicQualityMin",
|
("DynamicQualityMin",
|
||||||
"The minimum dynamic JPEG quality, 0 = low, 9 = high",
|
"The minimum dynamic JPEG quality, 0 = low, 9 = high",
|
||||||
@@ -149,15 +145,15 @@ rfb::IntParameter rfb::Server::webpVideoQuality
|
|||||||
rfb::IntParameter rfb::Server::DLP_ClipSendMax
|
rfb::IntParameter rfb::Server::DLP_ClipSendMax
|
||||||
("DLP_ClipSendMax",
|
("DLP_ClipSendMax",
|
||||||
"Limit clipboard bytes to send to clients in one transaction",
|
"Limit clipboard bytes to send to clients in one transaction",
|
||||||
0, 0, INT_MAX);
|
10000, 0, INT_MAX);
|
||||||
rfb::IntParameter rfb::Server::DLP_ClipAcceptMax
|
rfb::IntParameter rfb::Server::DLP_ClipAcceptMax
|
||||||
("DLP_ClipAcceptMax",
|
("DLP_ClipAcceptMax",
|
||||||
"Limit clipboard bytes to receive from clients in one transaction",
|
"Limit clipboard bytes to receive from clients in one transaction",
|
||||||
0, 0, INT_MAX);
|
10000, 0, INT_MAX);
|
||||||
rfb::IntParameter rfb::Server::DLP_ClipDelay
|
rfb::IntParameter rfb::Server::DLP_ClipDelay
|
||||||
("DLP_ClipDelay",
|
("DLP_ClipDelay",
|
||||||
"This many milliseconds must pass between clipboard actions",
|
"This many milliseconds must pass between clipboard actions",
|
||||||
0, 0, INT_MAX);
|
1000, 0, INT_MAX);
|
||||||
rfb::IntParameter rfb::Server::DLP_KeyRateLimit
|
rfb::IntParameter rfb::Server::DLP_KeyRateLimit
|
||||||
("DLP_KeyRateLimit",
|
("DLP_KeyRateLimit",
|
||||||
"Reject keyboard presses over this many per second",
|
"Reject keyboard presses over this many per second",
|
||||||
@@ -171,10 +167,6 @@ rfb::StringParameter rfb::Server::DLP_Region
|
|||||||
("DLP_Region",
|
("DLP_Region",
|
||||||
"Black out anything outside this region",
|
"Black out anything outside this region",
|
||||||
"");
|
"");
|
||||||
rfb::StringParameter rfb::Server::DLP_Clip_Types
|
|
||||||
("DLP_ClipTypes",
|
|
||||||
"Allowed binary clipboard mimetypes",
|
|
||||||
"text/html,image/png");
|
|
||||||
|
|
||||||
rfb::BoolParameter rfb::Server::DLP_RegionAllowClick
|
rfb::BoolParameter rfb::Server::DLP_RegionAllowClick
|
||||||
("DLP_RegionAllowClick",
|
("DLP_RegionAllowClick",
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ namespace rfb {
|
|||||||
static IntParameter DLP_KeyRateLimit;
|
static IntParameter DLP_KeyRateLimit;
|
||||||
static StringParameter DLP_ClipLog;
|
static StringParameter DLP_ClipLog;
|
||||||
static StringParameter DLP_Region;
|
static StringParameter DLP_Region;
|
||||||
static StringParameter DLP_Clip_Types;
|
|
||||||
static BoolParameter DLP_RegionAllowClick;
|
static BoolParameter DLP_RegionAllowClick;
|
||||||
static BoolParameter DLP_RegionAllowRelease;
|
static BoolParameter DLP_RegionAllowRelease;
|
||||||
static IntParameter jpegVideoQuality;
|
static IntParameter jpegVideoQuality;
|
||||||
@@ -75,7 +74,6 @@ namespace rfb {
|
|||||||
static BoolParameter detectScrolling;
|
static BoolParameter detectScrolling;
|
||||||
static BoolParameter detectHorizontal;
|
static BoolParameter detectHorizontal;
|
||||||
static BoolParameter ignoreClientSettingsKasm;
|
static BoolParameter ignoreClientSettingsKasm;
|
||||||
static BoolParameter selfBench;
|
|
||||||
static PresetParameter preferBandwidth;
|
static PresetParameter preferBandwidth;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -71,12 +71,12 @@ static const struct TightWEBPConfiguration conf[10] = {
|
|||||||
{ 24, 0 }, // 1
|
{ 24, 0 }, // 1
|
||||||
{ 30, 0 }, // 2
|
{ 30, 0 }, // 2
|
||||||
{ 37, 0 }, // 3
|
{ 37, 0 }, // 3
|
||||||
{ 42, 0 }, // 4
|
{ 42, 1 }, // 4
|
||||||
{ 65, 0 }, // 5
|
{ 65, 1 }, // 5
|
||||||
{ 78, 0 }, // 6
|
{ 78, 1 }, // 6
|
||||||
{ 85, 0 }, // 7
|
{ 85, 2 }, // 7
|
||||||
{ 88, 0 }, // 8
|
{ 88, 3 }, // 8
|
||||||
{ 100, 0 } // 9
|
{ 100, 4 } // 9
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ void TightWEBPEncoder::compressOnly(const PixelBuffer* pb, const uint8_t quality
|
|||||||
method = conf[qualityIn].method;
|
method = conf[qualityIn].method;
|
||||||
} else {
|
} else {
|
||||||
quality = 8;
|
quality = 8;
|
||||||
method = 0;
|
method = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebPConfigInit(&cfg);
|
WebPConfigInit(&cfg);
|
||||||
@@ -214,7 +214,7 @@ void TightWEBPEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)
|
|||||||
method = conf[qualityLevel].method;
|
method = conf[qualityLevel].method;
|
||||||
} else {
|
} else {
|
||||||
quality = 8;
|
quality = 8;
|
||||||
method = 0;
|
method = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebPConfigInit(&cfg);
|
WebPConfigInit(&cfg);
|
||||||
@@ -265,7 +265,7 @@ rdr::U32 TightWEBPEncoder::benchmark() const
|
|||||||
rdr::U8* buffer;
|
rdr::U8* buffer;
|
||||||
struct timeval start;
|
struct timeval start;
|
||||||
int stride, i;
|
int stride, i;
|
||||||
const uint8_t quality = 8, method = 2;
|
const uint8_t quality = 8, method = 4;
|
||||||
WebPConfig cfg;
|
WebPConfig cfg;
|
||||||
WebPPicture pic;
|
WebPPicture pic;
|
||||||
WebPMemoryWriter wrt;
|
WebPMemoryWriter wrt;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
* USA.
|
* USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <network/GetAPI.h>
|
|
||||||
#include <network/TcpSocket.h>
|
#include <network/TcpSocket.h>
|
||||||
|
|
||||||
#include <rfb/ComparingUpdateTracker.h>
|
#include <rfb/ComparingUpdateTracker.h>
|
||||||
@@ -57,13 +56,12 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
|
|||||||
inProcessMessages(false),
|
inProcessMessages(false),
|
||||||
pendingSyncFence(false), syncFence(false), fenceFlags(0),
|
pendingSyncFence(false), syncFence(false), fenceFlags(0),
|
||||||
fenceDataLen(0), fenceData(NULL), congestionTimer(this),
|
fenceDataLen(0), fenceData(NULL), congestionTimer(this),
|
||||||
losslessTimer(this), kbdLogTimer(this), binclipTimer(this),
|
losslessTimer(this), kbdLogTimer(this), server(server_), updates(false),
|
||||||
server(server_), updates(false),
|
|
||||||
updateRenderedCursor(false), removeRenderedCursor(false),
|
updateRenderedCursor(false), removeRenderedCursor(false),
|
||||||
continuousUpdates(false), encodeManager(this, &server_->encCache),
|
continuousUpdates(false), encodeManager(this, &server_->encCache),
|
||||||
needsPermCheck(false), pointerEventTime(0),
|
needsPermCheck(false), pointerEventTime(0),
|
||||||
clientHasCursor(false),
|
clientHasCursor(false),
|
||||||
accessRights(AccessDefault), startTime(time(0)), frameTracking(false)
|
accessRights(AccessDefault), startTime(time(0))
|
||||||
{
|
{
|
||||||
setStreams(&sock->inStream(), &sock->outStream());
|
setStreams(&sock->inStream(), &sock->outStream());
|
||||||
peerEndpoint.buf = sock->getPeerEndpoint();
|
peerEndpoint.buf = sock->getPeerEndpoint();
|
||||||
@@ -88,9 +86,8 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool write, owner;
|
bool write, owner;
|
||||||
if (!getPerms(write, owner) || !write) {
|
if (!getPerms(write, owner) || !write)
|
||||||
accessRights &= ~WRITER_PERMS;
|
accessRights = (accessRights & ~(AccessPtrEvents | AccessKeyEvents | AccessSetDesktopSize));
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the socket
|
// Configure the socket
|
||||||
setSocketTimeouts();
|
setSocketTimeouts();
|
||||||
@@ -100,9 +97,6 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
|
|||||||
gettimeofday(&lastKeyEvent, NULL);
|
gettimeofday(&lastKeyEvent, NULL);
|
||||||
|
|
||||||
server->clients.push_front(this);
|
server->clients.push_front(this);
|
||||||
|
|
||||||
if (server->apimessager)
|
|
||||||
server->apimessager->mainUpdateUserInfo(checkOwnerConn(), server->clients.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -133,11 +127,6 @@ VNCSConnectionST::~VNCSConnectionST()
|
|||||||
server->clients.remove(this);
|
server->clients.remove(this);
|
||||||
|
|
||||||
delete [] fenceData;
|
delete [] fenceData;
|
||||||
|
|
||||||
if (server->apimessager) {
|
|
||||||
server->apimessager->mainUpdateUserInfo(checkOwnerConn(), server->clients.size());
|
|
||||||
server->apimessager->mainClearBottleneckStats(peerEndpoint.buf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -414,6 +403,18 @@ static void keylog(unsigned keysym, const char *client) {
|
|||||||
flushKeylog(client);
|
flushKeylog(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VNCSConnectionST::requestClipboardOrClose()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (!(accessRights & AccessCutText)) return;
|
||||||
|
if (!rfb::Server::acceptCutText) return;
|
||||||
|
if (state() != RFBSTATE_NORMAL) return;
|
||||||
|
requestClipboard();
|
||||||
|
} catch(rdr::Exception& e) {
|
||||||
|
close(e.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::announceClipboardOrClose(bool available)
|
void VNCSConnectionST::announceClipboardOrClose(bool available)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -426,51 +427,29 @@ void VNCSConnectionST::announceClipboardOrClose(bool available)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::clearBinaryClipboardData()
|
void VNCSConnectionST::sendClipboardDataOrClose(const char* data)
|
||||||
{
|
|
||||||
clearBinaryClipboard();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VNCSConnectionST::sendBinaryClipboardDataOrClose(const char* mime,
|
|
||||||
const unsigned char *data,
|
|
||||||
const unsigned len)
|
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (!(accessRights & AccessCutText)) return;
|
if (!(accessRights & AccessCutText)) return;
|
||||||
if (!rfb::Server::sendCutText) return;
|
if (!rfb::Server::sendCutText) return;
|
||||||
if (rfb::Server::DLP_ClipSendMax && len > (unsigned) rfb::Server::DLP_ClipSendMax) {
|
if (msSince(&lastClipboardOp) < (unsigned) rfb::Server::DLP_ClipDelay) {
|
||||||
vlog.info("DLP: client %s: refused to send binary clipboard, too large",
|
vlog.info("DLP: client %s: refused to send clipboard, too soon",
|
||||||
sock->getPeerAddress());
|
sock->getPeerAddress());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
int len = strlen(data);
|
||||||
cliplog((const char *) data, len, len, "sent", sock->getPeerAddress());
|
const int origlen = len;
|
||||||
|
if (rfb::Server::DLP_ClipSendMax && len > rfb::Server::DLP_ClipSendMax)
|
||||||
|
len = rfb::Server::DLP_ClipSendMax;
|
||||||
|
cliplog(data, len, origlen, "sent", sock->getPeerAddress());
|
||||||
if (state() != RFBSTATE_NORMAL) return;
|
if (state() != RFBSTATE_NORMAL) return;
|
||||||
|
sendClipboardData(data, len);
|
||||||
addBinaryClipboard(mime, data, len);
|
gettimeofday(&lastClipboardOp, NULL);
|
||||||
binclipTimer.start(100);
|
|
||||||
} catch(rdr::Exception& e) {
|
} catch(rdr::Exception& e) {
|
||||||
close(e.str());
|
close(e.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::getBinaryClipboardData(const char* mime, const unsigned char **data,
|
|
||||||
unsigned *len)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
for (i = 0; i < binaryClipboard.size(); i++) {
|
|
||||||
if (!strcmp(binaryClipboard[i].mime, mime)) {
|
|
||||||
*data = &binaryClipboard[i].data[0];
|
|
||||||
*len = binaryClipboard[i].data.size();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vlog.error("Binary clipboard data for mime %s not found", mime);
|
|
||||||
*data = (const unsigned char *) "";
|
|
||||||
*len = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VNCSConnectionST::setDesktopNameOrClose(const char *name)
|
void VNCSConnectionST::setDesktopNameOrClose(const char *name)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -587,7 +566,6 @@ bool VNCSConnectionST::needRenderedCursor()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!cp.supportsLocalCursorWithAlpha &&
|
if (!cp.supportsLocalCursorWithAlpha &&
|
||||||
!cp.supportsVMWareCursor &&
|
|
||||||
!cp.supportsLocalCursor && !cp.supportsLocalXCursor)
|
!cp.supportsLocalCursor && !cp.supportsLocalXCursor)
|
||||||
return true;
|
return true;
|
||||||
if (!server->cursorPos.equals(pointerEventPos) &&
|
if (!server->cursorPos.equals(pointerEventPos) &&
|
||||||
@@ -703,14 +681,52 @@ void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
|
|||||||
setCursor();
|
setCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask, const bool skipClick, const bool skipRelease, int scrollX, int scrollY)
|
void VNCSConnectionST::pointerEvent(const Point& pos, const Point& abspos, int buttonMask, const bool skipClick, const bool skipRelease)
|
||||||
{
|
{
|
||||||
pointerEventTime = lastEventTime = time(0);
|
pointerEventTime = lastEventTime = time(0);
|
||||||
server->lastUserInputTime = lastEventTime;
|
server->lastUserInputTime = lastEventTime;
|
||||||
if (!(accessRights & AccessPtrEvents)) return;
|
if (!(accessRights & AccessPtrEvents)) return;
|
||||||
if (!rfb::Server::acceptPointerEvents) return;
|
if (!rfb::Server::acceptPointerEvents) return;
|
||||||
if (!server->pointerClient || server->pointerClient == this) {
|
if (!server->pointerClient || server->pointerClient == this) {
|
||||||
|
Point newpos = pos;
|
||||||
|
if (pos.x & 0x4000) {
|
||||||
|
newpos.x &= ~0x4000;
|
||||||
|
newpos.y &= ~0x4000;
|
||||||
|
|
||||||
|
if (newpos.x & 0x8000) {
|
||||||
|
newpos.x &= ~0x8000;
|
||||||
|
newpos.x = -newpos.x;
|
||||||
|
}
|
||||||
|
if (newpos.y & 0x8000) {
|
||||||
|
newpos.y &= ~0x8000;
|
||||||
|
newpos.y = -newpos.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newpos.x < 0) {
|
||||||
|
if (pointerEventPos.x + newpos.x >= 0)
|
||||||
|
pointerEventPos.x += newpos.x;
|
||||||
|
else
|
||||||
|
pointerEventPos.x = 0;
|
||||||
|
} else {
|
||||||
|
pointerEventPos.x += newpos.x;
|
||||||
|
if (pointerEventPos.x >= cp.width)
|
||||||
|
pointerEventPos.x = cp.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newpos.y < 0) {
|
||||||
|
if (pointerEventPos.y + newpos.y >= 0)
|
||||||
|
pointerEventPos.y += newpos.y;
|
||||||
|
else
|
||||||
|
pointerEventPos.y = 0;
|
||||||
|
} else {
|
||||||
|
pointerEventPos.y += newpos.y;
|
||||||
|
if (pointerEventPos.y >= cp.height)
|
||||||
|
pointerEventPos.y = cp.height;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
pointerEventPos = pos;
|
pointerEventPos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
if (buttonMask)
|
if (buttonMask)
|
||||||
server->pointerClient = this;
|
server->pointerClient = this;
|
||||||
else
|
else
|
||||||
@@ -731,7 +747,7 @@ void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask, const bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server->desktop->pointerEvent(pointerEventPos, buttonMask, skipclick, skiprelease, scrollX, scrollY);
|
server->desktop->pointerEvent(newpos, pointerEventPos, buttonMask, skipclick, skiprelease);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1025,6 +1041,12 @@ void VNCSConnectionST::enableContinuousUpdates(bool enable,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VNCSConnectionST::handleClipboardRequest()
|
||||||
|
{
|
||||||
|
if (!(accessRights & AccessCutText)) return;
|
||||||
|
server->handleClipboardRequest(this);
|
||||||
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::handleClipboardAnnounce(bool available)
|
void VNCSConnectionST::handleClipboardAnnounce(bool available)
|
||||||
{
|
{
|
||||||
if (!(accessRights & AccessCutText)) return;
|
if (!(accessRights & AccessCutText)) return;
|
||||||
@@ -1032,13 +1054,25 @@ void VNCSConnectionST::handleClipboardAnnounce(bool available)
|
|||||||
server->handleClipboardAnnounce(this, available);
|
server->handleClipboardAnnounce(this, available);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32])
|
void VNCSConnectionST::handleClipboardData(const char* data, int len)
|
||||||
{
|
{
|
||||||
if (!(accessRights & AccessCutText)) return;
|
if (!(accessRights & AccessCutText)) return;
|
||||||
if (!rfb::Server::acceptCutText) return;
|
if (!rfb::Server::acceptCutText) return;
|
||||||
server->handleClipboardAnnounceBinary(this, num, mimes);
|
if (msSince(&lastClipboardOp) < (unsigned) rfb::Server::DLP_ClipDelay) {
|
||||||
|
vlog.info("DLP: client %s: refused to receive clipboard, too soon",
|
||||||
|
sock->getPeerAddress());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int origlen = len;
|
||||||
|
if (rfb::Server::DLP_ClipAcceptMax && len > rfb::Server::DLP_ClipAcceptMax)
|
||||||
|
len = rfb::Server::DLP_ClipAcceptMax;
|
||||||
|
cliplog(data, len, origlen, "received", sock->getPeerAddress());
|
||||||
|
|
||||||
|
gettimeofday(&lastClipboardOp, NULL);
|
||||||
|
server->handleClipboardData(this, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// supportsLocalCursor() is called whenever the status of
|
// supportsLocalCursor() is called whenever the status of
|
||||||
// cp.supportsLocalCursor has changed. If the client does now support local
|
// cp.supportsLocalCursor has changed. If the client does now support local
|
||||||
// cursor, we make sure that the old server-side rendered cursor is cleaned up
|
// cursor, we make sure that the old server-side rendered cursor is cleaned up
|
||||||
@@ -1082,8 +1116,6 @@ bool VNCSConnectionST::handleTimeout(Timer* t)
|
|||||||
writeFramebufferUpdate();
|
writeFramebufferUpdate();
|
||||||
else if (t == &kbdLogTimer)
|
else if (t == &kbdLogTimer)
|
||||||
flushKeylog(sock->getPeerAddress());
|
flushKeylog(sock->getPeerAddress());
|
||||||
else if (t == &binclipTimer)
|
|
||||||
writeBinaryClipboard();
|
|
||||||
} catch (rdr::Exception& e) {
|
} catch (rdr::Exception& e) {
|
||||||
close(e.str());
|
close(e.str());
|
||||||
}
|
}
|
||||||
@@ -1189,7 +1221,6 @@ bool VNCSConnectionST::isCongested()
|
|||||||
void VNCSConnectionST::writeFramebufferUpdate()
|
void VNCSConnectionST::writeFramebufferUpdate()
|
||||||
{
|
{
|
||||||
congestion.updatePosition(sock->outStream().length());
|
congestion.updatePosition(sock->outStream().length());
|
||||||
encodeManager.clearEncodingTime();
|
|
||||||
|
|
||||||
// We're in the middle of processing a command that's supposed to be
|
// We're in the middle of processing a command that's supposed to be
|
||||||
// synchronised. Allowing an update to slip out right now might violate
|
// synchronised. Allowing an update to slip out right now might violate
|
||||||
@@ -1223,9 +1254,9 @@ void VNCSConnectionST::writeFramebufferUpdate()
|
|||||||
close("User was deleted");
|
close("User was deleted");
|
||||||
return;
|
return;
|
||||||
} else if (!write) {
|
} else if (!write) {
|
||||||
accessRights &= ~WRITER_PERMS;
|
accessRights = (accessRights & ~(AccessPtrEvents | AccessKeyEvents | AccessSetDesktopSize));
|
||||||
} else {
|
} else {
|
||||||
accessRights |= WRITER_PERMS;
|
accessRights |= AccessPtrEvents | AccessKeyEvents | AccessSetDesktopSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1235,9 +1266,6 @@ void VNCSConnectionST::writeFramebufferUpdate()
|
|||||||
// window.
|
// window.
|
||||||
sock->cork(true);
|
sock->cork(true);
|
||||||
|
|
||||||
if (frameTracking)
|
|
||||||
writer()->writeRequestFrameStats();
|
|
||||||
|
|
||||||
// First take care of any updates that cannot contain framebuffer data
|
// First take care of any updates that cannot contain framebuffer data
|
||||||
// changes.
|
// changes.
|
||||||
writeNoDataUpdate();
|
writeNoDataUpdate();
|
||||||
@@ -1441,18 +1469,6 @@ void VNCSConnectionST::writeDataUpdate()
|
|||||||
requested.clear();
|
requested.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::writeBinaryClipboard()
|
|
||||||
{
|
|
||||||
if (msSince(&lastClipboardOp) < (unsigned) rfb::Server::DLP_ClipDelay) {
|
|
||||||
vlog.info("DLP: client %s: refused to send binary clipboard, too soon",
|
|
||||||
sock->getPeerAddress());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer()->writeBinaryClipboard(binaryClipboard);
|
|
||||||
|
|
||||||
gettimeofday(&lastClipboardOp, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VNCSConnectionST::screenLayoutChange(rdr::U16 reason)
|
void VNCSConnectionST::screenLayoutChange(rdr::U16 reason)
|
||||||
{
|
{
|
||||||
@@ -1480,7 +1496,7 @@ static void pruneStatList(std::list<struct timeval> &list, const struct timeval
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::sendStats(const bool toClient) {
|
void VNCSConnectionST::sendStats() {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
|
|
||||||
@@ -1519,28 +1535,8 @@ void VNCSConnectionST::sendStats(const bool toClient) {
|
|||||||
|
|
||||||
#undef ten
|
#undef ten
|
||||||
|
|
||||||
if (toClient) {
|
|
||||||
vlog.info("Sending client stats:\n%s\n", buf);
|
vlog.info("Sending client stats:\n%s\n", buf);
|
||||||
writer()->writeStats(buf, strlen(buf));
|
writer()->writeStats(buf, strlen(buf));
|
||||||
} else if (server->apimessager) {
|
|
||||||
server->apimessager->mainUpdateBottleneckStats(peerEndpoint.buf, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VNCSConnectionST::handleFrameStats(rdr::U32 all, rdr::U32 render)
|
|
||||||
{
|
|
||||||
if (server->apimessager) {
|
|
||||||
const char *at = strchr(peerEndpoint.buf, '@');
|
|
||||||
if (!at)
|
|
||||||
at = peerEndpoint.buf;
|
|
||||||
else
|
|
||||||
at++;
|
|
||||||
|
|
||||||
server->apimessager->mainUpdateClientFrameStats(at, render, all,
|
|
||||||
congestion.getPingTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
frameTracking = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// setCursor() is called whenever the cursor has changed shape or pixel format.
|
// setCursor() is called whenever the cursor has changed shape or pixel format.
|
||||||
@@ -1561,7 +1557,6 @@ void VNCSConnectionST::setCursor()
|
|||||||
clientHasCursor = true;
|
clientHasCursor = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!writer()->writeSetVMwareCursor()) {
|
|
||||||
if (!writer()->writeSetCursorWithAlpha()) {
|
if (!writer()->writeSetCursorWithAlpha()) {
|
||||||
if (!writer()->writeSetCursor()) {
|
if (!writer()->writeSetCursor()) {
|
||||||
if (!writer()->writeSetXCursor()) {
|
if (!writer()->writeSetXCursor()) {
|
||||||
@@ -1570,7 +1565,6 @@ void VNCSConnectionST::setCursor()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// setCursorPos() is called whenever the cursor has changed position by the
|
// setCursorPos() is called whenever the cursor has changed position by the
|
||||||
@@ -1654,15 +1648,3 @@ int VNCSConnectionST::getStatus()
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VNCSConnectionST::checkOwnerConn() const
|
|
||||||
{
|
|
||||||
std::list<VNCSConnectionST*>::const_iterator it;
|
|
||||||
|
|
||||||
for (it = server->clients.begin(); it != server->clients.end(); it++) {
|
|
||||||
bool write, owner;
|
|
||||||
if ((*it)->getPerms(write, owner) && owner)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -77,12 +77,9 @@ namespace rfb {
|
|||||||
void bellOrClose();
|
void bellOrClose();
|
||||||
void setDesktopNameOrClose(const char *name);
|
void setDesktopNameOrClose(const char *name);
|
||||||
void setLEDStateOrClose(unsigned int state);
|
void setLEDStateOrClose(unsigned int state);
|
||||||
|
void requestClipboardOrClose();
|
||||||
void announceClipboardOrClose(bool available);
|
void announceClipboardOrClose(bool available);
|
||||||
void clearBinaryClipboardData();
|
void sendClipboardDataOrClose(const char* data);
|
||||||
void sendBinaryClipboardDataOrClose(const char* mime, const unsigned char *data,
|
|
||||||
const unsigned len);
|
|
||||||
void getBinaryClipboardData(const char* mime, const unsigned char **data,
|
|
||||||
unsigned *len);
|
|
||||||
|
|
||||||
// checkIdleTimeout() returns the number of milliseconds left until the
|
// checkIdleTimeout() returns the number of milliseconds left until the
|
||||||
// idle timeout expires. If it has expired, the connection is closed and
|
// idle timeout expires. If it has expired, the connection is closed and
|
||||||
@@ -167,35 +164,6 @@ namespace rfb {
|
|||||||
void setStatus(int status);
|
void setStatus(int status);
|
||||||
int getStatus();
|
int getStatus();
|
||||||
|
|
||||||
virtual void sendStats(const bool toClient = true);
|
|
||||||
virtual void handleFrameStats(rdr::U32 all, rdr::U32 render);
|
|
||||||
|
|
||||||
bool is_owner() const {
|
|
||||||
bool write, owner;
|
|
||||||
if (getPerms(write, owner) && owner)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFrameTracking() {
|
|
||||||
frameTracking = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
EncodeManager::codecstats_t getJpegStats() const {
|
|
||||||
return encodeManager.jpegstats;
|
|
||||||
}
|
|
||||||
|
|
||||||
EncodeManager::codecstats_t getWebpStats() const {
|
|
||||||
return encodeManager.webpstats;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned getEncodingTime() const {
|
|
||||||
return encodeManager.getEncodingTime();
|
|
||||||
}
|
|
||||||
unsigned getScalingTime() const {
|
|
||||||
return encodeManager.getScalingTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// SConnection callbacks
|
// SConnection callbacks
|
||||||
|
|
||||||
@@ -207,7 +175,7 @@ namespace rfb {
|
|||||||
virtual void queryConnection(const char* userName);
|
virtual void queryConnection(const char* userName);
|
||||||
virtual void clientInit(bool shared);
|
virtual void clientInit(bool shared);
|
||||||
virtual void setPixelFormat(const PixelFormat& pf);
|
virtual void setPixelFormat(const PixelFormat& pf);
|
||||||
virtual void pointerEvent(const Point& pos, int buttonMask, const bool skipClick, const bool skipRelease, int scrollX, int scrollY);
|
virtual void pointerEvent(const Point& pos, const Point& abspos, int buttonMask, const bool skipClick, const bool skipRelease);
|
||||||
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
|
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
|
||||||
virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
|
virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
|
||||||
virtual void setDesktopSize(int fb_width, int fb_height,
|
virtual void setDesktopSize(int fb_width, int fb_height,
|
||||||
@@ -215,13 +183,15 @@ namespace rfb {
|
|||||||
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
|
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
|
||||||
virtual void enableContinuousUpdates(bool enable,
|
virtual void enableContinuousUpdates(bool enable,
|
||||||
int x, int y, int w, int h);
|
int x, int y, int w, int h);
|
||||||
|
virtual void handleClipboardRequest();
|
||||||
virtual void handleClipboardAnnounce(bool available);
|
virtual void handleClipboardAnnounce(bool available);
|
||||||
virtual void handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
|
virtual void handleClipboardData(const char* data, int len);
|
||||||
virtual void supportsLocalCursor();
|
virtual void supportsLocalCursor();
|
||||||
virtual void supportsFence();
|
virtual void supportsFence();
|
||||||
virtual void supportsContinuousUpdates();
|
virtual void supportsContinuousUpdates();
|
||||||
virtual void supportsLEDState();
|
virtual void supportsLEDState();
|
||||||
|
|
||||||
|
virtual void sendStats();
|
||||||
virtual bool canChangeKasmSettings() const {
|
virtual bool canChangeKasmSettings() const {
|
||||||
return (accessRights & (AccessPtrEvents | AccessKeyEvents)) ==
|
return (accessRights & (AccessPtrEvents | AccessKeyEvents)) ==
|
||||||
(AccessPtrEvents | AccessKeyEvents);
|
(AccessPtrEvents | AccessKeyEvents);
|
||||||
@@ -236,7 +206,7 @@ namespace rfb {
|
|||||||
|
|
||||||
bool write, owner;
|
bool write, owner;
|
||||||
if (!getPerms(write, owner) || !write)
|
if (!getPerms(write, owner) || !write)
|
||||||
accessRights &= ~WRITER_PERMS;
|
accessRights = (accessRights & ~(AccessPtrEvents | AccessKeyEvents));
|
||||||
needsPermCheck = false;
|
needsPermCheck = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,8 +219,6 @@ namespace rfb {
|
|||||||
|
|
||||||
bool getPerms(bool &write, bool &owner) const;
|
bool getPerms(bool &write, bool &owner) const;
|
||||||
|
|
||||||
bool checkOwnerConn() const;
|
|
||||||
|
|
||||||
// Congestion control
|
// Congestion control
|
||||||
void writeRTTPing();
|
void writeRTTPing();
|
||||||
bool isCongested();
|
bool isCongested();
|
||||||
@@ -262,8 +230,6 @@ namespace rfb {
|
|||||||
void writeNoDataUpdate();
|
void writeNoDataUpdate();
|
||||||
void writeDataUpdate();
|
void writeDataUpdate();
|
||||||
|
|
||||||
void writeBinaryClipboard();
|
|
||||||
|
|
||||||
void screenLayoutChange(rdr::U16 reason);
|
void screenLayoutChange(rdr::U16 reason);
|
||||||
void setCursor();
|
void setCursor();
|
||||||
void setCursorPos();
|
void setCursorPos();
|
||||||
@@ -286,7 +252,6 @@ namespace rfb {
|
|||||||
Timer congestionTimer;
|
Timer congestionTimer;
|
||||||
Timer losslessTimer;
|
Timer losslessTimer;
|
||||||
Timer kbdLogTimer;
|
Timer kbdLogTimer;
|
||||||
Timer binclipTimer;
|
|
||||||
|
|
||||||
VNCServerST* server;
|
VNCServerST* server;
|
||||||
SimpleUpdateTracker updates;
|
SimpleUpdateTracker updates;
|
||||||
@@ -329,8 +294,6 @@ namespace rfb {
|
|||||||
time_t startTime;
|
time_t startTime;
|
||||||
|
|
||||||
std::vector<CopyPassRect> copypassed;
|
std::vector<CopyPassRect> copypassed;
|
||||||
|
|
||||||
bool frameTracking;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -52,11 +52,22 @@ namespace rfb {
|
|||||||
// getPixelBuffer() returns a pointer to the PixelBuffer object.
|
// getPixelBuffer() returns a pointer to the PixelBuffer object.
|
||||||
virtual PixelBuffer* getPixelBuffer() const = 0;
|
virtual PixelBuffer* getPixelBuffer() const = 0;
|
||||||
|
|
||||||
|
// requestClipboard() will result in a request to a client to
|
||||||
|
// transfer its clipboard data. A call to
|
||||||
|
// SDesktop::handleClipboardData() will be made once the data is
|
||||||
|
// available.
|
||||||
|
virtual void requestClipboard() = 0;
|
||||||
|
|
||||||
// announceClipboard() informs all clients of changes to the
|
// announceClipboard() informs all clients of changes to the
|
||||||
// clipboard on the server. A client may later request the
|
// clipboard on the server. A client may later request the
|
||||||
// clipboard data via SDesktop::handleClipboardRequest().
|
// clipboard data via SDesktop::handleClipboardRequest().
|
||||||
virtual void announceClipboard(bool available) = 0;
|
virtual void announceClipboard(bool available) = 0;
|
||||||
|
|
||||||
|
// sendClipboardData() transfers the clipboard data to a client
|
||||||
|
// and should be called whenever a client has requested the
|
||||||
|
// clipboard via SDesktop::handleClipboardRequest().
|
||||||
|
virtual void sendClipboardData(const char* data) = 0;
|
||||||
|
|
||||||
// bell() tells the server that it should make all clients make a bell sound.
|
// bell() tells the server that it should make all clients make a bell sound.
|
||||||
virtual void bell() = 0;
|
virtual void bell() = 0;
|
||||||
|
|
||||||
@@ -68,7 +79,7 @@ namespace rfb {
|
|||||||
// cursorData argument contains width*height rgba quadruplets with
|
// cursorData argument contains width*height rgba quadruplets with
|
||||||
// non-premultiplied alpha.
|
// non-premultiplied alpha.
|
||||||
virtual void setCursor(int width, int height, const Point& hotspot,
|
virtual void setCursor(int width, int height, const Point& hotspot,
|
||||||
const rdr::U8* cursorData, const bool resizing = false) = 0;
|
const rdr::U8* cursorData) = 0;
|
||||||
|
|
||||||
// setCursorPos() tells the server the current position of the cursor, and
|
// setCursorPos() tells the server the current position of the cursor, and
|
||||||
// whether the server initiated that change (e.g. through another X11
|
// whether the server initiated that change (e.g. through another X11
|
||||||
|
|||||||
@@ -53,7 +53,6 @@
|
|||||||
|
|
||||||
#include <network/GetAPI.h>
|
#include <network/GetAPI.h>
|
||||||
|
|
||||||
#include <rfb/cpuid.h>
|
|
||||||
#include <rfb/ComparingUpdateTracker.h>
|
#include <rfb/ComparingUpdateTracker.h>
|
||||||
#include <rfb/KeyRemapper.h>
|
#include <rfb/KeyRemapper.h>
|
||||||
#include <rfb/ListConnInfo.h>
|
#include <rfb/ListConnInfo.h>
|
||||||
@@ -77,8 +76,6 @@ static LogWriter slog("VNCServerST");
|
|||||||
LogWriter VNCServerST::connectionsLog("Connections");
|
LogWriter VNCServerST::connectionsLog("Connections");
|
||||||
EncCache VNCServerST::encCache;
|
EncCache VNCServerST::encCache;
|
||||||
|
|
||||||
void SelfBench();
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// -=- VNCServerST Implementation
|
// -=- VNCServerST Implementation
|
||||||
//
|
//
|
||||||
@@ -131,13 +128,10 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
|
|||||||
renderedCursorInvalid(false),
|
renderedCursorInvalid(false),
|
||||||
queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
|
queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
|
||||||
lastConnectionTime(0), disableclients(false),
|
lastConnectionTime(0), disableclients(false),
|
||||||
frameTimer(this), apimessager(NULL), trackingFrameStats(0)
|
frameTimer(this), apimessager(NULL)
|
||||||
{
|
{
|
||||||
lastUserInputTime = lastDisconnectTime = time(0);
|
lastUserInputTime = lastDisconnectTime = time(0);
|
||||||
slog.debug("creating single-threaded server %s", name.buf);
|
slog.debug("creating single-threaded server %s", name.buf);
|
||||||
slog.info("CPU capability: SSE2 %s, AVX512f %s",
|
|
||||||
supportsSSE2() ? "yes" : "no",
|
|
||||||
supportsAVX512f() ? "yes" : "no");
|
|
||||||
|
|
||||||
DLPRegion.enabled = DLPRegion.percents = false;
|
DLPRegion.enabled = DLPRegion.percents = false;
|
||||||
|
|
||||||
@@ -216,11 +210,6 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
|
|||||||
if (inotify_add_watch(inotifyfd, kasmpasswdpath, IN_CLOSE_WRITE | IN_DELETE_SELF) < 0)
|
if (inotify_add_watch(inotifyfd, kasmpasswdpath, IN_CLOSE_WRITE | IN_DELETE_SELF) < 0)
|
||||||
slog.error("Failed to set watch");
|
slog.error("Failed to set watch");
|
||||||
}
|
}
|
||||||
|
|
||||||
trackingClient[0] = 0;
|
|
||||||
|
|
||||||
if (Server::selfBench)
|
|
||||||
SelfBench();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VNCServerST::~VNCServerST()
|
VNCServerST::~VNCServerST()
|
||||||
@@ -282,11 +271,6 @@ void VNCServerST::removeSocket(network::Socket* sock) {
|
|||||||
std::list<VNCSConnectionST*>::iterator ci;
|
std::list<VNCSConnectionST*>::iterator ci;
|
||||||
for (ci = clients.begin(); ci != clients.end(); ci++) {
|
for (ci = clients.begin(); ci != clients.end(); ci++) {
|
||||||
if ((*ci)->getSock() == sock) {
|
if ((*ci)->getSock() == sock) {
|
||||||
|
|
||||||
if (clipboardClient == *ci)
|
|
||||||
handleClipboardAnnounce(*ci, false);
|
|
||||||
clipboardRequestors.remove(*ci);
|
|
||||||
|
|
||||||
// - Delete the per-Socket resources
|
// - Delete the per-Socket resources
|
||||||
delete *ci;
|
delete *ci;
|
||||||
|
|
||||||
@@ -518,6 +502,14 @@ void VNCServerST::setScreenLayout(const ScreenSet& layout)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VNCServerST::requestClipboard()
|
||||||
|
{
|
||||||
|
if (clipboardClient == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
clipboardClient->requestClipboard();
|
||||||
|
}
|
||||||
|
|
||||||
void VNCServerST::announceClipboard(bool available)
|
void VNCServerST::announceClipboard(bool available)
|
||||||
{
|
{
|
||||||
std::list<VNCSConnectionST*>::iterator ci, ci_next;
|
std::list<VNCSConnectionST*>::iterator ci, ci_next;
|
||||||
@@ -533,31 +525,20 @@ void VNCServerST::announceClipboard(bool available)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCServerST::sendBinaryClipboardData(const char* mime, const unsigned char *data,
|
void VNCServerST::sendClipboardData(const char* data)
|
||||||
const unsigned len)
|
|
||||||
{
|
{
|
||||||
std::list<VNCSConnectionST*>::iterator ci, ci_next;
|
std::list<VNCSConnectionST*>::iterator ci, ci_next;
|
||||||
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
|
|
||||||
ci_next = ci; ci_next++;
|
|
||||||
(*ci)->sendBinaryClipboardDataOrClose(mime, data, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VNCServerST::getBinaryClipboardData(const char* mime, const unsigned char **data,
|
if (strchr(data, '\r') != NULL)
|
||||||
unsigned *len)
|
throw Exception("Invalid carriage return in clipboard data");
|
||||||
{
|
|
||||||
if (!clipboardClient)
|
|
||||||
return;
|
|
||||||
clipboardClient->getBinaryClipboardData(mime, data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VNCServerST::clearBinaryClipboardData()
|
for (ci = clipboardRequestors.begin();
|
||||||
{
|
ci != clipboardRequestors.end(); ci = ci_next) {
|
||||||
std::list<VNCSConnectionST*>::iterator ci, ci_next;
|
|
||||||
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
|
|
||||||
ci_next = ci; ci_next++;
|
ci_next = ci; ci_next++;
|
||||||
(*ci)->clearBinaryClipboardData();
|
(*ci)->sendClipboardDataOrClose(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clipboardRequestors.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCServerST::bell()
|
void VNCServerST::bell()
|
||||||
@@ -598,7 +579,7 @@ void VNCServerST::add_copied(const Region& dest, const Point& delta)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
|
void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
|
||||||
const rdr::U8* data, const bool resizing)
|
const rdr::U8* data)
|
||||||
{
|
{
|
||||||
delete cursor;
|
delete cursor;
|
||||||
cursor = new Cursor(width, height, newHotspot, data);
|
cursor = new Cursor(width, height, newHotspot, data);
|
||||||
@@ -606,13 +587,6 @@ void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
|
|||||||
|
|
||||||
renderedCursorInvalid = true;
|
renderedCursorInvalid = true;
|
||||||
|
|
||||||
// If an app has an animated cursor on the resized edge, X internals
|
|
||||||
// will call for it to be rendered. Unlucky for us, the VNC screen
|
|
||||||
// is currently pointing to freed memory, and a cursor change
|
|
||||||
// would want to send a screen update. So, don't do that.
|
|
||||||
if (resizing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::list<VNCSConnectionST*>::iterator ci, ci_next;
|
std::list<VNCSConnectionST*>::iterator ci, ci_next;
|
||||||
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
|
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
|
||||||
ci_next = ci; ci_next++;
|
ci_next = ci; ci_next++;
|
||||||
@@ -793,8 +767,7 @@ int VNCServerST::msToNextUpdate()
|
|||||||
return frameTimer.getRemainingMs();
|
return frameTimer.getRemainingMs();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkAPIMessages(network::GetAPIMessager *apimessager,
|
static void checkAPIMessages(network::GetAPIMessager *apimessager)
|
||||||
rdr::U8 &trackingFrameStats, char trackingClient[])
|
|
||||||
{
|
{
|
||||||
if (pthread_mutex_lock(&apimessager->userMutex))
|
if (pthread_mutex_lock(&apimessager->userMutex))
|
||||||
return;
|
return;
|
||||||
@@ -847,20 +820,6 @@ static void checkAPIMessages(network::GetAPIMessager *apimessager,
|
|||||||
slog.error("Tried to give control to nonexistent user %s", act.data.user);
|
slog.error("Tried to give control to nonexistent user %s", act.data.user);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case network::GetAPIMessager::WANT_FRAME_STATS_SERVERONLY:
|
|
||||||
trackingFrameStats = act.action;
|
|
||||||
break;
|
|
||||||
case network::GetAPIMessager::WANT_FRAME_STATS_ALL:
|
|
||||||
trackingFrameStats = act.action;
|
|
||||||
break;
|
|
||||||
case network::GetAPIMessager::WANT_FRAME_STATS_OWNER:
|
|
||||||
trackingFrameStats = act.action;
|
|
||||||
break;
|
|
||||||
case network::GetAPIMessager::WANT_FRAME_STATS_SPECIFIC:
|
|
||||||
trackingFrameStats = act.action;
|
|
||||||
memcpy(trackingClient, act.data.password, 128);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set) {
|
if (set) {
|
||||||
@@ -957,9 +916,6 @@ void VNCServerST::writeUpdate()
|
|||||||
assert(blockCounter == 0);
|
assert(blockCounter == 0);
|
||||||
assert(desktopStarted);
|
assert(desktopStarted);
|
||||||
|
|
||||||
struct timeval start;
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
|
|
||||||
if (DLPRegion.enabled) {
|
if (DLPRegion.enabled) {
|
||||||
comparer->enable_copyrect(false);
|
comparer->enable_copyrect(false);
|
||||||
blackOut();
|
blackOut();
|
||||||
@@ -986,9 +942,6 @@ void VNCServerST::writeUpdate()
|
|||||||
else
|
else
|
||||||
comparer->disable();
|
comparer->disable();
|
||||||
|
|
||||||
struct timeval beforeAnalysis;
|
|
||||||
gettimeofday(&beforeAnalysis, NULL);
|
|
||||||
|
|
||||||
// Skip scroll detection if the client is slow, and didn't get the previous one yet
|
// Skip scroll detection if the client is slow, and didn't get the previous one yet
|
||||||
if (comparer->compare(clients.size() == 1 && (*clients.begin())->has_copypassed(),
|
if (comparer->compare(clients.size() == 1 && (*clients.begin())->has_copypassed(),
|
||||||
cursorReg))
|
cursorReg))
|
||||||
@@ -996,8 +949,6 @@ void VNCServerST::writeUpdate()
|
|||||||
|
|
||||||
comparer->clear();
|
comparer->clear();
|
||||||
|
|
||||||
const unsigned analysisMs = msSince(&beforeAnalysis);
|
|
||||||
|
|
||||||
encCache.clear();
|
encCache.clear();
|
||||||
encCache.enabled = clients.size() > 1;
|
encCache.enabled = clients.size() > 1;
|
||||||
|
|
||||||
@@ -1023,22 +974,11 @@ void VNCServerST::writeUpdate()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned shottime = 0;
|
|
||||||
if (apimessager) {
|
if (apimessager) {
|
||||||
struct timeval shotstart;
|
|
||||||
gettimeofday(&shotstart, NULL);
|
|
||||||
apimessager->mainUpdateScreen(pb);
|
apimessager->mainUpdateScreen(pb);
|
||||||
shottime = msSince(&shotstart);
|
|
||||||
|
|
||||||
trackingFrameStats = 0;
|
checkAPIMessages(apimessager);
|
||||||
checkAPIMessages(apimessager, trackingFrameStats, trackingClient);
|
|
||||||
}
|
}
|
||||||
const rdr::U8 origtrackingFrameStats = trackingFrameStats;
|
|
||||||
|
|
||||||
EncodeManager::codecstats_t jpegstats, webpstats;
|
|
||||||
unsigned enctime = 0, scaletime = 0;
|
|
||||||
memset(&jpegstats, 0, sizeof(EncodeManager::codecstats_t));
|
|
||||||
memset(&webpstats, 0, sizeof(EncodeManager::codecstats_t));
|
|
||||||
|
|
||||||
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
|
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
|
||||||
ci_next = ci; ci_next++;
|
ci_next = ci; ci_next++;
|
||||||
@@ -1046,68 +986,10 @@ void VNCServerST::writeUpdate()
|
|||||||
if (permcheck)
|
if (permcheck)
|
||||||
(*ci)->recheckPerms();
|
(*ci)->recheckPerms();
|
||||||
|
|
||||||
if (trackingFrameStats == network::GetAPIMessager::WANT_FRAME_STATS_ALL ||
|
|
||||||
(trackingFrameStats == network::GetAPIMessager::WANT_FRAME_STATS_OWNER &&
|
|
||||||
(*ci)->is_owner()) ||
|
|
||||||
(trackingFrameStats == network::GetAPIMessager::WANT_FRAME_STATS_SPECIFIC &&
|
|
||||||
strstr((*ci)->getPeerEndpoint(), trackingClient))) {
|
|
||||||
|
|
||||||
(*ci)->setFrameTracking();
|
|
||||||
|
|
||||||
// Only one owner
|
|
||||||
if (trackingFrameStats == network::GetAPIMessager::WANT_FRAME_STATS_OWNER)
|
|
||||||
trackingFrameStats = network::GetAPIMessager::WANT_FRAME_STATS_SERVERONLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*ci)->add_copied(ui.copied, ui.copy_delta);
|
(*ci)->add_copied(ui.copied, ui.copy_delta);
|
||||||
(*ci)->add_copypassed(ui.copypassed);
|
(*ci)->add_copypassed(ui.copypassed);
|
||||||
(*ci)->add_changed(ui.changed);
|
(*ci)->add_changed(ui.changed);
|
||||||
(*ci)->writeFramebufferUpdateOrClose();
|
(*ci)->writeFramebufferUpdateOrClose();
|
||||||
|
|
||||||
if (apimessager) {
|
|
||||||
(*ci)->sendStats(false);
|
|
||||||
const EncodeManager::codecstats_t subjpeg = (*ci)->getJpegStats();
|
|
||||||
const EncodeManager::codecstats_t subwebp = (*ci)->getWebpStats();
|
|
||||||
|
|
||||||
jpegstats.ms += subjpeg.ms;
|
|
||||||
jpegstats.area += subjpeg.area;
|
|
||||||
jpegstats.rects += subjpeg.rects;
|
|
||||||
|
|
||||||
webpstats.ms += subwebp.ms;
|
|
||||||
webpstats.area += subwebp.area;
|
|
||||||
webpstats.rects += subwebp.rects;
|
|
||||||
|
|
||||||
enctime += (*ci)->getEncodingTime();
|
|
||||||
scaletime += (*ci)->getScalingTime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trackingFrameStats) {
|
|
||||||
if (enctime) {
|
|
||||||
const unsigned totalMs = msSince(&start);
|
|
||||||
|
|
||||||
if (apimessager)
|
|
||||||
apimessager->mainUpdateServerFrameStats(comparer->changedPerc, totalMs,
|
|
||||||
jpegstats.ms, webpstats.ms,
|
|
||||||
analysisMs,
|
|
||||||
jpegstats.area, webpstats.area,
|
|
||||||
jpegstats.rects, webpstats.rects,
|
|
||||||
enctime, scaletime, shottime,
|
|
||||||
pb->getRect().width(),
|
|
||||||
pb->getRect().height());
|
|
||||||
} else {
|
|
||||||
// Zero encoding time means this was a no-data frame; restore the stats request
|
|
||||||
if (apimessager && pthread_mutex_lock(&apimessager->userMutex) == 0) {
|
|
||||||
|
|
||||||
network::GetAPIMessager::action_data act;
|
|
||||||
act.action = (network::GetAPIMessager::USER_ACTION) origtrackingFrameStats;
|
|
||||||
memcpy(act.data.password, trackingClient, 128);
|
|
||||||
|
|
||||||
apimessager->actionQueue.push_back(act);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&apimessager->userMutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1201,6 +1083,13 @@ bool VNCServerST::getComparerState()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VNCServerST::handleClipboardRequest(VNCSConnectionST* client)
|
||||||
|
{
|
||||||
|
clipboardRequestors.push_back(client);
|
||||||
|
if (clipboardRequestors.size() == 1)
|
||||||
|
desktop->handleClipboardRequest();
|
||||||
|
}
|
||||||
|
|
||||||
void VNCServerST::handleClipboardAnnounce(VNCSConnectionST* client,
|
void VNCServerST::handleClipboardAnnounce(VNCSConnectionST* client,
|
||||||
bool available)
|
bool available)
|
||||||
{
|
{
|
||||||
@@ -1214,10 +1103,11 @@ void VNCServerST::handleClipboardAnnounce(VNCSConnectionST* client,
|
|||||||
desktop->handleClipboardAnnounce(available);
|
desktop->handleClipboardAnnounce(available);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCServerST::handleClipboardAnnounceBinary(VNCSConnectionST* client,
|
void VNCServerST::handleClipboardData(VNCSConnectionST* client,
|
||||||
const unsigned num,
|
const char* data, int len)
|
||||||
const char mimes[][32])
|
|
||||||
{
|
{
|
||||||
clipboardClient = client;
|
if (client != clipboardClient)
|
||||||
desktop->handleClipboardAnnounceBinary(num, mimes);
|
return;
|
||||||
|
desktop->handleClipboardData(data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,16 +96,13 @@ namespace rfb {
|
|||||||
virtual void setPixelBuffer(PixelBuffer* pb);
|
virtual void setPixelBuffer(PixelBuffer* pb);
|
||||||
virtual void setScreenLayout(const ScreenSet& layout);
|
virtual void setScreenLayout(const ScreenSet& layout);
|
||||||
virtual PixelBuffer* getPixelBuffer() const { if (DLPRegion.enabled && blackedpb) return blackedpb; else return pb; }
|
virtual PixelBuffer* getPixelBuffer() const { if (DLPRegion.enabled && blackedpb) return blackedpb; else return pb; }
|
||||||
|
virtual void requestClipboard();
|
||||||
virtual void announceClipboard(bool available);
|
virtual void announceClipboard(bool available);
|
||||||
virtual void clearBinaryClipboardData();
|
virtual void sendClipboardData(const char* data);
|
||||||
virtual void sendBinaryClipboardData(const char* mime, const unsigned char *data,
|
|
||||||
const unsigned len);
|
|
||||||
virtual void getBinaryClipboardData(const char *mime, const unsigned char **ptr,
|
|
||||||
unsigned *len);
|
|
||||||
virtual void add_changed(const Region ®ion);
|
virtual void add_changed(const Region ®ion);
|
||||||
virtual void add_copied(const Region &dest, const Point &delta);
|
virtual void add_copied(const Region &dest, const Point &delta);
|
||||||
virtual void setCursor(int width, int height, const Point& hotspot,
|
virtual void setCursor(int width, int height, const Point& hotspot,
|
||||||
const rdr::U8* data, const bool resizing = false);
|
const rdr::U8* data);
|
||||||
virtual void setCursorPos(const Point& p, bool warped);
|
virtual void setCursorPos(const Point& p, bool warped);
|
||||||
virtual void setLEDState(unsigned state);
|
virtual void setLEDState(unsigned state);
|
||||||
|
|
||||||
@@ -194,9 +191,9 @@ namespace rfb {
|
|||||||
|
|
||||||
void setAPIMessager(network::GetAPIMessager *msgr) { apimessager = msgr; }
|
void setAPIMessager(network::GetAPIMessager *msgr) { apimessager = msgr; }
|
||||||
|
|
||||||
|
void handleClipboardRequest(VNCSConnectionST* client);
|
||||||
void handleClipboardAnnounce(VNCSConnectionST* client, bool available);
|
void handleClipboardAnnounce(VNCSConnectionST* client, bool available);
|
||||||
void handleClipboardAnnounceBinary(VNCSConnectionST* client, const unsigned num,
|
void handleClipboardData(VNCSConnectionST* client, const char* data, int len);
|
||||||
const char mimes[][32]);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -270,9 +267,6 @@ namespace rfb {
|
|||||||
|
|
||||||
network::GetAPIMessager *apimessager;
|
network::GetAPIMessager *apimessager;
|
||||||
|
|
||||||
rdr::U8 trackingFrameStats;
|
|
||||||
char trackingClient[128];
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool enabled;
|
bool enabled;
|
||||||
int x1, y1, x2, y2;
|
int x1, y1, x2, y2;
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
/* Copyright (C) 2021 Kasm Web
|
|
||||||
*
|
|
||||||
* This is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this software; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
||||||
* USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
static uint32_t cpuid[4] = { 0 };
|
|
||||||
static uint32_t extcpuid[4] = { 0 };
|
|
||||||
|
|
||||||
static void getcpuid() {
|
|
||||||
if (cpuid[0])
|
|
||||||
return;
|
|
||||||
|
|
||||||
#if defined(__x86_64__) || defined(__i386__)
|
|
||||||
uint32_t eax, ecx = 0;
|
|
||||||
|
|
||||||
eax = 1; // normal feature bits
|
|
||||||
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"cpuid\n\t"
|
|
||||||
: "=a"(cpuid[0]), "=b"(cpuid[1]), "=c"(cpuid[2]), "=d"(cpuid[3])
|
|
||||||
: "0"(eax), "2"(ecx)
|
|
||||||
);
|
|
||||||
|
|
||||||
eax = 7; // ext feature bits
|
|
||||||
ecx = 0;
|
|
||||||
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"cpuid\n\t"
|
|
||||||
: "=a"(extcpuid[0]), "=b"(extcpuid[1]), "=c"(extcpuid[2]), "=d"(extcpuid[3])
|
|
||||||
: "0"(eax), "2"(ecx)
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace rfb {
|
|
||||||
|
|
||||||
bool supportsSSE2() {
|
|
||||||
getcpuid();
|
|
||||||
#if defined(__x86_64__) || defined(__i386__)
|
|
||||||
#define bit_SSE2 (1 << 26)
|
|
||||||
return cpuid[3] & bit_SSE2;
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool supportsAVX512f() {
|
|
||||||
getcpuid();
|
|
||||||
#if defined(__x86_64__) || defined(__i386__)
|
|
||||||
#define bit_AVX512f (1 << 16)
|
|
||||||
return extcpuid[1] & bit_AVX512f;
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}; // namespace rfb
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/* Copyright (C) 2021 Kasm Web
|
|
||||||
*
|
|
||||||
* This is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this software; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
||||||
* USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __RFB_CPUID_H__
|
|
||||||
#define __RFB_CPUID_H__
|
|
||||||
|
|
||||||
namespace rfb {
|
|
||||||
|
|
||||||
bool supportsSSE2();
|
|
||||||
bool supportsAVX512f();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -86,7 +86,6 @@ namespace rfb {
|
|||||||
const int pseudoEncodingVideoOutTimeLevel100 = -1887;
|
const int pseudoEncodingVideoOutTimeLevel100 = -1887;
|
||||||
|
|
||||||
// VMware-specific
|
// VMware-specific
|
||||||
const int pseudoEncodingVMwareCursor = 0x574d5664;
|
|
||||||
const int pseudoEncodingVMwareCursorPosition = 0x574d5666;
|
const int pseudoEncodingVMwareCursorPosition = 0x574d5666;
|
||||||
|
|
||||||
// UltraVNC-specific
|
// UltraVNC-specific
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ namespace rfb {
|
|||||||
|
|
||||||
// kasm
|
// kasm
|
||||||
const int msgTypeStats = 178;
|
const int msgTypeStats = 178;
|
||||||
const int msgTypeRequestFrameStats = 179;
|
|
||||||
const int msgTypeBinaryClipboard = 180;
|
|
||||||
|
|
||||||
const int msgTypeServerFence = 248;
|
const int msgTypeServerFence = 248;
|
||||||
|
|
||||||
@@ -49,8 +47,6 @@ namespace rfb {
|
|||||||
|
|
||||||
// kasm
|
// kasm
|
||||||
const int msgTypeRequestStats = 178;
|
const int msgTypeRequestStats = 178;
|
||||||
const int msgTypeFrameStats = 179;
|
|
||||||
//const int msgTypeBinaryClipboard = 180;
|
|
||||||
|
|
||||||
const int msgTypeClientFence = 248;
|
const int msgTypeClientFence = 248;
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
/* Copyright (C) 2021 Kasm Web
|
|
||||||
*
|
|
||||||
* This is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this software; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
||||||
* USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <rfb/scale_sse2.h>
|
|
||||||
|
|
||||||
namespace rfb {
|
|
||||||
|
|
||||||
void SSE2_halve(const uint8_t *oldpx,
|
|
||||||
const uint16_t tgtw, const uint16_t tgth,
|
|
||||||
uint8_t *newpx,
|
|
||||||
const unsigned oldstride, const unsigned newstride) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handles factors between 0.5 and 1.0
|
|
||||||
void SSE2_scale(const uint8_t *oldpx,
|
|
||||||
const uint16_t tgtw, const uint16_t tgth,
|
|
||||||
uint8_t *newpx,
|
|
||||||
const unsigned oldstride, const unsigned newstride,
|
|
||||||
const float tgtdiff) {
|
|
||||||
}
|
|
||||||
|
|
||||||
}; // namespace rfb
|
|
||||||
@@ -1,257 +0,0 @@
|
|||||||
/* Copyright (C) 2021 Kasm Web
|
|
||||||
*
|
|
||||||
* This is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this software; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
||||||
* USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <emmintrin.h>
|
|
||||||
|
|
||||||
#include <rfb/scale_sse2.h>
|
|
||||||
|
|
||||||
namespace rfb {
|
|
||||||
|
|
||||||
/*
|
|
||||||
static void print128(const char msg[], const __m128i v) {
|
|
||||||
union {
|
|
||||||
__m128i v;
|
|
||||||
uint8_t c[16];
|
|
||||||
} u;
|
|
||||||
|
|
||||||
u.v = v;
|
|
||||||
|
|
||||||
printf("%s %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
|
|
||||||
msg,
|
|
||||||
u.c[0],
|
|
||||||
u.c[1],
|
|
||||||
u.c[2],
|
|
||||||
u.c[3],
|
|
||||||
u.c[4],
|
|
||||||
u.c[5],
|
|
||||||
u.c[6],
|
|
||||||
u.c[7],
|
|
||||||
u.c[8],
|
|
||||||
u.c[9],
|
|
||||||
u.c[10],
|
|
||||||
u.c[11],
|
|
||||||
u.c[12],
|
|
||||||
u.c[13],
|
|
||||||
u.c[14],
|
|
||||||
u.c[15]);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
void SSE2_halve(const uint8_t *oldpx,
|
|
||||||
const uint16_t tgtw, const uint16_t tgth,
|
|
||||||
uint8_t *newpx,
|
|
||||||
const unsigned oldstride, const unsigned newstride) {
|
|
||||||
uint16_t x, y;
|
|
||||||
const uint16_t srcw = tgtw * 2, srch = tgth * 2;
|
|
||||||
const __m128i zero = _mm_setzero_si128();
|
|
||||||
const __m128i shift = _mm_set_epi32(0, 0, 0, 2);
|
|
||||||
const __m128i low = _mm_set_epi32(0, 0, 0xffffffff, 0xffffffff);
|
|
||||||
const __m128i high = _mm_set_epi32(0xffffffff, 0xffffffff, 0, 0);
|
|
||||||
|
|
||||||
for (y = 0; y < srch; y += 2) {
|
|
||||||
const uint8_t * const row0 = oldpx + oldstride * y * 4;
|
|
||||||
const uint8_t * const row1 = oldpx + oldstride * (y + 1) * 4;
|
|
||||||
|
|
||||||
uint8_t * const dst = newpx + newstride * (y / 2) * 4;
|
|
||||||
|
|
||||||
for (x = 0; x < srcw - 3; x += 4) {
|
|
||||||
__m128i lo, hi, a, b, c, d;
|
|
||||||
lo = _mm_loadu_si128((__m128i *) &row0[x * 4]);
|
|
||||||
hi = _mm_loadu_si128((__m128i *) &row1[x * 4]);
|
|
||||||
|
|
||||||
a = _mm_unpacklo_epi8(lo, zero);
|
|
||||||
b = _mm_unpackhi_epi8(lo, zero);
|
|
||||||
c = _mm_unpacklo_epi8(hi, zero);
|
|
||||||
d = _mm_unpackhi_epi8(hi, zero);
|
|
||||||
|
|
||||||
a = _mm_add_epi16(a, c);
|
|
||||||
b = _mm_add_epi16(b, d);
|
|
||||||
|
|
||||||
c = _mm_srli_si128(a, 8);
|
|
||||||
a = _mm_and_si128(a, low);
|
|
||||||
a = _mm_add_epi16(a, c);
|
|
||||||
|
|
||||||
d = _mm_slli_si128(b, 8);
|
|
||||||
b = _mm_and_si128(b, high);
|
|
||||||
b = _mm_add_epi16(b, d);
|
|
||||||
|
|
||||||
a = _mm_add_epi16(a, b);
|
|
||||||
|
|
||||||
a = _mm_srl_epi16(a, shift);
|
|
||||||
a = _mm_packus_epi16(a, zero);
|
|
||||||
|
|
||||||
_mm_storel_epi64((__m128i *) &dst[(x / 2) * 4], a);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; x < srcw; x += 2) {
|
|
||||||
// Remainder in C
|
|
||||||
uint8_t i;
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
dst[(x / 2) * 4 + i] =
|
|
||||||
(row0[x * 4 + i] +
|
|
||||||
row0[(x + 1) * 4 + i] +
|
|
||||||
row1[x * 4 + i] +
|
|
||||||
row1[(x + 1) * 4 + i]) / 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handles factors between 0.5 and 1.0
|
|
||||||
void SSE2_scale(const uint8_t *oldpx,
|
|
||||||
const uint16_t tgtw, const uint16_t tgth,
|
|
||||||
uint8_t *newpx,
|
|
||||||
const unsigned oldstride, const unsigned newstride,
|
|
||||||
const float tgtdiff) {
|
|
||||||
|
|
||||||
uint16_t x, y;
|
|
||||||
const __m128i zero = _mm_setzero_si128();
|
|
||||||
const __m128i low = _mm_set_epi32(0, 0, 0xffffffff, 0xffffffff);
|
|
||||||
const __m128i high = _mm_set_epi32(0xffffffff, 0xffffffff, 0, 0);
|
|
||||||
const float invdiff = 1 / tgtdiff;
|
|
||||||
|
|
||||||
for (y = 0; y < tgth; y++) {
|
|
||||||
const float ny = y * invdiff;
|
|
||||||
const uint16_t lowy = ny;
|
|
||||||
const uint16_t highy = lowy + 1;
|
|
||||||
const uint16_t bot = (ny - lowy) * 256;
|
|
||||||
const uint16_t top = 256 - bot;
|
|
||||||
const uint32_t * const row0 = (uint32_t *) (oldpx + oldstride * lowy * 4);
|
|
||||||
const uint32_t * const row1 = (uint32_t *) (oldpx + oldstride * highy * 4);
|
|
||||||
const uint8_t * const brow0 = (uint8_t *) row0;
|
|
||||||
const uint8_t * const brow1 = (uint8_t *) row1;
|
|
||||||
|
|
||||||
uint8_t * const dst = newpx + newstride * y * 4;
|
|
||||||
|
|
||||||
const __m128i vertmul = _mm_set1_epi16(top);
|
|
||||||
const __m128i vertmul2 = _mm_set1_epi16(bot);
|
|
||||||
|
|
||||||
for (x = 0; x < tgtw - 1; x += 2) {
|
|
||||||
const float nx[2] = {
|
|
||||||
x * invdiff,
|
|
||||||
(x + 1) * invdiff,
|
|
||||||
};
|
|
||||||
const uint16_t lowx[2] = {
|
|
||||||
(uint16_t) nx[0],
|
|
||||||
(uint16_t) nx[1],
|
|
||||||
};
|
|
||||||
const uint16_t highx[2] = {
|
|
||||||
(uint16_t) (lowx[0] + 1),
|
|
||||||
(uint16_t) (lowx[1] + 1),
|
|
||||||
};
|
|
||||||
const uint16_t right[2] = {
|
|
||||||
(uint16_t) ((nx[0] - lowx[0]) * 256),
|
|
||||||
(uint16_t) ((nx[1] - lowx[1]) * 256),
|
|
||||||
};
|
|
||||||
const uint16_t left[2] = {
|
|
||||||
(uint16_t) (256 - right[0]),
|
|
||||||
(uint16_t) (256 - right[1]),
|
|
||||||
};
|
|
||||||
|
|
||||||
const __m128i horzmul = _mm_set_epi16(
|
|
||||||
right[0],
|
|
||||||
right[0],
|
|
||||||
right[0],
|
|
||||||
right[0],
|
|
||||||
left[0],
|
|
||||||
left[0],
|
|
||||||
left[0],
|
|
||||||
left[0]
|
|
||||||
);
|
|
||||||
const __m128i horzmul2 = _mm_set_epi16(
|
|
||||||
right[1],
|
|
||||||
right[1],
|
|
||||||
right[1],
|
|
||||||
right[1],
|
|
||||||
left[1],
|
|
||||||
left[1],
|
|
||||||
left[1],
|
|
||||||
left[1]
|
|
||||||
);
|
|
||||||
|
|
||||||
__m128i lo, hi, a, b, c, d;
|
|
||||||
lo = _mm_setr_epi32(row0[lowx[0]],
|
|
||||||
row0[highx[0]],
|
|
||||||
row0[lowx[1]],
|
|
||||||
row0[highx[1]]);
|
|
||||||
hi = _mm_setr_epi32(row1[lowx[0]],
|
|
||||||
row1[highx[0]],
|
|
||||||
row1[lowx[1]],
|
|
||||||
row1[highx[1]]);
|
|
||||||
|
|
||||||
a = _mm_unpacklo_epi8(lo, zero);
|
|
||||||
b = _mm_unpackhi_epi8(lo, zero);
|
|
||||||
c = _mm_unpacklo_epi8(hi, zero);
|
|
||||||
d = _mm_unpackhi_epi8(hi, zero);
|
|
||||||
|
|
||||||
a = _mm_mullo_epi16(a, vertmul);
|
|
||||||
b = _mm_mullo_epi16(b, vertmul);
|
|
||||||
c = _mm_mullo_epi16(c, vertmul2);
|
|
||||||
d = _mm_mullo_epi16(d, vertmul2);
|
|
||||||
|
|
||||||
a = _mm_add_epi16(a, c);
|
|
||||||
a = _mm_srli_epi16(a, 8);
|
|
||||||
b = _mm_add_epi16(b, d);
|
|
||||||
b = _mm_srli_epi16(b, 8);
|
|
||||||
|
|
||||||
a = _mm_mullo_epi16(a, horzmul);
|
|
||||||
b = _mm_mullo_epi16(b, horzmul2);
|
|
||||||
|
|
||||||
lo = _mm_srli_si128(a, 8);
|
|
||||||
a = _mm_and_si128(a, low);
|
|
||||||
a = _mm_add_epi16(a, lo);
|
|
||||||
|
|
||||||
hi = _mm_slli_si128(b, 8);
|
|
||||||
b = _mm_and_si128(b, high);
|
|
||||||
b = _mm_add_epi16(b, hi);
|
|
||||||
|
|
||||||
a = _mm_add_epi16(a, b);
|
|
||||||
a = _mm_srli_epi16(a, 8);
|
|
||||||
|
|
||||||
a = _mm_packus_epi16(a, zero);
|
|
||||||
|
|
||||||
_mm_storel_epi64((__m128i *) &dst[x * 4], a);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; x < tgtw; x++) {
|
|
||||||
// Remainder in C
|
|
||||||
const float nx = x * invdiff;
|
|
||||||
const uint16_t lowx = nx;
|
|
||||||
const uint16_t highx = lowx + 1;
|
|
||||||
const uint16_t right = (nx - lowx) * 256;
|
|
||||||
const uint16_t left = 256 - right;
|
|
||||||
|
|
||||||
uint8_t i;
|
|
||||||
uint32_t val, val2;
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
val = brow0[lowx * 4 + i] * left;
|
|
||||||
val += brow0[highx * 4 + i] * right;
|
|
||||||
val >>= 8;
|
|
||||||
|
|
||||||
val2 = brow1[lowx * 4 + i] * left;
|
|
||||||
val2 += brow1[highx * 4 + i] * right;
|
|
||||||
val2 >>= 8;
|
|
||||||
|
|
||||||
dst[x * 4 + i] =
|
|
||||||
(val * top + val2 * bot) >> 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}; // namespace rfb
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/* Copyright (C) 2021 Kasm Web
|
|
||||||
*
|
|
||||||
* This is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this software; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
||||||
* USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __RFB_SCALE_SSE2_H__
|
|
||||||
#define __RFB_SCALE_SSE2_H__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace rfb {
|
|
||||||
|
|
||||||
void SSE2_halve(const uint8_t *oldpx,
|
|
||||||
const uint16_t tgtw, const uint16_t tgth,
|
|
||||||
uint8_t *newpx,
|
|
||||||
const unsigned oldstride, const unsigned newstride);
|
|
||||||
|
|
||||||
void SSE2_scale(const uint8_t *oldpx,
|
|
||||||
const uint16_t tgtw, const uint16_t tgth,
|
|
||||||
uint8_t *newpx,
|
|
||||||
const unsigned oldstride, const unsigned newstride,
|
|
||||||
const float tgtdiff);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
2
debian/Makefile.to_fakebuild_tar_package
vendored
2
debian/Makefile.to_fakebuild_tar_package
vendored
@@ -1,7 +1,7 @@
|
|||||||
TARGET_OS := $(shell lsb_release -is | tr '[:upper:]' '[:lower:]')
|
TARGET_OS := $(shell lsb_release -is | tr '[:upper:]' '[:lower:]')
|
||||||
TARGET_OS_CODENAME := $(shell lsb_release -cs | tr '[:upper:]' '[:lower:]')
|
TARGET_OS_CODENAME := $(shell lsb_release -cs | tr '[:upper:]' '[:lower:]')
|
||||||
TARBALL_DIR := builder/build
|
TARBALL_DIR := builder/build
|
||||||
TARBALL := $(TARBALL_DIR)/kasmvnc.$(TARGET_OS)_$(TARGET_OS_CODENAME)$(BUILD_TAG).tar.gz
|
TARBALL := $(TARBALL_DIR)/kasmvnc.$(TARGET_OS)_$(TARGET_OS_CODENAME).tar.gz
|
||||||
TAR_DATA := $(shell mktemp -d)
|
TAR_DATA := $(shell mktemp -d)
|
||||||
SRC := $(TAR_DATA)/usr/local
|
SRC := $(TAR_DATA)/usr/local
|
||||||
SRC_BIN := $(SRC)/bin
|
SRC_BIN := $(SRC)/bin
|
||||||
|
|||||||
4
debian/control
vendored
4
debian/control
vendored
@@ -3,14 +3,14 @@ Section: x11
|
|||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Kasm Technologies LLC <info@kasmweb.com>
|
Maintainer: Kasm Technologies LLC <info@kasmweb.com>
|
||||||
Build-Depends: debhelper (>= 11), rsync, libjpeg-dev, libjpeg-dev, libpng-dev,
|
Build-Depends: debhelper (>= 11), rsync, libjpeg-dev, libjpeg-dev, libpng-dev,
|
||||||
libtiff-dev, libgif-dev, libavcodec-dev, libssl-dev, libgl1, libxfont2, libsm6, libunwind8
|
libtiff-dev, libgif-dev, libavcodec-dev, libssl-dev, libgl1, libxfont2, libsm6
|
||||||
Standards-Version: 4.1.3
|
Standards-Version: 4.1.3
|
||||||
Homepage: https://github.com/kasmtech/KasmVNC
|
Homepage: https://github.com/kasmtech/KasmVNC
|
||||||
#Vcs-Browser: https://salsa.debian.org/debian/kasmvnc
|
#Vcs-Browser: https://salsa.debian.org/debian/kasmvnc
|
||||||
#Vcs-Git: https://salsa.debian.org/debian/kasmvnc.git
|
#Vcs-Git: https://salsa.debian.org/debian/kasmvnc.git
|
||||||
|
|
||||||
Package: kasmvncserver
|
Package: kasmvncserver
|
||||||
Architecture: amd64 arm64
|
Architecture: amd64
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, ssl-cert, xauth,
|
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, ssl-cert, xauth,
|
||||||
x11-xkb-utils, xkb-data, procps
|
x11-xkb-utils, xkb-data, procps
|
||||||
Provides: vnc-server
|
Provides: vnc-server
|
||||||
|
|||||||
2
kasmweb
2
kasmweb
Submodule kasmweb updated: 9383783efd...9f9f4b3557
@@ -234,12 +234,38 @@ void vncPointerMove(int x, int y)
|
|||||||
cursorPosY = y;
|
cursorPosY = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vncScroll(int x, int y) {
|
void vncPointerMoveRelative(int x, int y, int absx, int absy)
|
||||||
|
{
|
||||||
|
int valuators[2];
|
||||||
|
#if XORG < 111
|
||||||
|
int n;
|
||||||
|
#endif
|
||||||
|
#if XORG >= 110
|
||||||
ValuatorMask mask;
|
ValuatorMask mask;
|
||||||
valuator_mask_zero(&mask);
|
#endif
|
||||||
valuator_mask_set(&mask, 2, x);
|
|
||||||
valuator_mask_set(&mask, 3, y);
|
// if (cursorPosX == absx && cursorPosY == absy)
|
||||||
QueuePointerEvents(vncPointerDev, MotionNotify, 0, POINTER_RELATIVE, &mask);
|
// return;
|
||||||
|
|
||||||
|
valuators[0] = x;
|
||||||
|
valuators[1] = y;
|
||||||
|
#if XORG < 110
|
||||||
|
n = GetPointerEvents(eventq, vncPointerDev, MotionNotify, 0,
|
||||||
|
POINTER_RELATIVE, 0, 2, valuators);
|
||||||
|
enqueueEvents(vncPointerDev, n);
|
||||||
|
#elif XORG < 111
|
||||||
|
valuator_mask_set_range(&mask, 0, 2, valuators);
|
||||||
|
n = GetPointerEvents(eventq, vncPointerDev, MotionNotify, 0,
|
||||||
|
POINTER_RELATIVE, &mask);
|
||||||
|
enqueueEvents(vncPointerDev, n);
|
||||||
|
#else
|
||||||
|
valuator_mask_set_range(&mask, 0, 2, valuators);
|
||||||
|
QueuePointerEvents(vncPointerDev, MotionNotify, 0,
|
||||||
|
POINTER_RELATIVE, &mask);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cursorPosX = absx;
|
||||||
|
cursorPosY = absy;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vncGetPointerPos(int *x, int *y)
|
void vncGetPointerPos(int *x, int *y)
|
||||||
@@ -269,7 +295,7 @@ static int vncPointerProc(DeviceIntPtr pDevice, int onoff)
|
|||||||
* is not a bug.
|
* is not a bug.
|
||||||
*/
|
*/
|
||||||
Atom btn_labels[BUTTONS];
|
Atom btn_labels[BUTTONS];
|
||||||
Atom axes_labels[4];
|
Atom axes_labels[2];
|
||||||
|
|
||||||
switch (onoff) {
|
switch (onoff) {
|
||||||
case DEVICE_INIT:
|
case DEVICE_INIT:
|
||||||
@@ -286,29 +312,11 @@ static int vncPointerProc(DeviceIntPtr pDevice, int onoff)
|
|||||||
|
|
||||||
axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
|
axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
|
||||||
axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
|
axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
|
||||||
axes_labels[2] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL);
|
|
||||||
axes_labels[3] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL);
|
|
||||||
|
|
||||||
|
|
||||||
InitPointerDeviceStruct(pDev, map, BUTTONS, btn_labels,
|
InitPointerDeviceStruct(pDev, map, BUTTONS, btn_labels,
|
||||||
(PtrCtrlProcPtr)NoopDDA,
|
(PtrCtrlProcPtr)NoopDDA,
|
||||||
GetMotionHistorySize(),
|
GetMotionHistorySize(),
|
||||||
4, axes_labels);
|
2, axes_labels);
|
||||||
|
|
||||||
InitValuatorAxisStruct(pDevice, 2, axes_labels[2], NO_AXIS_LIMITS, NO_AXIS_LIMITS, 0, 0, 0, Relative);
|
|
||||||
InitValuatorAxisStruct(pDevice, 3, axes_labels[3], NO_AXIS_LIMITS, NO_AXIS_LIMITS, 0, 0, 0, Relative);
|
|
||||||
|
|
||||||
char* envScrollFactorH = getenv("SCROLL_FACTOR_H");
|
|
||||||
char* envScrollFactorV = getenv("SCROLL_FACTOR_V");
|
|
||||||
|
|
||||||
float scrollFactorH = envScrollFactorH ? atof(envScrollFactorH) : 50.0;
|
|
||||||
float scrollFactorV = envScrollFactorV ? atof(envScrollFactorV) : 50.0;
|
|
||||||
|
|
||||||
LOG_INFO("Mouse horizonatl scroll factor: %f", scrollFactorH);
|
|
||||||
LOG_INFO("Mouse vertical scroll factor: %f", scrollFactorV);
|
|
||||||
|
|
||||||
SetScrollValuator(pDevice, 2, SCROLL_TYPE_HORIZONTAL, scrollFactorH, SCROLL_FLAG_NONE);
|
|
||||||
SetScrollValuator(pDevice, 3, SCROLL_TYPE_VERTICAL, scrollFactorV, SCROLL_FLAG_PREFERRED);
|
|
||||||
break;
|
break;
|
||||||
case DEVICE_ON:
|
case DEVICE_ON:
|
||||||
pDev->on = TRUE;
|
pDev->on = TRUE;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ void vncInitInputDevice(void);
|
|||||||
void vncPointerButtonAction(int buttonMask, const unsigned char skipclick,
|
void vncPointerButtonAction(int buttonMask, const unsigned char skipclick,
|
||||||
const unsigned char skiprelease);
|
const unsigned char skiprelease);
|
||||||
void vncPointerMove(int x, int y);
|
void vncPointerMove(int x, int y);
|
||||||
void vncScroll(int x, int y);
|
void vncPointerMoveRelative(int x, int y, int absx, int absy);
|
||||||
void vncGetPointerPos(int *x, int *y);
|
void vncGetPointerPos(int *x, int *y);
|
||||||
|
|
||||||
void vncKeyboardEvent(KeySym keysym, unsigned xtcode, int down);
|
void vncKeyboardEvent(KeySym keysym, unsigned xtcode, int down);
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ XserverDesktop::XserverDesktop(int screenIndex_,
|
|||||||
: screenIndex(screenIndex_),
|
: screenIndex(screenIndex_),
|
||||||
server(0), listeners(listeners_),
|
server(0), listeners(listeners_),
|
||||||
directFbptr(true),
|
directFbptr(true),
|
||||||
queryConnectId(0), queryConnectTimer(this), resizing(false)
|
queryConnectId(0), queryConnectTimer(this)
|
||||||
{
|
{
|
||||||
format = pf;
|
format = pf;
|
||||||
|
|
||||||
@@ -176,6 +176,15 @@ XserverDesktop::queryConnection(network::Socket* sock,
|
|||||||
return rfb::VNCServerST::PENDING;
|
return rfb::VNCServerST::PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XserverDesktop::requestClipboard()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
server->requestClipboard();
|
||||||
|
} catch (rdr::Exception& e) {
|
||||||
|
vlog.error("XserverDesktop::requestClipboard: %s",e.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void XserverDesktop::announceClipboard(bool available)
|
void XserverDesktop::announceClipboard(bool available)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -185,34 +194,12 @@ void XserverDesktop::announceClipboard(bool available)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XserverDesktop::clearBinaryClipboardData()
|
void XserverDesktop::sendClipboardData(const char* data)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
server->clearBinaryClipboardData();
|
server->sendClipboardData(data);
|
||||||
} catch (rdr::Exception& e) {
|
} catch (rdr::Exception& e) {
|
||||||
vlog.error("XserverDesktop::clearBinaryClipboardData: %s",e.str());
|
vlog.error("XserverDesktop::sendClipboardData: %s",e.str());
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void XserverDesktop::sendBinaryClipboardData(const char* mime,
|
|
||||||
const unsigned char *data,
|
|
||||||
const unsigned len)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
server->sendBinaryClipboardData(mime, data, len);
|
|
||||||
} catch (rdr::Exception& e) {
|
|
||||||
vlog.error("XserverDesktop::sendBinaryClipboardData: %s",e.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void XserverDesktop::getBinaryClipboardData(const char* mime,
|
|
||||||
const unsigned char **data,
|
|
||||||
unsigned *len)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
server->getBinaryClipboardData(mime, data, len);
|
|
||||||
} catch (rdr::Exception& e) {
|
|
||||||
vlog.error("XserverDesktop::getBinaryClipboardData: %s",e.str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +251,7 @@ void XserverDesktop::setCursor(int width, int height, int hotX, int hotY,
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
server->setCursor(width, height, Point(hotX, hotY), cursorData, resizing);
|
server->setCursor(width, height, Point(hotX, hotY), cursorData);
|
||||||
} catch (rdr::Exception& e) {
|
} catch (rdr::Exception& e) {
|
||||||
vlog.error("XserverDesktop::setCursor: %s",e.str());
|
vlog.error("XserverDesktop::setCursor: %s",e.str());
|
||||||
}
|
}
|
||||||
@@ -458,15 +445,18 @@ void XserverDesktop::approveConnection(uint32_t opaqueId, bool accept,
|
|||||||
// SDesktop callbacks
|
// SDesktop callbacks
|
||||||
|
|
||||||
|
|
||||||
void XserverDesktop::pointerEvent(const Point& pos, int buttonMask,
|
void XserverDesktop::pointerEvent(const Point& pos, const Point& abspos, int buttonMask,
|
||||||
const bool skipClick, const bool skipRelease, int scrollX, int scrollY)
|
const bool skipClick, const bool skipRelease)
|
||||||
{
|
{
|
||||||
if (scrollX == 0 && scrollY == 0) {
|
if (pos.equals(abspos)) {
|
||||||
vncPointerMove(pos.x + vncGetScreenX(screenIndex), pos.y + vncGetScreenY(screenIndex));
|
vncPointerMove(pos.x + vncGetScreenX(screenIndex),
|
||||||
vncPointerButtonAction(buttonMask, skipClick, skipRelease);
|
pos.y + vncGetScreenY(screenIndex));
|
||||||
} else {
|
} else {
|
||||||
vncScroll(scrollX, scrollY);
|
vncPointerMoveRelative(pos.x, pos.y,
|
||||||
|
abspos.x + vncGetScreenX(screenIndex),
|
||||||
|
abspos.y + vncGetScreenY(screenIndex));
|
||||||
}
|
}
|
||||||
|
vncPointerButtonAction(buttonMask, skipClick, skipRelease);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
|
unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
|
||||||
@@ -478,11 +468,13 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
|
|||||||
layout.print(buffer, sizeof(buffer));
|
layout.print(buffer, sizeof(buffer));
|
||||||
vlog.debug("%s", buffer);
|
vlog.debug("%s", buffer);
|
||||||
|
|
||||||
resizing = true;
|
|
||||||
vncSetGlueContext(screenIndex);
|
vncSetGlueContext(screenIndex);
|
||||||
const unsigned int ret = ::setScreenLayout(fb_width, fb_height, layout, &outputIdMap);
|
return ::setScreenLayout(fb_width, fb_height, layout, &outputIdMap);
|
||||||
resizing = false;
|
}
|
||||||
return ret;
|
|
||||||
|
void XserverDesktop::handleClipboardRequest()
|
||||||
|
{
|
||||||
|
vncHandleClipboardRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
void XserverDesktop::handleClipboardAnnounce(bool available)
|
void XserverDesktop::handleClipboardAnnounce(bool available)
|
||||||
@@ -490,9 +482,9 @@ void XserverDesktop::handleClipboardAnnounce(bool available)
|
|||||||
vncHandleClipboardAnnounce(available);
|
vncHandleClipboardAnnounce(available);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XserverDesktop::handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32])
|
void XserverDesktop::handleClipboardData(const char* data_, int len)
|
||||||
{
|
{
|
||||||
vncHandleClipboardAnnounceBinary(num, mimes);
|
vncHandleClipboardData(data_, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XserverDesktop::grabRegion(const rfb::Region& region)
|
void XserverDesktop::grabRegion(const rfb::Region& region)
|
||||||
|
|||||||
@@ -62,11 +62,7 @@ public:
|
|||||||
void refreshScreenLayout();
|
void refreshScreenLayout();
|
||||||
void requestClipboard();
|
void requestClipboard();
|
||||||
void announceClipboard(bool available);
|
void announceClipboard(bool available);
|
||||||
void clearBinaryClipboardData();
|
void sendClipboardData(const char* data);
|
||||||
void sendBinaryClipboardData(const char* mime, const unsigned char *data,
|
|
||||||
const unsigned len);
|
|
||||||
void getBinaryClipboardData(const char *mime, const unsigned char **ptr,
|
|
||||||
unsigned *len);
|
|
||||||
void bell();
|
void bell();
|
||||||
void setLEDState(unsigned int state);
|
void setLEDState(unsigned int state);
|
||||||
void setDesktopName(const char* name);
|
void setDesktopName(const char* name);
|
||||||
@@ -93,13 +89,14 @@ public:
|
|||||||
const char* rejectMsg=0);
|
const char* rejectMsg=0);
|
||||||
|
|
||||||
// rfb::SDesktop callbacks
|
// rfb::SDesktop callbacks
|
||||||
virtual void pointerEvent(const rfb::Point& pos, int buttonMask,
|
virtual void pointerEvent(const rfb::Point& pos, const rfb::Point& abspos, int buttonMask,
|
||||||
const bool skipClick, const bool skipRelease, int scrollX = 0, int scrollY = 0);
|
const bool skipClick, const bool skipRelease);
|
||||||
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
|
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
|
||||||
virtual unsigned int setScreenLayout(int fb_width, int fb_height,
|
virtual unsigned int setScreenLayout(int fb_width, int fb_height,
|
||||||
const rfb::ScreenSet& layout);
|
const rfb::ScreenSet& layout);
|
||||||
|
virtual void handleClipboardRequest();
|
||||||
virtual void handleClipboardAnnounce(bool available);
|
virtual void handleClipboardAnnounce(bool available);
|
||||||
virtual void handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
|
virtual void handleClipboardData(const char* data, int len);
|
||||||
|
|
||||||
// rfb::PixelBuffer callbacks
|
// rfb::PixelBuffer callbacks
|
||||||
virtual void grabRegion(const rfb::Region& r);
|
virtual void grabRegion(const rfb::Region& r);
|
||||||
@@ -135,7 +132,5 @@ private:
|
|||||||
OutputIdMap outputIdMap;
|
OutputIdMap outputIdMap;
|
||||||
|
|
||||||
rfb::Point oldCursorPos;
|
rfb::Point oldCursorPos;
|
||||||
|
|
||||||
bool resizing;
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ Send clipboard changes to clients. Default is on.
|
|||||||
.TP
|
.TP
|
||||||
.B \-SendPrimary
|
.B \-SendPrimary
|
||||||
Send the primary selection and cut buffer to the server as well as the
|
Send the primary selection and cut buffer to the server as well as the
|
||||||
clipboard selection. Default is off.
|
clipboard selection. Default is on.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
.B \-AcceptPointerEvents
|
.B \-AcceptPointerEvents
|
||||||
@@ -295,22 +295,17 @@ Allow click releases inside the blacked-out region.
|
|||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
.B \-DLP_ClipSendMax \fIbytes\fP
|
.B \-DLP_ClipSendMax \fIbytes\fP
|
||||||
Limit clipboard bytes to send to clients in one transaction. Default 0.
|
Limit clipboard bytes to send to clients in one transaction. Default 10,000.
|
||||||
0 disables the limit, use \fBSendCutText\fP to disable clipboard sending entirely.
|
0 disables the limit, use \fBSendCutText\fP to disable clipboard sending entirely.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
.B \-DLP_ClipAcceptMax \fIbytes\fP
|
.B \-DLP_ClipAcceptMax \fIbytes\fP
|
||||||
Limit clipboard bytes to receive from clients in one transaction. Default 0.
|
Limit clipboard bytes to receive from clients in one transaction. Default 10,000.
|
||||||
0 disables the limit, use \fBAcceptCutText\fP to disable clipboard receiving entirely.
|
0 disables the limit, use \fBAcceptCutText\fP to disable clipboard receiving entirely.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
.B \-DLP_ClipDelay \fIms\fP
|
.B \-DLP_ClipDelay \fIms\fP
|
||||||
This many milliseconds must pass between clipboard actions. Default 0, 0 disables the limit.
|
This many milliseconds must pass between clipboard actions. Default 1000.
|
||||||
.
|
|
||||||
.TP
|
|
||||||
.B \-DLP_ClipTypes \fIa,b\fP
|
|
||||||
Allowed binary clipboard mimetypes, separated by commas. Default
|
|
||||||
chromium/x-web-custom-data,text/html,image/png
|
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
.B \-DLP_KeyRateLimit \fIkeys-per-second\fP
|
.B \-DLP_KeyRateLimit \fIkeys-per-second\fP
|
||||||
@@ -322,10 +317,6 @@ Log clipboard and keyboard actions. Info logs just clipboard direction and size,
|
|||||||
verbose adds the contents for both.
|
verbose adds the contents for both.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
.B \-selfBench
|
|
||||||
Run a set of self-benchmarks and exit.
|
|
||||||
.
|
|
||||||
.TP
|
|
||||||
.B \-noWebsocket
|
.B \-noWebsocket
|
||||||
Disable websockets and expose a traditional VNC port (5901, etc.).
|
Disable websockets and expose a traditional VNC port (5901, etc.).
|
||||||
.
|
.
|
||||||
|
|||||||
@@ -18,12 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <rfb/Configuration.h>
|
#include <rfb/Configuration.h>
|
||||||
#include <rfb/Logger_stdio.h>
|
#include <rfb/Logger_stdio.h>
|
||||||
@@ -66,8 +64,6 @@ int vncFbstride[MAXSCREENS];
|
|||||||
|
|
||||||
int vncInetdSock = -1;
|
int vncInetdSock = -1;
|
||||||
|
|
||||||
static std::vector<dlp_mimetype_t> dlp_mimetypes;
|
|
||||||
|
|
||||||
struct CaseInsensitiveCompare {
|
struct CaseInsensitiveCompare {
|
||||||
bool operator() (const std::string &a, const std::string &b) const {
|
bool operator() (const std::string &a, const std::string &b) const {
|
||||||
return strcasecmp(a.c_str(), b.c_str()) < 0;
|
return strcasecmp(a.c_str(), b.c_str()) < 0;
|
||||||
@@ -107,7 +103,7 @@ rfb::BoolParameter setPrimary("SetPrimary", "Set the PRIMARY as well "
|
|||||||
"as the CLIPBOARD selection", true);
|
"as the CLIPBOARD selection", true);
|
||||||
rfb::BoolParameter sendPrimary("SendPrimary",
|
rfb::BoolParameter sendPrimary("SendPrimary",
|
||||||
"Send the PRIMARY as well as the CLIPBOARD selection",
|
"Send the PRIMARY as well as the CLIPBOARD selection",
|
||||||
false);
|
true);
|
||||||
|
|
||||||
static PixelFormat vncGetPixelFormat(int scrIdx)
|
static PixelFormat vncGetPixelFormat(int scrIdx)
|
||||||
{
|
{
|
||||||
@@ -151,38 +147,6 @@ static void parseOverrideList(const char *text, ParamSet &out)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parseClipTypes()
|
|
||||||
{
|
|
||||||
char *str = strdup(Server::DLP_Clip_Types);
|
|
||||||
char * const origstr = str;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
char *cur = strsep(&str, ",");
|
|
||||||
if (!cur)
|
|
||||||
break;
|
|
||||||
if (!cur[0])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Hardcoded filters
|
|
||||||
if (!strcmp(cur, "TEXT") ||
|
|
||||||
!strcmp(cur, "STRING") ||
|
|
||||||
strstr(cur, "text/plain") ||
|
|
||||||
!strcmp(cur, "UTF8_STRING"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
struct dlp_mimetype_t m;
|
|
||||||
strncpy(m.mime, cur, sizeof(m.mime));
|
|
||||||
m.mime[sizeof(m.mime) - 1] = '\0';
|
|
||||||
|
|
||||||
dlp_mimetypes.push_back(m);
|
|
||||||
|
|
||||||
vlog.debug("Adding DLP binary mime type %s", m.mime);
|
|
||||||
}
|
|
||||||
vlog.debug("Total %u binary mime types", dlp_mimetypes.size());
|
|
||||||
|
|
||||||
free(origstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void vncExtensionInit(void)
|
void vncExtensionInit(void)
|
||||||
{
|
{
|
||||||
if (vncExtGeneration == vncGetServerGeneration()) {
|
if (vncExtGeneration == vncGetServerGeneration()) {
|
||||||
@@ -199,8 +163,6 @@ void vncExtensionInit(void)
|
|||||||
|
|
||||||
vncAddExtension();
|
vncAddExtension();
|
||||||
|
|
||||||
if (!initialised)
|
|
||||||
parseClipTypes();
|
|
||||||
vncSelectionInit();
|
vncSelectionInit();
|
||||||
|
|
||||||
vlog.info("VNC extension running!");
|
vlog.info("VNC extension running!");
|
||||||
@@ -353,30 +315,22 @@ void vncUpdateDesktopName(void)
|
|||||||
desktop[scr]->setDesktopName(desktopName);
|
desktop[scr]->setDesktopName(desktopName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vncRequestClipboard(void)
|
||||||
|
{
|
||||||
|
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
||||||
|
desktop[scr]->requestClipboard();
|
||||||
|
}
|
||||||
|
|
||||||
void vncAnnounceClipboard(int available)
|
void vncAnnounceClipboard(int available)
|
||||||
{
|
{
|
||||||
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
||||||
desktop[scr]->announceClipboard(available);
|
desktop[scr]->announceClipboard(available);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vncSendBinaryClipboardData(const char* mime, const unsigned char *data,
|
void vncSendClipboardData(const char* data)
|
||||||
const unsigned len)
|
|
||||||
{
|
{
|
||||||
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
||||||
desktop[scr]->sendBinaryClipboardData(mime, data, len);
|
desktop[scr]->sendClipboardData(data);
|
||||||
}
|
|
||||||
|
|
||||||
void vncGetBinaryClipboardData(const char *mime, const unsigned char **ptr,
|
|
||||||
unsigned *len)
|
|
||||||
{
|
|
||||||
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
|
||||||
desktop[scr]->getBinaryClipboardData(mime, ptr, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void vncClearBinaryClipboardData()
|
|
||||||
{
|
|
||||||
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
|
||||||
desktop[scr]->clearBinaryClipboardData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int vncConnectClient(const char *addr)
|
int vncConnectClient(const char *addr)
|
||||||
@@ -532,13 +486,3 @@ int vncOverrideParam(const char *nameAndValue)
|
|||||||
|
|
||||||
return rfb::Configuration::setParam(nameAndValue);
|
return rfb::Configuration::setParam(nameAndValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned dlp_num_mimetypes()
|
|
||||||
{
|
|
||||||
return dlp_mimetypes.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *dlp_get_mimetype(const unsigned i)
|
|
||||||
{
|
|
||||||
return dlp_mimetypes[i].mime;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -45,13 +45,6 @@ int vncNotifyQueryConnect(void);
|
|||||||
extern void* vncFbptr[];
|
extern void* vncFbptr[];
|
||||||
extern int vncFbstride[];
|
extern int vncFbstride[];
|
||||||
|
|
||||||
struct dlp_mimetype_t {
|
|
||||||
char mime[32];
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned dlp_num_mimetypes();
|
|
||||||
const char *dlp_get_mimetype(const unsigned i);
|
|
||||||
|
|
||||||
extern int vncInetdSock;
|
extern int vncInetdSock;
|
||||||
|
|
||||||
void vncExtensionInit(void);
|
void vncExtensionInit(void);
|
||||||
@@ -67,12 +60,9 @@ int vncGetSendPrimary(void);
|
|||||||
|
|
||||||
void vncUpdateDesktopName(void);
|
void vncUpdateDesktopName(void);
|
||||||
|
|
||||||
|
void vncRequestClipboard(void);
|
||||||
void vncAnnounceClipboard(int available);
|
void vncAnnounceClipboard(int available);
|
||||||
void vncClearBinaryClipboardData();
|
void vncSendClipboardData(const char* data);
|
||||||
void vncSendBinaryClipboardData(const char* mime, const unsigned char *data,
|
|
||||||
const unsigned len);
|
|
||||||
void vncGetBinaryClipboardData(const char *mime, const unsigned char **ptr,
|
|
||||||
unsigned *len);
|
|
||||||
|
|
||||||
int vncConnectClient(const char *addr);
|
int vncConnectClient(const char *addr);
|
||||||
|
|
||||||
|
|||||||
@@ -43,14 +43,6 @@
|
|||||||
|
|
||||||
static Atom xaPRIMARY, xaCLIPBOARD;
|
static Atom xaPRIMARY, xaCLIPBOARD;
|
||||||
static Atom xaTARGETS, xaTIMESTAMP, xaSTRING, xaTEXT, xaUTF8_STRING;
|
static Atom xaTARGETS, xaTIMESTAMP, xaSTRING, xaTEXT, xaUTF8_STRING;
|
||||||
static Atom xaINCR;
|
|
||||||
static Atom *xaBinclips;
|
|
||||||
static unsigned xaHtmlIndex, xaPngIndex;
|
|
||||||
static Bool htmlPngPresent;
|
|
||||||
|
|
||||||
static unsigned *mimeIndexesFromClient;
|
|
||||||
static unsigned numMimesFromClient;
|
|
||||||
static Bool textFromClient;
|
|
||||||
|
|
||||||
static WindowPtr pWindow;
|
static WindowPtr pWindow;
|
||||||
static Window wid;
|
static Window wid;
|
||||||
@@ -74,7 +66,8 @@ static int vncCreateSelectionWindow(void);
|
|||||||
static int vncOwnSelection(Atom selection);
|
static int vncOwnSelection(Atom selection);
|
||||||
static int vncConvertSelection(ClientPtr client, Atom selection,
|
static int vncConvertSelection(ClientPtr client, Atom selection,
|
||||||
Atom target, Atom property,
|
Atom target, Atom property,
|
||||||
Window requestor, CARD32 time);
|
Window requestor, CARD32 time,
|
||||||
|
const char* data, int len);
|
||||||
static int vncProcConvertSelection(ClientPtr client);
|
static int vncProcConvertSelection(ClientPtr client);
|
||||||
static void vncSelectionRequest(Atom selection, Atom target);
|
static void vncSelectionRequest(Atom selection, Atom target);
|
||||||
static int vncProcSendEvent(ClientPtr client);
|
static int vncProcSendEvent(ClientPtr client);
|
||||||
@@ -97,32 +90,6 @@ void vncSelectionInit(void)
|
|||||||
xaTEXT = MakeAtom("TEXT", 4, TRUE);
|
xaTEXT = MakeAtom("TEXT", 4, TRUE);
|
||||||
xaUTF8_STRING = MakeAtom("UTF8_STRING", 11, TRUE);
|
xaUTF8_STRING = MakeAtom("UTF8_STRING", 11, TRUE);
|
||||||
|
|
||||||
xaINCR = MakeAtom("INCR", 4, TRUE);
|
|
||||||
|
|
||||||
unsigned i;
|
|
||||||
mimeIndexesFromClient = calloc(dlp_num_mimetypes(), sizeof(unsigned));
|
|
||||||
numMimesFromClient = 0;
|
|
||||||
textFromClient = FALSE;
|
|
||||||
xaBinclips = calloc(dlp_num_mimetypes(), sizeof(Atom));
|
|
||||||
htmlPngPresent = FALSE;
|
|
||||||
Bool htmlfound = FALSE, pngfound = FALSE;
|
|
||||||
for (i = 0; i < dlp_num_mimetypes(); i++) {
|
|
||||||
const char *cur = dlp_get_mimetype(i);
|
|
||||||
xaBinclips[i] = MakeAtom(cur, strlen(cur), TRUE);
|
|
||||||
|
|
||||||
if (!strcmp(cur, "text/html")) {
|
|
||||||
xaHtmlIndex = i;
|
|
||||||
htmlfound = TRUE;
|
|
||||||
}
|
|
||||||
if (!strcmp(cur, "image/png")) {
|
|
||||||
xaPngIndex = i;
|
|
||||||
pngfound = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (htmlfound && pngfound)
|
|
||||||
htmlPngPresent = TRUE;
|
|
||||||
|
|
||||||
/* There are no hooks for when these are internal windows, so
|
/* There are no hooks for when these are internal windows, so
|
||||||
* override the relevant handlers. */
|
* override the relevant handlers. */
|
||||||
origProcConvertSelection = ProcVector[X_ConvertSelection];
|
origProcConvertSelection = ProcVector[X_ConvertSelection];
|
||||||
@@ -136,7 +103,7 @@ void vncSelectionInit(void)
|
|||||||
FatalError("Add VNC ClientStateCallback failed\n");
|
FatalError("Add VNC ClientStateCallback failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vncHandleClipboardRequest(void)
|
void vncHandleClipboardRequest(void)
|
||||||
{
|
{
|
||||||
if (activeSelection == None) {
|
if (activeSelection == None) {
|
||||||
LOG_DEBUG("Got request for local clipboard although no clipboard is active");
|
LOG_DEBUG("Got request for local clipboard although no clipboard is active");
|
||||||
@@ -194,55 +161,24 @@ void vncHandleClipboardAnnounce(int available)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vncHandleClipboardAnnounceBinary(const unsigned num, const char mimes[][32])
|
void vncHandleClipboardData(const char* data, int len)
|
||||||
{
|
{
|
||||||
if (num) {
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
LOG_DEBUG("Remote binary clipboard announced, grabbing local ownership");
|
|
||||||
|
|
||||||
if (vncGetSetPrimary()) {
|
|
||||||
rc = vncOwnSelection(xaPRIMARY);
|
|
||||||
if (rc != Success)
|
|
||||||
LOG_ERROR("Could not set PRIMARY selection");
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = vncOwnSelection(xaCLIPBOARD);
|
|
||||||
if (rc != Success)
|
|
||||||
LOG_ERROR("Could not set CLIPBOARD selection");
|
|
||||||
|
|
||||||
unsigned i, valid = 0;
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
unsigned j;
|
|
||||||
for (j = 0; j < dlp_num_mimetypes(); j++) {
|
|
||||||
if (!strcmp(dlp_get_mimetype(j), mimes[i])) {
|
|
||||||
mimeIndexesFromClient[valid] = j;
|
|
||||||
valid++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(mimes[i], "text/plain"))
|
|
||||||
textFromClient = TRUE;
|
|
||||||
}
|
|
||||||
numMimesFromClient = valid;
|
|
||||||
LOG_DEBUG("Client sent %u mimes, %u were valid", num, valid);
|
|
||||||
} else {
|
|
||||||
struct VncDataTarget* next;
|
struct VncDataTarget* next;
|
||||||
numMimesFromClient = 0;
|
|
||||||
textFromClient = FALSE;
|
|
||||||
|
|
||||||
if (pWindow == NULL)
|
LOG_DEBUG("Got remote clipboard data, sending to X11 clients");
|
||||||
return;
|
|
||||||
|
|
||||||
LOG_DEBUG("Remote binary clipboard lost, removing local ownership");
|
|
||||||
|
|
||||||
DeleteWindowFromAnySelections(pWindow);
|
|
||||||
|
|
||||||
/* Abort any pending transfer */
|
|
||||||
while (vncDataTargetHead != NULL) {
|
while (vncDataTargetHead != NULL) {
|
||||||
|
int rc;
|
||||||
xEvent event;
|
xEvent event;
|
||||||
|
|
||||||
|
rc = vncConvertSelection(vncDataTargetHead->client,
|
||||||
|
vncDataTargetHead->selection,
|
||||||
|
vncDataTargetHead->target,
|
||||||
|
vncDataTargetHead->property,
|
||||||
|
vncDataTargetHead->requestor,
|
||||||
|
vncDataTargetHead->time,
|
||||||
|
data, len);
|
||||||
|
if (rc != Success) {
|
||||||
event.u.u.type = SelectionNotify;
|
event.u.u.type = SelectionNotify;
|
||||||
event.u.selectionNotify.time = vncDataTargetHead->time;
|
event.u.selectionNotify.time = vncDataTargetHead->time;
|
||||||
event.u.selectionNotify.requestor = vncDataTargetHead->requestor;
|
event.u.selectionNotify.requestor = vncDataTargetHead->requestor;
|
||||||
@@ -250,12 +186,12 @@ void vncHandleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]
|
|||||||
event.u.selectionNotify.target = vncDataTargetHead->target;
|
event.u.selectionNotify.target = vncDataTargetHead->target;
|
||||||
event.u.selectionNotify.property = None;
|
event.u.selectionNotify.property = None;
|
||||||
WriteEventsToClient(vncDataTargetHead->client, 1, &event);
|
WriteEventsToClient(vncDataTargetHead->client, 1, &event);
|
||||||
|
}
|
||||||
|
|
||||||
next = vncDataTargetHead->next;
|
next = vncDataTargetHead->next;
|
||||||
free(vncDataTargetHead);
|
free(vncDataTargetHead);
|
||||||
vncDataTargetHead = next;
|
vncDataTargetHead = next;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vncCreateSelectionWindow(void)
|
static int vncCreateSelectionWindow(void)
|
||||||
@@ -341,22 +277,10 @@ static int vncOwnSelection(Atom selection)
|
|||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool clientHasBinaryAtom(const Atom target, unsigned *which)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
for (i = 0; i < numMimesFromClient; i++) {
|
|
||||||
if (xaBinclips[mimeIndexesFromClient[i]] == target) {
|
|
||||||
*which = mimeIndexesFromClient[i];
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vncConvertSelection(ClientPtr client, Atom selection,
|
static int vncConvertSelection(ClientPtr client, Atom selection,
|
||||||
Atom target, Atom property,
|
Atom target, Atom property,
|
||||||
Window requestor, CARD32 time)
|
Window requestor, CARD32 time,
|
||||||
|
const char* data, int len)
|
||||||
{
|
{
|
||||||
Selection *pSel;
|
Selection *pSel;
|
||||||
WindowPtr pWin;
|
WindowPtr pWin;
|
||||||
@@ -366,8 +290,13 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
|
|||||||
|
|
||||||
xEvent event;
|
xEvent event;
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
LOG_DEBUG("Selection request for %s (type %s)",
|
LOG_DEBUG("Selection request for %s (type %s)",
|
||||||
NameForAtom(selection), NameForAtom(target));
|
NameForAtom(selection), NameForAtom(target));
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("Sending data for selection request for %s (type %s)",
|
||||||
|
NameForAtom(selection), NameForAtom(target));
|
||||||
|
}
|
||||||
|
|
||||||
rc = dixLookupSelection(&pSel, selection, client, DixGetAttrAccess);
|
rc = dixLookupSelection(&pSel, selection, client, DixGetAttrAccess);
|
||||||
if (rc != Success)
|
if (rc != Success)
|
||||||
@@ -386,23 +315,14 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
|
|||||||
realProperty = target;
|
realProperty = target;
|
||||||
|
|
||||||
/* FIXME: MULTIPLE target */
|
/* FIXME: MULTIPLE target */
|
||||||
unsigned binatomidx;
|
|
||||||
|
|
||||||
if (target == xaTARGETS) {
|
if (target == xaTARGETS) {
|
||||||
Atom targets[5 + numMimesFromClient];
|
Atom targets[] = { xaTARGETS, xaTIMESTAMP,
|
||||||
targets[0] = xaTARGETS;
|
xaSTRING, xaTEXT, xaUTF8_STRING };
|
||||||
targets[1] = xaTIMESTAMP;
|
|
||||||
targets[2] = xaSTRING;
|
|
||||||
targets[3] = xaTEXT;
|
|
||||||
targets[4] = xaUTF8_STRING;
|
|
||||||
|
|
||||||
unsigned i;
|
|
||||||
for (i = 0; i < numMimesFromClient; i++)
|
|
||||||
targets[5 + i] = xaBinclips[mimeIndexesFromClient[i]];
|
|
||||||
|
|
||||||
rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
|
rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
|
||||||
XA_ATOM, 32, PropModeReplace,
|
XA_ATOM, 32, PropModeReplace,
|
||||||
5 + numMimesFromClient,
|
sizeof(targets)/sizeof(targets[0]),
|
||||||
targets, TRUE);
|
targets, TRUE);
|
||||||
if (rc != Success)
|
if (rc != Success)
|
||||||
return rc;
|
return rc;
|
||||||
@@ -413,22 +333,37 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
|
|||||||
TRUE);
|
TRUE);
|
||||||
if (rc != Success)
|
if (rc != Success)
|
||||||
return rc;
|
return rc;
|
||||||
} else if (clientHasBinaryAtom(target, &binatomidx)) {
|
} else {
|
||||||
const unsigned char *data;
|
if (data == NULL) {
|
||||||
unsigned len;
|
struct VncDataTarget* vdt;
|
||||||
vncGetBinaryClipboardData(dlp_get_mimetype(binatomidx), &data, &len);
|
|
||||||
rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
|
|
||||||
xaBinclips[binatomidx], 8, PropModeReplace,
|
|
||||||
len, (unsigned char *) data, TRUE);
|
|
||||||
if (rc != Success)
|
|
||||||
return rc;
|
|
||||||
} else if (textFromClient) {
|
|
||||||
const unsigned char *data;
|
|
||||||
unsigned len;
|
|
||||||
vncGetBinaryClipboardData("text/plain", &data, &len);
|
|
||||||
|
|
||||||
|
if ((target != xaSTRING) && (target != xaTEXT) &&
|
||||||
|
(target != xaUTF8_STRING))
|
||||||
|
return BadMatch;
|
||||||
|
|
||||||
|
vdt = calloc(1, sizeof(struct VncDataTarget));
|
||||||
|
if (vdt == NULL)
|
||||||
|
return BadAlloc;
|
||||||
|
|
||||||
|
vdt->client = client;
|
||||||
|
vdt->selection = selection;
|
||||||
|
vdt->target = target;
|
||||||
|
vdt->property = property;
|
||||||
|
vdt->requestor = requestor;
|
||||||
|
vdt->time = time;
|
||||||
|
|
||||||
|
vdt->next = vncDataTargetHead;
|
||||||
|
vncDataTargetHead = vdt;
|
||||||
|
|
||||||
|
LOG_DEBUG("Requesting clipboard data from client");
|
||||||
|
|
||||||
|
vncRequestClipboard();
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
} else {
|
||||||
if ((target == xaSTRING) || (target == xaTEXT)) {
|
if ((target == xaSTRING) || (target == xaTEXT)) {
|
||||||
char* latin1;
|
char* latin1;
|
||||||
|
|
||||||
latin1 = vncUTF8ToLatin1(data, (size_t)-1);
|
latin1 = vncUTF8ToLatin1(data, (size_t)-1);
|
||||||
if (latin1 == NULL)
|
if (latin1 == NULL)
|
||||||
return BadAlloc;
|
return BadAlloc;
|
||||||
@@ -444,16 +379,13 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
|
|||||||
} else if (target == xaUTF8_STRING) {
|
} else if (target == xaUTF8_STRING) {
|
||||||
rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
|
rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
|
||||||
xaUTF8_STRING, 8, PropModeReplace,
|
xaUTF8_STRING, 8, PropModeReplace,
|
||||||
len, (char *) data, TRUE);
|
len, data, TRUE);
|
||||||
if (rc != Success)
|
if (rc != Success)
|
||||||
return rc;
|
return rc;
|
||||||
} else {
|
} else {
|
||||||
return BadMatch;
|
return BadMatch;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
LOG_ERROR("Text clipboard paste requested, but client sent no text");
|
|
||||||
|
|
||||||
return BadMatch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event.u.u.type = SelectionNotify;
|
event.u.u.type = SelectionNotify;
|
||||||
@@ -492,7 +424,7 @@ static int vncProcConvertSelection(ClientPtr client)
|
|||||||
pSel->window == wid) {
|
pSel->window == wid) {
|
||||||
rc = vncConvertSelection(client, stuff->selection,
|
rc = vncConvertSelection(client, stuff->selection,
|
||||||
stuff->target, stuff->property,
|
stuff->target, stuff->property,
|
||||||
stuff->requestor, stuff->time);
|
stuff->requestor, stuff->time, NULL, 0);
|
||||||
if (rc != Success) {
|
if (rc != Success) {
|
||||||
xEvent event;
|
xEvent event;
|
||||||
|
|
||||||
@@ -551,21 +483,6 @@ static Bool vncHasAtom(Atom atom, const Atom list[], size_t size)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool vncHasBinaryClipboardAtom(const Atom list[], size_t size)
|
|
||||||
{
|
|
||||||
size_t i, b;
|
|
||||||
const unsigned num = dlp_num_mimetypes();
|
|
||||||
|
|
||||||
for (i = 0;i < size;i++) {
|
|
||||||
for (b = 0; b < num; b++) {
|
|
||||||
if (list[i] == xaBinclips[b])
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vncHandleSelection(Atom selection, Atom target,
|
static void vncHandleSelection(Atom selection, Atom target,
|
||||||
Atom property, Atom requestor,
|
Atom property, Atom requestor,
|
||||||
TimeStamp time)
|
TimeStamp time)
|
||||||
@@ -585,9 +502,6 @@ static void vncHandleSelection(Atom selection, Atom target,
|
|||||||
if (target != property)
|
if (target != property)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (prop->type == xaINCR)
|
|
||||||
LOG_INFO("Incremental clipboard transfer denied, too large");
|
|
||||||
|
|
||||||
if (target == xaTARGETS) {
|
if (target == xaTARGETS) {
|
||||||
if (prop->format != 32)
|
if (prop->format != 32)
|
||||||
return;
|
return;
|
||||||
@@ -596,36 +510,16 @@ static void vncHandleSelection(Atom selection, Atom target,
|
|||||||
|
|
||||||
if (probing) {
|
if (probing) {
|
||||||
if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size) ||
|
if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size) ||
|
||||||
vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size) ||
|
vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size)) {
|
||||||
vncHasBinaryClipboardAtom((const Atom*)prop->data, prop->size)) {
|
|
||||||
LOG_DEBUG("Compatible format found, notifying clients");
|
LOG_DEBUG("Compatible format found, notifying clients");
|
||||||
vncClearBinaryClipboardData();
|
|
||||||
activeSelection = selection;
|
activeSelection = selection;
|
||||||
vncAnnounceClipboard(TRUE);
|
vncAnnounceClipboard(TRUE);
|
||||||
vncHandleClipboardRequest();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size))
|
if (vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size))
|
||||||
vncSelectionRequest(selection, xaUTF8_STRING);
|
vncSelectionRequest(selection, xaUTF8_STRING);
|
||||||
else if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size))
|
else if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size))
|
||||||
vncSelectionRequest(selection, xaSTRING);
|
vncSelectionRequest(selection, xaSTRING);
|
||||||
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
Bool skiphtml = FALSE;
|
|
||||||
if (htmlPngPresent &&
|
|
||||||
vncHasAtom(xaBinclips[xaHtmlIndex], (const Atom*)prop->data, prop->size) &&
|
|
||||||
vncHasAtom(xaBinclips[xaPngIndex], (const Atom*)prop->data, prop->size))
|
|
||||||
skiphtml = TRUE;
|
|
||||||
|
|
||||||
for (i = 0; i < dlp_num_mimetypes(); i++) {
|
|
||||||
if (skiphtml && i == xaHtmlIndex)
|
|
||||||
continue;
|
|
||||||
if (vncHasAtom(xaBinclips[i], (const Atom*)prop->data, prop->size)) {
|
|
||||||
vncSelectionRequest(selection, xaBinclips[i]);
|
|
||||||
//break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (target == xaSTRING) {
|
} else if (target == xaSTRING) {
|
||||||
char* filtered;
|
char* filtered;
|
||||||
@@ -645,10 +539,10 @@ static void vncHandleSelection(Atom selection, Atom target,
|
|||||||
if (utf8 == NULL)
|
if (utf8 == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG_DEBUG("Sending text part of binary clipboard to clients (%d bytes)",
|
LOG_DEBUG("Sending clipboard to clients (%d bytes)",
|
||||||
(int)strlen(utf8));
|
(int)strlen(utf8));
|
||||||
|
|
||||||
vncSendBinaryClipboardData("text/plain", utf8, strlen(utf8));
|
vncSendClipboardData(utf8);
|
||||||
|
|
||||||
vncStrFree(utf8);
|
vncStrFree(utf8);
|
||||||
} else if (target == xaUTF8_STRING) {
|
} else if (target == xaUTF8_STRING) {
|
||||||
@@ -663,31 +557,12 @@ static void vncHandleSelection(Atom selection, Atom target,
|
|||||||
if (filtered == NULL)
|
if (filtered == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG_DEBUG("Sending text part of binary clipboard to clients (%d bytes)",
|
LOG_DEBUG("Sending clipboard to clients (%d bytes)",
|
||||||
(int)strlen(filtered));
|
(int)strlen(filtered));
|
||||||
|
|
||||||
vncSendBinaryClipboardData("text/plain", filtered, strlen(filtered));
|
vncSendClipboardData(filtered);
|
||||||
|
|
||||||
vncStrFree(filtered);
|
vncStrFree(filtered);
|
||||||
} else {
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
if (prop->format != 8)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; i < dlp_num_mimetypes(); i++) {
|
|
||||||
if (target == xaBinclips[i]) {
|
|
||||||
if (prop->type != xaBinclips[i])
|
|
||||||
return;
|
|
||||||
|
|
||||||
LOG_DEBUG("Sending binary clipboard to clients (%d bytes)",
|
|
||||||
prop->size);
|
|
||||||
|
|
||||||
vncSendBinaryClipboardData(dlp_get_mimetype(i), prop->data, prop->size);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ extern "C" {
|
|||||||
|
|
||||||
void vncSelectionInit(void);
|
void vncSelectionInit(void);
|
||||||
|
|
||||||
|
void vncHandleClipboardRequest(void);
|
||||||
void vncHandleClipboardAnnounce(int available);
|
void vncHandleClipboardAnnounce(int available);
|
||||||
void vncHandleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
|
void vncHandleClipboardData(const char* data, int len);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user