Merge branch 'master' into feature/KASM-3747-optional-systemd-start

This commit is contained in:
Dmitry Maksyoma 2025-10-23 15:19:15 +13:00
commit c1dda78ea2
No known key found for this signature in database
290 changed files with 9242 additions and 20597 deletions

View file

@ -61,24 +61,93 @@ function prepare_upload_filename() {
fi
};
list_files_in_directory() {
local dir="$1"
find "$1" -mindepth 1
}
upload_directory_to_s3() {
local dir_to_upload="$1"
local s3_directory="$2";
local s3_bucket="$3";
for file_to_upload in $(list_files_in_directory "$dir_to_upload"); do
upload_to_s3 "$file_to_upload" "$s3_directory/$file_to_upload" "$s3_bucket"
done
}
prepare_functional_tests_source_and_cd_into_it() {
cd kasmvnc-functional-tests
mkdir output && chown 1000:1000 output
mkdir report && chown 1000:1000 report
}
upload_report_to_s3() {
s3_tests_directory="kasmvnc/${CI_COMMIT_SHA}/tests"
upload_directory_to_s3 report "$s3_tests_directory" "$S3_BUCKET"
}
put_report_into_ci_pipeline() {
local functional_tests_exit_code="$1"
local report_name="Functional%20test%20report"
local report_url="https://${S3_BUCKET}.s3.amazonaws.com/${s3_tests_directory}/report/index.html"
local state="success"
if [ "$functional_tests_exit_code" -ne 0 ]; then
state="failed"
fi
curl --request POST --header "PRIVATE-TOKEN:${GITLAB_API_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/statuses/${CI_COMMIT_SHA}?state=${state}&name=${report_name}&target_url=${report_url}"
}
prepare_kasmvnc_built_packages_to_replace_workspaces_image_packages() {
cp -r ../output/jammy output/
}
prepare_to_run_functional_tests() {
install_packages_needed_for_functional_tests
prepare_functional_tests_source_and_cd_into_it
prepare_kasmvnc_built_packages_to_replace_workspaces_image_packages
heed_debug_variable_and_toggle_debug_in_functional_tests
}
heed_debug_variable_and_toggle_debug_in_functional_tests() {
if [ -z "$CI" ]; then
return
fi
if [ "$DEBUG" = "true" ]; then
export KASMVNC_FUNC_TESTS_DEBUG=1
fi
}
install_packages_needed_for_functional_tests() {
prepare_to_run_scripts_and_s3_uploads
apt-get install -y tree docker.io
}
is_build_this_distro() {
local distro="$1"
[[ "$BUILD_DISTROS_REGEX" = 'all' ]] || [[ "$distro" =~ $BUILD_DISTROS_REGEX ]]
}
function upload_to_s3() {
local package="$1";
local upload_filename="$2";
local file_to_upload="$1";
local s3_url_for_file="$2";
local s3_bucket="$3";
# Transfer to S3
python3 amazon-s3-bitbucket-pipelines-python/s3_upload.py "${s3_bucket}" "$package" "${upload_filename}";
aws s3 cp "$file_to_upload" \
"s3://${S3_BUCKET}/${s3_url_for_file}" \
--metadata-directive REPLACE \
--content-type "$(file --mime-type -b \"$file_to_upload\")"
# Use the Gitlab API to tell Gitlab where the artifact was stored
export S3_URL="https://${s3_bucket}.s3.amazonaws.com/${upload_filename}";
export S3_URL="https://${s3_bucket}.s3.amazonaws.com/${s3_url_for_file}";
};
function prepare_to_run_scripts_and_s3_uploads() {
export DEBIAN_FRONTEND=noninteractive;
apt-get update;
apt-get install -y ruby2.7 git wget;
apt-get install -y python3 python3-pip python3-boto3 curl pkg-config libxmlsec1-dev;
git clone https://bitbucket.org/awslabs/amazon-s3-bitbucket-pipelines-python.git;
};
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y ruby3.1 wget curl file awscli
}
detect_release_branch() {
if echo $CI_COMMIT_REF_NAME | grep -Pq '^release/([\d.]+)$'; then

6
.gitignore vendored
View file

@ -21,6 +21,9 @@ builder/build/
builder/www/
spec/tmp
Benchmark.xml
SelfBench.xml
# Deb building artefacts
debian/.debhelper/
debian/files
@ -29,6 +32,9 @@ debian/kasmvncserver/
.pc
.vscode/
# --run-test artifacts
run_test/
alpine/.abuild/kasmvnc_signing_key.rsa
alpine/.abuild/kasmvnc_signing_key.rsa.pub
alpine/packages/

View file

@ -3,14 +3,21 @@ services:
- docker:dind
variables:
DEBUG: true
KASMVNC_COMMIT_ID: $CI_COMMIT_SHA
GITLAB_SHARED_DIND_DIR: /builds/$CI_PROJECT_PATH/shared
GIT_SUBMODULE_STRATEGY: normal
GIT_SUBMODULE_STRATEGY: recursive
GIT_SUBMODULE_FORCE_HTTPS: "true"
GIT_FETCH_EXTRA_FLAGS: --tags --force
# E.g. BUILD_JOBS: build_debian_buster,build_ubuntu_focal. This will include
# arm builds, because build_debian_buster_arm matches build_debian_buster.
# "BUILD_JOBS: none" won't build any build jobs, nor www.
BUILD_JOBS: all
# For example, BUILD_DISTROS_REGEX: "jammy|focal".
# "BUILD_DISTROS_REGEX: none" won't build any distros, nor www.
# "BUILD_DISTROS_REGEX: all" would build all distros.
# Make sure you quote any whitespace characters you use.
# E.g. BUILD_DISTROS_REGEX: "jammy|\ focal".
BUILD_DISTROS_REGEX: all
# To debug upload stage, you can limit BUILD_DISTROS_REGEX to jammy and allow
# run_test distros to fail, by setting ALLOW_RUN_TESTS_TO_FAIL to true.
ALLOW_RUN_TESTS_TO_FAIL: false
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
@ -22,13 +29,16 @@ workflow:
stages:
- www
- build
- functional_test
- run_test
- test
- upload
.prepare_build: &prepare_build
- pwd
- apk add bash
- mkdir -p "$GITLAB_SHARED_DIND_DIR" && chmod 777 "$GITLAB_SHARED_DIND_DIR"
- apt-get update && apt-get install -y docker.io
- docker login --username $DOCKER_HUB_USERNAME --password $DOCKER_HUB_PASSWORD
.prepare_www: &prepare_www
- tar -zxf output/www/kasm_www.tar.gz -C builder/
@ -37,10 +47,36 @@ stages:
- cp -r builder/build/* output/
- rm output/*.tar.gz
.enable_core_dumps: &enable_core_dumps
- echo core > /proc/sys/kernel/core_pattern
default:
retry: 2
tags:
- oci-fixed-amd
functional_test:
stage: functional_test
image: debian:bookworm-slim
tags:
- oci-fixed-amd
before_script:
- . .ci/helpers.sh
script:
- prepare_to_run_functional_tests
- set +e; ./functional-test; exit_code=$?; set -e
- upload_report_to_s3
- put_report_into_ci_pipeline "$exit_code"
- exit "$exit_code"
dependencies:
- build_amd64
artifacts:
paths:
- kasmvnc-functional-tests/output/
reports:
junit:
- kasmvnc-functional-tests/report/*.xml
build_www:
stage: www
allow_failure: false
@ -61,641 +97,140 @@ build_www:
- tar -zcvf ../output/www/kasm_www.tar.gz www
only:
variables:
- $BUILD_JOBS !~ /^none$/
- $BUILD_DISTROS_REGEX !~ /^none$/
artifacts:
paths:
- output/
build_ubuntu_focal:
build_amd64:
stage: build
allow_failure: true
image: debian:bookworm-slim
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
- . .ci/helpers.sh
after_script:
- *prepare_artfacts
script:
- bash builder/build-package ubuntu focal;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
- set -e
- is_build_this_distro "$DISTRO" && builder/build-package $DISTRO
artifacts:
paths:
- output/
parallel:
matrix:
- DISTRO: [ 'ubuntu focal', 'ubuntu jammy', 'ubuntu noble', 'debian bullseye', 'debian bookworm', 'debian trixie', 'kali kali-rolling', 'oracle 8', 'oracle 9', 'opensuse 15', 'fedora forty', 'fedora fortyone', 'alpine 318', 'alpine 319', 'alpine 320', 'alpine 321' ]
build_ubuntu_focal_arm:
build_arm64:
stage: build
allow_failure: true
image: debian:bookworm-slim
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
- . .ci/helpers.sh
after_script:
- *prepare_artfacts
script:
- bash builder/build-package ubuntu focal;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
- set -e
- is_build_this_distro "$DISTRO" && builder/build-package $DISTRO
artifacts:
paths:
- output/
parallel:
matrix:
- DISTRO: [ 'ubuntu focal', 'ubuntu jammy', 'ubuntu noble', 'debian bullseye', 'debian bookworm', 'debian trixie', 'kali kali-rolling', 'oracle 8', 'oracle 9', 'opensuse 15', 'fedora forty', 'fedora fortyone', 'alpine 318', 'alpine 319', 'alpine 320', 'alpine 321' ]
build_ubuntu_jammy:
stage: build
allow_failure: true
run_test_amd64:
stage: run_test
image: debian:bookworm-slim
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
- *enable_core_dumps
- . .ci/helpers.sh
script:
- bash builder/build-package ubuntu jammy;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
- set -e
- is_build_this_distro "$DISTRO" && builder/test-barebones --run-test $DISTRO
rules:
- if: $ALLOW_RUN_TESTS_TO_FAIL == "false"
- if: $ALLOW_RUN_TESTS_TO_FAIL == "true"
allow_failure: true
dependencies:
- build_amd64
artifacts:
when: always
paths:
- output/
- run_test/core_dumps/*/core
reports:
junit:
- run_test/*.xml
parallel:
matrix:
- DISTRO: [ 'ubuntu focal', 'ubuntu jammy', 'ubuntu noble', 'debian bullseye', 'debian bookworm', 'debian trixie', 'kali kali-rolling', 'oracle 8', 'oracle 9', 'opensuse 15', 'fedora forty', 'fedora fortyone', 'alpine 318', 'alpine 319', 'alpine 320', 'alpine 321' ]
build_ubuntu_jammy_arm:
stage: build
allow_failure: true
run_test_arm64:
stage: run_test
image: debian:bookworm-slim
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
- *enable_core_dumps
- . .ci/helpers.sh
script:
- bash builder/build-package ubuntu jammy;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
- set -e
- is_build_this_distro "$DISTRO" && builder/test-barebones --run-test $DISTRO
rules:
- if: $ALLOW_RUN_TESTS_TO_FAIL == "false"
- if: $ALLOW_RUN_TESTS_TO_FAIL == "true"
allow_failure: true
dependencies:
- build_arm64
artifacts:
paths:
- output/
build_ubuntu_noble:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package ubuntu noble;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
when: always
paths:
- output/
- run_test/core_dumps/*/core
reports:
junit:
- run_test/*.xml
parallel:
matrix:
- DISTRO: [ 'ubuntu focal', 'ubuntu jammy', 'ubuntu noble', 'debian bullseye', 'debian bookworm', 'debian trixie', 'kali kali-rolling', 'oracle 8', 'oracle 9', 'opensuse 15', 'fedora forty', 'fedora fortyone', 'alpine 318', 'alpine 319', 'alpine 320', 'alpine 321' ]
build_ubuntu_noble_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package ubuntu noble;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_debian_bullseye:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package debian bullseye;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_debian_bullseye_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package debian bullseye;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_debian_bookworm:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package debian bookworm;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_debian_bookworm_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package debian bookworm;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_kali_rolling:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package kali kali-rolling;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_kali_rolling_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package kali kali-rolling;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_oracle_8:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package oracle 8;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_oracle_8_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package oracle 8;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_oracle_9:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package oracle 9;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_oracle_9_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package oracle 9;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_opensuse_15:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package opensuse 15;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_opensuse_15_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package opensuse 15;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_fedora_thirtynine:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package fedora thirtynine;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_fedora_thirtynine_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package fedora thirtynine;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_fedora_forty:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package fedora forty;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_fedora_forty_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package fedora forty;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_fedora_fortyone:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package fedora fortyone;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_fedora_fortyone_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package fedora fortyone;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
test:
spec_test:
stage: test
image: debian:bookworm-slim
tags:
- oci-fixed-amd
- kasmvnc-x86
before_script:
- *prepare_build
script:
- bash builder/test-vncserver
build_alpine_318:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package alpine 318;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_alpine_318_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
reports:
junit:
- SelfBench.xml
- Benchmark.xml
script:
- bash builder/build-package alpine 318;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
- builder/test-vncserver
build_alpine_319:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package alpine 319;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_alpine_319_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package alpine 319;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_alpine_320:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package alpine 320;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_alpine_320_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package alpine 320;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_alpine_321:
stage: build
allow_failure: true
tags:
- oci-fixed-amd
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package alpine 321;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_alpine_321_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package alpine 321;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
upload:
stage: upload
image: ubuntu:focal
image: debian:bookworm-slim
tags:
- oci-fixed-amd
artifacts:
paths:
- output/
before_script:
- . .ci/upload.sh
- . .ci/helpers.sh
script:
- prepare_to_run_scripts_and_s3_uploads
- S3_CRASHPAD_BUILD_DIRECTORY="kasmvnc/crashpad/${CI_COMMIT_SHA}"
@ -727,11 +262,11 @@ upload_build_preview:
stage: upload
needs: ["upload"]
dependencies: ["upload"]
image: ubuntu:focal
image: debian:bookworm-slim
tags:
- oci-fixed-amd
before_script:
- . .ci/upload.sh
- . .ci/helpers.sh
resource_group: upload_build_preview
only:
variables:

3
.gitmodules vendored
View file

@ -2,3 +2,6 @@
path = kasmweb
url = https://github.com/kasmtech/noVNC.git
branch = master
[submodule "kasmvnc-functional-tests"]
path = kasmvnc-functional-tests
url = git@gitlab.com:kasm-technologies/internal/kasmvnc-functional-tests.git

View file

@ -1,86 +1,17 @@
*******************************************************************************
** Building KasmVNC
*******************************************************************************
# Building KasmVNC
================================
Build Requirements (All Systems)
================================
-- CMake (http://www.cmake.org) v2.8 or later
-- zlib
-- If building TLS support:
* GnuTLS 3.x
* See "Building TLS Support" below.
-- If building native language support (NLS):
* Gnu gettext 0.14.4 or later
* See "Building Native Language Support" below.
-- libjpeg-turbo
* "Normal" libjpegv6 is also supported, although it is not
recommended as it is much slower.
-- libwebp
=========================
Build Requirements (Unix)
=========================
-- Non-Mac platforms:
* X11 development kit
-- If building Xvnc/libvnc.so:
* Xorg server source code, 1.7 or never
* All build requirements Xorg imposes (see its documentation)
============================
Build Requirements (Windows)
============================
-- MinGW or MinGW-w64
-- Inno Setup (needed to build the KasmVNC installer)
Inno Setup can be downloaded from http://www.jrsoftware.org/isinfo.php.
You also need the Inno Setup Preprocessor, which is available in the
Inno Setup QuickStart Pack.
Add the directory containing iscc.exe (for instance,
C:\Program Files\Inno Setup 5) to the system or user PATH environment
variable prior to building KasmVNC.
==================
Out-of-Tree Builds
==================
Binary objects, libraries, and executables are generated in the same directory
from which cmake was executed (the "binary directory"), and this directory need
not necessarily be the same as the KasmVNC source directory. You can create
multiple independent binary directories, in which different versions of
KasmVNC can be built from the same source tree using different compilers or
settings. In the sections below, {build_directory} refers to the binary
directory, whereas {source_directory} refers to the KasmVNC source directory.
For in-tree builds, these directories are the same.
=================
Building KasmVNC
=================
Building the KasmVNC Server using Docker
----------------------------------------
## Building the KasmVNC Server using Docker
```bash
git submodule init
git submodule update --remote --merge
sudo docker build -t kasmvnc:dev -f builder/dockerfile.ubuntu_jammy.dev .
sudo docker run -it -v ./:/src -p 6901:6901 kasmvnc:dev
sudo docker run -it --rm -v ./:/src -p 6901:6901 -p 8443:8443 --name kasmvnc_dev kasmvnc:dev
```
**The above assumes you are UID 1000 on the host as the container UID is 1000.**
Ensure you switch to the user associated to UID 1000 on the host.
Now from inside the container.
```bash
@ -89,9 +20,9 @@ cd kasmweb
npm install
npm run build # <-- only run this on subsequent changes to front-end code
cd ..
# build dependencies
sudo builder/scripts/build-webp
sudo builder/scripts/build-build-libjpeg-turbo
# build dependencies, this is optional as they are pre-built in the docker image. Only rebuild if you made version changes and need to test.
# sudo builder/scripts/build-webp
# sudo builder/scripts/build-libjpeg-turbo
# Build KasmVNC
builder/build.sh
```
@ -99,14 +30,93 @@ builder/build.sh
Now run Xvnc and Xfce4 from inside the container
```bash
/src/xorg.build/bin/Xvnc -interface 0.0.0.0 -PublicIP 127.0.0.1 -disableBasicAuth -RectThreads 0 -Log *:stdout:100 -httpd /src/kasmweb/dist -sslOnly 0 -SecurityTypes None -websocketPort 6901 :1 &
/src/xorg.build/bin/Xvnc -interface 0.0.0.0 -PublicIP 127.0.0.1 -disableBasicAuth -RectThreads 0 -Log *:stdout:100 -httpd /src/kasmweb/dist -sslOnly 0 -SecurityTypes None -websocketPort 6901 -FreeKeyMappings :1 &
/usr/bin/xfce4-session --display :1
```
Now open a browser and navigate to your dev VM on port 6901.
Building the KasmVNC Server on Modern Unix/Linux Systems
---------------------------------------------------------
## Running noVNC from source
If you need to debug or make changes to the UI code, use the following procedures to use npm to serve the web code. The code will automatically rebuild when changes are made and the code will not be packaged.
These steps assume you are inside the kasmvnc:dev container started in the above steps.
Now from inside the container. **This assumes KasmVNC is already built, follow steps above if you need to build KasmVNC**
```bash
# Run KasmVNC
/src/xorg.build/bin/Xvnc -interface 0.0.0.0 -PublicIP 127.0.0.1 -disableBasicAuth -RectThreads 0 -Log *:stdout:100 -httpd /src/kasmweb/dist -sslOnly 0 -SecurityTypes None -websocketPort 6901 -FreeKeyMappings :1 &
/usr/bin/xfce4-session --display :1 &
sudo nginx
cd kasmweb
npm install # only needs done first time
npm run serve # <-- Needs to run in foreground
```
Now open a browser and navigate to your dev VM on port 8443 over https.
NGINX is proxying the websocket to KasmVNC and all other requests go to the node server. NGINX listens on 8443 with ssl.
Since `npm run serve` needs to run in the foreground, you may need to exec into the container from another terminal to run additional commands like stopping Xvnc, rebuilding KasmVNC, etc.
```bash
sudo docker exec -it kasmvnc_dev /bin/bash
```
## Building in CI
### Achieve a faster feedback loop in CI
To achieve a faster feedback loop in CI, you can limit built distros to a few
distros you're interested in.
#### Best way to debug CI in a fast feedback loop
Specify `BUILD_DISTROS_REGEX: "jammy"`, and build only Ubuntu Jammy. That's
only 2 distro package build jobs, one for amd64 and one for arm64.
Specify `ALLOW_RUN_TESTS_TO_FAIL: true` to ignore `run_test` job failures and
debug the upload stage.
#### Build only a few distros
To build only distros you want, specify a regex in `$BUILD_DISTROS_REGEX`
variable. For example, build Ubuntu Jammy and Focal with `BUILD_DISTROS_REGEX:
"jammy|focal"`. Or simply a single distro Ubuntu Jammy with
`BUILD_DISTROS_REGEX: "jammy"`.<br>
To build all distros, specify `BUILD_DISTROS_REGEX: all`.<br>
To build no distros, and no www, specify `BUILD_DISTROS_REGEX: none`.
##### Required distros to build
Functional tests and spec tests use Ubuntu Jammy. If Jammy is not built, those
stages fail. If you want to debug pipeline stages after `functional_test`,
building Ubuntu Jammy is required.
Specify `BUILD_DISTROS_REGEX: "jammy|<distro_you're_interested_in>"`.
##### Heed, when writing regex
Regex placed in `$BUILD_DISTROS_REGEX` are [Bash
regex](https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_01.html) and are
processed by Bash.
Any whitespace in `$BUILD_DISTROS_REGEX` must be escaped. For example,
`BUILD_DISTROS_REGEX: "\ jammy"`.
#### Debug upload stage, while building only a few distros
`run_test` jobs fail the pipeline, whenever packages for a distro weren't
built. When building only a few distros, packages for the rest of distros aren't
built. Not finding the package to test, a `run_test` job fails, pipeline fails,
and the upload stage doesn't get executed.
To still execute and debug upload stage in a faster feedback loop (building only
a few distros), specify `ALLOW_RUN_TESTS_TO_FAIL: true`. Gitlab CI's
`allow_failure: true` is used to allow the pipeline to ignore failed `run_test`
jobs and continue to the upload stage.
## Building the KasmVNC Server on Modern Unix/Linux Systems
Building the KasmVNC Server (Xvnc) is a bit trickier. On newer systems
containing Xorg 7.4 or later (such as Fedora), Xvnc is typically built to use
@ -114,48 +124,49 @@ the X11 shared libraries provided with the system. The procedure for this is
system-specific, since it requires specifying such things as font directories,
but the general outline is as follows.
> cd {build_directory}
```bash
cd {build_directory}
If performing an out-of-tree build:
> mkdir unix
> cp -R {source_directory}/unix/xserver unix/
# If performing an out-of-tree build:
mkdir unix
cp -R {source_directory}/unix/xserver unix/
> cp -R {xorg_source}/* unix/xserver/
(NOTE: {xorg_source} is the directory containing the Xorg source for the
machine on which you are building KasmVNC. The most recent versions of
Red Hat/Fedora, for instance, provide an RPM called
"xorg-x11-server-source", which installs the Xorg source under
/usr/share/xorg-x11-server-source.)
cp -R {xorg_source}/* unix/xserver/
# (NOTE: {xorg_source} is the directory containing the Xorg source for the
# machine on which you are building KasmVNC. The most recent versions of
# Red Hat/Fedora, for instance, provide an RPM called
# "xorg-x11-server-source", which installs the Xorg source under
# /usr/share/xorg-x11-server-source.)
> cd unix/xserver/
> patch -p1 < {source_directory}/unix/xserver{version}.patch
(where {version} matches the X server version you are building, such as
"17" for version 1.7.x.)
> autoreconf -fiv
cd unix/xserver/
patch -p1 < {source_directory}/unix/xserver{version}.patch
(where {version} matches the X server version you are building, such as
"17" for version 1.7.x.)
autoreconf -fiv
> ./configure --with-pic --without-dtrace --disable-static --disable-dri \
--disable-xinerama --disable-xvfb --disable-xnest --disable-xorg \
--disable-dmx --disable-xwin --disable-xephyr --disable-kdrive \
--disable-config-dbus --disable-config-hal --disable-config-udev \
--disable-dri2 --enable-install-libxf86config --enable-glx \
--with-default-font-path="catalogue:/etc/X11/fontpath.d,built-ins" \
--with-fontdir=/usr/share/X11/fonts \
--with-xkb-path=/usr/share/X11/xkb \
--with-xkb-output=/var/lib/xkb \
--with-xkb-bin-directory=/usr/bin \
--with-serverconfig-path=/usr/lib[64]/xorg \
--with-dri-driver-path=/usr/lib[64]/dri \
{additional configure options}
(NOTE: This is merely an example that works with Red Hat Enterprise
and recent Fedora releases. You should customize it for your particular
system. In particular, it will be necessary to customize the font, XKB,
and DRI directories.)
./configure --with-pic --without-dtrace --disable-static --disable-dri \
--disable-xinerama --disable-xvfb --disable-xnest --disable-xorg \
--disable-dmx --disable-xwin --disable-xephyr --disable-kdrive \
--disable-config-dbus --disable-config-hal --disable-config-udev \
--disable-dri2 --enable-install-libxf86config --enable-glx \
--with-default-font-path="catalogue:/etc/X11/fontpath.d,built-ins" \
--with-fontdir=/usr/share/X11/fonts \
--with-xkb-path=/usr/share/X11/xkb \
--with-xkb-output=/var/lib/xkb \
--with-xkb-bin-directory=/usr/bin \
--with-serverconfig-path=/usr/lib[64]/xorg \
--with-dri-driver-path=/usr/lib[64]/dri \
{additional configure options}
# (NOTE: This is merely an example that works with Red Hat Enterprise
# and recent Fedora releases. You should customize it for your particular
# system. In particular, it will be necessary to customize the font, XKB,
# and DRI directories.)
> make KASMVNC_SRCDIR={source_directory}
make KASMVNC_SRCDIR={source_directory}
```
Building the KasmVNC Server on Legacy Unix/Linux Systems
---------------------------------------------------------
## Building the KasmVNC Server on Legacy Unix/Linux Systems
Those using systems with older versions of Xorg must build a "legacy-friendly"
version of the KasmVNC Server. This is accomplished by downloading and
@ -167,9 +178,11 @@ source distribution (located under contrib/xorg/) automates this process.
The following procedure will build a
"legacy-friendly" version of the KasmVNC Server:
```bash
cd {build_directory}
sh {source_directory}/contrib/xorg/build-xorg init
sh {source_directory}/contrib/xorg/build-xorg build [additional CMake flags]
```
build-xorg generates a version of Xvnc that has no external dependencies on the
X11 shared libraries or any other distribution-specific shared libraries. This
@ -183,30 +196,32 @@ once the X11 modules and other dependencies have been built for the first time.
This is convenient for testing changes that just apply to the KasmVNC source
code. To accomplish this, run:
```sh
sh {source_directory}/contrib/xorg/build-xorg rebuild [additional make flags]
```
For instance,
```sh
sh {source_directory}/contrib/xorg/build-xorg rebuild clean
```
will clean the Xvnc build without destroying any of the
build configuration or module dependencies.
Debug Build
-----------
## Debug Build
Add "-DCMAKE_BUILD_TYPE=Debug" to the CMake command line.
Add `-DCMAKE_BUILD_TYPE=Debug` to the CMake command line.
Portable (semi-static) Build
----------------------------
## Portable (semi-static) Build
KasmVNC can under favourble circumstances be built in a way that allows
the resulting binaries to run on any system without having to also install
all the dynamic libraries it depends on. Enable this mode by adding:
-DBUILD_STATIC=1
`-DBUILD_STATIC=1`
to the CMake command line.
@ -214,30 +229,53 @@ Note that the method used to achieve this is very fragile and it may be
necessary to tweak cmake/StaticBuild.cmake to make things work on your
specific system.
# Build Requirements (Windows)
======================================
Building TLS Support
======================================
-- MinGW or MinGW-w64
-- Inno Setup (needed to build the KasmVNC installer)
Inno Setup can be downloaded from http://www.jrsoftware.org/isinfo.php.
You also need the Inno Setup Preprocessor, which is available in the
Inno Setup QuickStart Pack.
Add the directory containing iscc.exe (for instance,
C:\Program Files\Inno Setup 5) to the system or user PATH environment
variable prior to building KasmVNC.
# Out-of-Tree Builds
Binary objects, libraries, and executables are generated in the same directory
from which cmake was executed (the "binary directory"), and this directory need
not necessarily be the same as the KasmVNC source directory. You can create
multiple independent binary directories, in which different versions of
KasmVNC can be built from the same source tree using different compilers or
settings. In the sections below, {build_directory} refers to the binary
directory, whereas {source_directory} refers to the KasmVNC source directory.
For in-tree builds, these directories are the same.
# Building TLS Support
TLS requires GnuTLS, which is supplied with most Linux distributions and
with MinGW for Windows and can be built from source on OS X and other
Unix variants. However, GnuTLS versions > 2.12.x && < 3.3.x should be
avoided because of potential incompatibilities during initial handshaking.
You can override the GNUTLS_LIBRARY and GNUTLS_INCLUDE_DIR CMake variables
You can override the `GNUTLS_LIBRARY` and `GNUTLS_INCLUDE_DIR` CMake variables
to specify the locations of libgnutls and any dependencies. For instance,
adding
```bash
-DGNUTLS_INCLUDE_DIR=/usr/local/include \
-DGNUTLS_LIBRARY=/usr/local/lib/libgnutls.a
```
to the CMake command line would link KasmVNC against a static version of
libgnutls located under /usr/local.
======================================
Building Native Language Support (NLS)
======================================
# Building Native Language Support (NLS)
NLS requires gettext, which is supplied with most Linux distributions and
with MinGW for Windows and which can easily be built from source on OS X and
@ -247,60 +285,57 @@ You can override the ICONV_LIBRARIES and LIBINTL_LIBRARY CMake variables to
specify the locations of libiconv and libintl, respectively. For instance,
adding
-DLIBINTL_LIBRARY=/opt/gettext/lib/libintl.a
`-DLIBINTL_LIBRARY=/opt/gettext/lib/libintl.a`
to the CMake command line would link KasmVNC against a static version of
libintl located under /opt/gettext. Adding
```bash
-DICONV_INCLUDE_DIR=/mingw/include \
-DICONV_LIBRARIES=/mingw/lib/libiconv.a \
-DGETTEXT_INCLUDE_DIR=/mingw/include \
-DLIBINTL_LIBRARY=/mingw/lib/libintl.a
```
to the CMake command line would link KasmVNC against the static versions of
libiconv and libintl included in the MinGW Developer Toolkit.
===================
Installing KasmVNC
===================
# Installing KasmVNC
You can use the build system to install KasmVNC into a directory of your
choosing. To do this, add:
-DCMAKE_INSTALL_PREFIX={install_directory}
`-DCMAKE_INSTALL_PREFIX={install_directory}`
to the CMake command line. Then, you can run 'make install' to build and
install it.
If you don't specify CMAKE_INSTALL_PREFIX, then the default is
c:\Program Files\KasmVNC on Windows and /usr/local on Unix.
If you don't specify `CMAKE_INSTALL_PREFIX`, then the default is
`c:\Program Files\KasmVNC` on Windows and `/usr/local` on Unix.
=========================
Creating Release Packages
=========================
# Creating Release Packages
The following commands can be used to create various types of release packages:
Unix
----
## Unix
make tarball
`make tarball`
Create a binary tarball containing the utils
make servertarball
`make servertarball`
Create a binary tarball containing both the KasmVNC Server and utils
make dmg
`make dmg`
Create Macintosh disk image file that contains an application bundle of the
utils
make udmg
`make udmg`
On 64-bit OS X systems, this creates a version of the Macintosh package and
disk image which contains universal i386/x86-64 binaries. You should first
@ -313,67 +348,69 @@ make udmg
using the instructions in the "Build Recipes" section.
Windows
-------
## Windows
make installer
`make installer`
Create a Windows installer using Inno Setup. The installer package
(KasmVNC[64].exe) will be located under {build_directory}.
=============
Build Recipes
=============
# Build Recipes
32-bit Build on 64-bit Linux/Unix (including OS X)
--------------------------------------------------
## 32-bit Build on 64-bit Linux/Unix (including OS X)
Set the following environment variables before building KasmVNC.
```bash
CFLAGS='-O3 -m32'
CXXFLAGS='-O3 -m32'
LDFLAGS=-m32
```
If you are building the KasmVNC Server on a modern Unix/Linux system, then
you will also need to pass the appropriate --host argument when configuring the
X server source (for instance, --host=i686-pc-linux-gnu).
64-bit Backward-Compatible Build on 64-bit OS X
-----------------------------------------------
## 64-bit Backward-Compatible Build on 64-bit OS X
Add
```bash
-DCMAKE_OSX_SYSROOT=/Developer/SDKs/MacOSX10.5.sdk \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.5
```
to the CMake command line. The OS X 10.5 SDK must be installed.
32-bit Backward-Compatible Build on 64-bit OS X
-----------------------------------------------
## 32-bit Backward-Compatible Build on 64-bit OS X
Set the following environment variables:
```bash
CC=gcc-4.0
CXX=g++-4.0
CFLAGS='-O3 -m32'
CXXFLAGS='-O3 -m32'
LDFLAGS=-m32
```
and add
```bash
-DCMAKE_OSX_SYSROOT=/Developer/SDKs/MacOSX10.4u.sdk \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.4
```
to the CMake command line. The OS X 10.4 SDK must be installed.
64-bit MinGW Build on Cygwin
----------------------------
## 64-bit MinGW Build on Cygwin
```bash
cd {build_directory}
CC=/usr/bin/x86_64-w64-mingw32-gcc CXX=/usr/bin/x86_64-w64-mingw32-g++ \
RC=/usr/bin/x86_64-w64-mingw32-windres \
@ -381,15 +418,16 @@ to the CMake command line. The OS X 10.4 SDK must be installed.
-DCMAKE_AR=/usr/bin/x86_64-w64-mingw32-ar \
-DCMAKE_RANLIB=/usr/bin/x86_64-w64-mingw32-ranlib {source_directory}
make
```
This produces a 64-bit build of KasmVNC that does not depend on cygwin1.dll or
other Cygwin DLL's. The mingw64-x86_64-gcc-core and mingw64-x86_64-gcc-g++
packages (and their dependencies) must be installed.
32-bit MinGW Build on Cygwin
----------------------------
## 32-bit MinGW Build on Cygwin
```bash
cd {build_directory}
CC=/usr/bin/i686-w64-mingw32-gcc CXX=/usr/bin/i686-w64-mingw32-g++ \
RC=/usr/bin/i686-w64-mingw32-windres \
@ -397,18 +435,19 @@ packages (and their dependencies) must be installed.
-DDCMAKE_AR=/usr/bin/i686-w64-mingw32-ar \
-DCMAKE_RANLIB=/usr/bin/i686-w64-mingw32-ranlib {source_directory}
make
```
This produces a 32-bit build of KasmVNC that does not depend on cygwin1.dll or
other Cygwin DLL's. The mingw64-i686-gcc-core and mingw64-i686-gcc-g++
packages (and their dependencies) must be installed.
MinGW-w64 Build on Windows
--------------------------
## MinGW-w64 Build on Windows
This produces a 64-bit build of KasmVNC using the "native" MinGW-w64 toolchain
(which is faster than the Cygwin version):
```bash
cd {build_directory}
CC={mingw-w64_binary_path}/x86_64-w64-mingw32-gcc \
CXX={mingw-w64_binary_path}/x86_64-w64-mingw32-g++ \
@ -418,11 +457,12 @@ This produces a 64-bit build of KasmVNC using the "native" MinGW-w64 toolchain
-DCMAKE_RANLIB={mingw-w64_binary_path}/x86_64-w64-mingw32-ranlib \
{source_directory}
make
```
MinGW Build on Linux
--------------------
## MinGW Build on Linux
```bash
cd {build_directory}
CC={mingw_binary_path}/i386-mingw32-gcc \
CXX={mingw_binary_path}/i386-mingw32-g++ \
@ -432,15 +472,13 @@ MinGW Build on Linux
-DCMAKE_RANLIB={mingw_binary_path}/i386-mingw32-ranlib \
{source_directory}
make
```
===============================
Distribution-Specific Packaging
===============================
# Distribution-Specific Packaging
RPM Packages for RHEL
------------------------------
## RPM Packages for RHEL
The RPM spec files and patches used to create the nightly builds
and releases can be found in the "contrib/rpm/el{5,6}" directories
@ -449,6 +487,7 @@ must be fetched manually and placed into the 'SOURCES' directory
under the rpmbuild root. Additionally, the following macros need
to be defined:
```
EL6:
%debug_package %{nil}
@ -457,10 +496,11 @@ to be defined:
%_smp_mflags -j3
%debug_package %{nil}
%__arch_install_post /usr/lib/rpm/check-rpaths /usr/lib/rpm/check-buildroot
```
Debian packages for Ubuntu 12.04LTS
-----------------------------------
## Debian packages for Ubuntu 12.04LTS
The debian folder used to create the nightly builds and releases
can be found in the "contrib/deb/ubuntu-precise" directory of the
KasmVNC subversion trunk.

View file

@ -21,7 +21,7 @@ include(CheckCSourceRuns)
include(CMakeMacroLibtoolFile)
project(kasmvnc)
project(kasmvnc LANGUAGES C CXX)
set(VERSION 0.9)
# The RC version must always be four comma-separated numbers
@ -74,13 +74,10 @@ set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -UNDEBUG")
# Make sure we get a sane C version
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
set(CMAKE_CXX_STANDARD 20)
# Enable OpenMP
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
# Enable C++ 11
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
# Tell the compiler to be stringent
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wformat=2")
@ -230,6 +227,7 @@ include_directories(${CMAKE_BINARY_DIR})
include(cmake/StaticBuild.cmake)
add_subdirectory(third_party)
add_subdirectory(common)
if(WIN32)
@ -242,11 +240,12 @@ else()
endif()
if(ENABLE_NLS)
add_subdirectory(po)
add_subdirectory(po)
endif()
####add_subdirectory(tests)
if (TESTS)
add_subdirectory(tests)
endif()
include(cmake/BuildPackages.cmake)

View file

@ -12,4 +12,4 @@ pexpect = "*"
[dev-packages]
[requires]
python_version = "3.8"
python_version = "3.10"

143
Pipfile.lock generated
View file

@ -1,11 +1,11 @@
{
"_meta": {
"hash": {
"sha256": "6745d5e5d90e44a18d73a0e23bc3d3e68acb950af0b87df50b45272d25b9e615"
"sha256": "f6a1fc809d6e02cd4f1ed8e45d4fc135a7c757cabe8eeb887a29e3664b796221"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.8"
"python_version": "3.10"
},
"sources": [
{
@ -30,61 +30,72 @@
},
"coverage": {
"hashes": [
"sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c",
"sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6",
"sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45",
"sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a",
"sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03",
"sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529",
"sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a",
"sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a",
"sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2",
"sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6",
"sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759",
"sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53",
"sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a",
"sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4",
"sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff",
"sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502",
"sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793",
"sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb",
"sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905",
"sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821",
"sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b",
"sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81",
"sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0",
"sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b",
"sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3",
"sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184",
"sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701",
"sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a",
"sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82",
"sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638",
"sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5",
"sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083",
"sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6",
"sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90",
"sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465",
"sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a",
"sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3",
"sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e",
"sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066",
"sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf",
"sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b",
"sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae",
"sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669",
"sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873",
"sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b",
"sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6",
"sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb",
"sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160",
"sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c",
"sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079",
"sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d",
"sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"
"sha256:042e7841a26498fff7a37d6fda770d17519982f5b7d8bf5278d140b67b61095f",
"sha256:04bfec25a8ef1c5f41f5e7e5c842f6b615599ca8ba8391ec33a9290d9d2db3a3",
"sha256:0915742f4c82208ebf47a2b154a5334155ed9ef9fe6190674b8a46c2fb89cb05",
"sha256:18c5ae6d061ad5b3e7eef4363fb27a0576012a7447af48be6c75b88494c6cf25",
"sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe",
"sha256:2e4b6b87bb0c846a9315e3ab4be2d52fac905100565f4b92f02c445c8799e257",
"sha256:3043ba1c88b2139126fc72cb48574b90e2e0546d4c78b5299317f61b7f718b78",
"sha256:379fe315e206b14e21db5240f89dc0774bdd3e25c3c58c2c733c99eca96f1ada",
"sha256:42421e04069fb2cbcbca5a696c4050b84a43b05392679d4068acbe65449b5c64",
"sha256:4dfd9a93db9e78666d178d4f08a5408aa3f2474ad4d0e0378ed5f2ef71640cb6",
"sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28",
"sha256:554fec1199d93ab30adaa751db68acec2b41c5602ac944bb19187cb9a41a8067",
"sha256:581a40c7b94921fffd6457ffe532259813fc68eb2bdda60fa8cc343414ce3733",
"sha256:5a26c0c795c3e0b63ec7da6efded5f0bc856d7c0b24b2ac84b4d1d7bc578d676",
"sha256:5a570cd9bd20b85d1a0d7b009aaf6c110b52b5755c17be6962f8ccd65d1dbd23",
"sha256:5aaeb00761f985007b38cf463b1d160a14a22c34eb3f6a39d9ad6fc27cb73008",
"sha256:5ac46d0c2dd5820ce93943a501ac5f6548ea81594777ca585bf002aa8854cacd",
"sha256:5c8a5c139aae4c35cbd7cadca1df02ea8cf28a911534fc1b0456acb0b14234f3",
"sha256:6b8af63b9afa1031c0ef05b217faa598f3069148eeee6bb24b79da9012423b82",
"sha256:769773614e676f9d8e8a0980dd7740f09a6ea386d0f383db6821df07d0f08545",
"sha256:771eb7587a0563ca5bb6f622b9ed7f9d07bd08900f7589b4febff05f469bea00",
"sha256:77af0f6447a582fdc7de5e06fa3757a3ef87769fbb0fdbdeba78c23049140a47",
"sha256:7a3d62b3b03b4b6fd41a085f3574874cf946cb4604d2b4d3e8dca8cd570ca501",
"sha256:821f7bcbaa84318287115d54becb1915eece6918136c6f91045bb84e2f88739d",
"sha256:89b1f4af0d4afe495cd4787a68e00f30f1d15939f550e869de90a86efa7e0814",
"sha256:8a1d96e780bdb2d0cbb297325711701f7c0b6f89199a57f2049e90064c29f6bd",
"sha256:8a40fcf208e021eb14b0fac6bdb045c0e0cab53105f93ba0d03fd934c956143a",
"sha256:8f99eb72bf27cbb167b636eb1726f590c00e1ad375002230607a844d9e9a2318",
"sha256:90e7fbc6216ecaffa5a880cdc9c77b7418c1dcb166166b78dbc630d07f278cc3",
"sha256:94ec0be97723ae72d63d3aa41961a0b9a6f5a53ff599813c324548d18e3b9e8c",
"sha256:95aa6ae391a22bbbce1b77ddac846c98c5473de0372ba5c463480043a07bff42",
"sha256:96121edfa4c2dfdda409877ea8608dd01de816a4dc4a0523356067b305e4e17a",
"sha256:a1f406a8e0995d654b2ad87c62caf6befa767885301f3b8f6f73e6f3c31ec3a6",
"sha256:a321c61477ff8ee705b8a5fed370b5710c56b3a52d17b983d9215861e37b642a",
"sha256:a5761c70c017c1b0d21b0815a920ffb94a670c8d5d409d9b38857874c21f70d7",
"sha256:a9abbccd778d98e9c7e85038e35e91e67f5b520776781d9a1e2ee9d400869487",
"sha256:ad80e6b4a0c3cb6f10f29ae4c60e991f424e6b14219d46f1e7d442b938ee68a4",
"sha256:b44674870709017e4b4036e3d0d6c17f06a0e6d4436422e0ad29b882c40697d2",
"sha256:b571bf5341ba8c6bc02e0baeaf3b061ab993bf372d982ae509807e7f112554e9",
"sha256:b8194fb8e50d556d5849753de991d390c5a1edeeba50f68e3a9253fbd8bf8ccd",
"sha256:b87eb6fc9e1bb8f98892a2458781348fa37e6925f35bb6ceb9d4afd54ba36c73",
"sha256:bbb5cc845a0292e0c520656d19d7ce40e18d0e19b22cb3e0409135a575bf79fc",
"sha256:be945402e03de47ba1872cd5236395e0f4ad635526185a930735f66710e1bd3f",
"sha256:bf13d564d310c156d1c8e53877baf2993fb3073b2fc9f69790ca6a732eb4bfea",
"sha256:cf60dd2696b457b710dd40bf17ad269d5f5457b96442f7f85722bdb16fa6c899",
"sha256:d1ba00ae33be84066cfbe7361d4e04dec78445b2b88bdb734d0d1cbab916025a",
"sha256:d39fc4817fd67b3915256af5dda75fd4ee10621a3d484524487e33416c6f3543",
"sha256:d766a4f0e5aa1ba056ec3496243150698dc0481902e2b8559314368717be82b1",
"sha256:dbf364b4c5e7bae9250528167dfe40219b62e2d573c854d74be213e1e52069f7",
"sha256:dd19608788b50eed889e13a5d71d832edc34fc9dfce606f66e8f9f917eef910d",
"sha256:e013b07ba1c748dacc2a80e69a46286ff145935f260eb8c72df7185bf048f502",
"sha256:e5d2b9be5b0693cf21eb4ce0ec8d211efb43966f6657807f6859aab3814f946b",
"sha256:e5ff52d790c7e1628241ffbcaeb33e07d14b007b6eb00a19320c7b8a7024c040",
"sha256:e75a2ad7b647fd8046d58c3132d7eaf31b12d8a53c0e4b21fa9c4d23d6ee6d3c",
"sha256:e7ac22a0bb2c7c49f441f7a6d46c9c80d96e56f5a8bc6972529ed43c8b694e27",
"sha256:ed2144b8a78f9d94d9515963ed273d620e07846acd5d4b0a642d4849e8d91a0c",
"sha256:f017a61399f13aa6d1039f75cd467be388d157cd81f1a119b9d9a68ba6f2830d",
"sha256:f1d8a2a57b47142b10374902777e798784abf400a004b14f1b0b9eaf1e528ba4",
"sha256:f2d32f95922927186c6dbc8bc60df0d186b6edb828d299ab10898ef3f40052fe",
"sha256:f319bae0321bc838e205bf9e5bc28f0a3165f30c203b610f17ab5552cff90323",
"sha256:f3c38e4e5ccbdc9198aecc766cedbb134b2d89bf64533973678dfcf07effd883",
"sha256:f9983d01d7705b2d1f7a95e10bbe4091fabc03a46881a256c2787637b087003f",
"sha256:fa260de59dfb143af06dcf30c2be0b200bed2a73737a8a59248fcb9fa601ef0f"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==5.5"
"markers": "python_version >= '3.9'",
"version": "==7.8.0"
},
"expects": {
"hashes": [
@ -95,34 +106,34 @@
},
"mamba": {
"hashes": [
"sha256:75cfc6dfd287dcccaf86dd753cf48e0a7337487c7c3fafda05a6a67ded6da496"
"sha256:4dcf69e9a53e78d4aa5ec3dee0bb2c65f02ea68a6b62c4275653d7170b8f5fe2"
],
"index": "pypi",
"version": "==0.11.2"
"version": "==0.11.3"
},
"path": {
"hashes": [
"sha256:2de925e8d421f93bcea80d511b81accfb6a7e6b249afa4a5559557b0cf817097",
"sha256:340054c5bb459fc9fd40e7eb6768c5989f3e599d18224238465b5333bc8faa7d"
"sha256:688e7ec254f07a1c25f5474662d4480c663a2c8c4eb15c0ba056d8ab81608d22",
"sha256:d41e05ed4fa1d4f6d702df3c1e0a1a255d7b544287432456455dc7c51e5f98e9"
],
"markers": "python_version >= '3.6'",
"version": "==16.2.0"
"markers": "python_version >= '3.9'",
"version": "==17.1.0"
},
"path.py": {
"hashes": [
"sha256:8d885e8b2497aed005703d94e0fd97943401f035e42a136810308bff034529a8",
"sha256:a43e82eb2c344c3fd0b9d6352f6b856f40b8b7d3d65cc05978b42c3715668496"
],
"index": "pypi",
"markers": "python_version >= '3.5'",
"version": "==12.5.0"
},
"pexpect": {
"hashes": [
"sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937",
"sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"
"sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523",
"sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"
],
"index": "pypi",
"version": "==4.8.0"
"version": "==4.9.0"
},
"ptyprocess": {
"hashes": [

View file

@ -3,7 +3,7 @@
# Contributor:
# Maintainer: Kasm Technologies LLC <info@kasmweb.com>
pkgname=kasmvncserver
pkgver=1.3.3
pkgver=1.3.4
pkgrel=0
pkgdesc="KasmVNC provides remote web-based access to a Desktop or application."
url="https://github.com/kasmtech/KasmVNC"

View file

@ -115,7 +115,7 @@ locally by doing stuff like this:
```
bash -c '
. .ci/upload.sh;
. .ci/helpers.sh;
prepare_upload_filename "focal/kasmvncserver_0.9.1~beta-1+libjpeg-turbo-latest_amd64.deb";
echo $upload_filename;'
```

View file

@ -6,14 +6,7 @@ os="$1"
codename="$2"
build_tag="$3"
detect_package_format() {
package_format=rpm
if ls builder/dockerfile*"$os"* | grep -q .deb.build; then
package_format=deb
elif ls builder/dockerfile*"$os"* | grep -q .apk.build; then
package_format=apk
fi
}
. ./builder/common.sh
warn_build_tag_not_supported_for_rpm_and_exit() {
if [[ "$build_tag" && "$package_format" = "rpm" ]]; then

View file

@ -44,38 +44,41 @@ if [[ "${XORG_VER}" == 21* ]]; then
else
XORG_PATCH=$(echo "$XORG_VER" | grep -Po '^\d.\d+' | sed 's#\.##')
fi
wget --no-check-certificate https://www.x.org/archive/individual/xserver/xorg-server-${XORG_VER}.tar.gz
TARBALL="xorg-server-${XORG_VER}.tar.gz"
if [ ! -f "$TARBALL" ]; then
wget --no-check-certificate https://www.x.org/archive/individual/xserver/"$TARBALL"
fi
#git clone https://kasmweb@bitbucket.org/kasmtech/kasmvnc.git
#cd kasmvnc
#git checkout dynjpeg
cd /src
# We only want the server, so FLTK and manual tests aren't useful.
# Alternatively, install fltk 1.3 and its dev packages.
sed -i -e '/find_package(FLTK/s@^@#@' \
-e '/add_subdirectory(tests/s@^@#@' \
CMakeLists.txt
cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo . -DBUILD_VIEWER:BOOL=OFF \
-DENABLE_GNUTLS:BOOL=OFF
make -j5
make -j"$(nproc)"
tar -C unix/xserver -xf /tmp/xorg-server-${XORG_VER}.tar.gz --strip-components=1
if [ ! -d unix/xserver/include ]; then
tar -C unix/xserver -xf /tmp/"$TARBALL" --strip-components=1
cd unix/xserver
# Apply patches
patch -Np1 -i ../xserver${XORG_PATCH}.patch
case "$XORG_VER" in
1.20.*)
patch -s -p0 < ../CVE-2022-2320-v1.20.patch
if [ -f ../xserver120.7.patch ]; then
patch -Np1 -i ../xserver120.7.patch
fi ;;
1.19.*)
patch -s -p0 < ../CVE-2022-2320-v1.19.patch
;;
esac
cd unix/xserver
# Apply patches
patch -Np1 -i ../xserver"${XORG_PATCH}".patch
case "$XORG_VER" in
1.20.*)
patch -s -p0 < ../CVE-2022-2320-v1.20.patch
if [ -f ../xserver120.7.patch ]; then
patch -Np1 -i ../xserver120.7.patch
fi ;;
1.19.*)
patch -s -p0 < ../CVE-2022-2320-v1.19.patch
;;
esac
else
cd unix/xserver
fi
autoreconf -i
# Configuring Xorg is long and has many distro-specific paths.
@ -110,33 +113,38 @@ fi
--with-sha1=libcrypto \
--with-xkb-bin-directory=/usr/bin \
--with-xkb-output=/var/lib/xkb \
--with-xkb-path=/usr/share/X11/xkb ${CONFIG_OPTIONS}
--with-xkb-path=/usr/share/X11/xkb "${CONFIG_OPTIONS}"
# remove array bounds errors for new versions of GCC
find . -name "Makefile" -exec sed -i 's/-Werror=array-bounds//g' {} \;
make -j5
make -j"$(nproc)"
# modifications for the servertarball
cd /src
mkdir -p xorg.build/bin
mkdir -p xorg.build/lib
cd xorg.build/bin/
ln -s /src/unix/xserver/hw/vnc/Xvnc Xvnc
ln -sfn /src/unix/xserver/hw/vnc/Xvnc Xvnc
cd ..
mkdir -p man/man1
touch man/man1/Xserver.1
cp /src/unix/xserver/hw/vnc/Xvnc.man man/man1/Xvnc.1
mkdir lib
mkdir -p lib
cd lib
if [ -d /usr/lib/x86_64-linux-gnu/dri ]; then
ln -s /usr/lib/x86_64-linux-gnu/dri dri
ln -sfn /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
ln -sfn /usr/lib/aarch64-linux-gnu/dri dri
elif [ -d /usr/lib/arm-linux-gnueabihf/dri ]; then
ln -s /usr/lib/arm-linux-gnueabihf/dri dri
ln -sfn /usr/lib/arm-linux-gnueabihf/dri dri
elif [ -d /usr/lib/xorg/modules/dri ]; then
ln -s /usr/lib/xorg/modules/dri dri
ln -sfn /usr/lib/xorg/modules/dri dri
else
ln -s /usr/lib64/dri dri
ln -sfn /usr/lib64/dri dri
fi
cd /src

View file

@ -1,20 +0,0 @@
#!/bin/bash
# this script will build kasmvnc and build a new kasm desktop image
# this script assumes you have an instance of kasm already deployed
# it will replace the existing kasm desktop image so the next kasm you launch will use the updated image
set -e
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
exit 1
fi
docker build -t kasmvncbuilder:latest -f builder/dockerfile.build .
docker run -v /tmp:/build kasmvncbuilder:latest
cp /tmp/kasmvnc*.tar.gz builder/
cd builder
docker build -t kasmweb/desktop-deluxe:develop -f dockerfile.test .
docker ps -aq --no-trunc -f status=exited | xargs docker rm
docker rmi $(docker images | grep "<none>" | awk "{print $3}")

View file

@ -7,7 +7,7 @@ spec_file=alpine/kasmvncserver/APKBUILD
bump_version() {
sed -i "s/^pkgver=.\+/pkgver=$new_version/" "$1"
sed -i "s/^pkgrel=.\+/pkgver=0/" "$1"
sed -i "s/^pkgrel=.\+/pkgrel=0/" "$1"
}
bump_version $spec_file

View file

@ -1 +1,27 @@
VNC_PORT=8443
core_dumps_dir_inside_container="/core_dumps"
core_dumps_dir_on_host="run_test/core_dumps"
core_dumps_dir_volume_option="-v ${PWD}/${core_dumps_dir_on_host}:/${core_dumps_dir_inside_container}"
detect_build_dir() {
if [ -n "$CI" ]; then
build_dir=output
else
build_dir=builder/build
fi
}
detect_interactive() {
if [ -z "$run_test" ]; then
interactive=-it
fi
}
detect_package_format() {
package_format=rpm
if ls builder/dockerfile*"$os"* | grep -q .deb.build; then
package_format=deb
elif ls builder/dockerfile*"$os"* | grep -q .apk.build; then
package_format=apk
fi
}

View file

@ -0,0 +1,42 @@
server {
listen 8443 ssl;
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
location / {
proxy_pass http://127.0.0.1:5173;
}
location /api/ {
proxy_pass https://127.0.0.1:6901;
}
location /websockify {
# The following configurations must be configured when proxying to Kasm Workspaces
# WebSocket Support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Host and X headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Connectivity Options
proxy_http_version 1.1;
proxy_read_timeout 1800s;
proxy_send_timeout 1800s;
proxy_connect_timeout 1800s;
proxy_buffering off;
# Allow large requests to support file uploads to sessions
client_max_body_size 10M;
# # Proxy to KasmVNC using SSL
#proxy_pass https://127.0.0.1:6901;
# Proxy to KasmVNC without SSL
proxy_pass http://127.0.0.1:6901;
}
}

View file

@ -3,7 +3,7 @@
set -e
default_os=ubuntu
default_os_codename=focal
default_os_codename=jammy
cd "$(dirname "$0")/.."
. ./builder/os_ver_cli.sh

View file

@ -0,0 +1,24 @@
ARG BASE_IMAGE
FROM $BASE_IMAGE
RUN apk add bash
ENV STARTUPDIR=/dockerstartup
COPY ./builder/scripts/ /tmp/scripts/
COPY alpine/kasmvncserver/APKBUILD /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver-*.apk /tmp/
RUN /tmp/scripts/install_kasmvncserver_package
ARG RUN_TEST
RUN [ "$RUN_TEST" = 1 ] || apk add xterm
RUN mkdir -p $STARTUPDIR
COPY builder/startup/vnc_startup_barebones.sh $STARTUPDIR
RUN adduser -D -s/bin/bash foo && addgroup foo kasmvnc-cert
USER foo
ENTRYPOINT "/$STARTUPDIR/vnc_startup_barebones.sh"

View file

@ -0,0 +1 @@
dockerfile.alpine.barebones.apk.test

View file

@ -14,6 +14,7 @@ RUN \
bash \
ca-certificates \
cmake \
nasm \
coreutils \
curl \
eudev-dev \
@ -66,13 +67,13 @@ RUN \
xorgproto \
xorg-server-common \
xorg-server-dev \
xtrans
xtrans \
ffmpeg-dev
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN $SCRIPTS_DIR/build-deps.sh
RUN useradd -m docker && echo "docker:docker" | chpasswd

View file

@ -0,0 +1 @@
dockerfile.alpine.barebones.apk.test

View file

@ -14,6 +14,7 @@ RUN \
bash \
ca-certificates \
cmake \
nasm \
coreutils \
curl \
eudev-dev \
@ -66,13 +67,13 @@ RUN \
xorgproto \
xorg-server-common \
xorg-server-dev \
xtrans
xtrans \
ffmpeg-dev
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN $SCRIPTS_DIR/build-deps.sh
RUN useradd -m docker && echo "docker:docker" | chpasswd

View file

@ -0,0 +1 @@
dockerfile.alpine.barebones.apk.test

View file

@ -14,6 +14,7 @@ RUN \
bash \
ca-certificates \
cmake \
nasm \
coreutils \
curl \
eudev-dev \
@ -66,13 +67,13 @@ RUN \
xorgproto \
xorg-server-common \
xorg-server-dev \
xtrans
xtrans \
ffmpeg-dev
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN $SCRIPTS_DIR/build-deps.sh
RUN useradd -m docker && echo "docker:docker" | chpasswd

View file

@ -1,7 +1,7 @@
FROM alpine:3.21
RUN apk add shadow bash
RUN apk add abuild sudo less
RUN apk add abuild sudo less ffmpeg-dev
ENV HOME /src/alpine
WORKDIR $HOME/kasmvncserver

View file

@ -0,0 +1 @@
dockerfile.alpine.barebones.apk.test

View file

@ -14,6 +14,7 @@ RUN \
bash \
ca-certificates \
cmake \
nasm \
coreutils \
curl \
eudev-dev \
@ -66,13 +67,13 @@ RUN \
xorgproto \
xorg-server-common \
xorg-server-dev \
xtrans
xtrans \
ffmpeg-dev
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN $SCRIPTS_DIR/build-deps.sh
RUN useradd -m docker && echo "docker:docker" | chpasswd

View file

@ -1,4 +1,5 @@
FROM debian:buster-slim
ARG BASE_IMAGE
FROM $BASE_IMAGE
ENV STARTUPDIR=/dockerstartup
@ -8,12 +9,14 @@ COPY ./debian/changelog /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
RUN /tmp/scripts/install_kasmvncserver_package
RUN apt-get update && apt-get -y install xterm
ARG RUN_TEST
RUN if [ "$RUN_TEST" != 1 ]; then apt-get update && apt-get -y install xterm lsb-release; fi
RUN mkdir -p $STARTUPDIR
COPY builder/startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo
USER foo:ssl-cert
RUN useradd -m foo && adduser foo ssl-cert
USER foo
ENTRYPOINT "/$STARTUPDIR/vnc_startup_barebones.sh"

View file

@ -0,0 +1 @@
dockerfile.debian.barebones.deb.test

View file

@ -22,13 +22,13 @@ RUN apt-get update && \
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 curl
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
RUN apt-get update && apt-get -y install ninja-build cmake nasm git libgnutls28-dev vim wget tightvncserver curl
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev \
libxcursor-dev libavformat-dev libswscale-dev
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN $SCRIPTS_DIR/build-deps.sh
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo

View file

@ -0,0 +1 @@
dockerfile.debian.barebones.deb.test

View file

@ -12,13 +12,26 @@ RUN apt-get update && \
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 curl
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
RUN apt-get update && apt-get -y install ninja-build nasm git libgnutls28-dev vim wget tightvncserver curl
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev \
libxcursor-dev libavformat-dev libswscale-dev
RUN CMAKE_URL="https://cmake.org/files/v3.22/cmake-3.22.0" && \
ARCH=$(arch) && \
if [ "$ARCH" = "x86_64" ]; then \
CMAKE_URL="${CMAKE_URL}-linux-x86_64.sh"; \
elif [ "$ARCH" = "aarch64" ]; then \
CMAKE_URL="${CMAKE_URL}-linux-aarch64.sh"; \
else \
echo "Unsupported architecture: $ARCH" && exit 1; \
fi && \
curl -fsSL $CMAKE_URL -o cmake.sh && \
(echo y; echo n) | bash cmake.sh --prefix=/usr/local --skip-license && \
rm cmake.sh
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN $SCRIPTS_DIR/build-deps.sh
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo

View file

@ -1,28 +0,0 @@
FROM debian:buster
ENV KASMVNC_BUILD_OS debian
ENV KASMVNC_BUILD_OS_CODENAME buster
ENV XORG_VER 1.20.10
ENV DEBIAN_FRONTEND noninteractive
RUN grep '^deb' /etc/apt/sources.list | sed 's#^deb#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 curl
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
COPY --chown=docker:docker . /src/
USER docker
ENTRYPOINT ["/src/builder/build.sh"]

View file

@ -0,0 +1 @@
dockerfile.debian.barebones.deb.test

View file

@ -0,0 +1,38 @@
FROM debian:trixie-slim
ENV KASMVNC_BUILD_OS debian
ENV KASMVNC_BUILD_OS_CODENAME trixie
ENV XORG_VER 21.1.7
ENV DEBIAN_FRONTEND noninteractive
RUN \
echo "**** add all sources ****" && \
echo "deb http://deb.debian.org/debian trixie main contrib non-free non-free-firmware" > /etc/apt/sources.list && \
echo "deb-src http://deb.debian.org/debian trixie main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb http://deb.debian.org/debian trixie-updates main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb-src http://deb.debian.org/debian trixie-updates main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb http://deb.debian.org/debian trixie-backports main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb-src http://deb.debian.org/debian trixie-backports main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb http://security.debian.org/debian-security/ trixie-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb-src http://security.debian.org/debian-security/ trixie-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
rm -f /etc/apt/sources.list.d/debian.sources
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 ninja-build cmake nasm git libgnutls28-dev vim wget tightvncserver curl
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev \
libxcursor-dev libavformat-dev libswscale-dev
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-deps.sh
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
COPY --chown=docker:docker . /src/
USER docker
ENTRYPOINT ["/src/builder/build.sh"]

View file

@ -1,4 +1,4 @@
FROM debian:buster
FROM debian:trixie-slim
ENV DEBIAN_FRONTEND noninteractive

View file

@ -1,4 +1,4 @@
FROM debian:buster-slim
FROM debian:trixie-slim
ENV DISPLAY=:1 \
VNC_PORT=8443 \
@ -29,7 +29,7 @@ WORKDIR $HOME
### REQUIRED STUFF ###
RUN apt-get update && apt-get install -y supervisor xfce4 xfce4-terminal xterm libnss-wrapper gettext wget
RUN apt-get update && apt-get install -y supervisor xfce4 xfce4-terminal dbus-x11 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
@ -40,6 +40,7 @@ RUN mkdir -p $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####
COPY ./builder/scripts/ /tmp/scripts/
COPY ./debian/changelog /tmp

View file

@ -0,0 +1,25 @@
FROM fedora:40
ENV STARTUPDIR=/dockerstartup
ARG RUN_TEST
RUN [ "$RUN_TEST" = 1 ] || dnf install -y \
less \
redhat-lsb-core \
vim \
xterm
COPY ./builder/scripts/ /tmp/scripts/
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver-*.rpm /tmp/
COPY fedora/kasmvncserver.spec /tmp/
RUN /tmp/scripts/install_kasmvncserver_package
RUN mkdir -p $STARTUPDIR
COPY builder/startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo
USER foo:kasmvnc-cert
ENTRYPOINT "/$STARTUPDIR/vnc_startup_barebones.sh"

View file

@ -16,6 +16,7 @@ RUN \
byacc \
bzip2 \
cmake \
nasm \
diffutils \
doxygen \
file \
@ -71,12 +72,13 @@ RUN \
xorg-x11-server-common \
xorg-x11-server-devel \
xorg-x11-xtrans-devel \
xsltproc
xsltproc \
libavformat-free-devel \
libswscale-free-devel
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN $SCRIPTS_DIR/build-deps.sh
RUN useradd -m docker && echo "docker:docker" | chpasswd

View file

@ -0,0 +1,25 @@
FROM fedora:41
ENV STARTUPDIR=/dockerstartup
ARG RUN_TEST
RUN [ "$RUN_TEST" = 1 ] || dnf install -y \
less \
redhat-lsb-core \
vim \
xterm
COPY ./builder/scripts/ /tmp/scripts/
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver-*.rpm /tmp/
COPY fedora/kasmvncserver.spec /tmp/
RUN /tmp/scripts/install_kasmvncserver_package
RUN mkdir -p $STARTUPDIR
COPY builder/startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo
USER foo:kasmvnc-cert
ENTRYPOINT "/$STARTUPDIR/vnc_startup_barebones.sh"

View file

@ -17,6 +17,7 @@ RUN \
byacc \
bzip2 \
cmake \
nasm \
diffutils \
doxygen \
file \
@ -72,12 +73,13 @@ RUN \
xorg-x11-server-common \
xorg-x11-server-devel \
xorg-x11-xtrans-devel \
xsltproc
xsltproc \
libavformat-free-devel \
libswscale-free-devel
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN $SCRIPTS_DIR/build-deps.sh
RUN useradd -m docker && echo "docker:docker" | chpasswd

View file

@ -1,86 +0,0 @@
FROM fedora:39
ENV KASMVNC_BUILD_OS fedora
ENV KASMVNC_BUILD_OS_CODENAME thirtynine
ENV XORG_VER 1.20.14
RUN \
echo "**** install build deps ****" && \
dnf group install -y \
"C Development Tools and Libraries" \
"Development Tools" && \
dnf install -y \
autoconf \
automake \
bison \
byacc \
bzip2 \
cmake \
diffutils \
doxygen \
file \
flex \
fop \
gcc \
gcc-c++ \
git \
glibc-devel \
libdrm-devel \
libepoxy-devel \
libmd-devel \
libpciaccess-devel \
libtool \
libwebp-devel \
libX11-devel \
libXau-devel \
libxcb-devel \
libXcursor-devel \
libxcvt-devel \
libXdmcp-devel \
libXext-devel \
libXfont2-devel \
libxkbfile-devel \
libXrandr-devel \
libxshmfence-devel \
libXtst-devel \
mesa-libEGL-devel \
mesa-libgbm-devel \
mesa-libGL-devel \
meson \
mingw64-binutils \
mt-st \
nettle-devel \
openssl-devel \
patch \
pixman-devel \
wayland-devel \
wget \
which \
xcb-util-devel \
xcb-util-image-devel \
xcb-util-keysyms-devel \
xcb-util-renderutil-devel \
xcb-util-wm-devel \
xinit \
xkbcomp \
xkbcomp-devel \
xkeyboard-config \
xmlto \
xorg-x11-font-utils \
xorg-x11-proto-devel \
xorg-x11-server-common \
xorg-x11-server-devel \
xorg-x11-xtrans-devel \
xsltproc
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN useradd -m docker && echo "docker:docker" | chpasswd
COPY --chown=docker:docker . /src/
USER docker
ENTRYPOINT ["/src/builder/build.sh"]

View file

@ -1,13 +0,0 @@
FROM fedora:39
RUN dnf install -y fedora-packager fedora-review
RUN dnf install -y tree vim less
RUN dnf install -y redhat-lsb-core
RUN dnf install -y dnf-plugins-core
COPY fedora/*.spec /tmp
RUN dnf builddep -y /tmp/*.spec
RUN useradd -m docker && echo "docker:docker" | chpasswd
USER docker

View file

@ -0,0 +1 @@
dockerfile.debian.barebones.deb.test

View file

@ -4,6 +4,8 @@ ENV KASMVNC_BUILD_OS kali
ENV KASMVNC_BUILD_OS_CODENAME kali-rolling
ENV XORG_VER 21.1.14
ENV DEBIAN_FRONTEND noninteractive
ENV CXXFLAGS="-Wno-stringop-overflow"
ENV CFLAGS="-Wno-stringop-overflow"
RUN grep '^deb' /etc/apt/sources.list | sed 's#^deb#deb-src#' >> /etc/apt/sources.list
@ -13,13 +15,13 @@ RUN apt-get update && \
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 gcc g++ curl
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 libxrandr-dev libxcursor-dev
RUN apt-get update && apt-get -y install ninja-build cmake nasm git libgnutls28-dev vim wget tightvncserver
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev \
libxcursor-dev libavformat-dev libswscale-dev
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN $SCRIPTS_DIR/build-deps.sh
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo

View file

@ -3,7 +3,8 @@ FROM opensuse/leap:15.5
ENV STARTUPDIR=/dockerstartup
# base tools
RUN zypper -n install -y \
ARG RUN_TEST
RUN [ "$RUN_TEST" = 1 ] || zypper -n install -y \
less \
vim \
xterm
@ -15,7 +16,7 @@ COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp
RUN zypper install -y --allow-unsigned-rpm /tmp/*.rpm
RUN mkdir -p $STARTUPDIR
COPY startup/vnc_startup_barebones.sh $STARTUPDIR
COPY builder/startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo
USER foo:kasmvnc-cert

View file

@ -8,13 +8,16 @@ ENV XORG_VER 1.20.3
RUN zypper install -ny \
bdftopcf \
bigreqsproto-devel \
cmake \
ninja \
nasm \
curl \
ffmpeg-4-libavcodec-devel \
ffmpeg-4-libswscale-devel \
ffmpeg-4-libavformat-devel \
fonttosfnt \
font-util \
gcc \
gcc-c++ \
gcc14 \
gcc14-c++ \
giflib-devel \
git \
gzip \
@ -45,17 +48,31 @@ RUN zypper install -ny \
xorg-x11-util-devel \
zlib-devel
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN useradd -u 1000 docker && \
groupadd -g 1000 docker && \
usermod -a -G docker docker
RUN ARCH=$(arch) && \
CMAKE_URL="https://cmake.org/files/v3.22/cmake-3.22.0" && \
if [ "$ARCH" = "x86_64" ]; then \
CMAKE_URL="${CMAKE_URL}-linux-x86_64.sh"; \
elif [ "$ARCH" = "aarch64" ]; then \
CMAKE_URL="${CMAKE_URL}-linux-aarch64.sh"; \
else \
echo "Unsupported architecture: $ARCH" && exit 1; \
fi && \
curl -fsSL $CMAKE_URL -o cmake.sh && \
(echo y; echo n) | bash cmake.sh --prefix=/usr/local --skip-license && \
rm cmake.sh
ENV SCRIPTS_DIR=/tmp/scripts
ENV CC=/usr/bin/gcc-14
ENV CXX=/usr/bin/g++-14
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-deps.sh
COPY --chown=docker:docker . /src/
USER docker
ENTRYPOINT ["/src/builder/build.sh"]
ENTRYPOINT ["bash", "-l", "-c", "/src/builder/build.sh"]

View file

@ -2,7 +2,8 @@ FROM oraclelinux:8
ENV STARTUPDIR=/dockerstartup
RUN dnf install -y \
ARG RUN_TEST
RUN [ "$RUN_TEST" = 1 ] || dnf install -y \
less \
redhat-lsb-core \
vim \
@ -10,12 +11,15 @@ RUN dnf install -y \
RUN dnf config-manager --set-enabled ol8_codeready_builder
RUN dnf install -y oracle-epel-release-el8
COPY ./builder/scripts/ /tmp/scripts/
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp
RUN dnf localinstall -y /tmp/*.rpm
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver-*.rpm /tmp/
COPY fedora/kasmvncserver.spec /tmp/
RUN /tmp/scripts/install_kasmvncserver_package
RUN mkdir -p $STARTUPDIR
COPY startup/vnc_startup_barebones.sh $STARTUPDIR
COPY builder/startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo
USER foo:kasmvnc-cert

View file

@ -11,10 +11,13 @@ RUN \
dnf install -y \
bzip2-devel \
ca-certificates \
ninja-build \
cmake \
nasm \
dnf-plugins-core \
gcc \
gcc-c++ \
gcc-toolset-14 \
git \
gnutls-devel \
libjpeg-turbo-devel \
@ -48,16 +51,18 @@ RUN dnf install -y \
xorg-x11-xtrans-devel \
libXrandr-devel \
libXtst-devel \
libXcursor-devel
libXcursor-devel \
libSM-devel
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
ENV PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig:${PKG_CONFIG_PATH:-/opt/rh/gcc-toolset-14/root/usr/lib64/pkgconfig}
RUN useradd -m docker && echo "docker:docker" | chpasswd
COPY builder/scripts $SCRIPTS_DIR
RUN echo "source /opt/rh/gcc-toolset-14/enable" > /etc/profile.d/gcc-toolset.sh && \
$SCRIPTS_DIR/build-deps.sh && \
useradd -m docker && echo "docker:docker" | chpasswd
COPY --chown=docker:docker . /src/
USER docker
ENTRYPOINT ["/src/builder/build.sh"]
ENTRYPOINT ["bash", "-l", "-c", "/src/builder/build.sh"]

View file

@ -2,7 +2,7 @@ FROM oraclelinux:9
ENV STARTUPDIR=/dockerstartup
RUN dnf install -y \
RUN [ "$RUN_TEST" = 1 ] || dnf install -y \
less \
vim \
xterm
@ -17,7 +17,7 @@ RUN dnf install -y crypto-policies-scripts
RUN update-crypto-policies --set FIPS:SHA1
RUN mkdir -p $STARTUPDIR
COPY startup/vnc_startup_barebones.sh $STARTUPDIR
COPY builder/startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo
USER foo:kasmvnc-cert

View file

@ -11,10 +11,13 @@ RUN \
dnf install -y \
bzip2-devel \
ca-certificates \
ninja-build \
cmake \
nasm \
dnf-plugins-core \
gcc \
gcc-c++ \
gcc-toolset-14 \
git \
gnutls-devel \
libjpeg-turbo-devel \
@ -40,6 +43,7 @@ RUN dnf install -y --nogpgcheck https://mirrors.rpmfusion.org/free/el/rpmfusion-
# Install from new repos
RUN dnf install -y \
giflib-devel \
ffmpeg-devel \
lbzip2 \
libXfont2-devel \
libxkbfile-devel \
@ -47,17 +51,16 @@ RUN dnf install -y \
xorg-x11-xtrans-devel \
libXrandr-devel \
libXtst-devel \
libXcursor-devel
libXcursor-devel \
libSM-devel
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN useradd -m docker && echo "docker:docker" | chpasswd
RUN echo "source /opt/rh/gcc-toolset-14/enable" > /etc/profile.d/gcc-toolset.sh && \
$SCRIPTS_DIR/build-deps.sh && \
useradd -m docker && echo "docker:docker" | chpasswd
COPY --chown=docker:docker . /src/
USER docker
ENTRYPOINT ["/src/builder/build.sh"]
ENTRYPOINT ["bash", "-l", "-c", "/src/builder/build.sh"]

View file

@ -1,20 +0,0 @@
FROM ubuntu:focal
ENV STARTUPDIR=/dockerstartup
COPY ./builder/scripts/ /tmp/scripts/
COPY ./debian/changelog /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
RUN /tmp/scripts/install_kasmvncserver_package
RUN apt-get update && apt-get -y install xterm lsb-release
RUN mkdir -p $STARTUPDIR
COPY builder/startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo && addgroup foo ssl-cert
USER foo
ENTRYPOINT "/$STARTUPDIR/vnc_startup_barebones.sh"

View file

@ -0,0 +1 @@
dockerfile.debian.barebones.deb.test

View file

@ -12,16 +12,30 @@ RUN apt-get update && \
RUN apt-get update && 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 vim wget curl
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
RUN apt-get update && apt-get -y install ninja-build nasm git vim wget curl
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev \
libxcursor-dev libavformat-dev libswscale-dev
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
RUN ARCH=$(arch) && \
CMAKE_URL="https://cmake.org/files/v3.22/cmake-3.22.0" && \
if [ "$ARCH" = "x86_64" ]; then \
CMAKE_URL="${CMAKE_URL}-linux-x86_64.sh"; \
elif [ "$ARCH" = "aarch64" ]; then \
CMAKE_URL="${CMAKE_URL}-linux-aarch64.sh"; \
else \
echo "Unsupported architecture: $ARCH" && exit 1; \
fi && \
curl -fsSL $CMAKE_URL -o cmake.sh && \
(echo y; echo n) | bash cmake.sh --prefix=/usr/local --skip-license && \
rm cmake.sh
RUN $SCRIPTS_DIR/build-deps.sh
COPY --chown=docker:docker . /src/
USER docker

View file

@ -0,0 +1 @@
dockerfile.debian.barebones.deb.test

View file

@ -12,13 +12,13 @@ RUN apt-get update && \
RUN apt-get update && 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 curl
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
RUN apt-get update && apt-get -y install ninja-build cmake nasm git libgnutls28-dev vim wget tightvncserver curl
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev \
libxcursor-dev libavformat-dev libswscale-dev
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN $SCRIPTS_DIR/build-deps.sh
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo

View file

@ -10,14 +10,60 @@ EXPOSE 6901
USER root
COPY builder/conf/nginx_kasm.conf /etc/nginx/conf.d/
RUN sed -i 's$# deb-src$deb-src$' /etc/apt/sources.list && \
apt update && \
apt install -y socat sudo libxfont-dev cmake git libgnutls28-dev vim wget tightvncserver curl libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev pkg-config libfreetype6-dev libxtst-dev autoconf automake libtool xutils-dev libpixman-1-dev libxshmfence-dev libxcvt-dev libxkbfile-dev x11proto-dev libgbm-dev inotify-tools && \
apt install -y \
ninja-build \
gdb \
valgrind \
rsync \
dos2unix \
socat \
sudo \
libxfont-dev \
cmake \
nasm \
git \
libgnutls28-dev \
vim \
wget \
tightvncserver \
curl \
libpng-dev \
libtiff-dev \
libgif-dev \
libavformat-dev \
libavcodec-dev \
libswscale-dev \
libssl-dev \
libxrandr-dev \
libxcursor-dev \
pkg-config \
libfreetype6-dev \
libxtst-dev \
autoconf \
automake \
libtool \
xutils-dev \
libpixman-1-dev \
libxshmfence-dev \
libxcvt-dev \
libxkbfile-dev \
x11proto-dev \
libgbm-dev \
htop \
inotify-tools && \
echo "kasm-user ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
RUN apt install -y nodejs
RUN apt install -y nodejs nginx
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-deps.sh
USER 1000
WORKDIR /src

View file

@ -1,4 +1,4 @@
FROM ubuntu:focal
FROM ubuntu:jammy
ENV DEBIAN_FRONTEND=noninteractive
@ -6,7 +6,7 @@ RUN apt-get update && apt-get install -y vim less
RUN apt-get update && apt-get install -y python3-pip
RUN apt-get update && apt-get install -y strace silversearcher-ag xfonts-base
RUN apt-get update && apt-get install -y cinnamon
RUN apt-get update && apt-get install -y mate
RUN apt-get update && apt-get install -y mate wget
RUN useradd -m docker

View file

@ -1,4 +1,4 @@
FROM ubuntu:focal
FROM ubuntu:jammy
ENV DEBIAN_FRONTEND=noninteractive
ENV VNC_PORT 8443

View file

@ -0,0 +1 @@
dockerfile.debian.barebones.deb.test

View file

@ -12,13 +12,13 @@ RUN apt-get update && \
RUN apt-get update && 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 curl
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
RUN apt-get update && apt-get -y install ninja-build cmake nasm git libgnutls28-dev vim wget curl
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev \
libxcursor-dev libavformat-dev libswscale-dev
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN $SCRIPTS_DIR/build-deps.sh
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo

View file

@ -6,7 +6,7 @@ usage() {
}
process_options() {
local sorted_options=$(getopt -o psh --long perf-test --long shell --long help -- "$@")
local sorted_options=$(getopt -o prsh --long perf-test --long run-test --long shell --long help -- "$@")
eval set -- $sorted_options
while : ; do
@ -16,6 +16,10 @@ process_options() {
entrypoint_executable="--entrypoint=/usr/bin/Xvnc"
shift
;;
-r|--run-test)
run_test=1
shift
;;
-s|--shell)
entrypoint_executable="--entrypoint=bash"
shift

26
builder/scripts/build-cpuid Executable file
View file

@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -euo pipefail
build_and_install() {
cmake -S . -B build -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DLIBCPUID_ENABLE_TESTS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -GNinja
ninja -C build install
}
prepare_source() {
DIR=tbb
cd /tmp
[ -d ./${DIR} ] && rm -rf ./${DIR}
mkdir ${DIR}
LIBCPUID_RELEASE=$(curl -sL "https://api.github.com/repos/anrieff/libcpuid/releases/latest" \
| grep '"tag_name":' | sed -E 's/.*"tag_name": "([^"]+)".*/\1/')
curl -Ls "https://github.com/anrieff/libcpuid/archive/${LIBCPUID_RELEASE}.tar.gz" | \
tar xzvf - -C ${DIR}/ --strip-components=1
cd ${DIR}
}
prepare_source
build_and_install

9
builder/scripts/build-deps.sh Executable file
View file

@ -0,0 +1,9 @@
#!/bin/bash
set -e
source_dir=$(dirname "$0")
"${source_dir}"/build-libjpeg-turbo
"${source_dir}"/build-webp
"${source_dir}"/build-tbb
"${source_dir}"/build-cpuid

View file

@ -3,20 +3,8 @@
set -euo pipefail
build_and_install() {
export MAKEFLAGS=-j`nproc`
export CFLAGS="-fpic"
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -G"Unix Makefiles"
make
make install
}
install_build_dependencies() {
install_packages cmake gcc
ensure_libjpeg_is_fast
}
ensure_libjpeg_is_fast() {
install_packages nasm
cmake -B build -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_POSITION_INDEPENDENT_CODE=ON -GNinja .
ninja -C build install
}
prepare_libjpeg_source() {
@ -32,6 +20,5 @@ prepare_libjpeg_source() {
source_dir=$(dirname "$0")
. "$source_dir/common.sh"
install_build_dependencies
prepare_libjpeg_source
build_and_install

63
builder/scripts/build-tbb Executable file
View file

@ -0,0 +1,63 @@
#!/usr/bin/env bash
set -euo pipefail
build_and_install() {
if [ $older_release -eq 1 ]; then
make extra_inc=big_iron.inc work_dir="$PWD"/ tbb_root="$PWD"
if [ -d /usr/lib/x86_64-linux-gnu ]; then
LIBS=lib/x86_64-linux-gnu
elif [ -d /usr/lib/aarch64-linux-gnu ]; then
LIBS=lib/aarch64-linux-gnu
elif [ -d /usr/lib/arm-linux-gnueabihf ]; then
LIBS=lib/arm-linux-gnu
fi
PC_FILE=/usr/${LIBS}/pkgconfig/tbb.pc
echo "prefix=/usr" > "${PC_FILE}"
echo "exec_prefix=\${prefix}" >> "${PC_FILE}"
echo "libdir=\${exec_prefix}/lib/${LIBS}" >> "${PC_FILE}"
echo "includedir=\${prefix}/include" >> "${PC_FILE}"
echo "Name: Threading Building Blocks" >> "${PC_FILE}"
echo "Description: Intel's parallelism library for C++" >> "${PC_FILE}"
echo "URL: http://www.threadingbuildingblocks.org/" >> "${PC_FILE}"
echo "Version: v2020.3.3" >> "${PC_FILE}"
echo "Libs: -ltbb -latomic" >> "${PC_FILE}"
echo "Cflags: -I\${includedir}" >> "${PC_FILE}"
cp _release/*.a /usr/"${LIBS}"/
cp -r include/* /usr/include/
else
cmake -B build -DCMAKE_INSTALL_PREFIX=/usr/local \
-DTBB_TEST=OFF -DBUILD_SHARED_LIBS=OFF -GNinja .
ninja -C build install
fi
}
prepare_source() {
DIR=tbb
cd /tmp
[ -d ./${DIR} ] && rm -rf ./${DIR}
mkdir ${DIR}
if [ $older_release -eq 1 ]; then
TBB_RELEASE="v2020.3.3"
else
TBB_RELEASE=$(curl -sL "https://api.github.com/repos/uxlfoundation/oneTBB/releases/latest" \
| grep '"tag_name":' | sed -E 's/.*"tag_name": "([^"]+)".*/\1/')
fi
curl -Ls "https://github.com/uxlfoundation/oneTBB/archive/${TBB_RELEASE}.tar.gz" | \
tar xzvf - -C ${DIR}/ --strip-components=1
cd ${DIR}
}
older_release=0
if grep -q 'Ubuntu 20.04\|Debian GNU/Linux 11' /etc/os-release 2>/dev/null; then
older_release=1
fi
prepare_source
build_and_install

View file

@ -2,7 +2,7 @@
set -euo pipefail
WEBP_VERSION="1.2.4"
WEBP_VERSION="1.5.0"
WEBP_TAR_URL="https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-${WEBP_VERSION}.tar.gz"
WEBP_TAR_FILE="/tmp/libwebp-${WEBP_VERSION}.tar.gz"
WEBP_SRC_DIR="/tmp/libwebp-${WEBP_VERSION}"
@ -21,7 +21,7 @@ prepare_source() {
build_and_install() {
export MAKEFLAGS=-j$(nproc)
./configure --enable-static --disable-shared
./configure --enable-static --disable-shared --enable-threading --enable-sse2 --enable-neon
make
make install
}

View file

@ -10,6 +10,10 @@ is_debian() {
[[ -f /etc/debian_version ]]
}
is_alpine() {
[[ -f /etc/alpine-release ]]
}
check_package_version_exists() {
if ! stat /tmp/kasmvncserver_"$package_version"*.deb; then
>&2 echo "No package found for version $package_version"
@ -42,7 +46,16 @@ install_package_built_for_current_branch_package_version_deb() {
--file /tmp/changelog)
check_package_version_exists
apt-get install -y /tmp/kasmvncserver_"$package_version"*"$tag"*.deb
dpkg_arch=$(dpkg-architecture -q DEB_BUILD_ARCH)
apt-get install -y /tmp/kasmvncserver_"$package_version"*"$tag"*_${dpkg_arch}.deb
}
detect_dnf_command() {
if command -v dnf5 >/dev/null; then
echo dnf install -y --allowerasing
else
echo dnf localinstall -y --allowerasing
fi
}
install_package_built_for_current_branch_package_version_rpm() {
@ -50,15 +63,24 @@ install_package_built_for_current_branch_package_version_rpm() {
$rpm_package_manager install -y rpmdevtools
package_version=$(rpmspec -q --qf '%{version}\n' /tmp/kasmvncserver.spec 2>/dev/null)
package_name=/tmp/kasmvncserver-"$package_version"*.$(arch).rpm
if [[ $rpm_package_manager = "dnf" ]]; then
dnf localinstall -y --allowerasing /tmp/kasmvncserver-"$package_version"*.rpm
local dnf_cmd=$(detect_dnf_command)
$dnf_cmd $package_name
else
yum install -y /tmp/kasmvncserver-"$package_version"*.rpm
yum install -y $package_name
fi
}
install_package_built_for_current_branch_package_version_apk() {
package_version=$(sed -n 's/pkgver=\(.\+\)/\1/p' /tmp/APKBUILD )
apk add /tmp/kasmvncserver-"$package_version"*.apk /tmp/kasmvncserver-doc-"$package_version"*.apk --allow-untrusted
}
if is_debian ; then
install_package_built_for_current_branch_package_version_deb
elif is_alpine; then
install_package_built_for_current_branch_package_version_apk
else
install_package_built_for_current_branch_package_version_rpm
fi

View file

@ -1,11 +0,0 @@
#!/bin/bash
set -e
display=:10
interface=0.0.0.0
vncserver $display -depth 24 -geometry 1280x1050 -websocketPort 8443 \
-cert /etc/ssl/certs/ssl-cert-snakeoil.pem \
-key /etc/ssl/private/ssl-cert-snakeoil.key -sslOnly -FrameRate=24 \
-interface $interface -httpd /usr/share/kasmvnc/www

View file

@ -12,11 +12,64 @@ create_kasm_user() {
echo -e "$VNC_PW\n$VNC_PW\n" | kasmvncpasswd -w -u "$VNC_USER"
}
wait_for_core_to_be_dumped() {
if [ "$vncserver_exit_code" -eq 0 ]; then
return
fi
local timeout=2
local elapsed=0
local interval=1
while [[ ! -f core && "$elapsed" -lt "$timeout" ]]; do
sleep $interval
elapsed=$(($elapsed + $interval))
done
}
copy_core_to_host() {
mkdir -p "$CORE_DUMP_DIR_INSIDE_CONTAINER"
cp core "$CORE_DUMP_DIR_INSIDE_CONTAINER"
}
allow_core_to_be_dumped() {
ulimit -c unlimited
cd "$HOME"
}
clean_up_old_core_dir() {
if [ -d "$CORE_DUMP_DIR_INSIDE_CONTAINER" ]; then
rm -r "$CORE_DUMP_DIR_INSIDE_CONTAINER"
fi
}
core_was_dumped() {
[ -f core ]
}
say_where_to_find_core_on_host() {
echo "Core dumped to $CORE_DUMP_DIR_ON_HOST"
}
config_dir="$HOME/.vnc"
xstartup="$config_dir/xstartup"
set_xterm_to_run
create_kasm_user
allow_core_to_be_dumped
clean_up_old_core_dir
set +e
vncserver -select-de manual -websocketPort "$VNC_PORT"
vncserver_exit_code=$?
set -e
wait_for_core_to_be_dumped
if core_was_dumped; then
copy_core_to_host
say_where_to_find_core_on_host
fi
if [ "$RUN_TEST" = 1 ]; then
exit "$vncserver_exit_code"
fi
tail -f "$config_dir"/*.log

37
builder/test-apk-barebones Executable file
View file

@ -0,0 +1,37 @@
#!/bin/bash
set -e
detect_base_image() {
BASE_IMAGE=$(echo "${os}:${os_codename}" | sed 's/\([0-9]\{2\}\)$/.\1/')
}
cd "$(dirname "$0")/.."
. ./builder/process_test_options.sh
. ./builder/common.sh
os="${1:-alpine}"
os_codename="${2:-321}"
distro="${os}_${os_codename}"
detect_build_dir
detect_base_image
docker build --build-arg KASMVNC_PACKAGE_DIR="${build_dir}/${distro}" \
--build-arg RUN_TEST="$run_test" \
--build-arg BASE_IMAGE="$BASE_IMAGE" \
-t kasmvnctester_barebones_${os}:$os_codename \
-f builder/dockerfile.${distro}.barebones.apk.test .
echo
detect_interactive
docker run $interactive -p "443:$VNC_PORT" --rm -e "VNC_USER=foo" -e "VNC_PW=foobar" \
$core_dumps_dir_volume_option \
-e "VNC_PORT=$VNC_PORT" \
-e RUN_TEST="$run_test" \
-e CORE_DUMP_DIR_ON_HOST="$core_dumps_dir_on_host/${distro}" \
-e CORE_DUMP_DIR_INSIDE_CONTAINER="${core_dumps_dir_inside_container}/${distro}" \
--cap-add=SYS_PTRACE \
--cap-add=SYS_RESOURCE \
--ulimit core=-1 \
$entrypoint_executable \
kasmvnctester_barebones_${os}:$os_codename \
$entrypoint_args

49
builder/test-barebones Executable file
View file

@ -0,0 +1,49 @@
#!/bin/bash
set -eo pipefail
create_gitlab_report() {
local error="$1"
failure_report=$(cat <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Run test" tests="1" failures="1" errors="0" skipped="0">
<testcase classname="$os_fullname" name="Test run">
<failure type="description">${error}</failure>
</testcase>
</testsuite>
EOF
)
}
write_gitlab_report() {
echo "$failure_report" > run_test/"${os}_${os_codename}.xml"
}
create_core_dumps_dir_writeable_by_container() {
mkdir -p "$core_dumps_dir_on_host"
if [[ -n "$CI" && $(id -u) = 0 ]]; then
chown 1000:1000 "$core_dumps_dir_on_host"
fi
}
saved_options=("$@")
. ./builder/process_test_options.sh
. ./builder/common.sh
os="$1"
os_codename="$2"
os_fullname="${os}_${os_codename}"
detect_package_format
if [ "$run_test" != 1 ]; then
builder/test-${package_format}-barebones "${saved_options[@]}"
exit $?
fi
create_core_dumps_dir_writeable_by_container
if ! builder/test-${package_format}-barebones "${saved_options[@]}" 2>&1 | \
tee run_test/"${os_fullname}.log"; then
create_gitlab_report "$(tail -1 run_test/${os_fullname}.log)"
write_gitlab_report
exit 1
fi

View file

@ -2,18 +2,40 @@
set -e
detect_base_image() {
if [ "$os" = kali ]; then
BASE_IMAGE=kalilinux/kali-rolling:latest
return
fi
BASE_IMAGE="${os}:${os_codename}"
}
cd "$(dirname "$0")/.."
. ./builder/process_test_options.sh
. ./builder/common.sh
os="${1:-debian}"
os_codename="${2:-buster}"
distro="${os}_${os_codename}"
docker build --build-arg KASMVNC_PACKAGE_DIR="builder/build/${os_codename}" \
detect_build_dir
detect_base_image
docker build --build-arg KASMVNC_PACKAGE_DIR="${build_dir}/${os_codename}" \
--build-arg RUN_TEST="$run_test" \
--build-arg BASE_IMAGE="$BASE_IMAGE" \
-t kasmvnctester_barebones_${os}:$os_codename \
-f builder/dockerfile.${os}_${os_codename}.barebones.deb.test .
-f builder/dockerfile.${distro}.barebones.deb.test .
echo
docker run -it -p "443:$VNC_PORT" --rm -e "VNC_USER=foo" -e "VNC_PW=foobar" \
detect_interactive
docker run $interactive -p "443:$VNC_PORT" --rm -e "VNC_USER=foo" -e "VNC_PW=foobar" \
$core_dumps_dir_volume_option \
-e "VNC_PORT=$VNC_PORT" \
-e RUN_TEST="$run_test" \
-e CORE_DUMP_DIR_ON_HOST="$core_dumps_dir_on_host/${distro}" \
-e CORE_DUMP_DIR_INSIDE_CONTAINER="${core_dumps_dir_inside_container}/${distro}" \
--cap-add=SYS_PTRACE \
--cap-add=SYS_RESOURCE \
--ulimit core=-1 \
$entrypoint_executable \
kasmvnctester_barebones_${os}:$os_codename \
$entrypoint_args

View file

@ -2,17 +2,29 @@
set -e
cd "$(dirname "$0")"
. ./process_test_options.sh
. ./common.sh
cd "$(dirname "$0")/.."
. ./builder/process_test_options.sh
. ./builder/common.sh
os="${1:-oracle}"
os_codename="${2:-8}"
distro="${os}_${os_codename}"
docker build --build-arg KASMVNC_PACKAGE_DIR="build/${os}_${os_codename}" \
detect_build_dir
docker build --build-arg KASMVNC_PACKAGE_DIR="${build_dir}/${distro}" \
--build-arg RUN_TEST="$run_test" \
-t kasmvnctester_barebones_${os}:$os_codename \
-f dockerfile.${os}_${os_codename}.barebones.rpm.test .
docker run -it -p "443:$VNC_PORT" --rm -e "VNC_USER=foo" -e "VNC_PW=foobar" \
-f builder/dockerfile.${distro}.barebones.rpm.test .
detect_interactive
docker run $interactive -p "443:$VNC_PORT" --rm -e "VNC_USER=foo" -e "VNC_PW=foobar" \
$core_dumps_dir_volume_option \
-e "VNC_PORT=$VNC_PORT" \
-e RUN_TEST="$run_test" \
-e CORE_DUMP_DIR_ON_HOST="$core_dumps_dir_on_host/${distro}" \
-e CORE_DUMP_DIR_INSIDE_CONTAINER="${core_dumps_dir_inside_container}/${distro}" \
--cap-add=SYS_PTRACE \
--cap-add=SYS_RESOURCE \
--ulimit core=-1 \
$entrypoint_executable \
kasmvnctester_barebones_${os}:$os_codename \
$entrypoint_args

View file

@ -3,7 +3,7 @@
set -e
default_os=ubuntu
default_os_codename=focal
default_os_codename=jammy
. ./builder/os_ver_cli.sh

54
builder/test_build_containers Executable file
View file

@ -0,0 +1,54 @@
#!/bin/bash
#set -e
script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
current_dir="$(pwd)"
images_list=()
for file in "$script_dir"/dockerfile.*.build; do
if [[ "$file" == *deb* ]] || [[ "$file" == *apk* ]] || [[ "$file" == *rpm* ]] || [[ "$file" == *www* ]]; then
continue
fi
[ -e "$file" ] || continue
filename="$(basename "$file")"
image_name=$(echo "$filename" | sed -E 's/^(dockerfile\.|Dockerfile\.)(.*)\.build$/\2/')
if [ -e builder/build/kasmvnc."$image_name".tar.gz ]; then
continue
fi
echo "Building docker image: $image_name using file: $file"
docker build -f "$file" -t "$image_name" "$current_dir"
exit_code=$?
if [ $exit_code -ne 0 ]; then
echo "Build failed for $filename"
break
fi
rm -rf .cmake CMakeFiles build.ninja cmake_install.cmake cmake_uninstall.cmake CMakeCache.txt config.h
echo "Running container from image '$image_name'"
# Run the container and capture the exit code
docker run -it -v "$current_dir":/src -v "$current_dir/builder/build":/build "$image_name"
exit_code=$?
echo "Container for image '$image_name' "
if [ $exit_code -ne 0 ]; then
echo "exited with error (exit code $exit_code)."
break
else
echo "finished successfully."
images_list+=("$image_name")
fi
done
echo "Removing all built docker images..."
for img in "${images_list[@]}"; do
echo "Removing docker image: $img"
docker rmi -f "$img"
done

View file

@ -9,7 +9,7 @@ add_subdirectory(rfb)
# because PIC code does not exist on that platform and MinGW complains if -fPIC
# is passed (additionally, libvnc is not used on Windows.)
if(NOT WIN32)
set_target_properties(os rdr network Xregion rfb
PROPERTIES COMPILE_FLAGS -fPIC)
endif()
if (NOT WIN32)
set_target_properties(os rdr network Xregion rfb
PROPERTIES COMPILE_FLAGS -fPIC)
endif ()

View file

@ -28,6 +28,7 @@
#include <map>
#include <string>
#include <vector>
#include <mutex>
namespace network {
@ -49,6 +50,8 @@ namespace network {
uint32_t ping);
void mainUpdateUserInfo(const uint8_t ownerConn, const uint8_t numUsers);
void mainUpdateSessionsInfo(std::string newSessionsInfo);
// from network threads
uint8_t *netGetScreenshot(uint16_t w, uint16_t h,
const uint8_t q, const bool dedup,
@ -61,6 +64,8 @@ namespace network {
const bool read, const bool write, const bool owner);
uint8_t netAddOrUpdateUser(const struct kasmpasswd_entry_t *entry);
void netGetUsers(const char **ptr);
const std::string_view netGetSessions();
void netGetBottleneckStats(char *buf, uint32_t len);
void netGetFrameStats(char *buf, uint32_t len);
void netResetFrameStatsCall();
@ -142,6 +147,8 @@ namespace network {
uint8_t ownerConnected;
uint8_t activeUsers;
pthread_mutex_t userInfoMutex;
std::mutex sessionInfoMutex;
std::string sessionsInfo;
};
}

View file

@ -28,6 +28,8 @@
#include <rfb/xxhash.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <utility>
using namespace network;
using namespace rfb;
@ -55,7 +57,8 @@ static const struct TightJPEGConfiguration conf[10] = {
GetAPIMessager::GetAPIMessager(const char *passwdfile_): passwdfile(passwdfile_),
screenW(0), screenH(0), screenHash(0),
cachedW(0), cachedH(0), cachedQ(0),
ownerConnected(0), activeUsers(0) {
ownerConnected(0), activeUsers(0),
sessionsInfo( "{\"users\":[]}"){
pthread_mutex_init(&screenMutex, NULL);
pthread_mutex_init(&userMutex, NULL);
@ -171,6 +174,15 @@ void GetAPIMessager::mainUpdateUserInfo(const uint8_t ownerConn, const uint8_t n
pthread_mutex_unlock(&userInfoMutex);
}
void GetAPIMessager::mainUpdateSessionsInfo(std::string newSessionsInfo)
{
std::unique_lock<std::mutex> lock (sessionInfoMutex,std::defer_lock);
if (!lock.try_lock())
return;
sessionsInfo = std::move(newSessionsInfo);
lock.unlock();
}
// from network threads
uint8_t *GetAPIMessager::netGetScreenshot(uint16_t w, uint16_t h,
const uint8_t q, const bool dedup,
@ -514,6 +526,12 @@ void GetAPIMessager::netGetUsers(const char **outptr) {
*outptr = buf;
}
const std::string_view GetAPIMessager::netGetSessions()
{
return sessionsInfo;
}
void GetAPIMessager::netGetBottleneckStats(char *buf, uint32_t len) {
/*
{
@ -819,3 +837,4 @@ void GetAPIMessager::netClearClipboard() {
pthread_mutex_unlock(&userMutex);
}

View file

@ -551,6 +551,18 @@ static void clearClipboardCb(void *messager)
msgr->netClearClipboard();
}
static void getSessionsCb(void *messager, char **ptr)
{
GetAPIMessager *msgr = (GetAPIMessager *) messager;
std::string_view sessionInfoView = msgr->netGetSessions();
//Since this data is being returned to a c function using char array
//memmoery needs to be freeded by calling function
char *sessionInfo = (char *) calloc(sessionInfoView.size() + 1, sizeof(char));
memcpy(sessionInfo, sessionInfoView.data(), sessionInfoView.size());
sessionInfo[sessionInfoView.size()] = '\0';
*ptr = sessionInfo;
}
#if OPENSSL_VERSION_NUMBER < 0x1010000f
static pthread_mutex_t *sslmutex;
@ -700,6 +712,7 @@ WebsocketListener::WebsocketListener(const struct sockaddr *listenaddr,
settings.serverFrameStatsReadyCb = serverFrameStatsReadyCb;
settings.clearClipboardCb = clearClipboardCb;
settings.getSessionsCb = getSessionsCb;
openssl_threads();

View file

@ -24,30 +24,40 @@
#include "cJSON.h"
void JSON_escape(const char *in, char *out) {
if (!in)
return;
for (; *in; in++) {
if (in[0] == '\b') {
*out++ = '\\';
*out++ = 'b';
} else if (in[0] == '\f') {
*out++ = '\\';
*out++ = 'f';
} else if (in[0] == '\n') {
*out++ = '\\';
*out++ = 'n';
} else if (in[0] == '\r') {
*out++ = '\\';
*out++ = 'r';
} else if (in[0] == '\t') {
*out++ = '\\';
*out++ = 't';
} else if (in[0] == '"') {
*out++ = '\\';
*out++ = '"';
} else if (in[0] == '\\') {
*out++ = '\\';
*out++ = '\\';
} else {
*out++ = *in;
switch (*in) {
case '\b':
*out++ = '\\';
*out++ = 'b';
break;
case '\f':
*out++ = '\\';
*out++ = 'f';
case '\n':
*out++ = '\\';
*out++ = 'n';
break;
case '\r':
*out++ = '\\';
*out++ = 'r';
break;
case '\t':
*out++ = '\\';
*out++ = 't';
break;
case '"':
*out++ = '\\';
*out++ = '"';
break;
case '\\':
*out++ = '\\';
*out++ = '\\';
break;
default:
*out++ = *in;
}
}

View file

@ -70,6 +70,8 @@ void fatal(char *msg)
exit(1);
}
#define WS_MAX_BUF_SIZE 4096
// 2022-05-18 19:51:26,810 [INFO] websocket 0: 71.62.44.0 172.12.15.5 - "GET /api/get_frame_stats?client=auto HTTP/1.1" 403 2
static void weblog(const unsigned code, const unsigned websocket,
const uint8_t debug,
@ -644,7 +646,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
strncpy(headers->path, start, end-start);
headers->path[end-start] = '\0';
start = strstr(handshake, "\r\nHost: ");
start = strcasestr(handshake, "\r\nHost: ");
if (!start) { err("missing Host header"); return 0; }
start += 8;
end = strstr(start, "\r\n");
@ -681,7 +683,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
strncpy(headers->key1, start, end-start);
headers->key1[end-start] = '\0';
start = strstr(handshake, "\r\nConnection: ");
start = strcasestr(handshake, "\r\nConnection: ");
if (!start) { err("missing Connection header"); return 0; }
start += 14;
end = strstr(start, "\r\n");
@ -834,7 +836,7 @@ static uint8_t isValidIp(const char *str, const unsigned len) {
static void dirlisting(ws_ctx_t *ws_ctx, const char fullpath[], const char path[],
const char * const user, const char * const ip,
const char * const origip) {
char buf[4096];
char buf[WS_MAX_BUF_SIZE];
char enc[PATH_MAX * 3 + 1];
unsigned i;
@ -895,7 +897,7 @@ static void dirlisting(ws_ctx_t *ws_ctx, const char fullpath[], const char path[
static void servefile(ws_ctx_t *ws_ctx, const char *in, const char * const user,
const char * const ip, const char * const origip) {
char buf[4096], path[4096], fullpath[4096];
char buf[WS_MAX_BUF_SIZE], path[PATH_MAX], fullpath[PATH_MAX];
//fprintf(stderr, "http servefile input '%s'\n", in);
@ -965,7 +967,7 @@ static void servefile(ws_ctx_t *ws_ctx, const char *in, const char * const user,
//fprintf(stderr, "http servefile output '%s'\n", buf);
unsigned count;
while ((count = fread(buf, 1, 4096, f))) {
while ((count = fread(buf, 1, WS_MAX_BUF_SIZE, f))) {
ws_send(ws_ctx, buf, count);
}
fclose(f);
@ -1020,7 +1022,7 @@ notfound:
}
static void send403(ws_ctx_t *ws_ctx, const char * const origip, const char * const ip) {
char buf[4096];
char buf[WS_MAX_BUF_SIZE];
sprintf(buf, "HTTP/1.1 403 Forbidden\r\n"
"Server: KasmVNC/4.0\r\n"
"Connection: close\r\n"
@ -1034,7 +1036,7 @@ static void send403(ws_ctx_t *ws_ctx, const char * const origip, const char * co
static void send400(ws_ctx_t *ws_ctx, const char * const origip, const char * const ip,
const char *info) {
char buf[4096];
char buf[WS_MAX_BUF_SIZE];
sprintf(buf, "HTTP/1.1 400 Bad Request\r\n"
"Server: KasmVNC/4.0\r\n"
"Connection: close\r\n"
@ -1048,7 +1050,7 @@ static void send400(ws_ctx_t *ws_ctx, const char * const origip, const char * co
static uint8_t ownerapi_post(ws_ctx_t *ws_ctx, const char *in, const char * const user,
const char * const ip, const char * const origip) {
char buf[4096], path[4096];
char buf[WS_MAX_BUF_SIZE], path[PATH_MAX];
uint8_t ret = 0; // 0 = continue checking
in += 5;
@ -1237,7 +1239,7 @@ nope:
static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in, const char * const user,
const char * const ip, const char * const origip) {
char buf[4096], path[4096], args[4096] = "", origpath[4096];
char buf[WS_MAX_BUF_SIZE], path[PATH_MAX], args[PATH_MAX] = "", origpath[PATH_MAX];
uint8_t ret = 0; // 0 = continue checking
if (strncmp(in, "GET ", 4)) {
@ -1509,7 +1511,8 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in, const char * const use
handler_msg("Sent bottleneck stats to API caller\n");
ret = 1;
} else entry("/api/get_users") {
} else entry("/api/get_users")
{
const char *ptr;
settings.getUsersCb(settings.messager, &ptr);
@ -1528,6 +1531,26 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in, const char * const use
handler_msg("Sent user list to API caller\n");
ret = 1;
} else entry("/api/get_sessions") {
char *sessionData;
settings.getSessionsCb(settings.messager, &sessionData);
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"
"%s"
"\r\n", strlen(sessionData), extra_headers ? extra_headers : "");
ws_send(ws_ctx, buf, strlen(buf));
ws_send(ws_ctx, sessionData, strlen(sessionData));
weblog(200, wsthread_handler_id, 0, origip, ip, user, 1, origpath, strlen(buf) + strlen(sessionData));
free((char *) sessionData);
handler_msg("Sent session list to API caller\n");
ret = 1;
} else entry("/api/get_frame_stats") {
char statbuf[4096], decname[1024];
unsigned waitfor;
@ -1671,11 +1694,11 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in, const char * const use
}
sprintf(buf, "HTTP/1.1 200 OK\r\n"
"Server: KasmVNC/4.0\r\n"
"Connection: close\r\n"
"Content-type: text/json\r\n"
"%s"
"\r\n", extra_headers ? extra_headers : "");
"Server: KasmVNC/4.0\r\n"
"Connection: close\r\n"
"Content-type: text/json\r\n"
"%s"
"\r\n", extra_headers ? extra_headers : "");
ws_send(ws_ctx, buf, strlen(buf));
len = 15;
@ -1687,7 +1710,7 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in, const char * const use
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
continue;
sprintf(path, "%s/%s", allpath, ent->d_name);
snprintf(path, PATH_MAX, "%s/%s", allpath, ent->d_name);
struct stat st;
if (lstat(path, &st))
continue;
@ -1709,23 +1732,35 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in, const char * const use
strcpy(grp, grpt.gr_name);
}
sprintf(buf, "%s{ \"filename\": \"%s\", "
"\"date_modified\": %lu, "
"\"date_created\": %lu, "
"\"is_dir\": %s, "
"\"size\": %lu, "
"\"owner\": \"%s\", "
"\"group\": \"%s\", "
"\"perms\": \"%s\" }",
sent ? ",\n" : "",
ent->d_name,
st.st_mtime,
st.st_ctime,
S_ISDIR(st.st_mode) ? "true" : "false",
S_ISDIR(st.st_mode) ? 0 : st.st_size,
own,
grp,
perms);
sprintf(buf, "%s{ \"filename\": \"", sent ? ",\n" : "");
ws_send(ws_ctx, buf, strlen(buf));
len += strlen(buf);
size_t max_out_length = 2 * strlen(ent->d_name) + 1; // worst case scenario
char *filename = malloc(max_out_length);
JSON_escape(ent->d_name, filename);
size_t size = strlen(filename);
ws_send(ws_ctx, filename, size);
len += size;
free(filename);
sprintf(buf, "\", "
"\"date_modified\": %lu, "
"\"date_created\": %lu, "
"\"is_dir\": %s, "
"\"size\": %lu, "
"\"owner\": \"%s\", "
"\"group\": \"%s\", "
"\"perms\": \"%s\" }",
st.st_mtime,
st.st_ctime,
S_ISDIR(st.st_mode) ? "true" : "false",
S_ISDIR(st.st_mode) ? 0 : st.st_size,
own,
grp,
perms);
sent = 1;
ws_send(ws_ctx, buf, strlen(buf));
len += strlen(buf);
@ -1883,7 +1918,7 @@ ws_ctx_t *do_handshake(int sock, char * const ip) {
unsigned char owner = 0;
char inuser[USERNAME_LEN] = "-";
if (!settings.disablebasicauth) {
const char *hdr = strstr(handshake, "Authorization: Basic ");
const char *hdr = strcasestr(handshake, "Authorization: Basic ");
if (!hdr) {
bl_addFailure(ip);
wserr("Authentication attempt failed, BasicAuth required, but client didn't send any\n");

View file

@ -108,6 +108,8 @@ typedef struct {
uint8_t (*serverFrameStatsReadyCb)(void *messager);
void (*clearClipboardCb)(void *messager);
void (*getSessionsCb)(void *messager, char **buf);
} settings_t;
#ifdef __cplusplus

View file

@ -1,130 +1,162 @@
include_directories(${CMAKE_SOURCE_DIR}/common ${JPEG_INCLUDE_DIR} ${PNG_INCLUDE_DIR}
${CMAKE_SOURCE_DIR}/unix/kasmvncpasswd)
set(RFB_SOURCES
Blacklist.cxx
Congestion.cxx
CConnection.cxx
CMsgHandler.cxx
CMsgReader.cxx
CMsgWriter.cxx
CSecurityPlain.cxx
CSecurityStack.cxx
CSecurityVeNCrypt.cxx
CSecurityVncAuth.cxx
ComparingUpdateTracker.cxx
Configuration.cxx
ConnParams.cxx
CopyRectDecoder.cxx
Cursor.cxx
DecodeManager.cxx
Decoder.cxx
d3des.c
EncCache.cxx
EncodeManager.cxx
Encoder.cxx
HextileDecoder.cxx
HextileEncoder.cxx
JpegCompressor.cxx
JpegDecompressor.cxx
KeyRemapper.cxx
LogWriter.cxx
Logger.cxx
Logger_file.cxx
Logger_stdio.cxx
Password.cxx
PixelBuffer.cxx
PixelFormat.cxx
RREEncoder.cxx
RREDecoder.cxx
RawDecoder.cxx
RawEncoder.cxx
Region.cxx
SConnection.cxx
SMsgHandler.cxx
SMsgReader.cxx
SMsgWriter.cxx
ServerCore.cxx
Security.cxx
SecurityServer.cxx
SecurityClient.cxx
SelfBench.cxx
SSecurityPlain.cxx
SSecurityStack.cxx
SSecurityVncAuth.cxx
SSecurityVeNCrypt.cxx
ScaleFilters.cxx
Timer.cxx
TightDecoder.cxx
TightEncoder.cxx
TightJPEGEncoder.cxx
TightWEBPEncoder.cxx
TightQOIEncoder.cxx
UpdateTracker.cxx
VNCSConnectionST.cxx
VNCServerST.cxx
ZRLEEncoder.cxx
ZRLEDecoder.cxx
Watermark.cxx
cpuid.cxx
encodings.cxx
util.cxx
xxhash.c)
benchmark.cxx
Blacklist.cxx
Congestion.cxx
CConnection.cxx
CMsgHandler.cxx
CMsgReader.cxx
CMsgWriter.cxx
CSecurityPlain.cxx
CSecurityStack.cxx
CSecurityVeNCrypt.cxx
CSecurityVncAuth.cxx
ComparingUpdateTracker.cxx
Configuration.cxx
ConnParams.cxx
CopyRectDecoder.cxx
Cursor.cxx
DecodeManager.cxx
Decoder.cxx
d3des.c
EncCache.cxx
EncodeManager.cxx
Encoder.cxx
HextileDecoder.cxx
HextileEncoder.cxx
JpegCompressor.cxx
JpegDecompressor.cxx
KeyRemapper.cxx
LogWriter.cxx
Logger.cxx
Logger_file.cxx
Logger_stdio.cxx
Password.cxx
PixelBuffer.cxx
PixelFormat.cxx
RREEncoder.cxx
RREDecoder.cxx
RawDecoder.cxx
RawEncoder.cxx
Region.cxx
SConnection.cxx
SMsgHandler.cxx
SMsgReader.cxx
SMsgWriter.cxx
ServerCore.cxx
Security.cxx
SecurityServer.cxx
SecurityClient.cxx
SelfBench.cxx
SSecurityPlain.cxx
SSecurityStack.cxx
SSecurityVncAuth.cxx
SSecurityVeNCrypt.cxx
ScaleFilters.cxx
Timer.cxx
TightDecoder.cxx
TightEncoder.cxx
TightJPEGEncoder.cxx
TightWEBPEncoder.cxx
TightQOIEncoder.cxx
UpdateTracker.cxx
VNCSConnectionST.cxx
VNCServerST.cxx
ZRLEEncoder.cxx
ZRLEDecoder.cxx
Watermark.cxx
cpuid.cxx
encodings.cxx
util.cxx
xxhash.c
ffmpeg.cxx
)
if(UNIX)
set(RFB_SOURCES ${RFB_SOURCES} Logger_syslog.cxx)
endif()
if (UNIX)
set(RFB_SOURCES ${RFB_SOURCES} Logger_syslog.cxx)
endif ()
if(WIN32)
include_directories(${CMAKE_SOURCE_DIR}/win)
set(RFB_SOURCES ${RFB_SOURCES} WinPasswdValidator.cxx)
endif(WIN32)
if (WIN32)
include_directories(${CMAKE_SOURCE_DIR}/win)
set(RFB_SOURCES ${RFB_SOURCES} WinPasswdValidator.cxx)
endif (WIN32)
set(RFB_LIBRARIES ${JPEG_LIBRARIES} ${PNG_LIBRARIES} os rdr Xregion)
if(HAVE_PAM)
set(RFB_SOURCES ${RFB_SOURCES} UnixPasswordValidator.cxx
UnixPasswordValidator.h pam.c pam.h)
set(RFB_LIBRARIES ${RFB_LIBRARIES} ${PAM_LIBS})
endif()
cmake_host_system_information(RESULT DISTRO QUERY DISTRIB_INFO)
if ((CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10) OR
(DISTRO_PLATFORM_ID MATCHES "platform:el8"))
set(RFB_LIBRARIES ${RFB_LIBRARIES} tbb)
endif ()
if(GNUTLS_FOUND)
set(RFB_SOURCES
${RFB_SOURCES}
CSecurityTLS.cxx
SSecurityTLS.cxx
)
set(RFB_LIBRARIES
${RFB_LIBRARIES}
${GNUTLS_LIBRARIES}
)
endif()
if (HAVE_PAM)
set(RFB_SOURCES
${RFB_SOURCES}
UnixPasswordValidator.cxx
UnixPasswordValidator.h pam.c pam.h)
set(RFB_LIBRARIES ${RFB_LIBRARIES} ${PAM_LIBS})
endif ()
if (GNUTLS_FOUND)
set(RFB_SOURCES
${RFB_SOURCES}
CSecurityTLS.cxx
SSecurityTLS.cxx
)
set(RFB_LIBRARIES
${RFB_LIBRARIES}
${GNUTLS_LIBRARIES}
)
endif ()
# SSE2
set(SSE2_SOURCES
scale_sse2.cxx)
scale_sse2.cxx)
set(SCALE_DUMMY_SOURCES
scale_dummy.cxx)
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()
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 ()
find_package(PkgConfig REQUIRED)
pkg_check_modules(FFMPEG REQUIRED libavcodec libavformat libavutil libswscale)
pkg_check_modules(CPUID REQUIRED libcpuid)
find_package(TBB)
if (TBB_FOUND)
set(RFB_LIBRARIES ${RFB_LIBRARIES} tbb)
else ()
pkg_check_modules(TBB tbb)
set(RFB_LIBRARIES ${RFB_LIBRARIES} ${TBB_LIBRARIES})
endif ()
add_library(rfb STATIC ${RFB_SOURCES})
target_link_libraries(rfb ${RFB_LIBRARIES})
target_include_directories(rfb PRIVATE
${CMAKE_SOURCE_DIR}/common
${JPEG_INCLUDE_DIR}
${PNG_INCLUDE_DIR}
${CMAKE_SOURCE_DIR}/unix/kasmvncpasswd
${CMAKE_SOURCE_DIR}/third_party/tinyxml2
${FFMPEG_INCLUDE_DIRS}
${TBB_INCLUDE_DIRS}
${CPUID_INCLUDE_DIRS}
)
if(UNIX)
libtool_create_control_file(rfb)
endif()
target_link_libraries(rfb PUBLIC ${RFB_LIBRARIES} tinyxml2_objs ${TBB_LIBRARIES} ${CPUID_LIBRARIES})
if (UNIX)
libtool_create_control_file(rfb)
endif ()

View file

@ -19,9 +19,7 @@
* USA.
*/
#include <omp.h>
#include <stdlib.h>
#include <cstdlib>
#include <rfb/cpuid.h>
#include <rfb/EncCache.h>
#include <rfb/EncodeManager.h>
@ -44,6 +42,8 @@
#include <rfb/TightJPEGEncoder.h>
#include <rfb/TightWEBPEncoder.h>
#include <rfb/TightQOIEncoder.h>
#include <execution>
#include <tbb/parallel_for.h>
using namespace rfb;
@ -93,9 +93,9 @@ struct RectInfo {
};
struct QualityInfo {
struct timeval lastUpdate;
struct timeval lastUpdate{};
Rect rect;
unsigned score;
unsigned score{};
};
};
@ -210,6 +210,9 @@ EncodeManager::EncodeManager(SConnection* conn_, EncCache *encCache_) : conn(con
dynamicQualityMin = Server::dynamicQualityMin;
dynamicQualityOff = Server::dynamicQualityMax - Server::dynamicQualityMin;
}
const auto num_cores = cpu_info::cores_count;
arena.initialize(num_cores);
}
EncodeManager::~EncodeManager()
@ -360,7 +363,6 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,
int nRects;
Region changed, cursorRegion;
struct timeval start;
unsigned screenArea;
updates++;
if (conn->cp.supportsUdp)
@ -390,16 +392,7 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,
memset(&webpstats, 0, sizeof(codecstats_t));
if (allowLossy && activeEncoders[encoderFullColour] == encoderTightWEBP) {
const unsigned rate = 1024 * 1000 / rfb::Server::frameRate;
screenArea = pb->getRect().width() * pb->getRect().height();
screenArea *= 1024;
screenArea /= 256 * 256;
screenArea *= webpBenchResult;
// Encoding the entire screen would take this many 1024*msecs, worst case
// Calculate how many us we can send webp for, before switching to jpeg
webpFallbackUs = rate * rate / screenArea;
webpFallbackUs = (1000 * 1000 / rfb::Server::frameRate) * (static_cast<double>(Server::webpEncodingTime) / 100.0);
}
/*
@ -880,14 +873,12 @@ void EncodeManager::findSolidRect(const Rect& rect, Region *changed,
}
}
void EncodeManager::checkWebpFallback(const struct timeval *start) {
void EncodeManager::checkWebpFallback(const timeval *start) {
// Have we taken too long for the frame? If so, drop from WEBP to JPEG
if (start && activeEncoders[encoderFullColour] == encoderTightWEBP && !webpTookTooLong) {
unsigned us;
us = msSince(start) * 1024;
if (start && activeEncoders[encoderFullColour] == encoderTightWEBP && !webpTookTooLong.load(std::memory_order_relaxed)) {
const auto us = msSince(start) * 1000;
if (us > webpFallbackUs)
#pragma omp atomic
webpTookTooLong |= true;
webpTookTooLong.store(true, std::memory_order_relaxed);
}
}
@ -1025,7 +1016,7 @@ PixelBuffer *rfb::progressiveBilinearScale(const PixelBuffer *pb,
const uint16_t tgtw, const uint16_t tgth,
const float tgtdiff)
{
if (supportsSSE2()) {
if (cpu_info::has_sse2) {
if (tgtdiff >= 0.5f) {
ManagedPixelBuffer *newpb = new ManagedPixelBuffer(pb->getPF(), tgtw, tgth);
@ -1122,18 +1113,13 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
const bool mainScreen)
{
std::vector<Rect> rects, subrects, scaledrects;
std::vector<Rect>::const_iterator rect;
std::vector<uint8_t> encoderTypes;
std::vector<uint8_t> isWebp, fromCache;
std::vector<Palette> palettes;
std::vector<std::vector<uint8_t> > compresseds;
std::vector<uint32_t> ms;
uint32_t i;
if (rfb::Server::rectThreads > 0)
omp_set_num_threads(rfb::Server::rectThreads);
webpTookTooLong = false;
webpTookTooLong.store(false, std::memory_order_relaxed);
changed.get_rects(&rects);
// Update stats
@ -1148,18 +1134,18 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
subrects.reserve(rects.size() * 1.5f);
for (rect = rects.begin(); rect != rects.end(); ++rect) {
int w, h, sw, sh;
for (const auto& rect : rects) {
int sw, sh;
Rect sr;
w = rect->width();
h = rect->height();
const auto w = rect.width();
const auto h = rect.height();
// No split necessary?
if ((((w*h) < SubRectMaxArea) && (w < SubRectMaxWidth)) ||
(videoDetected && !encoders[encoderTightWEBP]->isSupported())) {
subrects.push_back(*rect);
trackRectQuality(*rect);
subrects.push_back(rect);
trackRectQuality(rect);
continue;
}
@ -1170,15 +1156,15 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
sh = SubRectMaxArea / sw;
for (sr.tl.y = rect->tl.y; sr.tl.y < rect->br.y; sr.tl.y += sh) {
for (sr.tl.y = rect.tl.y; sr.tl.y < rect.br.y; sr.tl.y += sh) {
sr.br.y = sr.tl.y + sh;
if (sr.br.y > rect->br.y)
sr.br.y = rect->br.y;
if (sr.br.y > rect.br.y)
sr.br.y = rect.br.y;
for (sr.tl.x = rect->tl.x; sr.tl.x < rect->br.x; sr.tl.x += sw) {
for (sr.tl.x = rect.tl.x; sr.tl.x < rect.br.x; sr.tl.x += sw) {
sr.br.x = sr.tl.x + sw;
if (sr.br.x > rect->br.x)
sr.br.x = rect->br.x;
if (sr.br.x > rect.br.x)
sr.br.x = rect.br.x;
subrects.push_back(sr);
trackRectQuality(sr);
@ -1186,13 +1172,15 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
}
}
encoderTypes.resize(subrects.size());
isWebp.resize(subrects.size());
fromCache.resize(subrects.size());
palettes.resize(subrects.size());
compresseds.resize(subrects.size());
scaledrects.resize(subrects.size());
ms.resize(subrects.size());
const size_t subrects_size = subrects.size();
encoderTypes.resize(subrects_size);
isWebp.resize(subrects_size);
fromCache.resize(subrects_size);
palettes.resize(subrects_size);
compresseds.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,
// scale to that res, keeping aspect ratio
@ -1224,7 +1212,7 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
break;
}
for (i = 0; i < subrects.size(); ++i) {
for (uint32_t i = 0; i < subrects_size; ++i) {
const Rect old = scaledrects[i] = subrects[i];
scaledrects[i].br.x *= diff;
scaledrects[i].br.y *= diff;
@ -1249,15 +1237,16 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
}
scalingTime = msSince(&scalestart);
#pragma omp parallel for schedule(dynamic, 1)
for (i = 0; i < subrects.size(); ++i) {
encoderTypes[i] = getEncoderType(subrects[i], pb, &palettes[i], compresseds[i],
&isWebp[i], &fromCache[i],
scaledpb, scaledrects[i], ms[i]);
checkWebpFallback(start);
}
arena.execute([&] {
tbb::parallel_for(static_cast<size_t>(0), subrects_size, [&](size_t i) {
encoderTypes[i] = getEncoderType(subrects[i], pb, &palettes[i], compresseds[i],
&isWebp[i], &fromCache[i],
scaledpb, scaledrects[i], ms[i]);
checkWebpFallback(start);
});
});
for (i = 0; i < subrects.size(); ++i) {
for (uint32_t i = 0; i < subrects_size; ++i) {
if (encoderTypes[i] == encoderFullColour) {
if (isWebp[i])
webpstats.ms += ms[i];
@ -1269,7 +1258,7 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
if (start) {
encodingTime = msSince(start);
if (vlog.getLevel() >= vlog.LEVEL_DEBUG) {
if (vlog.getLevel() >= rfb::LogWriter::LEVEL_DEBUG) {
framesSinceEncPrint++;
if (maxEncodingTime < encodingTime)
maxEncodingTime = encodingTime;
@ -1284,11 +1273,11 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb,
}
}
if (webpTookTooLong)
if (webpTookTooLong.load(std::memory_order_relaxed))
activeEncoders[encoderFullColour] = encoderTightJPEG;
for (i = 0; i < subrects.size(); ++i) {
if (encCache->enabled && compresseds[i].size() && !fromCache[i] &&
for (uint32_t i = 0; i < subrects_size; ++i) {
if (encCache->enabled && !compresseds[i].empty() && !fromCache[i] &&
!encoders[encoderTightQOI]->isSupported()) {
void *tmp = malloc(compresseds[i].size());
memcpy(tmp, &compresseds[i][0], compresseds[i].size());

View file

@ -29,9 +29,10 @@
#include <rfb/Region.h>
#include <rfb/Timer.h>
#include <rfb/UpdateTracker.h>
#include <rfb/util.h>
#include <stdint.h>
#include <atomic>
#include <tbb/task_arena.h>
#include <sys/time.h>
namespace rfb {
@ -50,7 +51,7 @@ namespace rfb {
class EncodeManager: public Timer::Callback {
public:
EncodeManager(SConnection* conn, EncCache *encCache);
~EncodeManager();
~EncodeManager() override;
void logStats();
@ -72,10 +73,10 @@ namespace rfb {
encodingTime = 0;
};
unsigned getEncodingTime() const {
[[nodiscard]] unsigned getEncodingTime() const {
return encodingTime;
};
unsigned getScalingTime() const {
[[nodiscard]] unsigned getScalingTime() const {
return scalingTime;
};
@ -124,7 +125,8 @@ namespace rfb {
uint8_t *fromCache,
const PixelBuffer *scaledpb, const Rect& scaledrect,
uint32_t &ms) const;
virtual bool handleTimeout(Timer* t);
bool handleTimeout(Timer* t) override;
bool checkSolidTile(const Rect& r, const rdr::U8* colourValue,
const PixelBuffer *pb);
@ -166,6 +168,7 @@ namespace rfb {
protected:
SConnection *conn;
tbb::task_arena arena;
std::vector<Encoder*> encoders;
std::vector<int> activeEncoders;
@ -199,7 +202,7 @@ namespace rfb {
size_t curMaxUpdateSize;
unsigned webpFallbackUs;
unsigned webpBenchResult;
bool webpTookTooLong;
std::atomic<bool> webpTookTooLong{false};
unsigned encodingTime;
unsigned maxEncodingTime, framesSinceEncPrint;
unsigned scalingTime;
@ -208,14 +211,14 @@ namespace rfb {
class OffsetPixelBuffer : public FullFramePixelBuffer {
public:
OffsetPixelBuffer() {}
virtual ~OffsetPixelBuffer() {}
OffsetPixelBuffer() = default;
~OffsetPixelBuffer() override = default;
void update(const PixelFormat& pf, int width, int height,
const rdr::U8* data_, int stride);
private:
virtual rdr::U8* getBufferRW(const Rect& r, int* stride);
rdr::U8* getBufferRW(const Rect& r, int* stride) override;
};
};

View file

@ -20,8 +20,6 @@
#include <string.h>
#include <rfb/Exception.h>
#include <rfb/Security.h>
#include <rfb/clipboardTypes.h>
#include <rfb/msgTypes.h>
#include <rfb/fenceTypes.h>
#include <rfb/SMsgReader.h>
#include <rfb/SMsgWriter.h>
@ -274,19 +272,16 @@ void SConnection::writeConnFailedFromScratch(const char* msg,
os->flush();
}
void SConnection::setEncodings(int nEncodings, const rdr::S32* encodings)
{
int i;
preferredEncoding = encodingRaw;
for (i = 0;i < nEncodings;i++) {
if (EncodeManager::supported(encodings[i])) {
preferredEncoding = encodings[i];
break;
void SConnection::setEncodings(int nEncodings, const rdr::S32 *encodings) {
preferredEncoding = encodingRaw;
for (int i = 0; i < nEncodings; i++) {
if (EncodeManager::supported(encodings[i])) {
preferredEncoding = encodings[i];
break;
}
}
}
SMsgHandler::setEncodings(nEncodings, encodings);
SMsgHandler::setEncodings(nEncodings, encodings);
}
void SConnection::clearBinaryClipboard()

View file

@ -18,6 +18,7 @@
* USA.
*/
#include <stdio.h>
#include <string>
#include <rdr/OutStream.h>
#include <rdr/MemOutStream.h>
#include <rdr/ZlibOutStream.h>
@ -776,3 +777,17 @@ void SMsgWriter::writeUnixRelay(const char *name, const rdr::U8 *buf, const unsi
endMsg();
}
void SMsgWriter::writeUserJoinedSession(const std::string& username)
{
startMsg(msgTypeUserAddedToSession);
os->writeString(username.c_str());
endMsg();
}
void SMsgWriter::writeUserLeftSession(const std::string& username)
{
startMsg(msgTypeUserRemovedFromSession);
os->writeString(username.c_str());
endMsg();
}

View file

@ -23,6 +23,7 @@
#ifndef __RFB_SMSGWRITER_H__
#define __RFB_SMSGWRITER_H__
#include <string>
#include <rdr/types.h>
#include <rfb/encodings.h>
#include <rfb/ScreenSet.h>
@ -132,6 +133,9 @@ namespace rfb {
void writeSubscribeUnixRelay(const bool success, const char *msg);
void writeUnixRelay(const char *name, const rdr::U8 *buf, const unsigned len);
void writeUserJoinedSession(const std::string& username);
void writeUserLeftSession(const std::string& username);
protected:
void startMsg(int type);
void endMsg();

View file

@ -26,27 +26,32 @@
#include <rfb/TightWEBPEncoder.h>
#include <rfb/util.h>
#include <sys/time.h>
#include <stdint.h>
#include <stdlib.h>
#include <cstdint>
#include <cstdlib>
#include <chrono>
#include <tinyxml2.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
static constexpr uint32_t RUNS = 64;
#define W 1600
#define H 1200
static constexpr uint32_t WIDTH = 1600;
static constexpr uint32_t HEIGHT = 1200;
void SelfBench() {
tinyxml2::XMLDocument doc;
unsigned i, runs;
struct timeval start;
auto *test_suit = doc.NewElement("testsuite");
test_suit->SetAttribute("name", "SelfBench");
ManagedPixelBuffer f1(pfRGBX, W, H);
ManagedPixelBuffer f2(pfRGBX, W, H);
ManagedPixelBuffer screen(pfRGBX, W, H);
doc.InsertFirstChild(test_suit);
ManagedPixelBuffer f1(pfRGBX, WIDTH, HEIGHT);
ManagedPixelBuffer f2(pfRGBX, WIDTH, HEIGHT);
ManagedPixelBuffer screen(pfRGBX, WIDTH, HEIGHT);
int stride;
rdr::U8 *f1ptr = f1.getBufferRW(f1.getRect(), &stride);
@ -56,7 +61,7 @@ void SelfBench() {
rdr::U8 * const f1orig = f1ptr;
rdr::U8 * const f2orig = f2ptr;
for (i = 0; i < W * H * 4; i += 4) {
for (uint32_t i = 0; i < WIDTH * HEIGHT * 4; i += 4) {
f1ptr[0] = rand();
f1ptr[1] = rand();
f1ptr[2] = rand();
@ -74,124 +79,116 @@ void SelfBench() {
// Encoding
std::vector<uint8_t> vec;
TightJPEGEncoder jpeg(NULL);
TightJPEGEncoder jpeg(nullptr);
gettimeofday(&start, NULL);
runs = RUNS;
for (i = 0; i < runs; i++) {
uint32_t test_cases {};
uint64_t total_time {};
auto benchmark = [&doc, &test_suit, &test_cases, &total_time](const char *name, uint32_t runs, auto func) {
auto now = std::chrono::high_resolution_clock::now();
for (uint32_t i = 0; i < runs; i++) {
func(i);
}
++test_cases;
auto value = elapsedMs(now);
double junit_value = value / 1000.;
total_time += value;
vlog.info("%s took %lu ms (%u runs)", name, value, runs);
auto *test_case = doc.NewElement("testcase");
test_case->SetAttribute("name", name);
test_case->SetAttribute("time", junit_value);
test_case->SetAttribute("runs", runs);
test_case->SetAttribute("classname", "KasmVNC");
test_suit->InsertEndChild(test_case);
};
benchmark("Jpeg compression at quality 8", RUNS, [&jpeg, &vec, &f1](uint32_t) {
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++) {
benchmark("Jpeg compression at quality 4", RUNS, [&jpeg, &vec, &f1](uint32_t) {
jpeg.compressOnly(&f1, 4, vec, false);
}
vlog.info("Jpeg compression at quality 4 took %u ms (%u runs)", msSince(&start), runs);
});
TightWEBPEncoder webp(nullptr);
TightWEBPEncoder webp(NULL);
gettimeofday(&start, NULL);
runs = RUNS / 8;
for (i = 0; i < runs; i++) {
benchmark("Webp compression at quality 8", RUNS / 8, [&webp,&f1, &vec](uint32_t) {
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++) {
benchmark("Webp compression at quality 4", RUNS / 4, [&webp, &f1, &vec](uint32_t) {
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);
benchmark("Nearest scaling to 80%", RUNS, [&f1](uint32_t) {
PixelBuffer *pb = nearestScale(&f1, WIDTH * 0.8, HEIGHT * 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);
benchmark("Nearest scaling to 40%", RUNS, [&f1](uint32_t) {
PixelBuffer *pb = nearestScale(&f1, WIDTH * 0.4, HEIGHT * 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);
benchmark("Bilinear scaling to 80%", RUNS, [&f1](uint32_t) {
PixelBuffer *pb = bilinearScale(&f1, WIDTH * 0.8, HEIGHT * 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);
benchmark("Bilinear scaling to 40%", RUNS, [&f1](uint32_t) {
PixelBuffer *pb = bilinearScale(&f1, WIDTH * 0.4, HEIGHT * 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);
benchmark("Progressive bilinear scaling to 80%", RUNS, [&f1](uint32_t) {
PixelBuffer *pb = progressiveBilinearScale(&f1, WIDTH * 0.8, HEIGHT * 0.8, 0.8);
delete pb;
}
vlog.info("Progressive bilinear scaling to 40%% took %u ms (%u runs)", msSince(&start), runs);
});
benchmark("Progressive bilinear scaling to 40%", RUNS, [&f1](uint32_t) {
PixelBuffer *pb = progressiveBilinearScale(&f1, WIDTH * 0.4, HEIGHT * 0.4, 0.4);
delete pb;
});
// Analysis
ComparingUpdateTracker *comparer = new ComparingUpdateTracker(&screen);
auto *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);
benchmark("Analysis (incl. memcpy overhead)", RUNS,
[&screenptr, &comparer, &cursorReg, f1orig, f2orig](uint32_t i) {
memcpy(screenptr, i % 2 ? f1orig : f2orig, WIDTH * HEIGHT * 4);
comparer->compare(true, cursorReg);
});
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);
benchmark("Analysis w/ scroll detection (incl. memcpy overhead)", RUNS,
[&screenptr, &comparer, &cursorReg, f1orig, f2orig](uint32_t i) {
memcpy(screenptr, i % 2 ? f1orig : f2orig, WIDTH * HEIGHT * 4);
comparer->compare(false, cursorReg);
});
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);
benchmark("Analysis w/ horizontal scroll detection (incl. memcpy overhead)", RUNS / 2,
[&screenptr, &comparer, &cursorReg, f1orig, f2orig](uint32_t i) {
memcpy(screenptr, i % 2 ? f1orig : f2orig, WIDTH * HEIGHT * 4);
comparer->compare(false, cursorReg);
});
test_suit->SetAttribute("tests", test_cases);
test_suit->SetAttribute("failures", 0);
test_suit->SetAttribute("time", total_time);
doc.SaveFile("SelfBench.xml");
exit(0);
}

View file

@ -32,15 +32,15 @@ rfb::IntParameter rfb::Server::idleTimeout
0, 0);
rfb::IntParameter rfb::Server::maxDisconnectionTime
("MaxDisconnectionTime",
"Terminate when no client has been connected for s seconds",
"Terminate when no client has been connected for s seconds",
0, 0);
rfb::IntParameter rfb::Server::maxConnectionTime
("MaxConnectionTime",
"Terminate when a client has been connected for s seconds",
"Terminate when a client has been connected for s seconds",
0, 0);
rfb::IntParameter rfb::Server::maxIdleTime
("MaxIdleTime",
"Terminate after s seconds of user inactivity",
"Terminate after s seconds of user inactivity",
0, 0);
rfb::IntParameter rfb::Server::clientWaitTimeMillis
("ClientWaitTimeMillis",
@ -117,6 +117,16 @@ rfb::BoolParameter rfb::Server::selfBench
("SelfBench",
"Run self-benchmarks and exit.",
false);
rfb::StringParameter rfb::Server::benchmark(
"Benchmark",
"Run extended benchmarks and exit.",
"");
rfb::StringParameter rfb::Server::benchmarkResults(
"BenchmarkResults",
"The file to save becnhmark results to.",
"Benchmark.xml");
rfb::IntParameter rfb::Server::dynamicQualityMin
("DynamicQualityMin",
"The minimum dynamic JPEG quality, 0 = low, 9 = high",
@ -271,19 +281,24 @@ rfb::IntParameter rfb::Server::udpFullFrameFrequency
("udpFullFrameFrequency",
"Send a full frame every N frames for clients using UDP. 0 to disable",
0, 0, 1000);
rfb::IntParameter rfb::Server::udpPort
("udpPort",
"Which port to use for UDP. Default same as websocket",
0, 0, 65535);
static void bandwidthPreset() {
rfb::Server::dynamicQualityMin.setParam(2);
rfb::Server::dynamicQualityMax.setParam(9);
rfb::Server::treatLossless.setParam(8);
rfb::Server::dynamicQualityMin.setParam(2);
rfb::Server::dynamicQualityMax.setParam(9);
rfb::Server::treatLossless.setParam(8);
}
rfb::PresetParameter rfb::Server::preferBandwidth
("PreferBandwidth",
"Set various options for lower bandwidth use. The default is off, aka to prefer quality.",
false, bandwidthPreset);
rfb::IntParameter rfb::Server::webpEncodingTime
("webpEncodingTime",
"Percentage of time allotted for encoding a frame, that can be used for encoding rects in webp.",
30, 0, 100);

View file

@ -28,72 +28,71 @@
#include <rfb/util.h>
namespace rfb {
class Server {
public:
static IntParameter idleTimeout;
static IntParameter maxDisconnectionTime;
static IntParameter maxConnectionTime;
static IntParameter maxIdleTime;
static IntParameter clientWaitTimeMillis;
static IntParameter compareFB;
static IntParameter frameRate;
static IntParameter dynamicQualityMin;
static IntParameter dynamicQualityMax;
static IntParameter treatLossless;
static IntParameter scrollDetectLimit;
static IntParameter rectThreads;
static IntParameter DLP_ClipSendMax;
static IntParameter DLP_ClipAcceptMax;
static IntParameter DLP_ClipDelay;
static IntParameter DLP_KeyRateLimit;
static IntParameter DLP_WatermarkRepeatSpace;
static IntParameter DLP_WatermarkFontSize;
static IntParameter DLP_WatermarkTimeOffset;
static IntParameter DLP_WatermarkTimeOffsetMinutes;
static IntParameter DLP_WatermarkTextAngle;
static StringParameter DLP_ClipLog;
static StringParameter DLP_Region;
static StringParameter DLP_Clip_Types;
static StringParameter DLP_WatermarkImage;
static StringParameter DLP_WatermarkLocation;
static StringParameter DLP_WatermarkTint;
static StringParameter DLP_WatermarkText;
static StringParameter DLP_WatermarkFont;
static BoolParameter DLP_RegionAllowClick;
static BoolParameter DLP_RegionAllowRelease;
static IntParameter jpegVideoQuality;
static IntParameter webpVideoQuality;
static StringParameter maxVideoResolution;
static IntParameter videoTime;
static IntParameter videoOutTime;
static IntParameter videoArea;
static IntParameter videoScaling;
static IntParameter udpFullFrameFrequency;
static IntParameter udpPort;
static StringParameter kasmPasswordFile;
static StringParameter publicIP;
static StringParameter stunServer;
static BoolParameter printVideoArea;
static BoolParameter protocol3_3;
static BoolParameter alwaysShared;
static BoolParameter neverShared;
static BoolParameter disconnectClients;
static BoolParameter acceptKeyEvents;
static BoolParameter acceptPointerEvents;
static BoolParameter acceptCutText;
static BoolParameter sendCutText;
static BoolParameter acceptSetDesktopSize;
static BoolParameter queryConnect;
static BoolParameter detectScrolling;
static BoolParameter detectHorizontal;
static BoolParameter ignoreClientSettingsKasm;
static BoolParameter selfBench;
static PresetParameter preferBandwidth;
};
class Server {
public:
static IntParameter idleTimeout;
static IntParameter maxDisconnectionTime;
static IntParameter maxConnectionTime;
static IntParameter maxIdleTime;
static IntParameter clientWaitTimeMillis;
static IntParameter compareFB;
static IntParameter frameRate;
static IntParameter dynamicQualityMin;
static IntParameter dynamicQualityMax;
static IntParameter treatLossless;
static IntParameter scrollDetectLimit;
static IntParameter rectThreads;
static IntParameter DLP_ClipSendMax;
static IntParameter DLP_ClipAcceptMax;
static IntParameter DLP_ClipDelay;
static IntParameter DLP_KeyRateLimit;
static IntParameter DLP_WatermarkRepeatSpace;
static IntParameter DLP_WatermarkFontSize;
static IntParameter DLP_WatermarkTimeOffset;
static IntParameter DLP_WatermarkTimeOffsetMinutes;
static IntParameter DLP_WatermarkTextAngle;
static StringParameter DLP_ClipLog;
static StringParameter DLP_Region;
static StringParameter DLP_Clip_Types;
static StringParameter DLP_WatermarkImage;
static StringParameter DLP_WatermarkLocation;
static StringParameter DLP_WatermarkTint;
static StringParameter DLP_WatermarkText;
static StringParameter DLP_WatermarkFont;
static BoolParameter DLP_RegionAllowClick;
static BoolParameter DLP_RegionAllowRelease;
static IntParameter jpegVideoQuality;
static IntParameter webpVideoQuality;
static StringParameter maxVideoResolution;
static IntParameter videoTime;
static IntParameter videoOutTime;
static IntParameter videoArea;
static IntParameter videoScaling;
static IntParameter udpFullFrameFrequency;
static IntParameter udpPort;
static StringParameter kasmPasswordFile;
static StringParameter publicIP;
static StringParameter stunServer;
static BoolParameter printVideoArea;
static BoolParameter protocol3_3;
static BoolParameter alwaysShared;
static BoolParameter neverShared;
static BoolParameter disconnectClients;
static BoolParameter acceptKeyEvents;
static BoolParameter acceptPointerEvents;
static BoolParameter acceptCutText;
static BoolParameter sendCutText;
static BoolParameter acceptSetDesktopSize;
static BoolParameter queryConnect;
static BoolParameter detectScrolling;
static BoolParameter detectHorizontal;
static BoolParameter ignoreClientSettingsKasm;
static BoolParameter selfBench;
static StringParameter benchmark;
static StringParameter benchmarkResults;
static PresetParameter preferBandwidth;
static IntParameter webpEncodingTime;
};
};
#endif // __RFB_SERVER_CORE_H__
#endif // __RFB_SERVER_CORE_H__

View file

@ -25,6 +25,12 @@
#include <rfb/TightJPEGEncoder.h>
#include <rfb/TightConstants.h>
#include <ctime>
#include <fstream>
#include <sstream>
#include <iomanip>
using namespace rfb;
struct TightJPEGConfiguration {

View file

@ -259,13 +259,14 @@ void TightWEBPEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)
WebPMemoryWriterClear(&wrt);
}
// How many milliseconds would it take to encode a 256x256 block at quality 8
// How many milliseconds would it take to encode a 256x256 block at quality 5
rdr::U32 TightWEBPEncoder::benchmark() const
{
rdr::U8* buffer;
struct timeval start;
int stride, i;
const uint8_t quality = 8, method = 2;
// the minimum WebP quality settings used in KasmVNC
const uint8_t quality = 5, method = 0;
WebPConfig cfg;
WebPPicture pic;
WebPMemoryWriter wrt;

View file

@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <network/GetAPI.h>
#include <network/TcpSocket.h>
@ -62,11 +62,11 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
losslessTimer(this), kbdLogTimer(this), binclipTimer(this),
server(server_), updates(false),
updateRenderedCursor(false), removeRenderedCursor(false),
continuousUpdates(false), encodeManager(this, &server_->encCache),
continuousUpdates(false), encodeManager(this, &VNCServerST::encCache),
needsPermCheck(false), pointerEventTime(0),
clientHasCursor(false),
accessRights(AccessDefault), startTime(time(0)), frameTracking(false),
udpFramesSinceFull(0), complainedAboutNoViewRights(false)
udpFramesSinceFull(0), complainedAboutNoViewRights(false), clientUsername("username_unavailable")
{
setStreams(&sock->inStream(), &sock->outStream());
peerEndpoint.buf = sock->getPeerEndpoint();
@ -177,6 +177,19 @@ void VNCSConnectionST::close(const char* reason)
if (authenticated()) {
server->lastDisconnectTime = time(0);
// First update the client state to CLOSING to ensure it's not included in user lists
setState(RFBSTATE_CLOSING);
// Notify other clients about the user leaving
server->notifyUserAction(this, clientUsername, VNCServerST::Leave);
vlog.info("Notifying other clients that user '%s' left: %s",
clientUsername.c_str(), reason ? reason : "connection closed");
if (server->apimessager)
{
server->updateSessionUsersList();
}
}
try {
@ -190,11 +203,12 @@ void VNCSConnectionST::close(const char* reason)
vlog.error("Failed to flush remaining socket data on close: %s", e.str());
}
// Just shutdown the socket and mark our state as closing. Eventually the
// calling code will call VNCServerST's removeSocket() method causing us to
// be deleted.
// Just shutdown the socket and mark our state as closing if not already done.
// Eventually the calling code will call VNCServerST's removeSocket() method
// causing us to be deleted.
sock->shutdown();
setState(RFBSTATE_CLOSING);
if (state() != RFBSTATE_CLOSING)
setState(RFBSTATE_CLOSING);
}
@ -631,6 +645,8 @@ void VNCSConnectionST::approveConnectionOrClose(bool accept,
void VNCSConnectionST::authSuccess()
{
lastEventTime = time(0);
connectionTime = time(0); // Record when the user connected
vlog.info("User %s connected at %ld", clientUsername.c_str(), connectionTime);
server->startDesktop();
@ -649,11 +665,27 @@ void VNCSConnectionST::authSuccess()
// - Mark the entire display as "dirty"
updates.add_changed(server->pb->getRect());
startTime = time(0);
startTime = time(nullptr);
if (clientUsername.empty())
{
setUsername(get_default_name(sock->getPeerAddress()));
}
vlog.info("Authentication successful for user: %s", clientUsername.c_str());
}
void VNCSConnectionST::queryConnection(const char* userName)
{
if (userName && strlen(userName) > 0) {
setUsername(userName);
vlog.info("Setting username for connection: %s", userName);
} else {
// Generate a default username based on connection info
setUsername(get_default_name(sock->getPeerAddress()));
vlog.info("Generated username: %s", clientUsername.c_str());
}
// - Authentication succeeded - clear from blacklist
CharArray name; name.buf = sock->getPeerAddress();
server->blHosts->clearBlackmark(name.buf);
@ -708,6 +740,15 @@ void VNCSConnectionST::clientInit(bool shared)
}
}
SConnection::clientInit(shared);
if (shared && authenticated()) {
server->notifyUserAction(this, clientUsername, VNCServerST::Join);
vlog.info("Notifying other clients that user '%s' joined the shared session",
clientUsername.c_str());
}
if (server->apimessager && authenticated()) {
server->updateSessionUsersList();
}
}
void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
@ -997,6 +1038,8 @@ void VNCSConnectionST::setDesktopSize(int fb_width, int fb_height,
{
unsigned int result;
server->sendWatermark = true;
if (!(accessRights & AccessSetDesktopSize)) goto justnotify;
if (!rfb::Server::acceptSetDesktopSize) goto justnotify;

View file

@ -219,6 +219,16 @@ namespace rfb {
return server->sendWatermark;
}
const std::string& getUsername() const { return clientUsername; }
void setUsername(const std::string& username) {
clientUsername = username.empty() ? "" : username;
}
// Returns connection time
time_t getConnectionTime() const { return connectionTime; }
// Returns access rights
AccessRights getAccessRights() const { return accessRights; }
private:
// SConnection callbacks
@ -226,6 +236,10 @@ namespace rfb {
// none of these methods should call any of the above methods which may
// delete the SConnectionST object.
// Connection timestamp when user was authenticated
time_t connectionTime;
virtual void authSuccess();
virtual void queryConnection(const char* userName);
virtual void clientInit(bool shared);
@ -348,6 +362,7 @@ namespace rfb {
char unixRelaySubscriptions[MAX_UNIX_RELAYS][MAX_UNIX_RELAY_NAME_LEN];
bool complainedAboutNoViewRights;
std::string clientUsername;
};
}
#endif

View file

@ -48,8 +48,8 @@
// otherwise blacklisted connections might be "forgotten".
#include <assert.h>
#include <stdlib.h>
#include <cassert>
#include <cstdlib>
#include <network/GetAPI.h>
#include <network/Udp.h>
@ -65,6 +65,7 @@
#include <rfb/Watermark.h>
#include <rfb/util.h>
#include <rfb/ledStates.h>
#include <rfb/SMsgWriter.h>
#include <rdr/types.h>
@ -73,6 +74,8 @@
#include <sys/inotify.h>
#include <unistd.h>
#include <wordexp.h>
#include <filesystem>
#include <string_view>
using namespace rfb;
@ -82,6 +85,8 @@ EncCache VNCServerST::encCache;
void SelfBench();
void benchmark(std::string_view, std::string_view);
//
// -=- VNCServerST Implementation
//
@ -128,20 +133,26 @@ static void parseRegionPart(const bool percents, rdr::U16 &pcdest, int &dest,
VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
: blHosts(&blacklist), desktop(desktop_), desktopStarted(false),
blockCounter(0), pb(0), blackedpb(0), ledState(ledUnknown),
name(strDup(name_)), pointerClient(0), clipboardClient(0),
comparer(0), cursor(new Cursor(0, 0, Point(), NULL)),
blockCounter(0), pb(nullptr), blackedpb(nullptr), ledState(ledUnknown),
name(strDup(name_)), pointerClient(nullptr), clipboardClient(nullptr),
comparer(nullptr), cursor(new Cursor(0, 0, Point(), nullptr)),
renderedCursorInvalid(false),
queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
queryConnectionHandler(nullptr), keyRemapper(&KeyRemapper::defInstance),
lastConnectionTime(0), disableclients(false),
frameTimer(this), apimessager(NULL), trackingFrameStats(0),
frameTimer(this), apimessager(nullptr), trackingFrameStats(0),
clipboardId(0), sendWatermark(false)
{
lastUserInputTime = lastDisconnectTime = time(0);
slog.debug("creating single-threaded server %s", name.buf);
slog.info("CPU capability: SSE2 %s, AVX512f %s",
supportsSSE2() ? "yes" : "no",
supportsAVX512f() ? "yes" : "no");
auto to_string = [](const bool value) {
return value ? "yes" : "no";
};
lastUserInputTime = lastDisconnectTime = time(nullptr);
slog.debug("creating single-threaded server %s", name.buf);
slog.info("CPU capability: SSE2 %s, SSE4.1 %s, SSE4.2 %s, AVX512f %s",
to_string(cpu_info::has_sse2),
to_string(cpu_info::has_sse4_1),
to_string(cpu_info::has_sse4_2),
to_string(cpu_info::has_avx512f));
DLPRegion.enabled = DLPRegion.percents = false;
@ -198,7 +209,7 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
}
}
DLPRegion.enabled = 1;
DLPRegion.enabled = true;
}
kasmpasswdpath[0] = '\0';
@ -223,11 +234,18 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
trackingClient[0] = 0;
if (watermarkData)
sendWatermark = true;
if (watermarkData)
sendWatermark = true;
if (Server::selfBench)
SelfBench();
if (Server::selfBench)
SelfBench();
if (Server::benchmark[0]) {
auto *file_name = Server::benchmark.getValueStr();
if (!std::filesystem::exists(file_name))
throw Exception("Benchmarking video file does not exist");
benchmark(file_name, Server::benchmarkResults.getValueStr());
}
}
VNCServerST::~VNCServerST()
@ -756,6 +774,27 @@ void VNCServerST::stopDesktop()
}
}
std::vector<SessionInfo> VNCServerST::getSessionUsers() {
std::vector<SessionInfo> users;
for ( auto client : clients) {
if (!client->authenticated()) {
continue;
}
users.push_back(SessionInfo(client->getUsername(),client->getConnectionTime()));
}
return users;
}
void VNCServerST::updateSessionUsersList()
{
auto sessionUsers = getSessionUsers();
if (!sessionUsers.empty()) {
std::string sessionUsersJson = formatUsersToJson(sessionUsers);
apimessager->mainUpdateSessionsInfo(sessionUsersJson);
}
}
int VNCServerST::authClientCount() {
int count = 0;
std::list<VNCSConnectionST*>::iterator ci;
@ -1141,9 +1180,6 @@ void VNCServerST::writeUpdate()
}
}
// checkUpdate() is called by clients to see if it is safe to read from
// the framebuffer at this time.
Region VNCServerST::getPendingRegion()
{
UpdateInfo ui;
@ -1215,6 +1251,15 @@ void VNCServerST::notifyScreenLayoutChange(VNCSConnectionST* requester)
}
}
bool VNCServerST::checkClientOwnerships() {
std::list<VNCSConnectionST*>::iterator i;
for (i = clients.begin(); i != clients.end(); i++) {
if ((*i)->is_owner())
return true;
}
return false;
}
bool VNCServerST::getComparerState()
{
if (rfb::Server::compareFB == 0)
@ -1273,3 +1318,40 @@ void VNCServerST::sendUnixRelayData(const char name[],
}
}
}
void VNCServerST::notifyUserAction(const VNCSConnectionST* newConnection, std::string& username, const UserActionType actionType)
{
if (username.empty()) {
username = "username_unavailable";
}
std::string actionTypeStr = actionType == Join ? "joined" : "left";
int notificationsSent = 0;
std::string msgNotification = "Sent user " + actionTypeStr + " notification to client";
std::string errNotification = "Failed to send user " + actionTypeStr + " notification to client: ";
std::string logNotification = "User " + username + " " + actionTypeStr + " - sent notifications to ";
for (auto client : clients ) {
// Don't notify the connection that just joined, and only notify authenticated connections
if (client != newConnection && client->authenticated() &&
client->state() == SConnection::RFBSTATE_NORMAL) {
try {
if (actionType == Join) {
client->writer()->writeUserJoinedSession(username);
}
else {
client->writer()->writeUserLeftSession(username);
}
notificationsSent++;
slog.debug(msgNotification.c_str());
} catch (rdr::Exception& e) {
errNotification.append( e.str());
slog.error(errNotification.c_str());
}
}
}
logNotification.append( std::to_string(notificationsSent) + " clients");
slog.info(logNotification.c_str());
}

View file

@ -35,6 +35,7 @@
#include <rfb/Timer.h>
#include <network/Socket.h>
#include <rfb/ScreenSet.h>
#include <string>
namespace rfb {
@ -148,7 +149,7 @@ namespace rfb {
// the connection.
enum queryResult { ACCEPT, REJECT, PENDING };
struct QueryConnectionHandler {
virtual ~QueryConnectionHandler() {}
virtual ~QueryConnectionHandler() = default;
virtual queryResult queryConnection(network::Socket* sock,
const char* userName,
char** reason) = 0;
@ -200,6 +201,9 @@ namespace rfb {
void refreshClients();
void sendUnixRelayData(const char name[], const unsigned char *buf, const unsigned len);
enum UserActionType {Join, Leave};
void notifyUserAction(const VNCSConnectionST* newConnection, std::string& user_name, const UserActionType action_type);
protected:
friend class VNCSConnectionST;
@ -253,9 +257,13 @@ namespace rfb {
Region getPendingRegion();
const RenderedCursor* getRenderedCursor();
std::vector<SessionInfo> getSessionUsers();
void updateSessionUsersList();
void notifyScreenLayoutChange(VNCSConnectionST *requester);
bool getComparerState();
bool checkClientOwnerships();
void updateWatermark();

396
common/rfb/benchmark.cxx Normal file
View file

@ -0,0 +1,396 @@
/* Copyright 2015 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2015 D. R. Commander. All Rights Reserved.
* Copyright (C) 2025 Kasm Technologies Corp
*
* 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 "benchmark.h"
#include <string_view>
#include <rfb/LogWriter.h>
#include <numeric>
#include <tinyxml2.h>
#include <algorithm>
#include <cassert>
#include "ServerCore.h"
#include <cmath>
#include "EncCache.h"
#include "EncodeManager.h"
#include "SConnection.h"
#include "screenTypes.h"
#include "SMsgWriter.h"
#include "UpdateTracker.h"
#include "rdr/BufferedInStream.h"
#include "rdr/OutStream.h"
#include "ffmpeg.h"
namespace benchmarking {
class MockBufferStream final : public rdr::BufferedInStream {
bool fillBuffer(size_t maxSize, bool wait) override {
return true;
}
};
class MockStream final : public rdr::OutStream {
public:
MockStream() {
offset = 0;
ptr = buf;
end = buf + sizeof(buf);
}
private:
void overrun(size_t needed) override {
assert(end >= ptr);
if (needed > static_cast<size_t>(end - ptr))
flush();
}
public:
size_t length() override {
flush();
return offset;
}
void flush() override {
offset += ptr - buf;
ptr = buf;
}
private:
ptrdiff_t offset;
rdr::U8 buf[8192]{};
};
class MockSConnection final : public rfb::SConnection {
public:
MockSConnection() {
setStreams(nullptr, &out);
setWriter(new rfb::SMsgWriter(&cp, &out, &udps));
}
~MockSConnection() override = default;
void writeUpdate(const rfb::UpdateInfo &ui, const rfb::PixelBuffer *pb) {
cache.clear();
manager.clearEncodingTime();
if (!ui.is_empty()) {
manager.writeUpdate(ui, pb, nullptr);
} else {
rfb::Region region{pb->getRect()};
manager.writeLosslessRefresh(region, pb, nullptr, 2000);
}
}
void setDesktopSize(int fb_width, int fb_height,
const rfb::ScreenSet &layout) override {
cp.width = fb_width;
cp.height = fb_height;
cp.screenLayout = layout;
writer()->writeExtendedDesktopSize(rfb::reasonServer, 0, cp.width, cp.height,
cp.screenLayout);
}
void sendStats(const bool toClient) override {
}
[[nodiscard]] bool canChangeKasmSettings() const override {
return true;
}
void udpUpgrade(const char *resp) override {
}
void udpDowngrade(const bool) override {
}
void subscribeUnixRelay(const char *name) override {
}
void unixRelay(const char *name, const rdr::U8 *buf, const unsigned len) override {
}
void handleFrameStats(rdr::U32 all, rdr::U32 render) override {
}
[[nodiscard]] auto getJpegStats() const {
return manager.jpegstats;
}
[[nodiscard]] auto getWebPStats() const {
return manager.webpstats;
}
[[nodiscard]] auto bytes() { return out.length(); }
[[nodiscard]] auto udp_bytes() { return udps.length(); }
protected:
MockStream out{};
MockStream udps{};
EncCache cache{};
EncodeManager manager{this, &cache};
};
class MockCConnection final : public MockTestConnection {
public:
explicit MockCConnection(const std::vector<rdr::S32> &encodings, rfb::ManagedPixelBuffer *pb) {
setStreams(&in, nullptr);
// Need to skip the initial handshake and ServerInit
setState(RFBSTATE_NORMAL);
// That also means that the reader and writer weren't set up
setReader(new rfb::CMsgReader(this, &in));
auto &pf = pb->getPF();
CMsgHandler::setPixelFormat(pf);
MockCConnection::setDesktopSize(pb->width(), pb->height());
cp.setPF(pf);
sc.cp.setPF(pf);
sc.setEncodings(std::size(encodings), encodings.data());
setFramebuffer(pb);
}
void setCursor(int width, int height, const rfb::Point &hotspot, const rdr::U8 *data,
const bool resizing) override {
}
~MockCConnection() override = default;
struct stats_t {
EncodeManager::codecstats_t jpeg_stats;
EncodeManager::codecstats_t webp_stats;
uint64_t bytes;
uint64_t udp_bytes;
};
[[nodiscard]] stats_t getStats() {
return {
sc.getJpegStats(),
sc.getWebPStats(),
sc.bytes(),
sc.udp_bytes()
};
}
void setDesktopSize(int w, int h) override {
CConnection::setDesktopSize(w, h);
if (screen_layout.num_screens())
screen_layout.remove_screen(0);
screen_layout.add_screen(rfb::Screen(0, 0, 0, w, h, 0));
}
void setNewFrame(const AVFrame *frame) override {
auto *pb = getFramebuffer();
const int width = pb->width();
const int height = pb->height();
const rfb::Rect rect(0, 0, width, height);
int dstStride{};
auto *buffer = pb->getBufferRW(rect, &dstStride);
const rfb::PixelFormat &pf = pb->getPF();
// Source data and stride from FFmpeg
const auto *srcData = frame->data[0];
const int srcStride = frame->linesize[0] / 3; // Convert bytes to pixels
// Convert from the RGB format to the PixelBuffer's format
pf.bufferFromRGB(buffer, srcData, width, srcStride, height);
// Commit changes
pb->commitBufferRW(rect);
}
void framebufferUpdateStart() override {
updates.clear();
}
void framebufferUpdateEnd() override {
const rfb::PixelBuffer *pb = getFramebuffer();
rfb::UpdateInfo ui;
const rfb::Region clip(pb->getRect());
updates.add_changed(pb->getRect());
updates.getUpdateInfo(&ui, clip);
sc.writeUpdate(ui, pb);
}
void dataRect(const rfb::Rect &r, int encoding) override {
}
void setColourMapEntries(int, int, rdr::U16 *) override {
}
void bell() override {
}
void serverCutText(const char *, rdr::U32) override {
}
void serverCutText(const char *str) override {
}
protected:
MockBufferStream in;
rfb::ScreenSet screen_layout;
rfb::SimpleUpdateTracker updates;
MockSConnection sc;
};
}
void report(std::vector<uint64_t> &totals, std::vector<uint64_t> &timings,
std::vector<benchmarking::MockCConnection::stats_t> &stats, const std::string_view results_file) {
auto totals_sum = std::accumulate(totals.begin(), totals.end(), 0.);
auto totals_avg = totals_sum / static_cast<double>(totals.size());
auto variance = 0.;
for (auto t: totals)
variance += (static_cast<double>(t) - totals_avg) * (static_cast<double>(t) - totals_avg);
variance /= static_cast<double>(totals.size());
auto stddev = std::sqrt(variance);
const auto sum = std::accumulate(timings.begin(), timings.end(), 0.);
const auto size = timings.size();
const auto average = sum / static_cast<double>(size);
double median{};
std::sort(timings.begin(), timings.end());
if (size % 2 == 0)
median = static_cast<double>(timings[size / 2]);
else
median = static_cast<double>(timings[size / 2 - 1] + timings[size / 2]) / 2.;
vlog.info("Mean time encoding frame: %f ms", average);
vlog.info("Median time encoding frame: %f ms", median);
vlog.info("Total time (mean): %f ms", totals_avg);
vlog.info("Total time (stddev): %f ms", stddev);
uint32_t jpeg_sum{}, jpeg_rects{}, webp_sum{}, webp_rects{};
uint64_t bytes{};
for (const auto &item: stats) {
jpeg_sum += item.jpeg_stats.ms;
jpeg_rects += item.jpeg_stats.rects;
webp_sum += item.webp_stats.ms;
webp_rects += item.webp_stats.rects;
bytes += item.bytes;
}
auto jpeg_ms = jpeg_sum / static_cast<double>(stats.size());
vlog.info("JPEG stats: %f ms", jpeg_ms);
jpeg_rects /= stats.size();
vlog.info("JPEG stats: %u rects", jpeg_rects);
auto webp_ms = webp_sum / static_cast<double>(stats.size());
webp_rects /= stats.size();
bytes /= stats.size();
vlog.info("WebP stats: %f ms", webp_ms);
vlog.info("WebP stats: %u rects", webp_rects);
vlog.info("Total bytes sent: %lu bytes", bytes);
tinyxml2::XMLDocument doc;
auto *test_suit = doc.NewElement("testsuite");
test_suit->SetAttribute("name", "Benchmark");
doc.InsertFirstChild(test_suit);
auto total_tests{0};
auto add_benchmark_item = [&doc, &test_suit, &total_tests](const char *name, auto time_value, auto other_value) {
auto *test_case = doc.NewElement("testcase");
test_case->SetAttribute("name", name);
test_case->SetAttribute("file", other_value);
test_case->SetAttribute("time", time_value);
test_case->SetAttribute("runs", 1);
test_case->SetAttribute("classname", "KasmVNC");
test_suit->InsertEndChild(test_case);
++total_tests;
};
constexpr auto mult = 1 / 1000.;
add_benchmark_item("Average time encoding frame, ms", average * mult, "");
add_benchmark_item("Median time encoding frame, ms", median * mult, "");
add_benchmark_item("Total time encoding, ms", 0, totals_avg);
add_benchmark_item("Total time encoding, stddev", 0, stddev);
add_benchmark_item("Mean JPEG stats, ms", jpeg_ms, "");
add_benchmark_item("Mean JPEG stats, rects", 0., jpeg_rects);
add_benchmark_item("Mean WebP stats, ms", webp_ms, "");
add_benchmark_item("Mean WebP stats, rects", 0, webp_rects);
add_benchmark_item("Data sent, KBs", 0, bytes / 1024);
doc.SaveFile(results_file.data());
}
void benchmark(std::string_view path, const std::string_view results_file) {
try {
vlog.info("Benchmarking with video file %s", path.data());
FFmpegFrameFeeder frame_feeder{};
frame_feeder.open(path);
static const rfb::PixelFormat pf{32, 24, false, true, 0xFF, 0xFF, 0xFF, 0, 8, 16};
std::vector<rdr::S32> encodings{
std::begin(benchmarking::default_encodings), std::end(benchmarking::default_encodings)
};
constexpr auto runs = 20;
std::vector<uint64_t> totals(runs, 0);
std::vector<benchmarking::MockCConnection::stats_t> stats(runs);
std::vector<uint64_t> timings{};
auto [width, height] = frame_feeder.get_frame_dimensions();
for (int run = 0; run < runs; ++run) {
auto *pb = new rfb::ManagedPixelBuffer{pf, width, height};
benchmarking::MockCConnection connection{encodings, pb};
vlog.info("RUN %d. Reading frames...", run);
auto play_stats = frame_feeder.play(&connection);
vlog.info("RUN %d. Done reading frames...", run);
timings.insert(timings.end(), play_stats.timings.begin(), play_stats.timings.end());
totals[run] = play_stats.total;
stats[run] = connection.getStats();
vlog.info("JPEG stats: %u ms", stats[run].jpeg_stats.ms);
vlog.info("WebP stats: %u ms", stats[run].webp_stats.ms);
vlog.info("RUN %d. Bytes sent %lu..", run, stats[run].bytes);
}
if (!timings.empty())
report(totals, timings, stats, results_file);
exit(0);
} catch (std::exception &e) {
vlog.error("Benchmarking failed: %s", e.what());
exit(1);
}
}

67
common/rfb/benchmark.h Normal file
View file

@ -0,0 +1,67 @@
/* Copyright (C) 2025 Kasm Technologies Corp
*
* 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.
*/
#pragma once
#include "CConnection.h"
#include "CMsgReader.h"
#include "LogWriter.h"
extern "C" {
#include <libavutil/frame.h>
}
static rfb::LogWriter vlog("Benchmarking");
namespace benchmarking {
using namespace rfb;
class MockTestConnection : public CConnection {
public:
virtual void setNewFrame(const AVFrame *frame) = 0;
};
static constexpr rdr::S32 default_encodings[] = {
encodingTight,
encodingHextile,
encodingRRE,
encodingRaw,
pseudoEncodingQualityLevel0 + 6,
pseudoEncodingCompressLevel0 + 2,
pseudoEncodingDesktopSize,
pseudoEncodingLastRect,
pseudoEncodingQEMUKeyEvent,
pseudoEncodingExtendedDesktopSize,
pseudoEncodingFence,
pseudoEncodingContinuousUpdates,
pseudoEncodingDesktopName,
pseudoEncodingExtendedClipboard,
pseudoEncodingWEBP,
pseudoEncodingJpegVideoQualityLevel0 + 7,
pseudoEncodingWebpVideoQualityLevel0 + 7,
pseudoEncodingTreatLosslessLevel0 + 7,
pseudoEncodingDynamicQualityMinLevel0 + 4,
pseudoEncodingDynamicQualityMaxLevel0 + 9,
pseudoEncodingVideoAreaLevel1 - 1 + 65,
pseudoEncodingVideoTimeLevel0 + 5,
pseudoEncodingVideoOutTimeLevel1 - 1 + 3,
pseudoEncodingFrameRateLevel10 - 10 + 60,
pseudoEncodingMaxVideoResolution
};
}

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