Compare commits
496 Commits
v0.9.2-bet
...
KASM-1810_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d94b30c2fa | ||
|
|
8e040e58a1 | ||
|
|
c0229f8470 | ||
|
|
dcccd1d1f2 | ||
|
|
c2f302cdc6 | ||
|
|
becfa90a2c | ||
|
|
e5233f27bd | ||
|
|
377269129c | ||
|
|
8ea6704fcd | ||
|
|
a9888b9ca7 | ||
|
|
71b3515d6c | ||
|
|
b1ee23dc62 | ||
|
|
a675f411cc | ||
|
|
35e0157431 | ||
|
|
6fa5b9271f | ||
|
|
dc4e4ce348 | ||
|
|
b842460724 | ||
|
|
e4ad356c7d | ||
|
|
26f1b52b70 | ||
|
|
8c2c099342 | ||
|
|
314e7e9615 | ||
|
|
77b97415ef | ||
|
|
f79c3b3b11 | ||
|
|
8e96d4cac5 | ||
|
|
ab4642aa87 | ||
|
|
7ad6810d7f | ||
|
|
42021dd29a | ||
|
|
11d3958702 | ||
|
|
27f0ed29ca | ||
|
|
628033af45 | ||
|
|
3fac7c4947 | ||
|
|
2ecf9a25ed | ||
|
|
a4a8d3aad5 | ||
|
|
d6132154fb | ||
|
|
219e2c5cb1 | ||
|
|
7cced9dd05 | ||
|
|
f3681c87f9 | ||
|
|
303fde284e | ||
|
|
8cd49ebbf8 | ||
|
|
bc2e2512e3 | ||
|
|
dd276e5e87 | ||
|
|
a9434a300d | ||
|
|
6219b85ba8 | ||
|
|
d3add8150c | ||
|
|
5b28a168d0 | ||
|
|
e6d1b8c3c8 | ||
|
|
620dbe558c | ||
|
|
aefbb4d143 | ||
|
|
b34fe08786 | ||
|
|
ee3b7f9aa5 | ||
|
|
f7254e9708 | ||
|
|
bcad19542e | ||
|
|
24e21325ef | ||
|
|
e3a41bc055 | ||
|
|
0a45fcc700 | ||
|
|
1bda8ab452 | ||
|
|
02ef620f67 | ||
|
|
3f3d31312c | ||
|
|
e453c7d73b | ||
|
|
e857b86924 | ||
|
|
e470021ca6 | ||
|
|
5a1f9b9ae2 | ||
|
|
93e47e5d54 | ||
|
|
dd26c40844 | ||
|
|
3f680a7b80 | ||
|
|
ca42870585 | ||
|
|
0b53e9f0a6 | ||
|
|
3f69b7bd33 | ||
|
|
4cb75459ed | ||
|
|
8a424a0463 | ||
|
|
a9d85aa99b | ||
|
|
cca1dabb71 | ||
|
|
183917d046 | ||
|
|
a31601de9a | ||
|
|
e21366cc7b | ||
|
|
76a5b18748 | ||
|
|
04379056af | ||
|
|
49908e1867 | ||
|
|
df4a5ac910 | ||
|
|
606075ddc0 | ||
|
|
17fa6911c1 | ||
|
|
5f7d3ad43a | ||
|
|
f857d47ccf | ||
|
|
3b3c8d0881 | ||
|
|
fe3569c6e8 | ||
|
|
90d9cbe65b | ||
|
|
f0e63b2e3d | ||
|
|
b5eaf71248 | ||
|
|
e643cf4115 | ||
|
|
df35fadc9b | ||
|
|
a27ad89677 | ||
|
|
04e93956b5 | ||
|
|
5de1b80ca7 | ||
|
|
d3e209c9ba | ||
|
|
ff8ab63aab | ||
|
|
a51444257a | ||
|
|
e23e5cc63b | ||
|
|
043438e2e0 | ||
|
|
8152596519 | ||
|
|
fe2bd6c6d6 | ||
|
|
5d0e8b1b03 | ||
|
|
9faf87389f | ||
|
|
ec948ab20f | ||
|
|
2fa381a3fe | ||
|
|
9161015aca | ||
|
|
3fe52a84ba | ||
|
|
0c26c4cb85 | ||
|
|
177da18fc8 | ||
|
|
0b495fd3f9 | ||
|
|
0011fa6afd | ||
|
|
ed78c9dcc5 | ||
|
|
dca392eafd | ||
|
|
28c06893e3 | ||
|
|
0f23baa647 | ||
|
|
d1f0d6f7e7 | ||
|
|
d522457723 | ||
|
|
159d752795 | ||
|
|
d8bbb9884d | ||
|
|
7cb1ea9ebc | ||
|
|
dbd54fe35c | ||
|
|
0cb2c0ba9f | ||
|
|
dc21d5f97c | ||
|
|
6287114cbf | ||
|
|
f999acc490 | ||
|
|
71c420fc86 | ||
|
|
f766c3a8c0 | ||
|
|
c96d38bbe5 | ||
|
|
c2a5876127 | ||
|
|
64c190e2bb | ||
|
|
4ed2c57ce3 | ||
|
|
3a528b94e6 | ||
|
|
fbdda196b8 | ||
|
|
75b42e4f3f | ||
|
|
003958dd9f | ||
|
|
69a9ba66cd | ||
|
|
279e91dcb1 | ||
|
|
91eb953f62 | ||
|
|
102d9b9a6c | ||
|
|
3eb1ffd94b | ||
|
|
551f292144 | ||
|
|
36ffbe1572 | ||
|
|
c775f7198b | ||
|
|
0fa98100f8 | ||
|
|
b0ffc6a27e | ||
|
|
fa7b3492da | ||
|
|
4a4e1d65b8 | ||
|
|
cb08058d34 | ||
|
|
6f2805e186 | ||
|
|
d80eb39686 | ||
|
|
4b28667e90 | ||
|
|
5341bc6fba | ||
|
|
b4612d548f | ||
|
|
9ec4cba184 | ||
|
|
d0fe229684 | ||
|
|
643a0cfed6 | ||
|
|
9ca850a108 | ||
|
|
ded3840f6b | ||
|
|
c6f7d2eff0 | ||
|
|
7e854294a2 | ||
|
|
5635096978 | ||
|
|
34565c5950 | ||
|
|
3522000d1f | ||
|
|
3f23bddb6b | ||
|
|
b350557afd | ||
|
|
7dc12ccb8a | ||
|
|
f187aa9540 | ||
|
|
79a21347f1 | ||
|
|
0c1423f0b1 | ||
|
|
1e21e09754 | ||
|
|
6e0d272946 | ||
|
|
c64e83732d | ||
|
|
acb9793841 | ||
|
|
9a6ea64e0f | ||
|
|
68554d84d6 | ||
|
|
ac51bd1d57 | ||
|
|
3ef297a7cd | ||
|
|
0ca46888a0 | ||
|
|
8ca36e349e | ||
|
|
cc90fe9ff6 | ||
|
|
2b4f01f5ae | ||
|
|
65f957695e | ||
|
|
06e9e92ee1 | ||
|
|
13f4ce0fba | ||
|
|
349a33e402 | ||
|
|
a44241971e | ||
|
|
b26a20d44d | ||
|
|
f15aae2db8 | ||
|
|
895f8bc10d | ||
|
|
649868241c | ||
|
|
8a3cf76f82 | ||
|
|
cfac63aec5 | ||
|
|
59f990b372 | ||
|
|
aa5fd48852 | ||
|
|
a2a748a582 | ||
|
|
5f3fcddcde | ||
|
|
fa4308c542 | ||
|
|
db2901e673 | ||
|
|
a0f09dea15 | ||
|
|
21b42e462b | ||
|
|
ec6bd697a8 | ||
|
|
544a9fc592 | ||
|
|
7b5838a1ea | ||
|
|
27f7f823fe | ||
|
|
93d2c6c716 | ||
|
|
a9b66833a9 | ||
|
|
fa342f624f | ||
|
|
a6e9f94e27 | ||
|
|
ffb88ee8e6 | ||
|
|
c99d82fd8b | ||
|
|
69a2f9a13b | ||
|
|
08ede14dfe | ||
|
|
79c9c7157b | ||
|
|
8f58d9bc92 | ||
|
|
7ee1522143 | ||
|
|
e208d5bb5f | ||
|
|
f57e6e644b | ||
|
|
c1ed769780 | ||
|
|
df5d3e506d | ||
|
|
7954cc506c | ||
|
|
84764bac80 | ||
|
|
bc54f75226 | ||
|
|
42eadfe784 | ||
|
|
1bea4d0a41 | ||
|
|
6181c249d7 | ||
|
|
4a63e93582 | ||
|
|
f6667e99be | ||
|
|
d6fa4b55d7 | ||
|
|
dc1850f1e7 | ||
|
|
a6b3eb1f24 | ||
|
|
efbf401c8e | ||
|
|
c79da47c21 | ||
|
|
55525a627b | ||
|
|
c435e6ba7d | ||
|
|
59d53dbb19 | ||
|
|
8da1612d4c | ||
|
|
a560276817 | ||
|
|
2cb5098060 | ||
|
|
ed51231b4e | ||
|
|
f903fd6c9d | ||
|
|
a3b9a96df7 | ||
|
|
5811e14b42 | ||
|
|
fc732f3603 | ||
|
|
fae8aa9051 | ||
|
|
438271d68b | ||
|
|
b330856d67 | ||
|
|
1165159180 | ||
|
|
25e761326f | ||
|
|
53c545a9ad | ||
|
|
fb9dd56703 | ||
|
|
32e8d40472 | ||
|
|
7c28908722 | ||
|
|
6bdcbc32b1 | ||
|
|
fe736c8a2b | ||
|
|
b13698eb56 | ||
|
|
7941e10b0a | ||
|
|
fc1aa63a44 | ||
|
|
1bd14fe881 | ||
|
|
8deac5cfa7 | ||
|
|
ba942e102e | ||
|
|
c4cc856e56 | ||
|
|
7d842fe3d2 | ||
|
|
7c4896ac66 | ||
|
|
24336b236a | ||
|
|
8a11d171d5 | ||
|
|
892c285963 | ||
|
|
26cc3845b0 | ||
|
|
f046e3340c | ||
|
|
bd144b71bf | ||
|
|
66d999beaf | ||
|
|
3584d8c3cb | ||
|
|
f8bcfcc493 | ||
|
|
22654f7ab6 | ||
|
|
33327c1159 | ||
|
|
aeec23bd68 | ||
|
|
34a389f714 | ||
|
|
b8fd6a28a4 | ||
|
|
240b1342fd | ||
|
|
811e7cde3a | ||
|
|
640a195e3e | ||
|
|
72affbfcf4 | ||
|
|
b362110b07 | ||
|
|
29e0e2bd2e | ||
|
|
9144045718 | ||
|
|
7a695c976e | ||
|
|
aefdb1392f | ||
|
|
14e08a2067 | ||
|
|
f64bd4f1a4 | ||
|
|
0b6334369c | ||
|
|
b8c69a7560 | ||
|
|
e84a37fb3d | ||
|
|
23935145a8 | ||
|
|
7f7b177b1a | ||
|
|
95d34f7e58 | ||
|
|
a1cf454f06 | ||
|
|
04461b9d4c | ||
|
|
0d482f9a9b | ||
|
|
a7773bee6b | ||
|
|
75cef8b726 | ||
|
|
380bc0e7f8 | ||
|
|
999cfbb806 | ||
|
|
12a0c0d8af | ||
|
|
7bfcb19ee1 | ||
|
|
df9ca2e0ce | ||
|
|
4fda2526f4 | ||
|
|
102257cb32 | ||
|
|
77509c1e56 | ||
|
|
9e0a5d26af | ||
|
|
c6c2661121 | ||
|
|
8b8201fd73 | ||
|
|
33a113a475 | ||
|
|
6d1cebc24a | ||
|
|
fcd7836a83 | ||
|
|
073737c8ac | ||
|
|
16c72ba0a7 | ||
|
|
d3c9ff8b12 | ||
|
|
4bc4c1d7f6 | ||
|
|
d8ba9a61e2 | ||
|
|
0e2a25476f | ||
|
|
b3b4acaaa3 | ||
|
|
201f2517f7 | ||
|
|
f51167a2ce | ||
|
|
87b3a630cf | ||
|
|
7412dde8ee | ||
|
|
3ef6e1333b | ||
|
|
b84220f319 | ||
|
|
42d437ad25 | ||
|
|
d5b84d9185 | ||
|
|
6db1c2bf0d | ||
|
|
ae1bc396bf | ||
|
|
c7a7ce70be | ||
|
|
55178c76b8 | ||
|
|
5752bf8ab7 | ||
|
|
6fd1035fb1 | ||
|
|
212e0f1a10 | ||
|
|
69b945fc87 | ||
|
|
b837bd6f59 | ||
|
|
670eefbc97 | ||
|
|
b2d8db3f7b | ||
|
|
a3e2b1e46e | ||
|
|
472ede66ea | ||
|
|
da228af778 | ||
|
|
59f5648592 | ||
|
|
19c473f792 | ||
|
|
8a8fa1d906 | ||
|
|
5a81223d96 | ||
|
|
eff38d47f9 | ||
|
|
1de3769fd3 | ||
|
|
749ddce5b9 | ||
|
|
d420aa6413 | ||
|
|
93e42772bc | ||
|
|
9098478faf | ||
|
|
4710ec1822 | ||
|
|
02b9b268ff | ||
|
|
a015e33111 | ||
|
|
950d871b0e | ||
|
|
02e7b006de | ||
|
|
95af51e28d | ||
|
|
64dfb8d1d6 | ||
|
|
b173c8854a | ||
|
|
888f24e7af | ||
|
|
8be81165bd | ||
|
|
509b5795a0 | ||
|
|
581fe511ad | ||
|
|
9ca647667b | ||
|
|
dbe2930758 | ||
|
|
b690ae4c2d | ||
|
|
5e4544d5fc | ||
|
|
0b19961b06 | ||
|
|
286694869b | ||
|
|
fdeefcfab4 | ||
|
|
24cf1f0f9a | ||
|
|
d01f6e6d27 | ||
|
|
c1160d1468 | ||
|
|
1c38b6f120 | ||
|
|
70dd0058ac | ||
|
|
a4c5c38b53 | ||
|
|
789308212b | ||
|
|
ce5fe304cb | ||
|
|
781075c841 | ||
|
|
2f43cead79 | ||
|
|
e7a5aa271e | ||
|
|
ad206180d2 | ||
|
|
89dd199317 | ||
|
|
8be70e5ae0 | ||
|
|
ce94d92e18 | ||
|
|
c3ef9ff557 | ||
|
|
c0276776e9 | ||
|
|
10f4aa9e7b | ||
|
|
b2dc76ee18 | ||
|
|
12cdad066e | ||
|
|
a850be4afa | ||
|
|
354d544843 | ||
|
|
0bf9403a36 | ||
|
|
29db8997ec | ||
|
|
46f15667f7 | ||
|
|
edb5fee88b | ||
|
|
23871b42d1 | ||
|
|
d6d875ef3b | ||
|
|
6c84631bbc | ||
|
|
6bb87ee2b2 | ||
|
|
15c74e7dc9 | ||
|
|
f1be4be653 | ||
|
|
b5f1a00282 | ||
|
|
740a8217ab | ||
|
|
796de9653f | ||
|
|
6916c83b48 | ||
|
|
d10d7167f6 | ||
|
|
a8dc933701 | ||
|
|
d61bf69c33 | ||
|
|
62fca18cb9 | ||
|
|
dc3ddc8efc | ||
|
|
e497b53d09 | ||
|
|
7dc51fa7a5 | ||
|
|
443858cf83 | ||
|
|
6b39933658 | ||
|
|
6067290169 | ||
|
|
a8699ab8cb | ||
|
|
996895268e | ||
|
|
fb14c2dec9 | ||
|
|
83d5e5bffd | ||
|
|
19dfb7901c | ||
|
|
6acf3c9e62 | ||
|
|
0dcb896920 | ||
|
|
d88aefba4e | ||
|
|
b0c54f6b24 | ||
|
|
6342a117ff | ||
|
|
766fc43855 | ||
|
|
19f0803636 | ||
|
|
3c3ac34eb8 | ||
|
|
8c43287afb | ||
|
|
c16cc6e2b9 | ||
|
|
c211f31113 | ||
|
|
4cc536636a | ||
|
|
734bdd3746 | ||
|
|
8218a0cb2a | ||
|
|
2525174260 | ||
|
|
b0896c8859 | ||
|
|
09de4b8349 | ||
|
|
d4747a8c80 | ||
|
|
5b73c1ca23 | ||
|
|
f21fb95bb9 | ||
|
|
7b02f3d8b8 | ||
|
|
03a333fb18 | ||
|
|
54253efaa0 | ||
|
|
8b859f4598 | ||
|
|
8c5b5f17eb | ||
|
|
71fa476514 | ||
|
|
4fd1f19f3b | ||
|
|
257aabecb0 | ||
|
|
74161066af | ||
|
|
e2d86788ba | ||
|
|
4c635f65d3 | ||
|
|
1d4ada6815 | ||
|
|
d3ec2aa4d1 | ||
|
|
10c334303a | ||
|
|
c4987024ef | ||
|
|
04d7bef2ae | ||
|
|
12565dc4ac | ||
|
|
46b7d1db95 | ||
|
|
0045f07965 | ||
|
|
d1fdb877ef | ||
|
|
e62e12fbfe | ||
|
|
50183c7caa | ||
|
|
79ab05192b | ||
|
|
c6c278f9d5 | ||
|
|
37c17ddbf9 | ||
|
|
c755008d15 | ||
|
|
075eed5cbb | ||
|
|
7b7295fd4e | ||
|
|
5964156a6f | ||
|
|
1ff792cf4b | ||
|
|
3043216b63 | ||
|
|
499b251716 | ||
|
|
d20f751441 | ||
|
|
915901848d | ||
|
|
ee2423ed2b | ||
|
|
ce6d66f030 | ||
|
|
41e6fedba6 | ||
|
|
642a67f76f | ||
|
|
d7198cbe5d | ||
|
|
25b8e64adb | ||
|
|
d8caab699d | ||
|
|
da83ecf86a | ||
|
|
189f503b98 | ||
|
|
f54dc7829a | ||
|
|
fde088ce65 | ||
|
|
a55f142c98 | ||
|
|
25995e2490 | ||
|
|
281d65292a | ||
|
|
57a3c3bba8 | ||
|
|
92c7695981 | ||
|
|
7f90205cf2 | ||
|
|
910fd8fa3e | ||
|
|
c97828471c | ||
|
|
c5b7137f2b | ||
|
|
a3c0ce55c9 |
@@ -1,16 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
is_kasmvnc() {
|
||||
local package="$1";
|
||||
|
||||
echo "$package" | grep -q 'kasmvncserver_'
|
||||
}
|
||||
|
||||
function prepare_upload_filename() {
|
||||
local package="$1";
|
||||
|
||||
if ! is_kasmvnc "$package"; then
|
||||
export upload_filename="$package"
|
||||
return
|
||||
fi
|
||||
|
||||
.ci/detect_os_arch_package_format "$package" > /tmp/os_arch_package_format;
|
||||
source /tmp/os_arch_package_format;
|
||||
detect_release_branch
|
||||
|
||||
detect_revision "$package" "$OS_ARCH"
|
||||
if [ -n "$REVISION" ]; then
|
||||
REVISION="_${REVISION}"
|
||||
fi
|
||||
|
||||
if [ -n "$RELEASE_BRANCH" ]; then
|
||||
export upload_filename="kasmvncserver_${PACKAGE_OS}_${RELEASE_VERSION}_${OS_ARCH}.${PACKAGE_FORMAT}";
|
||||
export upload_filename="kasmvncserver_${PACKAGE_OS}_${RELEASE_VERSION}${REVISION}_${OS_ARCH}.${PACKAGE_FORMAT}";
|
||||
else
|
||||
export SANITIZED_BRANCH="$(echo $CI_COMMIT_REF_NAME | sed 's/\//_/g')";
|
||||
export upload_filename="kasmvncserver_${PACKAGE_OS}_${RELEASE_VERSION}_${SANITIZED_BRANCH}_${CI_COMMIT_SHA:0:6}_${OS_ARCH}.${PACKAGE_FORMAT}";
|
||||
export upload_filename="kasmvncserver_${PACKAGE_OS}_${RELEASE_VERSION}_${SANITIZED_BRANCH}_${CI_COMMIT_SHA:0:6}${REVISION}_${OS_ARCH}.${PACKAGE_FORMAT}";
|
||||
fi
|
||||
};
|
||||
|
||||
@@ -25,6 +42,7 @@ function upload_to_s3() {
|
||||
export BUILD_STATUS="{\"key\":\"doc\", \"state\":\"SUCCESSFUL\", \"name\":\"${upload_filename}\", \"url\":\"${S3_URL}\"}";
|
||||
curl --request POST --header "PRIVATE-TOKEN:${GITLAB_API_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/statuses/${CI_COMMIT_SHA}?state=success&name=build-url&target_url=${S3_URL}";
|
||||
};
|
||||
|
||||
function prepare_to_run_scripts_and_s3_uploads() {
|
||||
export DEBIAN_FRONTEND=noninteractive;
|
||||
apt-get update;
|
||||
@@ -38,3 +56,16 @@ detect_release_branch() {
|
||||
export RELEASE_BRANCH=1;
|
||||
fi
|
||||
}
|
||||
|
||||
detect_revision() {
|
||||
local package="$1"
|
||||
local arch="$2"
|
||||
|
||||
REVISION=
|
||||
|
||||
if ! echo "$package" | grep -q '+'; then
|
||||
return
|
||||
fi
|
||||
|
||||
REVISION=$(echo "$package" | sed "s/_${arch}.\+//" | sed 's/.\++//')
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
builder/build
|
||||
142
.gitlab-ci.yml
142
.gitlab-ci.yml
@@ -4,27 +4,49 @@ services:
|
||||
|
||||
variables:
|
||||
GITLAB_SHARED_DIND_DIR: /builds/$CI_PROJECT_PATH/shared
|
||||
GIT_SUBMODULE_STRATEGY: normal
|
||||
GIT_FETCH_EXTRA_FLAGS: --tags
|
||||
|
||||
stages:
|
||||
- www
|
||||
- build
|
||||
- upload
|
||||
|
||||
.prepare_build: &prepare_build
|
||||
- ls -l
|
||||
- pwd
|
||||
- apk add bash
|
||||
- mkdir -p "$GITLAB_SHARED_DIND_DIR" && chmod 777 "$GITLAB_SHARED_DIND_DIR"
|
||||
|
||||
.prepare_www: &prepare_www
|
||||
- tar -zxf output/www/kasm_www.tar.gz -C builder/
|
||||
|
||||
.prepare_artfacts: &prepare_artfacts
|
||||
- mkdir output
|
||||
- cp -r builder/build/* output/
|
||||
- rm output/*.tar.gz
|
||||
|
||||
build_ubuntu_bionic:
|
||||
stage: build
|
||||
build_www:
|
||||
stage: www
|
||||
allow_failure: false
|
||||
before_script:
|
||||
- *prepare_build
|
||||
script:
|
||||
- webpacked_www=$PWD/builder/www
|
||||
- src_www=kasmweb
|
||||
- docker build -t kasmweb/www -f builder/dockerfile.www.build .
|
||||
- docker run --rm -v $PWD/builder/www:/build kasmweb/www:latest
|
||||
- mkdir -p output/www
|
||||
- cd builder
|
||||
- tar -zcvf ../output/www/kasm_www.tar.gz www
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_ubuntu_bionic:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
@@ -33,46 +55,150 @@ build_ubuntu_bionic:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_ubuntu_focal:
|
||||
build_ubuntu_bionic_arm:
|
||||
stage: build
|
||||
allow_failure: false
|
||||
tags:
|
||||
- arm
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package ubuntu bionic
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_ubuntu_bionic_libjpeg_turbo:
|
||||
stage: build
|
||||
allow_failure: false
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package ubuntu bionic +libjpeg-turbo_latest
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_ubuntu_focal:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package ubuntu focal;
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [Cc][Ii]\]/
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_ubuntu_focal_arm:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
tags:
|
||||
- arm
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package ubuntu focal;
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [Cc][Ii]\]/
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_debian_buster:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package debian buster;
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_debian_buster_arm:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
tags:
|
||||
- arm
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package debian buster;
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_debian_bullseye:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package debian bullseye;
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_debian_bullseye_arm:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
tags:
|
||||
- arm
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package debian bullseye;
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_kali_rolling:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
@@ -83,8 +209,10 @@ build_kali_rolling:
|
||||
|
||||
build_centos7:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
@@ -102,9 +230,11 @@ upload:
|
||||
- export S3_BUILD_DIRECTORY="kasmvnc/${CI_COMMIT_SHA}"
|
||||
- prepare_to_run_scripts_and_s3_uploads
|
||||
- export RELEASE_VERSION=$(.ci/next_release_version "$CI_COMMIT_REF_NAME")
|
||||
- for package in `find output/ -type f -name 'kasmvncserver_*.deb' -or -name '*.rpm'`; do
|
||||
- for package in `find output/ -type f -name '*.deb' -or -name '*.rpm'`; do
|
||||
prepare_upload_filename "$package";
|
||||
echo;
|
||||
echo "File to upload $upload_filename";
|
||||
upload_to_s3 "$package" "$upload_filename";
|
||||
UPLOAD_NAME=$(echo $upload_filename | sed 's#kasmvncserver_##' | sed -r 's#_([0-9]{1,3}\.){2}[0-9]{1,2}_\S+?([a-f0-9]{6})##' | sed -r 's#\.(deb|rpm)##');
|
||||
curl --request POST --header "PRIVATE-TOKEN:${GITLAB_API_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/statuses/${CI_COMMIT_SHA}?state=success&name=${UPLOAD_NAME}&target_url=${S3_URL}";
|
||||
done
|
||||
|
||||
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
[submodule "kasmweb"]
|
||||
path = kasmweb
|
||||
url = https://github.com/kasmtech/noVNC.git
|
||||
branch = master
|
||||
@@ -20,7 +20,7 @@ Incomplete and generally out of date copyright list::
|
||||
All Rights Reserved.
|
||||
|
||||
This software is distributed under the GNU General Public Licence as published
|
||||
by the Free Software Foundation. See the file LICENCE.TXT for the conditions
|
||||
by the Free Software Foundation. See the file LICENSE.TXT for the conditions
|
||||
under which this software is made available. KasmVNC also contains code from
|
||||
other sources. See the Acknowledgements section below, and the individual
|
||||
source files, for details of the conditions under which they are made
|
||||
@@ -105,4 +105,4 @@ This distribution contains software from the X Window System. This is:
|
||||
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
SOFTWARE.
|
||||
SOFTWARE.
|
||||
|
||||
@@ -16,6 +16,7 @@ include(CheckLibraryExists)
|
||||
include(CheckTypeSize)
|
||||
include(CheckCSourceCompiles)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckCSourceRuns)
|
||||
|
||||
include(CMakeMacroLibtoolFile)
|
||||
@@ -208,6 +209,9 @@ if(ENABLE_PAM)
|
||||
endif()
|
||||
set(HAVE_PAM ${ENABLE_PAM})
|
||||
|
||||
# Check for SSE2
|
||||
check_cxx_compiler_flag(-msse2 COMPILER_SUPPORTS_SSE2)
|
||||
|
||||
# Generate config.h and make sure the source finds it
|
||||
configure_file(config.h.in config.h)
|
||||
add_definitions(-DHAVE_CONFIG_H)
|
||||
|
||||
15
Pipfile
Normal file
15
Pipfile
Normal file
@@ -0,0 +1,15 @@
|
||||
[[source]]
|
||||
url = "https://pypi.python.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
mamba = "*"
|
||||
expects = "*"
|
||||
"path.py" = "*"
|
||||
pexpect = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.8"
|
||||
136
Pipfile.lock
generated
Normal file
136
Pipfile.lock
generated
Normal file
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "6745d5e5d90e44a18d73a0e23bc3d3e68acb950af0b87df50b45272d25b9e615"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.8"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.python.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"args": {
|
||||
"hashes": [
|
||||
"sha256:a785b8d837625e9b61c39108532d95b85274acd679693b71ebb5156848fcf814"
|
||||
],
|
||||
"version": "==0.1.0"
|
||||
},
|
||||
"clint": {
|
||||
"hashes": [
|
||||
"sha256:05224c32b1075563d0b16d0015faaf9da43aa214e4a2140e51f08789e7a4c5aa"
|
||||
],
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"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"
|
||||
],
|
||||
"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"
|
||||
},
|
||||
"expects": {
|
||||
"hashes": [
|
||||
"sha256:419902ccafe81b7e9559eeb6b7a07ef9d5c5604eddb93000f0642b3b2d594f4c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.9.0"
|
||||
},
|
||||
"mamba": {
|
||||
"hashes": [
|
||||
"sha256:75cfc6dfd287dcccaf86dd753cf48e0a7337487c7c3fafda05a6a67ded6da496"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.11.2"
|
||||
},
|
||||
"path": {
|
||||
"hashes": [
|
||||
"sha256:2de925e8d421f93bcea80d511b81accfb6a7e6b249afa4a5559557b0cf817097",
|
||||
"sha256:340054c5bb459fc9fd40e7eb6768c5989f3e599d18224238465b5333bc8faa7d"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==16.2.0"
|
||||
},
|
||||
"path.py": {
|
||||
"hashes": [
|
||||
"sha256:8d885e8b2497aed005703d94e0fd97943401f035e42a136810308bff034529a8",
|
||||
"sha256:a43e82eb2c344c3fd0b9d6352f6b856f40b8b7d3d65cc05978b42c3715668496"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==12.5.0"
|
||||
},
|
||||
"pexpect": {
|
||||
"hashes": [
|
||||
"sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937",
|
||||
"sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.8.0"
|
||||
},
|
||||
"ptyprocess": {
|
||||
"hashes": [
|
||||
"sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35",
|
||||
"sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"
|
||||
],
|
||||
"version": "==0.7.0"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
||||
54
README.md
54
README.md
@@ -1,11 +1,11 @@
|
||||
# KasmVNC - Linux Web Remote Desktop
|
||||
|
||||
[](https://kasmweb.com)
|
||||
|
||||
[Kasm Technologies LLC](https://www.kasmweb.com) developed Kasm Server, a Containerized Desktop Infrastructure (CDI) solution. Kasm started with TigerVNC and eventually forked it to create KasmVNC. KasmVNC is used within the overal Kasm CDI infrastructure, however, you can use KasmVNC for individual servers. KasmVNC has different goals than TigerVNC:
|
||||
<a href="https://kasmweb.com"><img src="https://kasm-static-content.s3.amazonaws.com/logo_kasm.png" width="300"><a/>
|
||||
|
||||
[Kasm Technologies](https://www.kasmweb.com) developed Kasm Workspaces, the Containerized Streaming Platform. Kasm has open-sourced the Workspace docker images, which include containerized [full desktops and apps](https://github.com/kasmtech/workspaces-images) and [base images](https://github.com/kasmtech/workspaces-core-images) intended for developers to create custimized streaming containers. These containers can be used standalone or within the [Kasm Workspaces Platform](https://www.kasmweb.com) which provides a full Enterprise feature set. KasmVNC is used as the streaming tech for our container images, however, you can use KasmVNC for individual servers. While the term VNC is in the name, KasmVNC is not intended to remain compliant with the RFB spec and has different goals than other VNC projects:
|
||||
|
||||
- Web-based - KasmVNC is designed to provide a web accessible remote desktop. It comes with a web server and websocket server built in. There is no need to install other components. Simply run and navigate to your desktop's URL on the port you specify. While you can still tun on the legacy VNC port, it is disabled by default.
|
||||
- Security - KasmVNC defaults to HTTPS and allows for HTTP Basic Auth. VNC Password authentication is limited by specification to 8 characters and is not suffecient for use on an internet accessible remote desktop. Our goal is to create a by default secure, web based experience.
|
||||
- Security - The RFB specification (VNC) limits the password field to 8 characters, so while the client may take a longer password, only the first 8 characters are sent. KasmVNC defaults to HTTPS with HTTP Basic Auth and disables the legacy VNC authentication method which is not sufficiently secure for internet accessible systems.
|
||||
- Simplicity - KasmVNC aims at being simple to deploy and configure.
|
||||
|
||||
# New Features!
|
||||
@@ -42,30 +42,30 @@ Future Goals:
|
||||
#### Debian-based
|
||||
|
||||
```sh
|
||||
wget -qO- https://github.com/kasmtech/KasmVNC/releases/download/v0.9.1-beta/kasmvncserver_0.9.1~beta-1_amd64.deb
|
||||
wget https://github.com/kasmtech/KasmVNC/releases/download/v0.9.2-beta/kasmvncserver_ubuntu_bionic_0.9.2_amd64.deb
|
||||
|
||||
sudo dpkg -i kasmvncserver_0.9.1~beta-1_amd64.deb
|
||||
sudo apt-get -f install
|
||||
|
||||
# We provide an example script to run KasmVNC at #
|
||||
# /usr/share/doc/kasmvncserver/examples/kasmvncserver-easy-start. It runs a VNC
|
||||
# server on display :10 and on interface 0.0.0.0. If you're happy with those
|
||||
# defaults you can just use it as is:
|
||||
sudo ln -s /usr/share/doc/kasmvncserver/examples/kasmvncserver-easy-start /usr/bin/
|
||||
sudo apt-get install ./kasmvncserver_0.9.1~beta-1_amd64.deb
|
||||
|
||||
# Add your user to the ssl-cert group
|
||||
sudo addgroup $USER ssl-cert
|
||||
# You will need to re-connect in order to pick up the group change
|
||||
|
||||
# Create ~/.vnc directory and corresponding files.
|
||||
kasmvncserver-easy-start -d && kasmvncserver-easy-start -kill
|
||||
# Run KasmVNC on display :10 and on interface 0.0.0.0:
|
||||
KASMVNC_OPTIONS=':10 -depth 24 -geometry 1280x1050
|
||||
-cert /etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||
-key /etc/ssl/private/ssl-cert-snakeoil.key -sslOnly -FrameRate=24
|
||||
-interface 0.0.0.0 -httpd /usr/share/kasmvnc/www'
|
||||
vncserver $KASMVNC_OPTIONS
|
||||
|
||||
# Modify vncstartup to launch your environment of choice, in this example LXDE
|
||||
# This may be optional depending on your system configuration
|
||||
echo '/usr/bin/lxsession -s LXDE &' >> ~/.vnc/xstartup
|
||||
# On the first run, vncserver will ask you to create a KasmVNC user and choose a desktop
|
||||
# environment you want to run. It can detect Cinnamon, Mate, LXDE, KDE, Gnome,
|
||||
# XFCE. You can also choose to manually edit xstartup.
|
||||
# After you chose a desktop environment or to manually edit xstartup,
|
||||
# vncserver won't ask you again, unless you run it as:
|
||||
vncserver $KASMVNC_OPTIONS -select-de
|
||||
|
||||
# Start KasmVNC with debug logging:
|
||||
kasmvncserver-easy-start -d
|
||||
# You can select a specific Desktop Environment like this:
|
||||
vncserver $KASMVNC_OPTIONS -select-de mate
|
||||
|
||||
# Tail the logs
|
||||
tail -f ~/.vnc/`hostname`:10.log
|
||||
@@ -73,10 +73,10 @@ tail -f ~/.vnc/`hostname`:10.log
|
||||
|
||||
Now navigate to your system at https://[ip-address]:8443/
|
||||
|
||||
To stop a running KasmVNC:
|
||||
To stop the KasmVNC you started earlier on display 10:
|
||||
|
||||
```sh
|
||||
kasmvncserver-easy-start -kill
|
||||
vncserver -kill :10
|
||||
```
|
||||
|
||||
The options for vncserver:
|
||||
@@ -91,14 +91,16 @@ The options for vncserver:
|
||||
| interface | Which interface to bind the web server to. |
|
||||
|
||||
### Development
|
||||
Would you like to contribute to KasmVNC? Please reachout to us at info@kasmweb.com
|
||||
Would you like to contribute to KasmVNC? Please reachout to us at info@kasmweb.com. We have investigated or are working on the following, if you have experience in these fields and would like to help please let us know.
|
||||
|
||||
We need help, especially in packaging KasmVNC for various operating systems. We would love to have standard debian or RMP packages and host our own repo, however, that all requires a lot of experience, proper testing, and pipeline development for automated builds.
|
||||
Real-time H264 encoding using NVIDIA and Intel encoding technology.
|
||||
|
||||
We also need help with Windows, which is not currently supported. While KasmVNC can technically be built for Windows 10, it is unusably slow, due to all the changes that occured in Windows since the original Windows support was added in the chain of VNC forked projects.
|
||||
Windows version of KasmVNC. We have been able to get it to compile for Windows and increased the performance, but still not releasable. Experienced Windows developers with a background in cross compiling would help.
|
||||
|
||||
ARM version of KasmVNC, we have had requests for this and at one point we did have an ARM build of KasmVNC but it takes dev cycles to mainain and bring it back to life.
|
||||
|
||||
### Compiling From Source
|
||||
See the [builder/README.md](https://github.com/kasmtech/KasmVNC/blob/master/builder/README.md). We containerize our build systems to ensure highly repeatable builds.
|
||||
|
||||
### License and Acknowledgements
|
||||
See the [LICENSE.TXT](https://github.com/kasmtech/KasmVNC/blob/master/LICENCE.TXT) and [ACKNOWLEDGEMENTS.MD](https://github.com/kasmtech/KasmVNC/blob/master/LICENSE.TXT)
|
||||
See the [LICENSE.TXT](https://github.com/kasmtech/KasmVNC/blob/master/LICENSE.TXT) and [ACKNOWLEDGEMENTS.MD](https://github.com/kasmtech/KasmVNC/blob/master/LICENSE.TXT)
|
||||
|
||||
@@ -3,8 +3,17 @@ Docker CE
|
||||
|
||||
# Build a deb/rpm package
|
||||
```
|
||||
# builder/build-package <os> <os_codename>
|
||||
# builder/build-package <os> <os_codename> <build_tag>
|
||||
# os_codename is what "lsb_release -c" outputs, e.g. buster, focal.
|
||||
#
|
||||
# build_tag allows building multiple versions of deb package (rpm not supported)
|
||||
# targeting a single distro release (e.g. Ubuntu Bionic). If build_tag is given,
|
||||
# the package name will include build_tag as part of Debian revision. For
|
||||
# example:
|
||||
# * with build_tag: kasmvncserver_0.9.1~beta-1+libjpeg-turbo-latest_amd64.deb
|
||||
# * without build_tag: kasmvncserver_0.9.1~beta-1_amd64.deb
|
||||
# You need to have .build and .deb.build for the build_tag.
|
||||
#
|
||||
# Packages will be placed under builder/build/
|
||||
|
||||
builder/build-package ubuntu bionic
|
||||
@@ -70,3 +79,63 @@ packages installed with XFCE.
|
||||
```
|
||||
builder/test-deb-barebones ubuntu focal
|
||||
```
|
||||
|
||||
# Preparing a release
|
||||
|
||||
Deb and rpm packages need their versions bumped to the new release version. It
|
||||
can be done with:
|
||||
|
||||
```
|
||||
builder/bump-package-version 0.9.4-beta
|
||||
```
|
||||
|
||||
This will update corresponding package files, use `git diff` to see changes.
|
||||
|
||||
If you've ran the command and curious about Debian version specifics, here's an
|
||||
explanation:
|
||||
Deb version will be `0.9.4~beta-1`. `~` (and not `-`) is required by packaging
|
||||
guidelines, and `-1` is Debian package revision for `0.9.4` upstream release. If
|
||||
a Debian-specific patch was later added on top of `0.9.4`, it'd be `-2` for the
|
||||
next Debian version. Rpm has a corresponding revision in its .spec file.
|
||||
|
||||
# CI development
|
||||
|
||||
S3 upload code is extracted to various files in `.ci`. It's possible to iterate
|
||||
locally by doing stuff like this:
|
||||
|
||||
```
|
||||
bash -c '
|
||||
. .ci/upload.sh;
|
||||
prepare_upload_filename "bionic/kasmvncserver_0.9.1~beta-1+libjpeg-turbo-latest_amd64.deb";
|
||||
echo $upload_filename;'
|
||||
```
|
||||
|
||||
# ARM
|
||||
|
||||
KasmVNC is supported on ARM, however, the build process needs to be broken into two parts with one occuring on a x64 system and the other on an ARM system. All our testing and official builds are done on AWS Graviton instances.
|
||||
|
||||
### Build www code on x86 System
|
||||
The www code is webpacked for performance and thus requires building. There are NPM packages, phantomjs, which do not have an ARM build. Therefore, this must be built on x86 and then copied over to the ARM system for final packaging.
|
||||
|
||||
```
|
||||
cd ~/KasmVNC
|
||||
mkdir builder/www
|
||||
sudo docker build -t kasmweb/www -f builder/dockerfile.www.build .
|
||||
sudo docker run --rm -v $PWD/builder/www:/build kasmweb/www:latest
|
||||
cd builder
|
||||
tar -zcvf /tmp/kasm_www.tar.gz www
|
||||
```
|
||||
|
||||
Now transfer ```kasm_www.tar.gz``` to the ARM system.
|
||||
|
||||
### Build KasmVNC ARM
|
||||
These instructions assume KasmVNC has been cloned at $HOME and ```kasm_www.tar.gz``` has been placed at $HOME as well, adjust for your environment.
|
||||
|
||||
```
|
||||
cd ~
|
||||
tar -zxf kasm_www.tar.gz -C KasmVNC/builder/
|
||||
cd KasmVNC
|
||||
sudo builder/build-package ubuntu bionic
|
||||
```
|
||||
The resulting deb package can be found under ~/KasmVNC/builder/build/bionic
|
||||
Replace ```bionic``` with ```focal``` to build for Ubuntu 20.04LTS. At this time, only Ubuntu Bionic has been tested, however, other Debian based builds we support should also work.
|
||||
|
||||
@@ -5,12 +5,17 @@ set -e
|
||||
cd "$(dirname "$0")/.."
|
||||
. builder/os_ver_cli.sh
|
||||
|
||||
docker build -t debbuilder_${os}:${os_codename} -f \
|
||||
builder/dockerfile.${os}_${os_codename}.deb.build .
|
||||
|
||||
deb_output_dir=$(cd .. && echo $PWD)
|
||||
L_UID=$(id -u) #Ubuntu already has UID env var, but this should work on all Linix systems
|
||||
L_GID=$(id -g)
|
||||
docker run --rm -v "$deb_output_dir":/src --user $L_UID:$L_GID \
|
||||
debbuilder_${os}:${os_codename} /bin/bash -c \
|
||||
|
||||
builder_image=debbuilder_${os}:${os_codename}${build_tag_for_images}
|
||||
docker build --build-arg KASMVNC_PACKAGE_DIR="builder/build/${os_codename}" \
|
||||
--build-arg L_UID="$L_UID" \
|
||||
-t "$builder_image" -f \
|
||||
builder/dockerfile.${os}_${os_codename}${build_tag}.deb.build .
|
||||
|
||||
deb_output_dir=$(cd .. && echo $PWD)
|
||||
docker run --rm -v "$deb_output_dir":/src -e BUILD_TAG="$build_tag" \
|
||||
--user "$L_UID:$L_GID" \
|
||||
"$builder_image" /bin/bash -c \
|
||||
'/src/*/builder/build-deb-inside-docker'
|
||||
|
||||
@@ -2,12 +2,31 @@
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
prepare_docker_copy_of_debian_dir_and_cd_to_id() {
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
local mounted_src_dir="$PWD"
|
||||
local docker_src_dir="$HOME/src"
|
||||
|
||||
mkdir "$docker_src_dir"
|
||||
cd "$docker_src_dir"
|
||||
cp -a "$mounted_src_dir/debian/" .
|
||||
ln -s "$mounted_src_dir/builder" .
|
||||
}
|
||||
|
||||
prepare_docker_copy_of_debian_dir_and_cd_to_id
|
||||
|
||||
os=$(lsb_release -is | tr '[:upper:]' '[:lower:]')
|
||||
os_codename=$(lsb_release -cs)
|
||||
os_dir="builder/build/${os_codename}"
|
||||
|
||||
if [ "$BUILD_TAG" = "+libjpeg-turbo_latest" ]; then
|
||||
echo 'libjpeg 62 libjpeg-turbo (>= 2.1.1)' > debian/shlibs.local
|
||||
|
||||
debian_revision="$(echo $BUILD_TAG | tr _ -)"
|
||||
sed -i -e "1 s/)/$debian_revision)/" debian/changelog
|
||||
fi
|
||||
|
||||
dpkg-buildpackage -us -uc -b
|
||||
mkdir -p "$os_dir"
|
||||
cp ../*.deb "$os_dir"
|
||||
|
||||
@@ -4,6 +4,7 @@ set -e
|
||||
|
||||
os="$1"
|
||||
codename="$2"
|
||||
build_tag="$3"
|
||||
|
||||
detect_package_format() {
|
||||
package_format=rpm
|
||||
@@ -12,8 +13,17 @@ detect_package_format() {
|
||||
fi
|
||||
}
|
||||
|
||||
warn_build_tag_not_supported_for_rpm_and_exit() {
|
||||
if [[ "$build_tag" && "$package_format" = "rpm" ]]; then
|
||||
echo >&2 "<build_tag> isn't supported for rpm"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
detect_package_format
|
||||
builder/build-tarball "$os" "$codename"
|
||||
builder/build-${package_format} "$os" "$codename"
|
||||
warn_build_tag_not_supported_for_rpm_and_exit
|
||||
|
||||
builder/build-tarball "$os" "$codename" "$build_tag"
|
||||
builder/build-${package_format} "$os" "$codename" "$build_tag"
|
||||
|
||||
@@ -2,8 +2,18 @@
|
||||
|
||||
set -e
|
||||
|
||||
warn_build_tag_not_supported_for_rpm_and_exit() {
|
||||
local build_tag="$1"
|
||||
|
||||
if [[ -n "$build_tag" ]]; then
|
||||
echo >&2 "<build_tag> isn't supported for rpm"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
. builder/os_ver_cli.sh
|
||||
warn_build_tag_not_supported_for_rpm_and_exit "$build_tag"
|
||||
|
||||
docker build -t kasmvnc_rpmbuilder_${os}:${os_codename} -f \
|
||||
builder/dockerfile.${os}_${os_codename}.rpm.build .
|
||||
|
||||
@@ -12,6 +12,13 @@ build_www_dir() {
|
||||
fi
|
||||
}
|
||||
|
||||
move_libjpeg_turbo_to_os_specific_dir() {
|
||||
chown $L_UID:$L_GID $shared_with_docker_dir/${os_codename}/*
|
||||
mkdir -p $PWD/builder/build/${os_codename}/
|
||||
mv $shared_with_docker_dir/${os_codename}/libjpeg-turbo*.deb \
|
||||
$PWD/builder/build/${os_codename}/
|
||||
}
|
||||
|
||||
shared_with_docker_dir=${GITLAB_SHARED_DIND_DIR:-/tmp}
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
@@ -19,13 +26,21 @@ cd "$(dirname "$0")/.."
|
||||
|
||||
build_www_dir
|
||||
|
||||
docker build -t kasmvncbuilder:$os_codename \
|
||||
-f builder/dockerfile.${os}_${os_codename}.build .
|
||||
builder_image=kasmvncbuilder:$os_codename${build_tag_for_images}
|
||||
docker build -t "$builder_image" \
|
||||
-f builder/dockerfile.${os}_${os_codename}${build_tag}.build .
|
||||
mkdir -p builder/build
|
||||
docker run -v $shared_with_docker_dir:/build --rm kasmvncbuilder:$os_codename
|
||||
docker run -v $shared_with_docker_dir:/build -e BUILD_TAG="$build_tag" \
|
||||
--rm "$builder_image"
|
||||
|
||||
L_GID=$(id -g)
|
||||
L_UID=$(id -u)
|
||||
tarball_name="kasmvnc.${os}_${os_codename}.tar.gz"
|
||||
tarball_name_with_build_tag="kasmvnc.${os}_${os_codename}${build_tag}.tar.gz"
|
||||
chown $L_UID:$L_GID $shared_with_docker_dir/$tarball_name
|
||||
mv $shared_with_docker_dir/$tarball_name $PWD/builder/build/
|
||||
mv $shared_with_docker_dir/$tarball_name \
|
||||
$PWD/builder/build/"$tarball_name_with_build_tag"
|
||||
|
||||
if [ "$build_tag" = "+libjpeg-turbo_latest" ]; then
|
||||
move_libjpeg_turbo_to_os_specific_dir
|
||||
fi
|
||||
|
||||
@@ -17,7 +17,7 @@ cd /tmp
|
||||
# default to the version of x in Ubuntu 18.04, otherwise caller will need to specify
|
||||
XORG_VER=${XORG_VER:-"1.19.6"}
|
||||
XORG_PATCH=$(echo "$XORG_VER" | grep -Po '^\d.\d+' | sed 's#\.##')
|
||||
wget https://www.x.org/archive/individual/xserver/xorg-server-${XORG_VER}.tar.bz2
|
||||
wget --no-check-certificate https://www.x.org/archive/individual/xserver/xorg-server-${XORG_VER}.tar.bz2
|
||||
|
||||
#git clone https://kasmweb@bitbucket.org/kasmtech/kasmvnc.git
|
||||
#cd kasmvnc
|
||||
@@ -30,16 +30,19 @@ sed -i -e '/find_package(FLTK/s@^@#@' \
|
||||
-e '/add_subdirectory(tests/s@^@#@' \
|
||||
CMakeLists.txt
|
||||
|
||||
cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo .
|
||||
cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo . -DBUILD_VIEWER:BOOL=OFF
|
||||
make -j5
|
||||
|
||||
tar -C unix/xserver -xvf /tmp/xorg-server-${XORG_VER}.tar.bz2 --strip-components=1
|
||||
tar -C unix/xserver -xf /tmp/xorg-server-${XORG_VER}.tar.bz2 --strip-components=1
|
||||
|
||||
cd unix/xserver
|
||||
patch -Np1 -i ../xserver${XORG_PATCH}.patch
|
||||
if [[ $XORG_VER =~ ^1\.20\..*$ ]]; then
|
||||
patch -Np1 -i ../xserver120.7.patch
|
||||
fi
|
||||
case "$XORG_VER" in
|
||||
1.20.*)
|
||||
if [ -f ../xserver120.7.patch ]; then
|
||||
patch -Np1 -i ../xserver120.7.patch
|
||||
fi ;;
|
||||
esac
|
||||
|
||||
autoreconf -i
|
||||
# Configuring Xorg is long and has many distro-specific paths.
|
||||
@@ -72,6 +75,8 @@ mkdir lib
|
||||
cd lib
|
||||
if [ -d /usr/lib/x86_64-linux-gnu/dri ]; then
|
||||
ln -s /usr/lib/x86_64-linux-gnu/dri dri
|
||||
elif [ -d /usr/lib/aarch64-linux-gnu/dri ]; then
|
||||
ln -s /usr/lib/aarch64-linux-gnu/dri dri
|
||||
else
|
||||
ln -s /usr/lib64/dri dri
|
||||
fi
|
||||
@@ -84,3 +89,7 @@ fi
|
||||
make servertarball
|
||||
|
||||
cp kasmvnc*.tar.gz /build/kasmvnc.${KASMVNC_BUILD_OS}_${KASMVNC_BUILD_OS_CODENAME}.tar.gz
|
||||
if [ "$BUILD_TAG" = "+libjpeg-turbo_latest" ]; then
|
||||
mkdir -p /build/${KASMVNC_BUILD_OS_CODENAME}/
|
||||
cp /libjpeg-turbo/libjpeg*.deb /build/${KASMVNC_BUILD_OS_CODENAME}/
|
||||
fi
|
||||
|
||||
@@ -14,6 +14,5 @@ cp -R ./* /build/
|
||||
cd /build
|
||||
rm *.md
|
||||
rm AUTHORS
|
||||
rm *.yml
|
||||
rm vnc.html
|
||||
rm vnc_lite.html
|
||||
|
||||
41
builder/bump-package-version
Executable file
41
builder/bump-package-version
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
update_version_to_meet_packaging_standards() {
|
||||
new_version=$(echo "$new_version" |
|
||||
sed -e 's/\([0-9]\)-\([a-zA-Z]\)/\1~\2/')
|
||||
}
|
||||
|
||||
add_debian_revision_to_new_version() {
|
||||
echo "$new_version-1"
|
||||
}
|
||||
|
||||
bump_rpm() {
|
||||
sed -i "s/^Version:.\+/Version: $new_version/" centos/kasmvncserver.spec
|
||||
}
|
||||
|
||||
bump_deb() {
|
||||
local image="debbump_package_version:dev"
|
||||
local L_UID=$(id -u)
|
||||
local L_GID=$(id -g)
|
||||
local debian_version=$(add_debian_revision_to_new_version)
|
||||
|
||||
docker build -t "$image" -f builder/dockerfile.bump-package-version .
|
||||
docker run --rm -v "$PWD":/src --user "$L_UID:$L_GID" \
|
||||
"$image" /bin/bash -c \
|
||||
"cd /src && builder/bump-package-version-inside-docker-deb $debian_version"
|
||||
}
|
||||
|
||||
new_version="$1"
|
||||
|
||||
if [[ -z "$new_version" ]]; then
|
||||
echo >&2 "Usage: $(basename "$0") <new_version>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
update_version_to_meet_packaging_standards
|
||||
bump_rpm
|
||||
bump_deb
|
||||
15
builder/bump-package-version-inside-docker-deb
Executable file
15
builder/bump-package-version-inside-docker-deb
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
new_version="$1"
|
||||
|
||||
update_version() {
|
||||
dch --newversion $new_version 'New upstream release.'
|
||||
}
|
||||
|
||||
mark_as_released() {
|
||||
dch --release ""
|
||||
}
|
||||
|
||||
update_version
|
||||
mark_as_released
|
||||
6
builder/dockerfile.bump-package-version
Normal file
6
builder/dockerfile.bump-package-version
Normal file
@@ -0,0 +1,6 @@
|
||||
FROM debian:buster
|
||||
|
||||
ENV DEBEMAIL="Kasm Technologies LLC <info@kasmweb.com>"
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install vim devscripts
|
||||
@@ -3,6 +3,7 @@ FROM centos:centos7
|
||||
ENV KASMVNC_BUILD_OS centos
|
||||
ENV KASMVNC_BUILD_OS_CODENAME core
|
||||
|
||||
RUN yum update -y ca-certificates
|
||||
RUN yum install -y build-dep xorg-server libxfont-dev sudo
|
||||
RUN yum install -y gcc cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver
|
||||
RUN yum install -y libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev openssl-devel
|
||||
@@ -15,15 +16,14 @@ RUN yum install -y mesa-dri-drivers
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
||||
RUN cd /tmp/libwebp-1.0.2 && \
|
||||
./configure --enable-static --disable-shared && \
|
||||
make && make install
|
||||
|
||||
RUN useradd -m docker && echo "docker:docker" | chpasswd
|
||||
|
||||
COPY . /src
|
||||
RUN chown -R docker:docker /src
|
||||
COPY --chown=docker:docker . /src/
|
||||
|
||||
USER docker
|
||||
ENTRYPOINT ["/src/builder/build.sh"]
|
||||
|
||||
@@ -37,6 +37,7 @@ RUN yum install -y epel-release && yum groupinstall xfce -y
|
||||
RUN yum erase -y pm-utils xscreensaver*
|
||||
RUN yum install -y redhat-lsb-core
|
||||
RUN yum install -y vim less
|
||||
RUN yum localinstall -y --nogpgcheck https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-7.noarch.rpm https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-7.noarch.rpm
|
||||
|
||||
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
|
||||
|
||||
|
||||
@@ -17,15 +17,14 @@ RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libg
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
||||
RUN cd /tmp/libwebp-1.0.2 && \
|
||||
./configure --enable-static --disable-shared && \
|
||||
make && make install
|
||||
|
||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||
|
||||
COPY . /src
|
||||
RUN chown -R docker:docker /src
|
||||
COPY --chown=docker:docker . /src/
|
||||
|
||||
USER docker
|
||||
ENTRYPOINT ["/src/builder/build.sh"]
|
||||
|
||||
@@ -9,4 +9,11 @@ RUN apt-get update && \
|
||||
COPY ./debian/control /tmp
|
||||
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
||||
|
||||
USER 1000
|
||||
ARG L_UID
|
||||
RUN if [ "$L_UID" -eq 0 ]; then \
|
||||
useradd -m docker; \
|
||||
else \
|
||||
useradd -m docker -u $L_UID;\
|
||||
fi
|
||||
|
||||
USER docker
|
||||
|
||||
@@ -42,8 +42,8 @@ COPY startup/ $STARTUPDIR
|
||||
### START CUSTOM STUFF ####
|
||||
|
||||
ARG KASMVNC_PACKAGE_DIR
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||
RUN dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
|
||||
### END CUSTOM STUFF ###
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
FROM debian:buster-slim
|
||||
|
||||
ARG KASMVNC_PACKAGE_DIR
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||
RUN apt-get update && dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; apt-get update && dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
RUN apt-get update && apt-get -y install xterm
|
||||
|
||||
COPY startup/deb/kasmvncserver-easy-start /usr/local/bin
|
||||
|
||||
@@ -17,15 +17,14 @@ RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libg
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
||||
RUN cd /tmp/libwebp-1.0.2 && \
|
||||
./configure --enable-static --disable-shared && \
|
||||
make && make install
|
||||
|
||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||
|
||||
COPY . /src
|
||||
RUN chown -R docker:docker /src
|
||||
COPY --chown=docker:docker . /src/
|
||||
|
||||
USER docker
|
||||
ENTRYPOINT ["/src/builder/build.sh"]
|
||||
|
||||
@@ -9,4 +9,11 @@ RUN apt-get update && \
|
||||
COPY ./debian/control /tmp
|
||||
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
||||
|
||||
USER 1000
|
||||
ARG L_UID
|
||||
RUN if [ "$L_UID" -eq 0 ]; then \
|
||||
useradd -m docker; \
|
||||
else \
|
||||
useradd -m docker -u $L_UID;\
|
||||
fi
|
||||
|
||||
USER docker
|
||||
|
||||
@@ -34,6 +34,14 @@ RUN apt-get purge -y pm-utils xscreensaver*
|
||||
RUN apt-get update && apt-get install -y vim less
|
||||
RUN apt-get update && apt-get -y install lsb-release
|
||||
|
||||
RUN apt-get update && apt-get install -y task-cinnamon-desktop
|
||||
RUN apt-get update && apt-get install -y task-gnome-desktop
|
||||
RUN mkdir -p /usr/share/man/man1
|
||||
RUN apt-get update && apt-get install -y apt-utils openjdk-11-jre
|
||||
RUN apt-get update && apt-get install -y task-lxde-desktop
|
||||
RUN apt-get update && apt-get install -y task-mate-desktop
|
||||
RUN apt-get update && apt-get install -y task-kde-desktop
|
||||
|
||||
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
|
||||
|
||||
RUN mkdir -p $STARTUPDIR
|
||||
@@ -42,8 +50,8 @@ COPY startup/ $STARTUPDIR
|
||||
### START CUSTOM STUFF ####
|
||||
|
||||
ARG KASMVNC_PACKAGE_DIR
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||
RUN dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
|
||||
### END CUSTOM STUFF ###
|
||||
|
||||
|
||||
@@ -24,15 +24,14 @@ RUN dnf install -y bzip2 redhat-lsb-core
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
||||
RUN cd /tmp/libwebp-1.0.2 && \
|
||||
./configure --enable-static --disable-shared && \
|
||||
make && make install
|
||||
|
||||
RUN useradd -m docker && echo "docker:docker" | chpasswd
|
||||
|
||||
COPY . /src
|
||||
RUN chown -R docker:docker /src
|
||||
COPY --chown=docker:docker . /src/
|
||||
|
||||
USER docker
|
||||
ENTRYPOINT ["/src/builder/build.sh"]
|
||||
|
||||
@@ -17,15 +17,14 @@ RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libg
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
||||
RUN cd /tmp/libwebp-1.0.2 && \
|
||||
./configure --enable-static --disable-shared && \
|
||||
make && make install
|
||||
|
||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||
|
||||
COPY . /src
|
||||
RUN chown -R docker:docker /src
|
||||
COPY --chown=docker:docker . /src/
|
||||
|
||||
USER docker
|
||||
ENTRYPOINT ["/src/builder/build.sh"]
|
||||
|
||||
@@ -9,4 +9,11 @@ RUN apt-get update && \
|
||||
COPY ./debian/control /tmp
|
||||
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
||||
|
||||
USER 1000
|
||||
ARG L_UID
|
||||
RUN if [ "$L_UID" -eq 0 ]; then \
|
||||
useradd -m docker; \
|
||||
else \
|
||||
useradd -m docker -u $L_UID;\
|
||||
fi
|
||||
|
||||
USER docker
|
||||
|
||||
@@ -42,8 +42,8 @@ COPY startup/ $STARTUPDIR
|
||||
### START CUSTOM STUFF ####
|
||||
|
||||
ARG KASMVNC_PACKAGE_DIR
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||
RUN dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
|
||||
### END CUSTOM STUFF ###
|
||||
|
||||
|
||||
@@ -14,8 +14,7 @@ RUN cd /tmp/libwebp-1.0.2 && ./configure && make && make install
|
||||
|
||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||
|
||||
COPY . /src
|
||||
RUN chown -R docker:docker /src
|
||||
COPY --chown=docker:docker . /src/
|
||||
|
||||
|
||||
USER docker
|
||||
|
||||
39
builder/dockerfile.ubuntu_bionic+libjpeg-turbo_latest.build
Normal file
39
builder/dockerfile.ubuntu_bionic+libjpeg-turbo_latest.build
Normal file
@@ -0,0 +1,39 @@
|
||||
FROM ubuntu:18.04
|
||||
|
||||
ENV KASMVNC_BUILD_OS ubuntu
|
||||
ENV KASMVNC_BUILD_OS_CODENAME bionic
|
||||
ENV XORG_VER 1.20.10
|
||||
|
||||
RUN sed -i 's$# deb-src$deb-src$' /etc/apt/sources.list
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install sudo
|
||||
|
||||
RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev
|
||||
RUN apt-get update && apt-get -y install cmake git libgnutls28-dev vim wget tightvncserver
|
||||
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev
|
||||
|
||||
RUN apt-get update && apt-get install -y cmake nasm gcc
|
||||
RUN git clone https://github.com/libjpeg-turbo/libjpeg-turbo.git
|
||||
RUN export MAKEFLAGS=-j`nproc`; cd libjpeg-turbo && cmake -G"Unix Makefiles" && make deb
|
||||
RUN export MAKEFLAGS=-j`nproc`; cd libjpeg-turbo && cmake -DCMAKE_INSTALL_PREFIX=/usr/local -G"Unix Makefiles" && make && make install
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
||||
RUN cd /tmp/libwebp-1.0.2 && \
|
||||
./configure --enable-static --disable-shared && \
|
||||
make && make install
|
||||
|
||||
# Fix for older required libs
|
||||
#RUN cd /tmp && wget http://launchpadlibrarian.net/347526424/libxfont1-dev_1.5.2-4ubuntu2_amd64.deb && \
|
||||
# wget http://launchpadlibrarian.net/347526425/libxfont1_1.5.2-4ubuntu2_amd64.deb && \
|
||||
# dpkg -i libxfont1_1.5.2-4ubuntu2_amd64.deb && \
|
||||
# dpkg -i libxfont1-dev_1.5.2-4ubuntu2_amd64.deb
|
||||
|
||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||
|
||||
COPY --chown=docker:docker . /src
|
||||
|
||||
USER docker
|
||||
ENTRYPOINT ["/src/builder/build.sh"]
|
||||
@@ -0,0 +1,23 @@
|
||||
FROM ubuntu:bionic
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install vim build-essential devscripts equivs
|
||||
|
||||
ARG KASMVNC_PACKAGE_DIR
|
||||
COPY $KASMVNC_PACKAGE_DIR/libjpeg-turbo*deb /tmp
|
||||
RUN apt-get install /tmp/libjpeg-turbo*deb
|
||||
|
||||
# Install build-deps for the package.
|
||||
COPY ./debian/control /tmp
|
||||
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
||||
|
||||
ENV LD_LIBRARY_PATH="/opt/libjpeg-turbo/lib64/:$LD_LIBRARY_PATH"
|
||||
|
||||
ARG L_UID
|
||||
RUN if [ "$L_UID" -eq 0 ]; then \
|
||||
useradd -m docker; \
|
||||
else \
|
||||
useradd -m docker -u $L_UID;\
|
||||
fi
|
||||
|
||||
USER docker
|
||||
@@ -0,0 +1,58 @@
|
||||
FROM ubuntu:bionic
|
||||
|
||||
ENV DISPLAY=:1 \
|
||||
VNC_PORT=8443 \
|
||||
VNC_RESOLUTION=1280x720 \
|
||||
MAX_FRAME_RATE=24 \
|
||||
VNCOPTIONS="-PreferBandwidth -DynamicQualityMin=4 -DynamicQualityMax=7" \
|
||||
HOME=/home/user \
|
||||
TERM=xterm \
|
||||
STARTUPDIR=/dockerstartup \
|
||||
INST_SCRIPTS=/dockerstartup/install \
|
||||
KASM_RX_HOME=/dockerstartup/kasmrx \
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
VNC_COL_DEPTH=24 \
|
||||
VNC_RESOLUTION=1280x1024 \
|
||||
VNC_PW=vncpassword \
|
||||
VNC_USER=user \
|
||||
VNC_VIEW_ONLY_PW=vncviewonlypassword \
|
||||
LD_LIBRARY_PATH=/opt/libjpeg-turbo/lib64/:/usr/local/lib/ \
|
||||
OMP_WAIT_POLICY=PASSIVE \
|
||||
SHELL=/bin/bash \
|
||||
SINGLE_APPLICATION=0 \
|
||||
KASMVNC_BUILD_OS=ubuntu \
|
||||
KASMVNC_BUILD_OS_CODENAME=bionic
|
||||
|
||||
EXPOSE $VNC_PORT
|
||||
|
||||
WORKDIR $HOME
|
||||
|
||||
### REQUIRED STUFF ###
|
||||
|
||||
RUN apt-get update && apt-get install -y supervisor xfce4 xfce4-terminal xterm libnss-wrapper gettext wget
|
||||
RUN apt-get purge -y pm-utils xscreensaver*
|
||||
RUN apt-get update && apt-get install -y vim less
|
||||
RUN apt-get update && apt-get -y install lsb-release
|
||||
|
||||
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
|
||||
|
||||
RUN mkdir -p $STARTUPDIR
|
||||
COPY startup/ $STARTUPDIR
|
||||
|
||||
### START CUSTOM STUFF ####
|
||||
|
||||
ARG KASMVNC_PACKAGE_DIR
|
||||
COPY $KASMVNC_PACKAGE_DIR/libjpeg-turbo_*.deb /tmp
|
||||
RUN apt-get install /tmp/libjpeg-turbo*deb
|
||||
|
||||
ARG BUILD_DEBIAN_REVISION
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*$BUILD_DEBIAN_REVISION*.deb /tmp
|
||||
RUN dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
|
||||
### END CUSTOM STUFF ###
|
||||
|
||||
RUN chown -R 1000:0 $HOME
|
||||
USER 1000:ssl-cert
|
||||
WORKDIR $HOME
|
||||
|
||||
ENTRYPOINT [ "/dockerstartup/vnc_startup.sh" ]
|
||||
@@ -15,7 +15,7 @@ RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libg
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
||||
RUN cd /tmp/libwebp-1.0.2 && \
|
||||
./configure --enable-static --disable-shared && \
|
||||
make && make install
|
||||
@@ -28,8 +28,7 @@ RUN cd /tmp/libwebp-1.0.2 && \
|
||||
|
||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||
|
||||
COPY . /src
|
||||
RUN chown -R docker:docker /src
|
||||
COPY --chown=docker:docker . /src/
|
||||
|
||||
USER docker
|
||||
ENTRYPOINT ["/src/builder/build.sh"]
|
||||
|
||||
@@ -7,4 +7,11 @@ RUN apt-get update && \
|
||||
COPY ./debian/control /tmp
|
||||
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
||||
|
||||
USER 1000
|
||||
ARG L_UID
|
||||
RUN if [ "$L_UID" -eq 0 ]; then \
|
||||
useradd -m docker; \
|
||||
else \
|
||||
useradd -m docker -u $L_UID;\
|
||||
fi
|
||||
|
||||
USER docker
|
||||
|
||||
@@ -42,8 +42,8 @@ COPY startup/ $STARTUPDIR
|
||||
### START CUSTOM STUFF ####
|
||||
|
||||
ARG KASMVNC_PACKAGE_DIR
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||
RUN dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
|
||||
### END CUSTOM STUFF ###
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
FROM ubuntu:focal
|
||||
|
||||
ARG KASMVNC_PACKAGE_DIR
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||
RUN apt-get update && dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; apt-get update && dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
RUN apt-get update && apt-get -y install xterm lsb-release
|
||||
|
||||
RUN useradd -m foo && addgroup foo ssl-cert
|
||||
|
||||
@@ -17,15 +17,14 @@ RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libg
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
|
||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
||||
RUN cd /tmp/libwebp-1.0.2 && \
|
||||
./configure --enable-static --disable-shared && \
|
||||
make && make install
|
||||
|
||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||
|
||||
COPY . /src
|
||||
RUN chown -R docker:docker /src
|
||||
COPY --chown=docker:docker . /src/
|
||||
|
||||
USER docker
|
||||
ENTRYPOINT ["/src/builder/build.sh"]
|
||||
|
||||
@@ -9,4 +9,11 @@ RUN apt-get update && \
|
||||
COPY ./debian/control /tmp
|
||||
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
|
||||
|
||||
USER 1000
|
||||
ARG L_UID
|
||||
RUN if [ "$L_UID" -eq 0 ]; then \
|
||||
useradd -m docker; \
|
||||
else \
|
||||
useradd -m docker -u $L_UID;\
|
||||
fi
|
||||
|
||||
USER docker
|
||||
|
||||
@@ -42,8 +42,8 @@ COPY startup/ $STARTUPDIR
|
||||
### START CUSTOM STUFF ####
|
||||
|
||||
ARG KASMVNC_PACKAGE_DIR
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||
RUN dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
|
||||
RUN mkdir ~/.vnc && echo '/usr/bin/xfce4-session &' >> ~/.vnc/xstartup && \
|
||||
chmod +x ~/.vnc/xstartup
|
||||
|
||||
54
builder/dockerfile.ubuntu_focal.vncserver.test
Normal file
54
builder/dockerfile.ubuntu_focal.vncserver.test
Normal file
@@ -0,0 +1,54 @@
|
||||
FROM ubuntu:focal
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV VNC_PORT 8443
|
||||
ENV VNC_PORT2 8444
|
||||
ENV VNC_PORT3 8445
|
||||
EXPOSE $VNC_PORT
|
||||
EXPOSE $VNC_PORT2
|
||||
EXPOSE $VNC_PORT3
|
||||
|
||||
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 vim less
|
||||
RUN apt-get update && apt-get -y install lsb-release
|
||||
RUN apt-get update && apt-get -y install net-tools
|
||||
|
||||
# RUN mkdir -p /usr/share/man/man1
|
||||
# RUN apt-get update && apt-get install -y apt-utils openjdk-11-jre
|
||||
RUN apt-get update && apt-get install -y ubuntu-mate-desktop
|
||||
RUN apt-get update && apt-get install -y lxde
|
||||
RUN apt-get update && apt-get install -y lxqt
|
||||
RUN apt-get update && apt-get install -y kde-full
|
||||
RUN apt-get update && apt-get install -y cinnamon
|
||||
RUN apt-get update && apt-get install -y ubuntu-gnome-desktop
|
||||
RUN apt-get purge -y pm-utils xscreensaver*
|
||||
RUN apt-get purge -y clipit magnus kgpg
|
||||
|
||||
RUN apt-get update && apt-get install -y python3-pip
|
||||
RUN apt-get update && apt-get install -y strace
|
||||
|
||||
RUN useradd -m docker
|
||||
ENV USER docker
|
||||
|
||||
ARG KASMVNC_PACKAGE_DIR
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp
|
||||
RUN dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
|
||||
ENV HOME /home/docker
|
||||
RUN chown -R 1000:0 $HOME
|
||||
USER 1000:ssl-cert
|
||||
WORKDIR $HOME
|
||||
|
||||
RUN pip3 install --user pipenv
|
||||
RUN echo 'PATH="/src/unix:~/.local/bin/:$PATH"' >> ~/.bashrc
|
||||
RUN echo 'alias s="sh /src/s"' >> ~/.bashrc
|
||||
RUN echo 'alias k="vncserver -kill :1; pkill baloo_file; pkill gpg-agent; pkill ssh-agent; pkill xiccd"' >> ~/.bashrc
|
||||
RUN echo 'alias r="k; s"' >> ~/.bashrc
|
||||
RUN echo 'alias go="sh /src/s; vncserver -kill :1"' >> ~/.bashrc
|
||||
RUN echo 'alias ns="netstat -nltp"' >> ~/.bashrc
|
||||
RUN echo 'alias mamba="pipenv run mamba spec/"' >> ~/.bashrc
|
||||
|
||||
ENV LC_ALL=C.UTF-8
|
||||
ENV LANG=C.UTF-8
|
||||
|
||||
ENTRYPOINT ["bash", "-ic", "cd /src && pipenv install; exec bash"]
|
||||
@@ -3,6 +3,11 @@ default_os_codename=bionic
|
||||
|
||||
os=${1:-$default_os}
|
||||
os_codename=${2:-$default_os_codename}
|
||||
build_tag="${3:-}"
|
||||
if [[ -n "$build_tag" ]]; then
|
||||
build_tag_for_images="_${build_tag#+}"
|
||||
build_debian_revision="$(echo $build_tag | tr _ -)"
|
||||
fi
|
||||
os_image="$os:$os_codename"
|
||||
|
||||
echo "Building for $os_image"
|
||||
|
||||
50
builder/startup/deb/cli-processing.sh
Normal file
50
builder/startup/deb/cli-processing.sh
Normal file
@@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
|
||||
debug() {
|
||||
if [ -z "$debug" ]; then return; fi
|
||||
|
||||
echo "$@"
|
||||
}
|
||||
|
||||
enable_debug() {
|
||||
debug=1
|
||||
log_option="-log *:stderr:100"
|
||||
}
|
||||
|
||||
kill_vnc_server() {
|
||||
vncserver -kill $display
|
||||
}
|
||||
|
||||
process_cli_options() {
|
||||
for option in "$@"; do
|
||||
case "$option" in
|
||||
--help)
|
||||
show_help
|
||||
exit
|
||||
;;
|
||||
-d|--debug)
|
||||
enable_debug
|
||||
;;
|
||||
-k|--kill)
|
||||
kill_vnc_server
|
||||
exit
|
||||
;;
|
||||
-s|--select-de)
|
||||
action=select-de-and-start
|
||||
;;
|
||||
*)
|
||||
echo >&2 "Unsupported argument: $option"
|
||||
exit 1
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
show_help() {
|
||||
cat >&2 <<-USAGE
|
||||
Usage: $(basename "$0") [options]
|
||||
-d, --debug Debug output
|
||||
-k, --kill Kill vncserver
|
||||
-s, --select-de Select desktop environent to run
|
||||
--help Show this help
|
||||
USAGE
|
||||
}
|
||||
@@ -4,43 +4,8 @@ set -e
|
||||
|
||||
display=:10
|
||||
interface=0.0.0.0
|
||||
cert_group=ssl-cert
|
||||
|
||||
if [[ "$1" = "--help" ]]; then
|
||||
cat >&2 <<-USAGE
|
||||
Usage: `basename $0` [options]
|
||||
-d Debug output
|
||||
-kill Kill vncserver
|
||||
--help show this help
|
||||
USAGE
|
||||
exit
|
||||
fi
|
||||
|
||||
if [[ "$1" = "-d" ]]; then
|
||||
log_option="-log *:stderr:100"
|
||||
fi
|
||||
|
||||
action=start
|
||||
if [[ "$1" = "-kill" ]]; then
|
||||
action=kill
|
||||
fi
|
||||
|
||||
if groups | grep -qvw ssl-cert; then
|
||||
cat <<-EOF
|
||||
Can't access TLS certificate.
|
||||
Please add your user to $cert_group via 'addgroup <user> ssl-cert'
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$action" = "kill" ]]; then
|
||||
vncserver -kill $display
|
||||
exit
|
||||
fi
|
||||
|
||||
vncserver $display -interface $interface
|
||||
vncserver -kill $display
|
||||
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 $log_option
|
||||
-interface $interface -httpd /usr/share/kasmvnc/www
|
||||
|
||||
258
builder/startup/deb/select-de.sh
Executable file
258
builder/startup/deb/select-de.sh
Executable file
@@ -0,0 +1,258 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
xstartup_script=~/.vnc/xstartup
|
||||
de_was_selected_file="$HOME/.vnc/.de-was-selected"
|
||||
|
||||
debug() {
|
||||
if [ -z "$debug" ]; then return; fi
|
||||
|
||||
echo "$@"
|
||||
}
|
||||
|
||||
enable_debug() {
|
||||
debug=1
|
||||
}
|
||||
|
||||
process_cli_options() {
|
||||
while [ $# -gt 0 ]; do
|
||||
local option="$1"
|
||||
shift
|
||||
|
||||
case "$option" in
|
||||
--help|-h)
|
||||
show_help
|
||||
exit
|
||||
;;
|
||||
-d|--debug)
|
||||
enable_debug
|
||||
;;
|
||||
-y|--assume-yes)
|
||||
assume_yes=1
|
||||
;;
|
||||
-s|--select-de)
|
||||
action=select-de
|
||||
if [[ -n "$1" && "${1:0:1}" != "-" ]]; then
|
||||
selected_de="$1"
|
||||
assume_yes_for_xstartup_overwrite=1
|
||||
if [ "$selected_de" = "manual" ]; then
|
||||
selected_de="$manual_xstartup_choice"
|
||||
fi
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo >&2 "Unsupported argument: $option"
|
||||
exit 1
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
show_help() {
|
||||
cat >&2 <<-USAGE
|
||||
Usage: $(basename "$0") [options]
|
||||
-d, --debug Debug output
|
||||
-y, --assume-yes Automatic "yes" to prompts
|
||||
-s, --select-de Select desktop environent to run
|
||||
--help Show this help
|
||||
USAGE
|
||||
}
|
||||
|
||||
add_uppercase_desktop_environment_keys() {
|
||||
local de_cmd
|
||||
|
||||
for de in "${!all_desktop_environments[@]}"; do
|
||||
de_cmd=${all_desktop_environments[$de]};
|
||||
all_desktop_environments[${de^^}]="$de_cmd"
|
||||
done
|
||||
}
|
||||
|
||||
process_cli_options "$@"
|
||||
|
||||
manual_xstartup_choice="Manually edit xstartup"
|
||||
declare -A all_desktop_environments=(
|
||||
[Cinnamon]="exec cinnamon-session"
|
||||
[Mate]="XDG_CURRENT_DESKTOP=MATE exec dbus-launch --exit-with-session mate-session"
|
||||
[LXDE]="exec lxsession"
|
||||
[Lxqt]="exec startlxqt"
|
||||
[KDE]="exec startkde"
|
||||
[Gnome]="XDG_CURRENT_DESKTOP=GNOME exec dbus-launch --exit-with-session /usr/bin/gnome-session"
|
||||
[XFCE]="exec xfce4-session")
|
||||
|
||||
readarray -t sorted_desktop_environments < <(for de in "${!all_desktop_environments[@]}"; do echo "$de"; done | sort)
|
||||
|
||||
all_desktop_environments[$manual_xstartup_choice]=""
|
||||
sorted_desktop_environments+=("$manual_xstartup_choice")
|
||||
add_uppercase_desktop_environment_keys
|
||||
|
||||
detected_desktop_environments=()
|
||||
declare -A numbered_desktop_environments
|
||||
|
||||
print_detected_desktop_environments() {
|
||||
declare -i i=1
|
||||
|
||||
echo "Please choose Desktop Environment to run:"
|
||||
for detected_de in "${detected_desktop_environments[@]}"; do
|
||||
echo "[$i] $detected_de"
|
||||
numbered_desktop_environments[$i]=$detected_de
|
||||
i+=1
|
||||
done
|
||||
}
|
||||
|
||||
detect_desktop_environments() {
|
||||
for de_name in "${sorted_desktop_environments[@]}"; do
|
||||
if [[ "$de_name" = "$manual_xstartup_choice" ]]; then
|
||||
detected_desktop_environments+=("$de_name")
|
||||
continue;
|
||||
fi
|
||||
|
||||
local executable=${all_desktop_environments[$de_name]}
|
||||
executable=($executable)
|
||||
executable=${executable[-1]}
|
||||
|
||||
if detect_desktop_environment "$de_name" "$executable"; then
|
||||
detected_desktop_environments+=("$de_name")
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
ask_user_to_choose_de() {
|
||||
while : ; do
|
||||
print_detected_desktop_environments
|
||||
read -r de_number_to_run
|
||||
de_name_from_number "$de_number_to_run"
|
||||
if [[ -n "$de_name" ]]; then
|
||||
break;
|
||||
fi
|
||||
|
||||
echo "Incorrect number: $de_number_to_run"
|
||||
echo
|
||||
done
|
||||
}
|
||||
|
||||
remember_de_choice() {
|
||||
touch "$de_was_selected_file"
|
||||
}
|
||||
|
||||
de_was_selected_on_previous_run() {
|
||||
[[ -f "$de_was_selected_file" ]]
|
||||
}
|
||||
|
||||
detect_desktop_environment() {
|
||||
local de_name="$1"
|
||||
local executable="$2"
|
||||
|
||||
if command -v "$executable" &>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
did_user_forbid_replacing_xstartup() {
|
||||
grep -q -v KasmVNC-safe-to-replace-this-file "$xstartup_script"
|
||||
}
|
||||
|
||||
de_cmd_from_name() {
|
||||
de_cmd=${all_desktop_environments[${de_name^^}]}
|
||||
}
|
||||
|
||||
de_name_from_number() {
|
||||
local de_number_to_run="$1"
|
||||
|
||||
de_name=${numbered_desktop_environments[$de_number_to_run]}
|
||||
}
|
||||
|
||||
warn_xstartup_will_be_overwriten() {
|
||||
if [[ -n "$assume_yes" || -n "$assume_yes_for_xstartup_overwrite" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ ! -f "$xstartup_script" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -n "WARNING: $xstartup_script will be overwritten y/N?"
|
||||
read -r do_overwrite_xstartup
|
||||
if [[ "$do_overwrite_xstartup" = "y" || "$do_overwrite_xstartup" = "Y" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
setup_de_to_run_via_xstartup() {
|
||||
warn_xstartup_will_be_overwriten
|
||||
generate_xstartup "$de_name"
|
||||
}
|
||||
|
||||
generate_xstartup() {
|
||||
local de_name="$1"
|
||||
|
||||
de_cmd_from_name
|
||||
|
||||
cat <<-SCRIPT > "$xstartup_script"
|
||||
#!/bin/sh
|
||||
$de_cmd
|
||||
SCRIPT
|
||||
chmod +x "$xstartup_script"
|
||||
}
|
||||
|
||||
user_asked_to_select_de() {
|
||||
[[ "$action" = "select-de" ]]
|
||||
}
|
||||
|
||||
user_specified_de() {
|
||||
[ -n "$selected_de" ]
|
||||
}
|
||||
|
||||
check_de_name_is_valid() {
|
||||
local selected_de="$1"
|
||||
local de_cmd=${all_desktop_environments["${selected_de^^}"]:-}
|
||||
if [ -z "$de_cmd" ]; then
|
||||
echo >&2 "'$selected_de': not supported Desktop Environment"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
de_installed() {
|
||||
local de_name="${1^^}"
|
||||
|
||||
for de in "${detected_desktop_environments[@]}"; do
|
||||
if [ "${de^^}" = "$de_name" ]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
check_de_installed() {
|
||||
local de_name="$1"
|
||||
|
||||
if ! de_installed "$de_name"; then
|
||||
echo >&2 "'$de_name': Desktop Environment not installed"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
if user_asked_to_select_de || ! de_was_selected_on_previous_run; then
|
||||
if user_specified_de; then
|
||||
check_de_name_is_valid "$selected_de"
|
||||
fi
|
||||
|
||||
detect_desktop_environments
|
||||
if user_specified_de; then
|
||||
check_de_installed "$selected_de"
|
||||
de_name="$selected_de"
|
||||
else
|
||||
ask_user_to_choose_de
|
||||
fi
|
||||
|
||||
debug "You selected $de_name desktop environment"
|
||||
if [[ "$de_name" != "$manual_xstartup_choice" ]]; then
|
||||
setup_de_to_run_via_xstartup
|
||||
fi
|
||||
remember_de_choice
|
||||
fi
|
||||
@@ -61,9 +61,6 @@ kasmvncpasswd -d -u "$VNC_USER-to-delete" $HOME/.kasmpasswd
|
||||
chmod 0600 $HOME/.kasmpasswd
|
||||
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout $HOME/.vnc/self.pem -out $HOME/.vnc/self.pem -subj "/C=US/ST=VA/L=None/O=None/OU=DoFu/CN=kasm/emailAddress=none@none.none"
|
||||
|
||||
vncserver :1 -interface 0.0.0.0
|
||||
vncserver -kill :1
|
||||
|
||||
if [[ -f $PASSWD_PATH ]]; then
|
||||
rm -f $PASSWD_PATH
|
||||
fi
|
||||
@@ -86,10 +83,10 @@ vncserver -kill $DISPLAY &> $HOME/.vnc/vnc_startup.log \
|
||||
|
||||
detect_www_dir
|
||||
detect_cert_location
|
||||
[ -n "$KASMVNC_VERBOSE_LOGGING" ] && verbose_logging_option="-log *:stderr:100"
|
||||
[ -n "$KASMVNC_VERBOSE_LOGGING" ] && verbose_logging_option="-debug"
|
||||
|
||||
echo -e "start vncserver with param: VNC_COL_DEPTH=$VNC_COL_DEPTH, VNC_RESOLUTION=$VNC_RESOLUTION\n..."
|
||||
vncserver $DISPLAY -depth $VNC_COL_DEPTH -geometry $VNC_RESOLUTION -FrameRate=$MAX_FRAME_RATE -websocketPort $VNC_PORT $cert_option -sslOnly -interface 0.0.0.0 $VNCOPTIONS $package_www_dir_option $verbose_logging_option #&> $STARTUPDIR/no_vnc_startup.log
|
||||
vncserver $DISPLAY -select-de xfce -depth $VNC_COL_DEPTH -geometry $VNC_RESOLUTION -FrameRate=$MAX_FRAME_RATE -websocketPort $VNC_PORT $cert_option -sslOnly -interface 0.0.0.0 $VNCOPTIONS $package_www_dir_option $verbose_logging_option #&> $STARTUPDIR/no_vnc_startup.log
|
||||
|
||||
PID_SUN=$!
|
||||
|
||||
|
||||
@@ -5,10 +5,12 @@ set -e
|
||||
cd "$(dirname "$0")"
|
||||
. ./os_ver_cli.sh
|
||||
|
||||
tester_image=kasmvnctester_${os}:$os_codename${build_tag_for_images}
|
||||
docker build --build-arg KASMVNC_PACKAGE_DIR="build/${os_codename}" \
|
||||
-t kasmvnctester_${os}:$os_codename \
|
||||
-f dockerfile.${os}_${os_codename}.deb.test .
|
||||
--build-arg BUILD_DEBIAN_REVISION="$build_debian_revision" \
|
||||
-t "$tester_image" \
|
||||
-f dockerfile.${os}_${os_codename}${build_tag}.deb.test .
|
||||
docker run -it -p 443:8443 --rm \
|
||||
-e KASMVNC_VERBOSE_LOGGING=$KASMVNC_VERBOSE_LOGGING \
|
||||
-e "VNC_USER=foo" -e "VNC_PW=foobar" \
|
||||
kasmvnctester_${os}:$os_codename
|
||||
"$tester_image"
|
||||
|
||||
15
builder/test-vncserver
Executable file
15
builder/test-vncserver
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
. ./os_ver_cli.sh
|
||||
|
||||
docker build --build-arg KASMVNC_PACKAGE_DIR="build/${os_codename}" \
|
||||
-t kasmvnctester_${os}:$os_codename \
|
||||
-f dockerfile.${os}_${os_codename}.vncserver.test .
|
||||
docker run -it -v $(realpath ${PWD}/..):/src -p 8443:8443 -p 8444:8444 \
|
||||
-p 8445:8445 --rm \
|
||||
-e KASMVNC_VERBOSE_LOGGING=$KASMVNC_VERBOSE_LOGGING \
|
||||
-e "VNC_USER=foo" -e "VNC_PW=foobar" \
|
||||
kasmvnctester_${os}:$os_codename
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: kasmvncserver
|
||||
Version: 0.9.1~beta
|
||||
Version: 0.9.3~beta
|
||||
Release: 1%{?dist}
|
||||
Summary: VNC server accessible from a web browser
|
||||
|
||||
@@ -7,7 +7,7 @@ License: GPLv2+
|
||||
URL: https://github.com/kasmtech/KasmVNC
|
||||
|
||||
BuildRequires: rsync
|
||||
Requires: xorg-x11-xauth, xorg-x11-xkb-utils, xkeyboard-config, xorg-x11-server-utils, openssl, perl
|
||||
Requires: xorg-x11-xauth, xorg-x11-xkb-utils, xkeyboard-config, xorg-x11-server-utils, openssl, perl, perl-Switch, rpmfusion-free-release, perl-Hash-Merge-Simple, perl-Scalar-List-Utils
|
||||
Conflicts: tigervnc-server, tigervnc-server-minimal
|
||||
|
||||
%description
|
||||
@@ -48,11 +48,12 @@ DESTDIR=$RPM_BUILD_ROOT
|
||||
DST_MAN=$DESTDIR/usr/share/man/man1
|
||||
|
||||
mkdir -p $DESTDIR/usr/bin $DESTDIR/usr/share/man/man1 \
|
||||
$DESTDIR/usr/share/doc/kasmvncserver
|
||||
$DESTDIR/usr/share/doc/kasmvncserver $DESTDIR/usr/lib
|
||||
cp $SRC_BIN/Xvnc $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/vncserver $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/vncconfig $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/kasmvncpasswd $DESTDIR/usr/bin;
|
||||
cp -r $SRC/lib/kasmvnc/ $DESTDIR/usr/lib/kasmvncserver
|
||||
cd $DESTDIR/usr/bin && ln -s kasmvncpasswd vncpasswd;
|
||||
cp -r $SRC/share/doc/kasmvnc*/* $DESTDIR/usr/share/doc/kasmvncserver/
|
||||
rsync -r --exclude '.git*' --exclude po2js --exclude xgettext-html \
|
||||
@@ -66,10 +67,11 @@ cd $DST_MAN && ln -s vncpasswd.1 kasmvncpasswd.1;
|
||||
|
||||
%files
|
||||
/usr/bin/*
|
||||
/usr/lib/kasmvncserver
|
||||
/usr/share/man/man1/*
|
||||
/usr/share/kasmvnc/www
|
||||
|
||||
%license /usr/share/doc/kasmvncserver/LICENCE.TXT
|
||||
%license /usr/share/doc/kasmvncserver/LICENSE.TXT
|
||||
%doc /usr/share/doc/kasmvncserver/README.md
|
||||
|
||||
%changelog
|
||||
|
||||
@@ -76,5 +76,5 @@ endif() #UNIX
|
||||
# Common
|
||||
#
|
||||
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/LICENCE.TXT DESTINATION ${DOC_DIR})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE.TXT DESTINATION ${DOC_DIR})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/README.md DESTINATION ${DOC_DIR})
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <rfb/PixelBuffer.h>
|
||||
#include <rfb/PixelFormat.h>
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace network {
|
||||
@@ -34,6 +36,17 @@ namespace network {
|
||||
|
||||
// from main thread
|
||||
void mainUpdateScreen(rfb::PixelBuffer *pb);
|
||||
void mainUpdateBottleneckStats(const char userid[], const char stats[]);
|
||||
void mainClearBottleneckStats(const char userid[]);
|
||||
void mainUpdateServerFrameStats(uint8_t changedPerc, uint32_t all,
|
||||
uint32_t jpeg, uint32_t webp, uint32_t analysis,
|
||||
uint32_t jpegarea, uint32_t webparea,
|
||||
uint16_t njpeg, uint16_t nwebp,
|
||||
uint16_t enc, uint16_t scale, uint16_t shot,
|
||||
uint16_t w, uint16_t h);
|
||||
void mainUpdateClientFrameStats(const char userid[], uint32_t render, uint32_t all,
|
||||
uint32_t ping);
|
||||
void mainUpdateUserInfo(const uint8_t ownerConn, const uint8_t numUsers);
|
||||
|
||||
// from network threads
|
||||
uint8_t *netGetScreenshot(uint16_t w, uint16_t h,
|
||||
@@ -42,13 +55,25 @@ namespace network {
|
||||
uint8_t netAddUser(const char name[], const char pw[], const bool write);
|
||||
uint8_t netRemoveUser(const char name[]);
|
||||
uint8_t netGiveControlTo(const char name[]);
|
||||
void netGetBottleneckStats(char *buf, uint32_t len);
|
||||
void netGetFrameStats(char *buf, uint32_t len);
|
||||
uint8_t netServerFrameStatsReady();
|
||||
|
||||
enum USER_ACTION {
|
||||
//USER_ADD, - handled locally for interactivity
|
||||
USER_REMOVE,
|
||||
USER_GIVE_CONTROL,
|
||||
WANT_FRAME_STATS_SERVERONLY,
|
||||
WANT_FRAME_STATS_ALL,
|
||||
WANT_FRAME_STATS_OWNER,
|
||||
WANT_FRAME_STATS_SPECIFIC,
|
||||
};
|
||||
|
||||
uint8_t netRequestFrameStats(USER_ACTION what, const char *client);
|
||||
uint8_t netOwnerConnected();
|
||||
uint8_t netNumActiveUsers();
|
||||
uint8_t netGetClientFrameStatsNum();
|
||||
|
||||
struct action_data {
|
||||
enum USER_ACTION action;
|
||||
kasmpasswd_entry_t data;
|
||||
@@ -68,6 +93,40 @@ namespace network {
|
||||
std::vector<uint8_t> cachedJpeg;
|
||||
uint16_t cachedW, cachedH;
|
||||
uint8_t cachedQ;
|
||||
|
||||
std::map<std::string, std::string> bottleneckStats;
|
||||
pthread_mutex_t statMutex;
|
||||
|
||||
struct clientFrameStats_t {
|
||||
uint32_t render;
|
||||
uint32_t all;
|
||||
uint32_t ping;
|
||||
};
|
||||
struct serverFrameStats_t {
|
||||
uint32_t all;
|
||||
uint32_t jpeg;
|
||||
uint32_t webp;
|
||||
uint32_t analysis;
|
||||
uint32_t jpegarea;
|
||||
uint32_t webparea;
|
||||
uint16_t njpeg;
|
||||
uint16_t nwebp;
|
||||
uint16_t enc;
|
||||
uint16_t scale;
|
||||
uint16_t shot;
|
||||
uint16_t w;
|
||||
uint16_t h;
|
||||
uint8_t changedPerc;
|
||||
|
||||
uint8_t inprogress;
|
||||
};
|
||||
std::map<std::string, clientFrameStats_t> clientFrameStats;
|
||||
serverFrameStats_t serverFrameStats;
|
||||
pthread_mutex_t frameStatMutex;
|
||||
|
||||
uint8_t ownerConnected;
|
||||
uint8_t activeUsers;
|
||||
pthread_mutex_t userInfoMutex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <network/GetAPI.h>
|
||||
#include <rfb/ConnParams.h>
|
||||
#include <rfb/EncodeManager.h>
|
||||
#include <rfb/LogWriter.h>
|
||||
#include <rfb/JpegCompressor.h>
|
||||
#include <rfb/xxhash.h>
|
||||
@@ -32,10 +33,6 @@ using namespace rfb;
|
||||
|
||||
static LogWriter vlog("GetAPIMessager");
|
||||
|
||||
PixelBuffer *progressiveBilinearScale(const PixelBuffer *pb,
|
||||
const uint16_t tgtw, const uint16_t tgth,
|
||||
const float tgtdiff);
|
||||
|
||||
struct TightJPEGConfiguration {
|
||||
int quality;
|
||||
int subsampling;
|
||||
@@ -56,10 +53,16 @@ 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) {
|
||||
cachedW(0), cachedH(0), cachedQ(0),
|
||||
ownerConnected(0), activeUsers(0) {
|
||||
|
||||
pthread_mutex_init(&screenMutex, NULL);
|
||||
pthread_mutex_init(&userMutex, NULL);
|
||||
pthread_mutex_init(&statMutex, NULL);
|
||||
pthread_mutex_init(&frameStatMutex, NULL);
|
||||
pthread_mutex_init(&userInfoMutex, NULL);
|
||||
|
||||
serverFrameStats.inprogress = 0;
|
||||
}
|
||||
|
||||
// from main thread
|
||||
@@ -95,6 +98,78 @@ void GetAPIMessager::mainUpdateScreen(rfb::PixelBuffer *pb) {
|
||||
pthread_mutex_unlock(&screenMutex);
|
||||
}
|
||||
|
||||
void GetAPIMessager::mainUpdateBottleneckStats(const char userid[], const char stats[]) {
|
||||
if (pthread_mutex_trylock(&statMutex))
|
||||
return;
|
||||
|
||||
bottleneckStats[userid] = stats;
|
||||
|
||||
pthread_mutex_unlock(&statMutex);
|
||||
}
|
||||
|
||||
void GetAPIMessager::mainClearBottleneckStats(const char userid[]) {
|
||||
if (pthread_mutex_lock(&statMutex))
|
||||
return;
|
||||
|
||||
bottleneckStats.erase(userid);
|
||||
|
||||
pthread_mutex_unlock(&statMutex);
|
||||
}
|
||||
|
||||
void GetAPIMessager::mainUpdateServerFrameStats(uint8_t changedPerc,
|
||||
uint32_t all, uint32_t jpeg, uint32_t webp, uint32_t analysis,
|
||||
uint32_t jpegarea, uint32_t webparea,
|
||||
uint16_t njpeg, uint16_t nwebp,
|
||||
uint16_t enc, uint16_t scale, uint16_t shot,
|
||||
uint16_t w, uint16_t h) {
|
||||
|
||||
if (pthread_mutex_lock(&frameStatMutex))
|
||||
return;
|
||||
|
||||
serverFrameStats.changedPerc = changedPerc;
|
||||
serverFrameStats.all = all;
|
||||
serverFrameStats.jpeg = jpeg;
|
||||
serverFrameStats.webp = webp;
|
||||
serverFrameStats.analysis = analysis;
|
||||
serverFrameStats.jpegarea = jpegarea;
|
||||
serverFrameStats.webparea = webparea;
|
||||
serverFrameStats.njpeg = njpeg;
|
||||
serverFrameStats.nwebp = nwebp;
|
||||
serverFrameStats.enc = enc;
|
||||
serverFrameStats.scale = scale;
|
||||
serverFrameStats.shot = shot;
|
||||
serverFrameStats.w = w;
|
||||
serverFrameStats.h = h;
|
||||
|
||||
pthread_mutex_unlock(&frameStatMutex);
|
||||
}
|
||||
|
||||
void GetAPIMessager::mainUpdateClientFrameStats(const char userid[], uint32_t render,
|
||||
uint32_t all, uint32_t ping) {
|
||||
|
||||
if (pthread_mutex_lock(&frameStatMutex))
|
||||
return;
|
||||
|
||||
clientFrameStats_t s;
|
||||
s.render = render;
|
||||
s.all = all;
|
||||
s.ping = ping;
|
||||
|
||||
clientFrameStats[userid] = s;
|
||||
|
||||
pthread_mutex_unlock(&frameStatMutex);
|
||||
}
|
||||
|
||||
void GetAPIMessager::mainUpdateUserInfo(const uint8_t ownerConn, const uint8_t numUsers) {
|
||||
if (pthread_mutex_lock(&userInfoMutex))
|
||||
return;
|
||||
|
||||
ownerConnected = ownerConn;
|
||||
activeUsers = numUsers;
|
||||
|
||||
pthread_mutex_unlock(&userInfoMutex);
|
||||
}
|
||||
|
||||
// from network threads
|
||||
uint8_t *GetAPIMessager::netGetScreenshot(uint16_t w, uint16_t h,
|
||||
const uint8_t q, const bool dedup,
|
||||
@@ -286,3 +361,271 @@ uint8_t GetAPIMessager::netGiveControlTo(const char name[]) {
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void GetAPIMessager::netGetBottleneckStats(char *buf, uint32_t len) {
|
||||
/*
|
||||
{
|
||||
"username.1": {
|
||||
"192.168.100.2:14908": [ 100, 100, 100, 100 ],
|
||||
"192.168.100.3:14918": [ 100, 100, 100, 100 ]
|
||||
},
|
||||
"username.2": {
|
||||
"192.168.100.5:14904": [ 100, 100, 100, 100 ]
|
||||
}
|
||||
}
|
||||
*/
|
||||
std::map<std::string, std::string>::const_iterator it;
|
||||
const char *prev = NULL;
|
||||
FILE *f;
|
||||
|
||||
if (pthread_mutex_lock(&statMutex)) {
|
||||
buf[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Conservative estimate
|
||||
if (len < bottleneckStats.size() * 60) {
|
||||
buf[0] = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
f = fmemopen(buf, len, "w");
|
||||
|
||||
fprintf(f, "{\n");
|
||||
|
||||
for (it = bottleneckStats.begin(); it != bottleneckStats.end(); it++) {
|
||||
// user@127.0.0.1_1627311208.791752::websocket
|
||||
const char *id = it->first.c_str();
|
||||
const char *data = it->second.c_str();
|
||||
|
||||
const char *at = strchr(id, '@');
|
||||
if (!at)
|
||||
continue;
|
||||
|
||||
const unsigned userlen = at - id;
|
||||
if (prev && !strncmp(prev, id, userlen)) {
|
||||
// Same user
|
||||
fprintf(f, ",\n\t\t\"%s\": %s", at + 1, data);
|
||||
} else {
|
||||
// New one
|
||||
if (prev) {
|
||||
fprintf(f, "\n\t},\n");
|
||||
}
|
||||
fprintf(f, "\t\"%.*s\": {\n", userlen, id);
|
||||
fprintf(f, "\t\t\"%s\": %s", at + 1, data);
|
||||
}
|
||||
|
||||
prev = id;
|
||||
}
|
||||
|
||||
if (!bottleneckStats.size())
|
||||
fprintf(f, "}\n");
|
||||
else
|
||||
fprintf(f, "\n\t}\n}\n");
|
||||
|
||||
fclose(f);
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&statMutex);
|
||||
}
|
||||
|
||||
void GetAPIMessager::netGetFrameStats(char *buf, uint32_t len) {
|
||||
/*
|
||||
{
|
||||
"frame" : {
|
||||
"resx": 1024,
|
||||
"resy": 1280,
|
||||
"changed": 75,
|
||||
"server_time": 23
|
||||
},
|
||||
"server_side" : [
|
||||
{ "process_name": "Analysis", "time": 20 },
|
||||
{ "process_name": "TightWEBPEncoder", "time": 20, "count": 64, "area": 12 },
|
||||
{ "process_name": "TightJPEGEncoder", "time": 20, "count": 64, "area": 12 }
|
||||
],
|
||||
"client_side" : [
|
||||
{
|
||||
"client": "123.1.2.1:1211",
|
||||
"client_time": 20,
|
||||
"ping": 20,
|
||||
"processes" : [
|
||||
{ "process_name": "scanRenderQ", "time": 20 }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
std::map<std::string, clientFrameStats_t>::const_iterator it;
|
||||
unsigned i = 0;
|
||||
FILE *f;
|
||||
|
||||
if (pthread_mutex_lock(&frameStatMutex)) {
|
||||
buf[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned num = clientFrameStats.size();
|
||||
|
||||
// Conservative estimate
|
||||
if (len < 1024) {
|
||||
buf[0] = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
f = fmemopen(buf, len, "w");
|
||||
|
||||
fprintf(f, "{\n");
|
||||
|
||||
fprintf(f, "\t\"frame\" : {\n"
|
||||
"\t\t\"resx\": %u,\n"
|
||||
"\t\t\"resy\": %u,\n"
|
||||
"\t\t\"changed\": %u,\n"
|
||||
"\t\t\"server_time\": %u\n"
|
||||
"\t},\n",
|
||||
serverFrameStats.w,
|
||||
serverFrameStats.h,
|
||||
serverFrameStats.changedPerc,
|
||||
serverFrameStats.all);
|
||||
|
||||
fprintf(f, "\t\"server_side\" : [\n"
|
||||
"\t\t{ \"process_name\": \"Analysis\", \"time\": %u },\n"
|
||||
"\t\t{ \"process_name\": \"Screenshot\", \"time\": %u },\n"
|
||||
"\t\t{ \"process_name\": \"Encoding_total\", \"time\": %u, \"videoscaling\": %u },\n"
|
||||
"\t\t{ \"process_name\": \"TightJPEGEncoder\", \"time\": %u, \"count\": %u, \"area\": %u },\n"
|
||||
"\t\t{ \"process_name\": \"TightWEBPEncoder\", \"time\": %u, \"count\": %u, \"area\": %u }\n"
|
||||
"\t],\n",
|
||||
serverFrameStats.analysis,
|
||||
serverFrameStats.shot,
|
||||
serverFrameStats.enc,
|
||||
serverFrameStats.scale,
|
||||
serverFrameStats.jpeg,
|
||||
serverFrameStats.njpeg,
|
||||
serverFrameStats.jpegarea,
|
||||
serverFrameStats.webp,
|
||||
serverFrameStats.nwebp,
|
||||
serverFrameStats.webparea);
|
||||
|
||||
fprintf(f, "\t\"client_side\" : [\n");
|
||||
|
||||
for (it = clientFrameStats.begin(); it != clientFrameStats.end(); it++, i++) {
|
||||
const char *id = it->first.c_str();
|
||||
const clientFrameStats_t &s = it->second;
|
||||
|
||||
fprintf(f, "\t\t\{\n"
|
||||
"\t\t\t\"client\": \"%s\",\n"
|
||||
"\t\t\t\"client_time\": %u,\n"
|
||||
"\t\t\t\"ping\": %u,\n"
|
||||
"\t\t\t\"processes\" : [\n"
|
||||
"\t\t\t\t{ \"process_name\": \"scanRenderQ\", \"time\": %u }\n"
|
||||
"\t\t\t]\n"
|
||||
"\t\t}",
|
||||
id,
|
||||
s.all,
|
||||
s.ping,
|
||||
s.render);
|
||||
|
||||
if (i == num - 1)
|
||||
fprintf(f, "\n");
|
||||
else
|
||||
fprintf(f, ",\n");
|
||||
}
|
||||
|
||||
fprintf(f, "\t]\n}\n");
|
||||
|
||||
fclose(f);
|
||||
|
||||
serverFrameStats.inprogress = 0;
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&frameStatMutex);
|
||||
}
|
||||
|
||||
uint8_t GetAPIMessager::netRequestFrameStats(USER_ACTION what, const char *client) {
|
||||
// Return 1 for success
|
||||
action_data act;
|
||||
act.action = what;
|
||||
if (client) {
|
||||
strncpy(act.data.password, client, PASSWORD_LEN);
|
||||
act.data.password[PASSWORD_LEN - 1] = '\0';
|
||||
}
|
||||
|
||||
// In progress already?
|
||||
bool fail = false;
|
||||
if (pthread_mutex_lock(&frameStatMutex))
|
||||
return 0;
|
||||
|
||||
if (serverFrameStats.inprogress) {
|
||||
fail = true;
|
||||
vlog.error("Frame stats request already in progress, refusing another");
|
||||
} else {
|
||||
clientFrameStats.clear();
|
||||
memset(&serverFrameStats, 0, sizeof(serverFrameStats_t));
|
||||
serverFrameStats.inprogress = 1;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&frameStatMutex);
|
||||
if (fail)
|
||||
return 0;
|
||||
|
||||
// Send it in
|
||||
if (pthread_mutex_lock(&userMutex))
|
||||
return 0;
|
||||
|
||||
actionQueue.push_back(act);
|
||||
|
||||
pthread_mutex_unlock(&userMutex);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t GetAPIMessager::netOwnerConnected() {
|
||||
uint8_t ret;
|
||||
|
||||
if (pthread_mutex_lock(&userInfoMutex))
|
||||
return 0;
|
||||
|
||||
ret = ownerConnected;
|
||||
|
||||
pthread_mutex_unlock(&userInfoMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t GetAPIMessager::netNumActiveUsers() {
|
||||
uint8_t ret;
|
||||
|
||||
if (pthread_mutex_lock(&userInfoMutex))
|
||||
return 0;
|
||||
|
||||
ret = activeUsers;
|
||||
|
||||
pthread_mutex_unlock(&userInfoMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t GetAPIMessager::netGetClientFrameStatsNum() {
|
||||
uint8_t ret;
|
||||
|
||||
if (pthread_mutex_lock(&frameStatMutex))
|
||||
return 0;
|
||||
|
||||
ret = clientFrameStats.size();
|
||||
|
||||
pthread_mutex_unlock(&frameStatMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t GetAPIMessager::netServerFrameStatsReady() {
|
||||
uint8_t ret;
|
||||
|
||||
if (pthread_mutex_lock(&frameStatMutex))
|
||||
return 0;
|
||||
|
||||
ret = serverFrameStats.w != 0;
|
||||
|
||||
pthread_mutex_unlock(&frameStatMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define errorNumber WSAGetLastError()
|
||||
#define SHUT_RD SD_RECEIVE
|
||||
#define SHUT_WR SD_SEND
|
||||
#define SHUT_RDWR SD_BOTH
|
||||
#else
|
||||
#define errorNumber errno
|
||||
#define closesocket close
|
||||
@@ -94,7 +97,7 @@ Socket::~Socket()
|
||||
void Socket::shutdown()
|
||||
{
|
||||
isShutdown_ = true;
|
||||
::shutdown(getFd(), 2);
|
||||
::shutdown(getFd(), SHUT_RDWR);
|
||||
}
|
||||
|
||||
bool Socket::isShutdown() const
|
||||
@@ -149,7 +152,7 @@ void SocketListener::shutdown()
|
||||
closesocket(fd);
|
||||
fd = -1;
|
||||
#else
|
||||
::shutdown(fd, 2);
|
||||
::shutdown(fd, SHUT_RDWR);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <wordexp.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "websocket.h"
|
||||
|
||||
#include <network/GetAPI.h>
|
||||
@@ -459,6 +461,67 @@ static uint8_t givecontrolCb(void *messager, const char name[])
|
||||
return msgr->netGiveControlTo(name);
|
||||
}
|
||||
|
||||
static void bottleneckStatsCb(void *messager, char *buf, uint32_t len)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
msgr->netGetBottleneckStats(buf, len);
|
||||
}
|
||||
|
||||
static void frameStatsCb(void *messager, char *buf, uint32_t len)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
msgr->netGetFrameStats(buf, len);
|
||||
}
|
||||
|
||||
static uint8_t requestFrameStatsNoneCb(void *messager)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
return msgr->netRequestFrameStats(GetAPIMessager::WANT_FRAME_STATS_SERVERONLY, NULL);
|
||||
}
|
||||
|
||||
static uint8_t requestFrameStatsOwnerCb(void *messager)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
return msgr->netRequestFrameStats(GetAPIMessager::WANT_FRAME_STATS_OWNER, NULL);
|
||||
}
|
||||
|
||||
static uint8_t requestFrameStatsAllCb(void *messager)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
return msgr->netRequestFrameStats(GetAPIMessager::WANT_FRAME_STATS_ALL, NULL);
|
||||
}
|
||||
|
||||
static uint8_t requestFrameStatsOneCb(void *messager, const char *client)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
return msgr->netRequestFrameStats(GetAPIMessager::WANT_FRAME_STATS_SPECIFIC, client);
|
||||
}
|
||||
|
||||
static uint8_t ownerConnectedCb(void *messager)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
return msgr->netOwnerConnected();
|
||||
}
|
||||
|
||||
static uint8_t numActiveUsersCb(void *messager)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
return msgr->netNumActiveUsers();
|
||||
}
|
||||
|
||||
static uint8_t getClientFrameStatsNumCb(void *messager)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
return msgr->netGetClientFrameStatsNum();
|
||||
}
|
||||
|
||||
static uint8_t serverFrameStatsReadyCb(void *messager)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
return msgr->netServerFrameStatsReady();
|
||||
}
|
||||
|
||||
|
||||
WebsocketListener::WebsocketListener(const struct sockaddr *listenaddr,
|
||||
socklen_t listenaddrlen,
|
||||
bool sslonly, const char *cert, const char *certkey,
|
||||
@@ -503,7 +566,7 @@ WebsocketListener::WebsocketListener(const struct sockaddr *listenaddr,
|
||||
if (bind(sock, &sa.u.sa, listenaddrlen) == -1) {
|
||||
int e = errorNumber;
|
||||
closesocket(sock);
|
||||
throw SocketException("failed to bind socket", e);
|
||||
throw SocketException("failed to bind socket, is someone else on our -websocketPort?", e);
|
||||
}
|
||||
|
||||
listen(sock); // sets the internal fd
|
||||
@@ -513,13 +576,16 @@ WebsocketListener::WebsocketListener(const struct sockaddr *listenaddr,
|
||||
//
|
||||
internalSocket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
char sockname[32];
|
||||
sprintf(sockname, ".KasmVNCSock%u", getpid());
|
||||
|
||||
struct sockaddr_un addr;
|
||||
addr.sun_family = AF_UNIX;
|
||||
strcpy(addr.sun_path, ".KasmVNCSock");
|
||||
strcpy(addr.sun_path, sockname);
|
||||
addr.sun_path[0] = '\0';
|
||||
|
||||
if (bind(internalSocket, (struct sockaddr *) &addr,
|
||||
sizeof(sa_family_t) + sizeof(".KasmVNCSock"))) {
|
||||
sizeof(sa_family_t) + strlen(sockname))) {
|
||||
throw SocketException("failed to bind socket", errorNumber);
|
||||
}
|
||||
|
||||
@@ -548,6 +614,18 @@ WebsocketListener::WebsocketListener(const struct sockaddr *listenaddr,
|
||||
settings.adduserCb = adduserCb;
|
||||
settings.removeCb = removeCb;
|
||||
settings.givecontrolCb = givecontrolCb;
|
||||
settings.bottleneckStatsCb = bottleneckStatsCb;
|
||||
settings.frameStatsCb = frameStatsCb;
|
||||
|
||||
settings.requestFrameStatsNoneCb = requestFrameStatsNoneCb;
|
||||
settings.requestFrameStatsOwnerCb = requestFrameStatsOwnerCb;
|
||||
settings.requestFrameStatsAllCb = requestFrameStatsAllCb;
|
||||
settings.requestFrameStatsOneCb = requestFrameStatsOneCb;
|
||||
|
||||
settings.ownerConnectedCb = ownerConnectedCb;
|
||||
settings.numActiveUsersCb = numActiveUsersCb;
|
||||
settings.getClientFrameStatsNumCb = getClientFrameStatsNumCb;
|
||||
settings.serverFrameStatsReadyCb = serverFrameStatsReadyCb;
|
||||
|
||||
pthread_t tid;
|
||||
pthread_create(&tid, NULL, start_server, NULL);
|
||||
|
||||
@@ -111,7 +111,7 @@ static const char *parse_get(const char * const in, const char * const opt, unsi
|
||||
return "";
|
||||
}
|
||||
|
||||
static void percent_decode(const char *src, char *dst) {
|
||||
static void percent_decode(const char *src, char *dst, const uint8_t filter) {
|
||||
while (1) {
|
||||
if (!*src)
|
||||
break;
|
||||
@@ -127,7 +127,32 @@ static void percent_decode(const char *src, char *dst) {
|
||||
hex[2] = '\0';
|
||||
|
||||
src += 2;
|
||||
*dst++ = strtol(hex, NULL, 16);
|
||||
*dst = strtol(hex, NULL, 16);
|
||||
|
||||
if (filter) {
|
||||
// Avoid directory traversal
|
||||
if (*dst == '/')
|
||||
*dst = '_';
|
||||
}
|
||||
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
static void percent_encode(const char *src, char *dst) {
|
||||
while (1) {
|
||||
if (!*src)
|
||||
break;
|
||||
if (isalnum(*src) || *src == '.' || *src == ',') {
|
||||
*dst++ = *src++;
|
||||
} else {
|
||||
*dst++ = '%';
|
||||
sprintf(dst, "%02X", *src);
|
||||
dst += 2;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,7 +591,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
|
||||
headers->key3[0] = '\0';
|
||||
|
||||
if ((strlen(handshake) < 92) || (bcmp(handshake, "GET ", 4) != 0) ||
|
||||
(!strstr(handshake, "Upgrade: websocket"))) {
|
||||
(!strcasestr(handshake, "Upgrade: websocket"))) {
|
||||
return 0;
|
||||
}
|
||||
start = handshake+4;
|
||||
@@ -583,11 +608,11 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
|
||||
headers->host[end-start] = '\0';
|
||||
|
||||
headers->origin[0] = '\0';
|
||||
start = strstr(handshake, "\r\nOrigin: ");
|
||||
start = strcasestr(handshake, "\r\nOrigin: ");
|
||||
if (start) {
|
||||
start += 10;
|
||||
} else {
|
||||
start = strstr(handshake, "\r\nSec-WebSocket-Origin: ");
|
||||
start = strcasestr(handshake, "\r\nSec-WebSocket-Origin: ");
|
||||
if (!start) { return 0; }
|
||||
start += 24;
|
||||
}
|
||||
@@ -595,7 +620,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
|
||||
strncpy(headers->origin, start, end-start);
|
||||
headers->origin[end-start] = '\0';
|
||||
|
||||
start = strstr(handshake, "\r\nSec-WebSocket-Version: ");
|
||||
start = strcasestr(handshake, "\r\nSec-WebSocket-Version: ");
|
||||
if (start) {
|
||||
// HyBi/RFC 6455
|
||||
start += 25;
|
||||
@@ -605,7 +630,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
|
||||
ws_ctx->hixie = 0;
|
||||
ws_ctx->hybi = strtol(headers->version, NULL, 10);
|
||||
|
||||
start = strstr(handshake, "\r\nSec-WebSocket-Key: ");
|
||||
start = strcasestr(handshake, "\r\nSec-WebSocket-Key: ");
|
||||
if (!start) { return 0; }
|
||||
start += 21;
|
||||
end = strstr(start, "\r\n");
|
||||
@@ -619,7 +644,7 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
|
||||
strncpy(headers->connection, start, end-start);
|
||||
headers->connection[end-start] = '\0';
|
||||
|
||||
start = strstr(handshake, "\r\nSec-WebSocket-Protocol: ");
|
||||
start = strcasestr(handshake, "\r\nSec-WebSocket-Protocol: ");
|
||||
if (!start) { return 0; }
|
||||
start += 26;
|
||||
end = strstr(start, "\r\n");
|
||||
@@ -637,14 +662,14 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) {
|
||||
strncpy(headers->key3, start, 8);
|
||||
headers->key3[8] = '\0';
|
||||
|
||||
start = strstr(handshake, "\r\nSec-WebSocket-Key1: ");
|
||||
start = strcasestr(handshake, "\r\nSec-WebSocket-Key1: ");
|
||||
if (!start) { return 0; }
|
||||
start += 22;
|
||||
end = strstr(start, "\r\n");
|
||||
strncpy(headers->key1, start, end-start);
|
||||
headers->key1[end-start] = '\0';
|
||||
|
||||
start = strstr(handshake, "\r\nSec-WebSocket-Key2: ");
|
||||
start = strcasestr(handshake, "\r\nSec-WebSocket-Key2: ");
|
||||
if (!start) { return 0; }
|
||||
start += 22;
|
||||
end = strstr(start, "\r\n");
|
||||
@@ -746,6 +771,7 @@ def:
|
||||
|
||||
static void dirlisting(ws_ctx_t *ws_ctx, const char fullpath[], const char path[]) {
|
||||
char buf[4096];
|
||||
char enc[PATH_MAX * 3 + 1];
|
||||
unsigned i;
|
||||
|
||||
// Redirect?
|
||||
@@ -779,7 +805,15 @@ static void dirlisting(ws_ctx_t *ws_ctx, const char fullpath[], const char path[
|
||||
if (!strcmp(names[i]->d_name, ".") || !strcmp(names[i]->d_name, ".."))
|
||||
continue;
|
||||
|
||||
sprintf(buf, "<li><a href=\"%s\">%s</a></li>", names[i]->d_name, names[i]->d_name);
|
||||
percent_encode(names[i]->d_name, enc);
|
||||
|
||||
if (names[i]->d_type == DT_DIR)
|
||||
sprintf(buf, "<li><a href=\"%s/\">%s/</a></li>", enc,
|
||||
names[i]->d_name);
|
||||
else
|
||||
sprintf(buf, "<li><a href=\"%s\">%s</a></li>", enc,
|
||||
names[i]->d_name);
|
||||
|
||||
ws_send(ws_ctx, buf, strlen(buf));
|
||||
}
|
||||
|
||||
@@ -816,13 +850,15 @@ static void servefile(ws_ctx_t *ws_ctx, const char *in) {
|
||||
len = strlen(path);
|
||||
}
|
||||
|
||||
wserr("Requested file '%s'\n", path);
|
||||
sprintf(fullpath, "%s/%s", settings.httpdir, path);
|
||||
percent_decode(path, buf, 1);
|
||||
|
||||
wserr("Requested file '%s'\n", buf);
|
||||
sprintf(fullpath, "%s/%s", settings.httpdir, buf);
|
||||
|
||||
DIR *dir = opendir(fullpath);
|
||||
if (dir) {
|
||||
closedir(dir);
|
||||
dirlisting(ws_ctx, fullpath, path);
|
||||
dirlisting(ws_ctx, fullpath, buf);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -970,14 +1006,14 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
||||
if (len) {
|
||||
memcpy(buf, param, len);
|
||||
buf[len] = '\0';
|
||||
percent_decode(buf, decname);
|
||||
percent_decode(buf, decname, 0);
|
||||
}
|
||||
|
||||
param = parse_get(args, "password", &len);
|
||||
if (len) {
|
||||
memcpy(buf, param, len);
|
||||
buf[len] = '\0';
|
||||
percent_decode(buf, decpw);
|
||||
percent_decode(buf, decpw, 0);
|
||||
|
||||
struct crypt_data cdata;
|
||||
cdata.initialized = 0;
|
||||
@@ -1017,7 +1053,7 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
||||
if (len) {
|
||||
memcpy(buf, param, len);
|
||||
buf[len] = '\0';
|
||||
percent_decode(buf, decname);
|
||||
percent_decode(buf, decname, 0);
|
||||
}
|
||||
|
||||
if (!decname[0])
|
||||
@@ -1046,7 +1082,7 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
||||
if (len) {
|
||||
memcpy(buf, param, len);
|
||||
buf[len] = '\0';
|
||||
percent_decode(buf, decname);
|
||||
percent_decode(buf, decname, 0);
|
||||
}
|
||||
|
||||
if (!decname[0])
|
||||
@@ -1068,6 +1104,89 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
||||
|
||||
wserr("Passed give_control request to main thread\n");
|
||||
ret = 1;
|
||||
} else entry("/api/get_bottleneck_stats") {
|
||||
char statbuf[4096];
|
||||
settings.bottleneckStatsCb(settings.messager, statbuf, 4096);
|
||||
|
||||
sprintf(buf, "HTTP/1.1 200 OK\r\n"
|
||||
"Server: KasmVNC/4.0\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-type: text/plain\r\n"
|
||||
"Content-length: %lu\r\n"
|
||||
"\r\n", strlen(statbuf));
|
||||
ws_send(ws_ctx, buf, strlen(buf));
|
||||
ws_send(ws_ctx, statbuf, strlen(statbuf));
|
||||
|
||||
wserr("Sent bottleneck stats to API caller\n");
|
||||
ret = 1;
|
||||
} else entry("/api/get_frame_stats") {
|
||||
char statbuf[4096], decname[1024];
|
||||
unsigned waitfor;
|
||||
|
||||
param = parse_get(args, "client", &len);
|
||||
if (len) {
|
||||
memcpy(buf, param, len);
|
||||
buf[len] = '\0';
|
||||
percent_decode(buf, decname, 0);
|
||||
} else {
|
||||
wserr("client param required\n");
|
||||
goto nope;
|
||||
}
|
||||
|
||||
if (!decname[0])
|
||||
goto nope;
|
||||
|
||||
if (!strcmp(decname, "none")) {
|
||||
waitfor = 0;
|
||||
if (!settings.requestFrameStatsNoneCb(settings.messager))
|
||||
goto nope;
|
||||
} else if (!strcmp(decname, "auto")) {
|
||||
waitfor = settings.ownerConnectedCb(settings.messager);
|
||||
if (!waitfor) {
|
||||
if (!settings.requestFrameStatsNoneCb(settings.messager))
|
||||
goto nope;
|
||||
} else {
|
||||
if (!settings.requestFrameStatsOwnerCb(settings.messager))
|
||||
goto nope;
|
||||
}
|
||||
} else if (!strcmp(decname, "all")) {
|
||||
waitfor = settings.numActiveUsersCb(settings.messager);
|
||||
if (!settings.requestFrameStatsAllCb(settings.messager))
|
||||
goto nope;
|
||||
} else {
|
||||
waitfor = 1;
|
||||
if (!settings.requestFrameStatsOneCb(settings.messager, decname))
|
||||
goto nope;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
usleep(10 * 1000);
|
||||
if (settings.serverFrameStatsReadyCb(settings.messager))
|
||||
break;
|
||||
}
|
||||
|
||||
if (waitfor) {
|
||||
unsigned waits;
|
||||
for (waits = 0; waits < 20; waits++) { // wait up to 2s
|
||||
if (settings.getClientFrameStatsNumCb(settings.messager) >= waitfor)
|
||||
break;
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
settings.frameStatsCb(settings.messager, statbuf, 4096);
|
||||
|
||||
sprintf(buf, "HTTP/1.1 200 OK\r\n"
|
||||
"Server: KasmVNC/4.0\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-type: text/plain\r\n"
|
||||
"Content-length: %lu\r\n"
|
||||
"\r\n", strlen(statbuf));
|
||||
ws_send(ws_ctx, buf, strlen(buf));
|
||||
ws_send(ws_ctx, statbuf, strlen(statbuf));
|
||||
|
||||
wserr("Sent frame stats to API caller\n");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
#undef entry
|
||||
@@ -1231,6 +1350,8 @@ ws_ctx_t *do_handshake(int sock) {
|
||||
} else {
|
||||
// Client tried an empty password, just fail them
|
||||
response[0] = '\0';
|
||||
authbuf[0] = 'a';
|
||||
authbuf[1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,18 @@ typedef struct {
|
||||
const uint8_t write);
|
||||
uint8_t (*removeCb)(void *messager, const char name[]);
|
||||
uint8_t (*givecontrolCb)(void *messager, const char name[]);
|
||||
void (*bottleneckStatsCb)(void *messager, char *buf, uint32_t len);
|
||||
void (*frameStatsCb)(void *messager, char *buf, uint32_t len);
|
||||
|
||||
uint8_t (*requestFrameStatsNoneCb)(void *messager);
|
||||
uint8_t (*requestFrameStatsOwnerCb)(void *messager);
|
||||
uint8_t (*requestFrameStatsAllCb)(void *messager);
|
||||
uint8_t (*requestFrameStatsOneCb)(void *messager, const char *client);
|
||||
|
||||
uint8_t (*ownerConnectedCb)(void *messager);
|
||||
uint8_t (*numActiveUsersCb)(void *messager);
|
||||
uint8_t (*getClientFrameStatsNumCb)(void *messager);
|
||||
uint8_t (*serverFrameStatsReadyCb)(void *messager);
|
||||
} settings_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include "websocket.h"
|
||||
|
||||
/*
|
||||
@@ -42,11 +44,11 @@ static void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
||||
int maxfd, client = ws_ctx->sockfd;
|
||||
unsigned int opcode, left, ret;
|
||||
unsigned int tout_start, tout_end, cout_start, cout_end;
|
||||
unsigned int tin_start, tin_end;
|
||||
unsigned int tin_end;
|
||||
ssize_t len, bytes;
|
||||
|
||||
tout_start = tout_end = cout_start = cout_end =
|
||||
tin_start = tin_end = 0;
|
||||
tin_end = 0;
|
||||
maxfd = client > target ? client+1 : target+1;
|
||||
|
||||
while (1) {
|
||||
@@ -163,7 +165,7 @@ static void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
||||
}
|
||||
|
||||
if (FD_ISSET(client, &rlist)) {
|
||||
bytes = ws_recv(ws_ctx, ws_ctx->tin_buf + tin_end, BUFSIZE-1);
|
||||
bytes = ws_recv(ws_ctx, ws_ctx->tin_buf + tin_end, BUFSIZE-1-tin_end);
|
||||
if (pipe_error) { break; }
|
||||
if (bytes <= 0) {
|
||||
handler_emsg("client closed connection\n");
|
||||
@@ -178,13 +180,13 @@ static void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
||||
printf("\n");
|
||||
*/
|
||||
if (ws_ctx->hybi) {
|
||||
len = decode_hybi(ws_ctx->tin_buf + tin_start,
|
||||
tin_end-tin_start,
|
||||
len = decode_hybi(ws_ctx->tin_buf,
|
||||
tin_end,
|
||||
ws_ctx->tout_buf, BUFSIZE-1,
|
||||
&opcode, &left);
|
||||
} else {
|
||||
len = decode_hixie(ws_ctx->tin_buf + tin_start,
|
||||
tin_end-tin_start,
|
||||
len = decode_hixie(ws_ctx->tin_buf,
|
||||
tin_end,
|
||||
ws_ctx->tout_buf, BUFSIZE-1,
|
||||
&opcode, &left);
|
||||
}
|
||||
@@ -206,10 +208,13 @@ static void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
||||
break;
|
||||
}
|
||||
if (left) {
|
||||
tin_start = tin_end - left;
|
||||
//printf("partial frame from client");
|
||||
const unsigned tin_start = tin_end - left;
|
||||
//handler_emsg("partial frame from client, %u left, start %u end %u, lens %lu %lu\n",
|
||||
// left, tin_start, tin_end, bytes, len);
|
||||
memmove(ws_ctx->tin_buf, ws_ctx->tin_buf + tin_start, left);
|
||||
tin_end = left;
|
||||
} else {
|
||||
tin_start = 0;
|
||||
//handler_emsg("handled %lu/%lu bytes\n", bytes, len);
|
||||
tin_end = 0;
|
||||
}
|
||||
|
||||
@@ -222,14 +227,21 @@ static void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
||||
|
||||
void proxy_handler(ws_ctx_t *ws_ctx) {
|
||||
|
||||
char sockname[32];
|
||||
sprintf(sockname, ".KasmVNCSock%u", getpid());
|
||||
|
||||
struct sockaddr_un addr;
|
||||
addr.sun_family = AF_UNIX;
|
||||
strcpy(addr.sun_path, ".KasmVNCSock");
|
||||
strcpy(addr.sun_path, sockname);
|
||||
addr.sun_path[0] = '\0';
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
struct sockaddr_un myaddr;
|
||||
myaddr.sun_family = AF_UNIX;
|
||||
sprintf(myaddr.sun_path, ".%s@%s", ws_ctx->user, ws_ctx->ip);
|
||||
sprintf(myaddr.sun_path, ".%s@%s_%lu.%lu", ws_ctx->user, ws_ctx->ip,
|
||||
tv.tv_sec, tv.tv_usec);
|
||||
myaddr.sun_path[0] = '\0';
|
||||
|
||||
int tsock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
@@ -238,7 +250,7 @@ void proxy_handler(ws_ctx_t *ws_ctx) {
|
||||
handler_msg("connecting to VNC target\n");
|
||||
|
||||
if (connect(tsock, (struct sockaddr *) &addr,
|
||||
sizeof(sa_family_t) + sizeof(".KasmVNCSock")) < 0) {
|
||||
sizeof(sa_family_t) + strlen(sockname)) < 0) {
|
||||
|
||||
handler_emsg("Could not connect to target: %s\n",
|
||||
strerror(errno));
|
||||
|
||||
69
common/rdr/BufferedInStream.cxx
Normal file
69
common/rdr/BufferedInStream.cxx
Normal file
@@ -0,0 +1,69 @@
|
||||
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
|
||||
* Copyright 2020 Pierre Ossman for Cendio AB
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <rdr/BufferedInStream.h>
|
||||
#include <rdr/Exception.h>
|
||||
|
||||
using namespace rdr;
|
||||
|
||||
static const size_t DEFAULT_BUF_SIZE = 8192;
|
||||
|
||||
BufferedInStream::BufferedInStream()
|
||||
: bufSize(DEFAULT_BUF_SIZE), offset(0)
|
||||
{
|
||||
ptr = end = start = new U8[bufSize];
|
||||
}
|
||||
|
||||
BufferedInStream::~BufferedInStream()
|
||||
{
|
||||
delete [] start;
|
||||
}
|
||||
|
||||
size_t BufferedInStream::pos()
|
||||
{
|
||||
return offset + ptr - start;
|
||||
}
|
||||
|
||||
bool BufferedInStream::overrun(size_t needed, bool wait)
|
||||
{
|
||||
if (needed > bufSize)
|
||||
throw Exception("BufferedInStream overrun: "
|
||||
"requested size of %lu bytes exceeds maximum of %lu bytes",
|
||||
(long unsigned)needed, (long unsigned)bufSize);
|
||||
|
||||
// Do we need to shuffle things around?
|
||||
if ((bufSize - (ptr - start)) < needed) {
|
||||
memmove(start, ptr, end - ptr);
|
||||
|
||||
offset += ptr - start;
|
||||
end -= ptr - start;
|
||||
ptr = start;
|
||||
}
|
||||
|
||||
while (avail() < needed) {
|
||||
if (!fillBuffer(start + bufSize - end, wait))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
54
common/rdr/BufferedInStream.h
Normal file
54
common/rdr/BufferedInStream.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
|
||||
* Copyright 2020 Pierre Ossman for Cendio AB
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Base class for input streams with a buffer
|
||||
//
|
||||
|
||||
#ifndef __RDR_BUFFEREDINSTREAM_H__
|
||||
#define __RDR_BUFFEREDINSTREAM_H__
|
||||
|
||||
#include <rdr/InStream.h>
|
||||
|
||||
namespace rdr {
|
||||
|
||||
class BufferedInStream : public InStream {
|
||||
|
||||
public:
|
||||
virtual ~BufferedInStream();
|
||||
|
||||
virtual size_t pos();
|
||||
|
||||
private:
|
||||
virtual bool fillBuffer(size_t maxSize, bool wait) = 0;
|
||||
|
||||
virtual bool overrun(size_t needed, bool wait);
|
||||
|
||||
private:
|
||||
size_t bufSize;
|
||||
size_t offset;
|
||||
U8* start;
|
||||
|
||||
protected:
|
||||
BufferedInStream();
|
||||
};
|
||||
|
||||
} // end of namespace rdr
|
||||
|
||||
#endif
|
||||
108
common/rdr/BufferedOutStream.cxx
Normal file
108
common/rdr/BufferedOutStream.cxx
Normal file
@@ -0,0 +1,108 @@
|
||||
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
|
||||
* Copyright 2011-2020 Pierre Ossman for Cendio AB
|
||||
* Copyright 2017 Peter Astrand <astrand@cendio.se> for Cendio AB
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <rdr/BufferedOutStream.h>
|
||||
#include <rdr/Exception.h>
|
||||
|
||||
|
||||
using namespace rdr;
|
||||
|
||||
static const size_t DEFAULT_BUF_SIZE = 16384;
|
||||
|
||||
BufferedOutStream::BufferedOutStream()
|
||||
: bufSize(DEFAULT_BUF_SIZE), offset(0)
|
||||
{
|
||||
ptr = start = sentUpTo = new U8[bufSize];
|
||||
end = start + bufSize;
|
||||
}
|
||||
|
||||
BufferedOutStream::~BufferedOutStream()
|
||||
{
|
||||
// FIXME: Complain about non-flushed buffer?
|
||||
delete [] start;
|
||||
}
|
||||
|
||||
size_t BufferedOutStream::length()
|
||||
{
|
||||
return offset + ptr - sentUpTo;
|
||||
}
|
||||
|
||||
size_t BufferedOutStream::bufferUsage()
|
||||
{
|
||||
return ptr - sentUpTo;
|
||||
}
|
||||
|
||||
void BufferedOutStream::flush()
|
||||
{
|
||||
while (sentUpTo < ptr) {
|
||||
size_t len;
|
||||
|
||||
len = bufferUsage();
|
||||
|
||||
if (!flushBuffer(false))
|
||||
break;
|
||||
|
||||
offset += len - bufferUsage();
|
||||
}
|
||||
|
||||
// Managed to flush everything?
|
||||
if (sentUpTo == ptr)
|
||||
ptr = sentUpTo = start;
|
||||
}
|
||||
|
||||
void BufferedOutStream::overrun(size_t needed)
|
||||
{
|
||||
if (needed > bufSize)
|
||||
throw Exception("BufferedOutStream overrun: "
|
||||
"requested size of %lu bytes exceeds maximum of %lu bytes",
|
||||
(long unsigned)needed, (long unsigned)bufSize);
|
||||
|
||||
// First try to get rid of the data we have
|
||||
flush();
|
||||
|
||||
// Still not enough space?
|
||||
while (needed > avail()) {
|
||||
// Can we shuffle things around?
|
||||
// (don't do this if it gains us less than 25%)
|
||||
if (((size_t)(sentUpTo - start) > bufSize / 4) &&
|
||||
(needed < bufSize - (ptr - sentUpTo))) {
|
||||
memmove(start, sentUpTo, ptr - sentUpTo);
|
||||
ptr = start + (ptr - sentUpTo);
|
||||
sentUpTo = start;
|
||||
} else {
|
||||
size_t len;
|
||||
|
||||
len = bufferUsage();
|
||||
|
||||
// Have to get rid of more data, so allow the flush to wait...
|
||||
flushBuffer(true);
|
||||
|
||||
offset += len - bufferUsage();
|
||||
|
||||
// Managed to flush everything?
|
||||
if (sentUpTo == ptr)
|
||||
ptr = sentUpTo = start;
|
||||
}
|
||||
}
|
||||
}
|
||||
65
common/rdr/BufferedOutStream.h
Normal file
65
common/rdr/BufferedOutStream.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
|
||||
* Copyright 2011-2020 Pierre Ossman for Cendio AB
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Base class for output streams with a buffer
|
||||
//
|
||||
|
||||
#ifndef __RDR_BUFFEREDOUTSTREAM_H__
|
||||
#define __RDR_BUFFEREDOUTSTREAM_H__
|
||||
|
||||
#include <rdr/OutStream.h>
|
||||
|
||||
namespace rdr {
|
||||
|
||||
class BufferedOutStream : public OutStream {
|
||||
|
||||
public:
|
||||
virtual ~BufferedOutStream();
|
||||
|
||||
virtual size_t length();
|
||||
virtual void flush();
|
||||
|
||||
size_t bufferUsage();
|
||||
|
||||
private:
|
||||
// flushBuffer() requests that the stream be flushed. Returns true if it is
|
||||
// able to progress the output (which might still not mean any bytes
|
||||
// actually moved) and can be called again. If wait is true then it will
|
||||
// block until all data has been written.
|
||||
|
||||
virtual bool flushBuffer(bool wait) = 0;
|
||||
|
||||
virtual void overrun(size_t needed);
|
||||
|
||||
private:
|
||||
size_t bufSize;
|
||||
size_t offset;
|
||||
U8* start;
|
||||
|
||||
protected:
|
||||
U8* sentUpTo;
|
||||
|
||||
protected:
|
||||
BufferedOutStream();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,8 @@
|
||||
include_directories(${CMAKE_SOURCE_DIR}/common ${ZLIB_INCLUDE_DIRS})
|
||||
|
||||
add_library(rdr STATIC
|
||||
BufferedInStream.cxx
|
||||
BufferedOutStream.cxx
|
||||
Exception.cxx
|
||||
FdInStream.cxx
|
||||
FdOutStream.cxx
|
||||
|
||||
@@ -36,13 +36,6 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef vncmin
|
||||
#define vncmin(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef vncmax
|
||||
#define vncmax(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/* Old systems have select() in sys/time.h */
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
@@ -53,31 +46,22 @@
|
||||
|
||||
using namespace rdr;
|
||||
|
||||
enum { DEFAULT_BUF_SIZE = 8192,
|
||||
MIN_BULK_SIZE = 1024 };
|
||||
enum { DEFAULT_BUF_SIZE = 8192 };
|
||||
|
||||
FdInStream::FdInStream(int fd_, int timeoutms_, size_t bufSize_,
|
||||
FdInStream::FdInStream(int fd_, int timeoutms_,
|
||||
bool closeWhenDone_)
|
||||
: fd(fd_), closeWhenDone(closeWhenDone_),
|
||||
timeoutms(timeoutms_), blockCallback(0),
|
||||
timing(false), timeWaitedIn100us(5), timedKbits(0),
|
||||
bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
|
||||
timeoutms(timeoutms_), blockCallback(0)
|
||||
{
|
||||
ptr = end = start = new U8[bufSize];
|
||||
}
|
||||
|
||||
FdInStream::FdInStream(int fd_, FdInStreamBlockCallback* blockCallback_,
|
||||
size_t bufSize_)
|
||||
: fd(fd_), timeoutms(0), blockCallback(blockCallback_),
|
||||
timing(false), timeWaitedIn100us(5), timedKbits(0),
|
||||
bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
|
||||
FdInStream::FdInStream(int fd_, FdInStreamBlockCallback* blockCallback_)
|
||||
: fd(fd_), timeoutms(0), blockCallback(blockCallback_)
|
||||
{
|
||||
ptr = end = start = new U8[bufSize];
|
||||
}
|
||||
|
||||
FdInStream::~FdInStream()
|
||||
{
|
||||
delete [] start;
|
||||
if (closeWhenDone) close(fd);
|
||||
}
|
||||
|
||||
@@ -92,72 +76,15 @@ void FdInStream::setBlockCallback(FdInStreamBlockCallback* blockCallback_)
|
||||
timeoutms = 0;
|
||||
}
|
||||
|
||||
size_t FdInStream::pos()
|
||||
|
||||
bool FdInStream::fillBuffer(size_t maxSize, bool wait)
|
||||
{
|
||||
return offset + ptr - start;
|
||||
}
|
||||
size_t n = readWithTimeoutOrCallback((U8*)end, maxSize, wait);
|
||||
if (n == 0)
|
||||
return false;
|
||||
end += n;
|
||||
|
||||
void FdInStream::readBytes(void* data, size_t length)
|
||||
{
|
||||
if (length < MIN_BULK_SIZE) {
|
||||
InStream::readBytes(data, length);
|
||||
return;
|
||||
}
|
||||
|
||||
U8* dataPtr = (U8*)data;
|
||||
|
||||
size_t n = end - ptr;
|
||||
if (n > length) n = length;
|
||||
|
||||
memcpy(dataPtr, ptr, n);
|
||||
dataPtr += n;
|
||||
length -= n;
|
||||
ptr += n;
|
||||
|
||||
while (length > 0) {
|
||||
n = readWithTimeoutOrCallback(dataPtr, length);
|
||||
dataPtr += n;
|
||||
length -= n;
|
||||
offset += n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t FdInStream::overrun(size_t itemSize, size_t nItems, bool wait)
|
||||
{
|
||||
if (itemSize > bufSize)
|
||||
throw Exception("FdInStream overrun: max itemSize exceeded");
|
||||
|
||||
if (end - ptr != 0)
|
||||
memmove(start, ptr, end - ptr);
|
||||
|
||||
offset += ptr - start;
|
||||
end -= ptr - start;
|
||||
ptr = start;
|
||||
|
||||
size_t bytes_to_read;
|
||||
while ((size_t)(end - start) < itemSize) {
|
||||
bytes_to_read = start + bufSize - end;
|
||||
if (!timing) {
|
||||
// When not timing, we must be careful not to read too much
|
||||
// extra data into the buffer. Otherwise, the line speed
|
||||
// estimation might stay at zero for a long time: All reads
|
||||
// during timing=1 can be satisfied without calling
|
||||
// readWithTimeoutOrCallback. However, reading only 1 or 2 bytes
|
||||
// bytes is ineffecient.
|
||||
bytes_to_read = vncmin(bytes_to_read, vncmax(itemSize*nItems, 8));
|
||||
}
|
||||
size_t n = readWithTimeoutOrCallback((U8*)end, bytes_to_read, wait);
|
||||
if (n == 0) return 0;
|
||||
end += n;
|
||||
}
|
||||
|
||||
size_t nAvail;
|
||||
nAvail = (end - ptr) / itemSize;
|
||||
if (nAvail < nItems)
|
||||
return nAvail;
|
||||
|
||||
return nItems;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -175,10 +102,6 @@ size_t FdInStream::overrun(size_t itemSize, size_t nItems, bool wait)
|
||||
|
||||
size_t FdInStream::readWithTimeoutOrCallback(void* buf, size_t len, bool wait)
|
||||
{
|
||||
struct timeval before, after;
|
||||
if (timing)
|
||||
gettimeofday(&before, 0);
|
||||
|
||||
int n;
|
||||
while (true) {
|
||||
do {
|
||||
@@ -215,48 +138,5 @@ size_t FdInStream::readWithTimeoutOrCallback(void* buf, size_t len, bool wait)
|
||||
if (n < 0) throw SystemException("read",errno);
|
||||
if (n == 0) throw EndOfStream();
|
||||
|
||||
if (timing) {
|
||||
gettimeofday(&after, 0);
|
||||
int newTimeWaited = ((after.tv_sec - before.tv_sec) * 10000 +
|
||||
(after.tv_usec - before.tv_usec) / 100);
|
||||
int newKbits = n * 8 / 1000;
|
||||
|
||||
// limit rate to between 10kbit/s and 40Mbit/s
|
||||
|
||||
if (newTimeWaited > newKbits*1000) newTimeWaited = newKbits*1000;
|
||||
if (newTimeWaited < newKbits/4) newTimeWaited = newKbits/4;
|
||||
|
||||
timeWaitedIn100us += newTimeWaited;
|
||||
timedKbits += newKbits;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void FdInStream::startTiming()
|
||||
{
|
||||
timing = true;
|
||||
|
||||
// Carry over up to 1s worth of previous rate for smoothing.
|
||||
|
||||
if (timeWaitedIn100us > 10000) {
|
||||
timedKbits = timedKbits * 10000 / timeWaitedIn100us;
|
||||
timeWaitedIn100us = 10000;
|
||||
}
|
||||
}
|
||||
|
||||
void FdInStream::stopTiming()
|
||||
{
|
||||
timing = false;
|
||||
if (timeWaitedIn100us < timedKbits/2)
|
||||
timeWaitedIn100us = timedKbits/2; // upper limit 20Mbit/s
|
||||
}
|
||||
|
||||
unsigned int FdInStream::kbitsPerSecond()
|
||||
{
|
||||
// The following calculation will overflow 32-bit arithmetic if we have
|
||||
// received more than about 50Mbytes (400Mbits) since we started timing, so
|
||||
// it should be OK for a single RFB update.
|
||||
|
||||
return timedKbits * 10000 / timeWaitedIn100us;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#ifndef __RDR_FDINSTREAM_H__
|
||||
#define __RDR_FDINSTREAM_H__
|
||||
|
||||
#include <rdr/InStream.h>
|
||||
#include <rdr/BufferedInStream.h>
|
||||
|
||||
namespace rdr {
|
||||
|
||||
@@ -33,31 +33,21 @@ namespace rdr {
|
||||
virtual ~FdInStreamBlockCallback() {}
|
||||
};
|
||||
|
||||
class FdInStream : public InStream {
|
||||
class FdInStream : public BufferedInStream {
|
||||
|
||||
public:
|
||||
|
||||
FdInStream(int fd, int timeoutms=-1, size_t bufSize=0,
|
||||
bool closeWhenDone_=false);
|
||||
FdInStream(int fd, FdInStreamBlockCallback* blockCallback,
|
||||
size_t bufSize=0);
|
||||
FdInStream(int fd, int timeoutms=-1, bool closeWhenDone_=false);
|
||||
FdInStream(int fd, FdInStreamBlockCallback* blockCallback);
|
||||
virtual ~FdInStream();
|
||||
|
||||
void setTimeout(int timeoutms);
|
||||
void setBlockCallback(FdInStreamBlockCallback* blockCallback);
|
||||
int getFd() { return fd; }
|
||||
size_t pos();
|
||||
void readBytes(void* data, size_t length);
|
||||
|
||||
void startTiming();
|
||||
void stopTiming();
|
||||
unsigned int kbitsPerSecond();
|
||||
unsigned int timeWaited() { return timeWaitedIn100us; }
|
||||
|
||||
protected:
|
||||
size_t overrun(size_t itemSize, size_t nItems, bool wait);
|
||||
|
||||
private:
|
||||
virtual bool fillBuffer(size_t maxSize, bool wait);
|
||||
|
||||
size_t readWithTimeoutOrCallback(void* buf, size_t len, bool wait=true);
|
||||
|
||||
int fd;
|
||||
@@ -65,11 +55,6 @@ namespace rdr {
|
||||
int timeoutms;
|
||||
FdInStreamBlockCallback* blockCallback;
|
||||
|
||||
bool timing;
|
||||
unsigned int timeWaitedIn100us;
|
||||
unsigned int timedKbits;
|
||||
|
||||
size_t bufSize;
|
||||
size_t offset;
|
||||
U8* start;
|
||||
};
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
|
||||
/* Old systems have select() in sys/time.h */
|
||||
@@ -49,26 +51,19 @@
|
||||
|
||||
using namespace rdr;
|
||||
|
||||
enum { DEFAULT_BUF_SIZE = 16384 };
|
||||
|
||||
FdOutStream::FdOutStream(int fd_, bool blocking_, int timeoutms_, size_t bufSize_)
|
||||
: fd(fd_), blocking(blocking_), timeoutms(timeoutms_),
|
||||
bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
|
||||
FdOutStream::FdOutStream(int fd_, bool blocking_, int timeoutms_)
|
||||
: fd(fd_), blocking(blocking_), timeoutms(timeoutms_)
|
||||
{
|
||||
ptr = start = sentUpTo = new U8[bufSize];
|
||||
end = start + bufSize;
|
||||
|
||||
gettimeofday(&lastWrite, NULL);
|
||||
}
|
||||
|
||||
FdOutStream::~FdOutStream()
|
||||
{
|
||||
try {
|
||||
blocking = true;
|
||||
flush();
|
||||
while (sentUpTo != ptr)
|
||||
flushBuffer(true);
|
||||
} catch (Exception&) {
|
||||
}
|
||||
delete [] start;
|
||||
}
|
||||
|
||||
void FdOutStream::setTimeout(int timeoutms_) {
|
||||
@@ -79,82 +74,29 @@ void FdOutStream::setBlocking(bool blocking_) {
|
||||
blocking = blocking_;
|
||||
}
|
||||
|
||||
size_t FdOutStream::length()
|
||||
{
|
||||
return offset + ptr - sentUpTo;
|
||||
}
|
||||
|
||||
int FdOutStream::bufferUsage()
|
||||
{
|
||||
return ptr - sentUpTo;
|
||||
}
|
||||
|
||||
unsigned FdOutStream::getIdleTime()
|
||||
{
|
||||
return rfb::msSince(&lastWrite);
|
||||
}
|
||||
|
||||
void FdOutStream::flush()
|
||||
bool FdOutStream::flushBuffer(bool wait)
|
||||
{
|
||||
while (sentUpTo < ptr) {
|
||||
size_t n = writeWithTimeout((const void*) sentUpTo,
|
||||
ptr - sentUpTo,
|
||||
blocking? timeoutms : 0);
|
||||
size_t n = writeWithTimeout((const void*) sentUpTo,
|
||||
ptr - sentUpTo,
|
||||
(blocking || wait)? timeoutms : 0);
|
||||
|
||||
// Timeout?
|
||||
if (n == 0) {
|
||||
// If non-blocking then we're done here
|
||||
if (!blocking)
|
||||
break;
|
||||
// Timeout?
|
||||
if (n == 0) {
|
||||
// If non-blocking then we're done here
|
||||
if (!blocking && !wait)
|
||||
return false;
|
||||
|
||||
throw TimedOut();
|
||||
}
|
||||
|
||||
sentUpTo += n;
|
||||
offset += n;
|
||||
throw TimedOut();
|
||||
}
|
||||
|
||||
// Managed to flush everything?
|
||||
if (sentUpTo == ptr)
|
||||
ptr = sentUpTo = start;
|
||||
}
|
||||
sentUpTo += n;
|
||||
|
||||
|
||||
size_t FdOutStream::overrun(size_t itemSize, size_t nItems)
|
||||
{
|
||||
if (itemSize > bufSize)
|
||||
throw Exception("FdOutStream overrun: max itemSize exceeded");
|
||||
|
||||
// First try to get rid of the data we have
|
||||
flush();
|
||||
|
||||
// Still not enough space?
|
||||
if (itemSize > (size_t)(end - ptr)) {
|
||||
// Can we shuffle things around?
|
||||
// (don't do this if it gains us less than 25%)
|
||||
if (((size_t)(sentUpTo - start) > bufSize / 4) &&
|
||||
(itemSize < bufSize - (ptr - sentUpTo))) {
|
||||
memmove(start, sentUpTo, ptr - sentUpTo);
|
||||
ptr = start + (ptr - sentUpTo);
|
||||
sentUpTo = start;
|
||||
} else {
|
||||
// Have to get rid of more data, so turn off non-blocking
|
||||
// for a bit...
|
||||
bool realBlocking;
|
||||
|
||||
realBlocking = blocking;
|
||||
blocking = true;
|
||||
flush();
|
||||
blocking = realBlocking;
|
||||
}
|
||||
}
|
||||
|
||||
size_t nAvail;
|
||||
nAvail = (end - ptr) / itemSize;
|
||||
if (nAvail < nItems)
|
||||
return nAvail;
|
||||
|
||||
return nItems;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -26,38 +26,29 @@
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <rdr/OutStream.h>
|
||||
#include <rdr/BufferedOutStream.h>
|
||||
|
||||
namespace rdr {
|
||||
|
||||
class FdOutStream : public OutStream {
|
||||
class FdOutStream : public BufferedOutStream {
|
||||
|
||||
public:
|
||||
|
||||
FdOutStream(int fd, bool blocking=true, int timeoutms=-1, size_t bufSize=0);
|
||||
FdOutStream(int fd, bool blocking=true, int timeoutms=-1);
|
||||
virtual ~FdOutStream();
|
||||
|
||||
void setTimeout(int timeoutms);
|
||||
void setBlocking(bool blocking);
|
||||
int getFd() { return fd; }
|
||||
|
||||
void flush();
|
||||
size_t length();
|
||||
|
||||
int bufferUsage();
|
||||
|
||||
unsigned getIdleTime();
|
||||
|
||||
private:
|
||||
size_t overrun(size_t itemSize, size_t nItems);
|
||||
virtual bool flushBuffer(bool wait);
|
||||
size_t writeWithTimeout(const void* data, size_t length, int timeoutms);
|
||||
int fd;
|
||||
bool blocking;
|
||||
int timeoutms;
|
||||
size_t bufSize;
|
||||
size_t offset;
|
||||
U8* start;
|
||||
U8* sentUpTo;
|
||||
struct timeval lastWrite;
|
||||
};
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ FileInStream::FileInStream(const char *fileName)
|
||||
file = fopen(fileName, "rb");
|
||||
if (!file)
|
||||
throw SystemException("fopen", errno);
|
||||
ptr = end = b;
|
||||
}
|
||||
|
||||
FileInStream::~FileInStream(void) {
|
||||
@@ -40,50 +39,17 @@ FileInStream::~FileInStream(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void FileInStream::reset(void) {
|
||||
if (!file)
|
||||
throw Exception("File is not open");
|
||||
if (fseek(file, 0, SEEK_SET) != 0)
|
||||
throw SystemException("fseek", errno);
|
||||
ptr = end = b;
|
||||
}
|
||||
|
||||
size_t FileInStream::pos()
|
||||
bool FileInStream::fillBuffer(size_t maxSize, bool wait)
|
||||
{
|
||||
if (!file)
|
||||
throw Exception("File is not open");
|
||||
|
||||
return ftell(file) + ptr - b;
|
||||
}
|
||||
|
||||
size_t FileInStream::overrun(size_t itemSize, size_t nItems, bool wait)
|
||||
{
|
||||
if (itemSize > sizeof(b))
|
||||
throw Exception("FileInStream overrun: max itemSize exceeded");
|
||||
|
||||
if (end - ptr != 0)
|
||||
memmove(b, ptr, end - ptr);
|
||||
|
||||
end -= ptr - b;
|
||||
ptr = b;
|
||||
|
||||
|
||||
while ((size_t)(end - b) < itemSize) {
|
||||
size_t n = fread((U8 *)end, b + sizeof(b) - end, 1, file);
|
||||
if (n == 0) {
|
||||
if (ferror(file))
|
||||
throw SystemException("fread", errno);
|
||||
if (feof(file))
|
||||
throw EndOfStream();
|
||||
return 0;
|
||||
}
|
||||
end += b + sizeof(b) - end;
|
||||
size_t n = fread((U8 *)end, 1, maxSize, file);
|
||||
if (n == 0) {
|
||||
if (ferror(file))
|
||||
throw SystemException("fread", errno);
|
||||
if (feof(file))
|
||||
throw EndOfStream();
|
||||
return false;
|
||||
}
|
||||
end += n;
|
||||
|
||||
size_t nAvail;
|
||||
nAvail = (end - ptr) / itemSize;
|
||||
if (nAvail < nItems)
|
||||
return nAvail;
|
||||
|
||||
return nItems;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -22,26 +22,21 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <rdr/InStream.h>
|
||||
#include <rdr/BufferedInStream.h>
|
||||
|
||||
namespace rdr {
|
||||
|
||||
class FileInStream : public InStream {
|
||||
class FileInStream : public BufferedInStream {
|
||||
|
||||
public:
|
||||
|
||||
FileInStream(const char *fileName);
|
||||
~FileInStream(void);
|
||||
|
||||
void reset(void);
|
||||
|
||||
size_t pos();
|
||||
|
||||
protected:
|
||||
size_t overrun(size_t itemSize, size_t nItems, bool wait = true);
|
||||
private:
|
||||
virtual bool fillBuffer(size_t maxSize, bool wait);
|
||||
|
||||
private:
|
||||
U8 b[131072];
|
||||
FILE *file;
|
||||
};
|
||||
|
||||
|
||||
@@ -24,18 +24,14 @@
|
||||
|
||||
using namespace rdr;
|
||||
|
||||
const int DEFAULT_BUF_LEN = 16384;
|
||||
|
||||
static inline int min(int a, int b) {return a<b ? a : b;}
|
||||
|
||||
HexInStream::HexInStream(InStream& is, size_t bufSize_)
|
||||
: bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_LEN), offset(0), in_stream(is)
|
||||
HexInStream::HexInStream(InStream& is)
|
||||
: in_stream(is)
|
||||
{
|
||||
ptr = end = start = new U8[bufSize];
|
||||
}
|
||||
|
||||
HexInStream::~HexInStream() {
|
||||
delete [] start;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,44 +72,24 @@ decodeError:
|
||||
}
|
||||
|
||||
|
||||
size_t HexInStream::pos() {
|
||||
return offset + ptr - start;
|
||||
}
|
||||
bool HexInStream::fillBuffer(size_t maxSize, bool wait) {
|
||||
if (!in_stream.check(2, wait))
|
||||
return false;
|
||||
|
||||
size_t HexInStream::overrun(size_t itemSize, size_t nItems, bool wait) {
|
||||
if (itemSize > bufSize)
|
||||
throw Exception("HexInStream overrun: max itemSize exceeded");
|
||||
const U8* iptr = in_stream.getptr();
|
||||
const U8* eptr = in_stream.getend();
|
||||
size_t length = min((eptr - iptr)/2, maxSize);
|
||||
|
||||
if (end - ptr != 0)
|
||||
memmove(start, ptr, end - ptr);
|
||||
|
||||
end -= ptr - start;
|
||||
offset += ptr - start;
|
||||
ptr = start;
|
||||
|
||||
while ((size_t)(end - ptr) < itemSize) {
|
||||
size_t n = in_stream.check(2, 1, wait);
|
||||
if (n == 0) return 0;
|
||||
const U8* iptr = in_stream.getptr();
|
||||
const U8* eptr = in_stream.getend();
|
||||
size_t length = min((eptr - iptr)/2, start + bufSize - end);
|
||||
|
||||
U8* optr = (U8*) end;
|
||||
for (size_t i=0; i<length; i++) {
|
||||
int v = 0;
|
||||
readHexAndShift(iptr[i*2], &v);
|
||||
readHexAndShift(iptr[i*2+1], &v);
|
||||
optr[i] = v;
|
||||
}
|
||||
|
||||
in_stream.setptr(iptr + length*2);
|
||||
end += length;
|
||||
U8* optr = (U8*) end;
|
||||
for (size_t i=0; i<length; i++) {
|
||||
int v = 0;
|
||||
readHexAndShift(iptr[i*2], &v);
|
||||
readHexAndShift(iptr[i*2+1], &v);
|
||||
optr[i] = v;
|
||||
}
|
||||
|
||||
size_t nAvail;
|
||||
nAvail = (end - ptr) / itemSize;
|
||||
if (nAvail < nItems)
|
||||
return nAvail;
|
||||
in_stream.setptr(iptr + length*2);
|
||||
end += length;
|
||||
|
||||
return nItems;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -19,29 +19,23 @@
|
||||
#ifndef __RDR_HEX_INSTREAM_H__
|
||||
#define __RDR_HEX_INSTREAM_H__
|
||||
|
||||
#include <rdr/InStream.h>
|
||||
#include <rdr/BufferedInStream.h>
|
||||
|
||||
namespace rdr {
|
||||
|
||||
class HexInStream : public InStream {
|
||||
class HexInStream : public BufferedInStream {
|
||||
public:
|
||||
|
||||
HexInStream(InStream& is, size_t bufSize=0);
|
||||
HexInStream(InStream& is);
|
||||
virtual ~HexInStream();
|
||||
|
||||
size_t pos();
|
||||
|
||||
static bool readHexAndShift(char c, int* v);
|
||||
static bool hexStrToBin(const char* s, char** data, size_t* length);
|
||||
|
||||
protected:
|
||||
size_t overrun(size_t itemSize, size_t nItems, bool wait);
|
||||
private:
|
||||
virtual bool fillBuffer(size_t maxSize, bool wait);
|
||||
|
||||
private:
|
||||
size_t bufSize;
|
||||
U8* start;
|
||||
size_t offset;
|
||||
|
||||
InStream& in_stream;
|
||||
};
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ const int DEFAULT_BUF_LEN = 16384;
|
||||
|
||||
static inline size_t min(size_t a, size_t b) {return a<b ? a : b;}
|
||||
|
||||
HexOutStream::HexOutStream(OutStream& os, size_t buflen)
|
||||
: out_stream(os), offset(0), bufSize(buflen ? buflen : DEFAULT_BUF_LEN)
|
||||
HexOutStream::HexOutStream(OutStream& os)
|
||||
: out_stream(os), offset(0), bufSize(DEFAULT_BUF_LEN)
|
||||
{
|
||||
if (bufSize % 2)
|
||||
bufSize--;
|
||||
@@ -95,18 +95,10 @@ HexOutStream::flush() {
|
||||
out_stream.flush();
|
||||
}
|
||||
|
||||
size_t
|
||||
HexOutStream::overrun(size_t itemSize, size_t nItems) {
|
||||
if (itemSize > bufSize)
|
||||
throw Exception("HexOutStream overrun: max itemSize exceeded");
|
||||
void HexOutStream::overrun(size_t needed) {
|
||||
if (needed > bufSize)
|
||||
throw Exception("HexOutStream overrun: buffer size exceeded");
|
||||
|
||||
writeBuffer();
|
||||
|
||||
size_t nAvail;
|
||||
nAvail = (end - ptr) / itemSize;
|
||||
if (nAvail < nItems)
|
||||
return nAvail;
|
||||
|
||||
return nItems;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace rdr {
|
||||
class HexOutStream : public OutStream {
|
||||
public:
|
||||
|
||||
HexOutStream(OutStream& os, size_t buflen=0);
|
||||
HexOutStream(OutStream& os);
|
||||
virtual ~HexOutStream();
|
||||
|
||||
void flush();
|
||||
@@ -37,7 +37,7 @@ namespace rdr {
|
||||
|
||||
private:
|
||||
void writeBuffer();
|
||||
size_t overrun(size_t itemSize, size_t nItems);
|
||||
virtual void overrun(size_t needed);
|
||||
|
||||
OutStream& out_stream;
|
||||
|
||||
|
||||
@@ -35,28 +35,25 @@ namespace rdr {
|
||||
|
||||
virtual ~InStream() {}
|
||||
|
||||
// check() ensures there is buffer data for at least one item of size
|
||||
// itemSize bytes. Returns the number of items in the buffer (up to a
|
||||
// maximum of nItems). If wait is false, then instead of blocking to wait
|
||||
// for the bytes, zero is returned if the bytes are not immediately
|
||||
// available. If itemSize or nItems is zero, check() will return zero.
|
||||
// avail() returns the number of bytes that are currenctly directly
|
||||
// available from the stream.
|
||||
|
||||
inline size_t check(size_t itemSize, size_t nItems=1, bool wait=true)
|
||||
inline size_t avail()
|
||||
{
|
||||
size_t nAvail;
|
||||
return end - ptr;
|
||||
}
|
||||
|
||||
if (itemSize == 0 || nItems == 0)
|
||||
return 0;
|
||||
// check() ensures there is buffer data for at least needed bytes. Returns
|
||||
// true once the data is available. If wait is false, then instead of
|
||||
// blocking to wait for the bytes, false is returned if the bytes are not
|
||||
// immediately available.
|
||||
|
||||
if (itemSize > (size_t)(end - ptr))
|
||||
return overrun(itemSize, nItems, wait);
|
||||
inline size_t check(size_t needed, bool wait=true)
|
||||
{
|
||||
if (needed > avail())
|
||||
return overrun(needed, wait);
|
||||
|
||||
// itemSize cannot be zero at this point
|
||||
nAvail = (end - ptr) / itemSize;
|
||||
if (nAvail < nItems)
|
||||
return nAvail;
|
||||
|
||||
return nItems;
|
||||
return true;
|
||||
}
|
||||
|
||||
// checkNoWait() tries to make sure that the given number of bytes can
|
||||
@@ -64,10 +61,7 @@ namespace rdr {
|
||||
// otherwise. The length must be "small" (less than the buffer size).
|
||||
// If length is zero, checkNoWait() will return true.
|
||||
|
||||
inline bool checkNoWait(size_t length)
|
||||
{
|
||||
return length == 0 || check(length, 1, false) > 0;
|
||||
}
|
||||
inline bool checkNoWait(size_t length) { return check(length, false); }
|
||||
|
||||
// readU/SN() methods read unsigned and signed N-bit integers.
|
||||
|
||||
@@ -138,13 +132,12 @@ namespace rdr {
|
||||
private:
|
||||
|
||||
// overrun() is implemented by a derived class to cope with buffer overrun.
|
||||
// It ensures there are at least itemSize bytes of buffer data. Returns
|
||||
// the number of items in the buffer (up to a maximum of nItems). itemSize
|
||||
// is supposed to be "small" (a few bytes). If wait is false, then
|
||||
// instead of blocking to wait for the bytes, zero is returned if the bytes
|
||||
// are not immediately available.
|
||||
// It ensures there are at least needed bytes of buffer data. Returns true
|
||||
// once the data is available. If wait is false, then instead of blocking
|
||||
// to wait for the bytes, false is returned if the bytes are not
|
||||
// immediately available.
|
||||
|
||||
virtual size_t overrun(size_t itemSize, size_t nItems, bool wait=true) = 0;
|
||||
virtual bool overrun(size_t needed, bool wait=true) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace rdr {
|
||||
|
||||
private:
|
||||
|
||||
size_t overrun(size_t itemSize, size_t nItems, bool wait) { throw EndOfStream(); }
|
||||
bool overrun(size_t needed, bool wait) { throw EndOfStream(); }
|
||||
const U8* start;
|
||||
bool deleteWhenDone;
|
||||
};
|
||||
|
||||
@@ -41,12 +41,6 @@ namespace rdr {
|
||||
delete [] start;
|
||||
}
|
||||
|
||||
void writeBytes(const void* data, size_t length) {
|
||||
check(length);
|
||||
memcpy(ptr, data, length);
|
||||
ptr += length;
|
||||
}
|
||||
|
||||
size_t length() { return ptr - start; }
|
||||
void clear() { ptr = start; };
|
||||
void clearAndZero() { memset(start, 0, ptr-start); clear(); }
|
||||
@@ -58,11 +52,11 @@ namespace rdr {
|
||||
|
||||
protected:
|
||||
|
||||
// overrun() either doubles the buffer or adds enough space for nItems of
|
||||
// size itemSize bytes.
|
||||
// overrun() either doubles the buffer or adds enough space for
|
||||
// needed bytes.
|
||||
|
||||
size_t overrun(size_t itemSize, size_t nItems) {
|
||||
size_t len = ptr - start + itemSize * nItems;
|
||||
virtual void overrun(size_t needed) {
|
||||
size_t len = ptr - start + needed;
|
||||
if (len < (size_t)(end - start) * 2)
|
||||
len = (end - start) * 2;
|
||||
|
||||
@@ -75,8 +69,6 @@ namespace rdr {
|
||||
delete [] start;
|
||||
start = newStart;
|
||||
end = newStart + len;
|
||||
|
||||
return nItems;
|
||||
}
|
||||
|
||||
U8* start;
|
||||
|
||||
@@ -40,22 +40,20 @@ namespace rdr {
|
||||
|
||||
virtual ~OutStream() {}
|
||||
|
||||
// check() ensures there is buffer space for at least one item of size
|
||||
// itemSize bytes. Returns the number of items which fit (up to a maximum
|
||||
// of nItems).
|
||||
// avail() returns the number of bytes that currently be written to the
|
||||
// stream without any risk of blocking.
|
||||
|
||||
inline size_t check(size_t itemSize, size_t nItems=1)
|
||||
inline size_t avail()
|
||||
{
|
||||
size_t nAvail;
|
||||
return end - ptr;
|
||||
}
|
||||
|
||||
if (itemSize > (size_t)(end - ptr))
|
||||
return overrun(itemSize, nItems);
|
||||
// check() ensures there is buffer space for at least needed bytes.
|
||||
|
||||
nAvail = (end - ptr) / itemSize;
|
||||
if (nAvail < nItems)
|
||||
return nAvail;
|
||||
|
||||
return nItems;
|
||||
inline void check(size_t needed)
|
||||
{
|
||||
if (needed > avail())
|
||||
overrun(needed);
|
||||
}
|
||||
|
||||
// writeU/SN() methods write unsigned and signed N-bit integers.
|
||||
@@ -83,19 +81,14 @@ namespace rdr {
|
||||
while (bytes-- > 0) writeU8(0);
|
||||
}
|
||||
|
||||
inline void skip(size_t bytes) {
|
||||
while (bytes > 0) {
|
||||
size_t n = check(1, bytes);
|
||||
ptr += n;
|
||||
bytes -= n;
|
||||
}
|
||||
}
|
||||
|
||||
// writeBytes() writes an exact number of bytes.
|
||||
|
||||
void writeBytes(const void* data, size_t length) {
|
||||
while (length > 0) {
|
||||
size_t n = check(1, length);
|
||||
check(1);
|
||||
size_t n = length;
|
||||
if (length > avail())
|
||||
n = avail();
|
||||
memcpy(ptr, data, n);
|
||||
ptr += n;
|
||||
data = (U8*)data + n;
|
||||
@@ -107,7 +100,10 @@ namespace rdr {
|
||||
|
||||
void copyBytes(InStream* is, size_t length) {
|
||||
while (length > 0) {
|
||||
size_t n = check(1, length);
|
||||
check(1);
|
||||
size_t n = length;
|
||||
if (length > avail())
|
||||
n = avail();
|
||||
is->readBytes(ptr, n);
|
||||
ptr += n;
|
||||
length -= n;
|
||||
@@ -143,11 +139,9 @@ namespace rdr {
|
||||
private:
|
||||
|
||||
// overrun() is implemented by a derived class to cope with buffer overrun.
|
||||
// It ensures there are at least itemSize bytes of buffer space. Returns
|
||||
// the number of items which fit (up to a maximum of nItems). itemSize is
|
||||
// supposed to be "small" (a few bytes).
|
||||
// It ensures there are at least needed bytes of buffer space.
|
||||
|
||||
virtual size_t overrun(size_t itemSize, size_t nItems) = 0;
|
||||
virtual void overrun(size_t needed) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@@ -32,15 +32,10 @@
|
||||
|
||||
using namespace rdr;
|
||||
|
||||
const size_t DEFAULT_BUF_LEN = 256;
|
||||
|
||||
unsigned int RandomStream::seed;
|
||||
|
||||
RandomStream::RandomStream()
|
||||
: offset(0)
|
||||
{
|
||||
ptr = end = start = new U8[DEFAULT_BUF_LEN];
|
||||
|
||||
#ifdef RFB_HAVE_WINCRYPT
|
||||
provider = 0;
|
||||
if (!CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, 0)) {
|
||||
@@ -72,8 +67,6 @@ RandomStream::RandomStream()
|
||||
}
|
||||
|
||||
RandomStream::~RandomStream() {
|
||||
delete [] start;
|
||||
|
||||
#ifdef RFB_HAVE_WINCRYPT
|
||||
if (provider)
|
||||
CryptReleaseContext(provider, 0);
|
||||
@@ -83,50 +76,29 @@ RandomStream::~RandomStream() {
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t RandomStream::pos() {
|
||||
return offset + ptr - start;
|
||||
}
|
||||
|
||||
size_t RandomStream::overrun(size_t itemSize, size_t nItems, bool wait) {
|
||||
if (itemSize > DEFAULT_BUF_LEN)
|
||||
throw Exception("RandomStream overrun: max itemSize exceeded");
|
||||
|
||||
if (end - ptr != 0)
|
||||
memmove(start, ptr, end - ptr);
|
||||
|
||||
end -= ptr - start;
|
||||
offset += ptr - start;
|
||||
ptr = start;
|
||||
|
||||
size_t length = start + DEFAULT_BUF_LEN - end;
|
||||
|
||||
bool RandomStream::fillBuffer(size_t maxSize, bool wait) {
|
||||
#ifdef RFB_HAVE_WINCRYPT
|
||||
if (provider) {
|
||||
if (!CryptGenRandom(provider, length, (U8*)end))
|
||||
if (!CryptGenRandom(provider, maxSize, (U8*)end))
|
||||
throw rdr::SystemException("unable to CryptGenRandom", GetLastError());
|
||||
end += length;
|
||||
end += maxSize;
|
||||
} else {
|
||||
#else
|
||||
#ifndef WIN32
|
||||
if (fp) {
|
||||
size_t n = fread((U8*)end, length, 1, fp);
|
||||
if (n != 1)
|
||||
size_t n = fread((U8*)end, 1, maxSize, fp);
|
||||
if (n <= 0)
|
||||
throw rdr::SystemException("reading /dev/urandom or /dev/random failed",
|
||||
errno);
|
||||
end += length;
|
||||
end += n;
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
#endif
|
||||
for (size_t i=0; i<length; i++)
|
||||
for (size_t i=0; i<maxSize; i++)
|
||||
*(U8*)end++ = (int) (256.0*rand()/(RAND_MAX+1.0));
|
||||
}
|
||||
|
||||
size_t nAvail;
|
||||
nAvail = (end - ptr) / itemSize;
|
||||
if (nAvail < nItems)
|
||||
return nAvail;
|
||||
|
||||
return nItems;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#define __RDR_RANDOMSTREAM_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <rdr/InStream.h>
|
||||
#include <rdr/BufferedInStream.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
@@ -32,22 +32,17 @@
|
||||
|
||||
namespace rdr {
|
||||
|
||||
class RandomStream : public InStream {
|
||||
class RandomStream : public BufferedInStream {
|
||||
|
||||
public:
|
||||
|
||||
RandomStream();
|
||||
virtual ~RandomStream();
|
||||
|
||||
size_t pos();
|
||||
|
||||
protected:
|
||||
size_t overrun(size_t itemSize, size_t nItems, bool wait);
|
||||
private:
|
||||
virtual bool fillBuffer(size_t maxSize, bool wait);
|
||||
|
||||
private:
|
||||
U8* start;
|
||||
size_t offset;
|
||||
|
||||
static unsigned int seed;
|
||||
#ifdef RFB_HAVE_WINCRYPT
|
||||
HCRYPTPROV provider;
|
||||
|
||||
@@ -30,21 +30,19 @@
|
||||
#ifdef HAVE_GNUTLS
|
||||
using namespace rdr;
|
||||
|
||||
enum { DEFAULT_BUF_SIZE = 16384 };
|
||||
|
||||
ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size)
|
||||
{
|
||||
TLSInStream* self= (TLSInStream*) str;
|
||||
InStream *in = self->in;
|
||||
|
||||
try {
|
||||
if (!in->check(1, 1, false)) {
|
||||
if (!in->check(1, false)) {
|
||||
gnutls_transport_set_errno(self->session, EAGAIN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((size_t)(in->getend() - in->getptr()) < size)
|
||||
size = in->getend() - in->getptr();
|
||||
if (in->avail() < size)
|
||||
size = in->avail();
|
||||
|
||||
in->readBytes(data, size);
|
||||
|
||||
@@ -57,12 +55,10 @@ ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size)
|
||||
}
|
||||
|
||||
TLSInStream::TLSInStream(InStream* _in, gnutls_session_t _session)
|
||||
: session(_session), in(_in), bufSize(DEFAULT_BUF_SIZE), offset(0)
|
||||
: session(_session), in(_in)
|
||||
{
|
||||
gnutls_transport_ptr_t recv, send;
|
||||
|
||||
ptr = end = start = new U8[bufSize];
|
||||
|
||||
gnutls_transport_set_pull_function(session, pull);
|
||||
gnutls_transport_get_ptr2(session, &recv, &send);
|
||||
gnutls_transport_set_ptr2(session, this, send);
|
||||
@@ -71,40 +67,16 @@ TLSInStream::TLSInStream(InStream* _in, gnutls_session_t _session)
|
||||
TLSInStream::~TLSInStream()
|
||||
{
|
||||
gnutls_transport_set_pull_function(session, NULL);
|
||||
|
||||
delete[] start;
|
||||
}
|
||||
|
||||
size_t TLSInStream::pos()
|
||||
bool TLSInStream::fillBuffer(size_t maxSize, bool wait)
|
||||
{
|
||||
return offset + ptr - start;
|
||||
}
|
||||
size_t n = readTLS((U8*) end, maxSize, wait);
|
||||
if (!wait && n == 0)
|
||||
return false;
|
||||
end += n;
|
||||
|
||||
size_t TLSInStream::overrun(size_t itemSize, size_t nItems, bool wait)
|
||||
{
|
||||
if (itemSize > bufSize)
|
||||
throw Exception("TLSInStream overrun: max itemSize exceeded");
|
||||
|
||||
if (end - ptr != 0)
|
||||
memmove(start, ptr, end - ptr);
|
||||
|
||||
offset += ptr - start;
|
||||
end -= ptr - start;
|
||||
ptr = start;
|
||||
|
||||
while ((size_t)(end - start) < itemSize) {
|
||||
size_t n = readTLS((U8*) end, start + bufSize - end, wait);
|
||||
if (!wait && n == 0)
|
||||
return 0;
|
||||
end += n;
|
||||
}
|
||||
|
||||
size_t nAvail;
|
||||
nAvail = (end - ptr) / itemSize;
|
||||
if (nAvail < nItems)
|
||||
return nAvail;
|
||||
|
||||
return nItems;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t TLSInStream::readTLS(U8* buf, size_t len, bool wait)
|
||||
@@ -112,7 +84,7 @@ size_t TLSInStream::readTLS(U8* buf, size_t len, bool wait)
|
||||
int n;
|
||||
|
||||
if (gnutls_record_check_pending(session) == 0) {
|
||||
n = in->check(1, 1, wait);
|
||||
n = in->check(1, wait);
|
||||
if (n == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -27,27 +27,22 @@
|
||||
#ifdef HAVE_GNUTLS
|
||||
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <rdr/InStream.h>
|
||||
#include <rdr/BufferedInStream.h>
|
||||
|
||||
namespace rdr {
|
||||
|
||||
class TLSInStream : public InStream {
|
||||
class TLSInStream : public BufferedInStream {
|
||||
public:
|
||||
TLSInStream(InStream* in, gnutls_session_t session);
|
||||
virtual ~TLSInStream();
|
||||
|
||||
size_t pos();
|
||||
|
||||
private:
|
||||
size_t overrun(size_t itemSize, size_t nItems, bool wait);
|
||||
virtual bool fillBuffer(size_t maxSize, bool wait);
|
||||
size_t readTLS(U8* buf, size_t len, bool wait);
|
||||
static ssize_t pull(gnutls_transport_ptr_t str, void* data, size_t size);
|
||||
|
||||
gnutls_session_t session;
|
||||
InStream* in;
|
||||
size_t bufSize;
|
||||
size_t offset;
|
||||
U8* start;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -93,19 +93,12 @@ void TLSOutStream::flush()
|
||||
out->flush();
|
||||
}
|
||||
|
||||
size_t TLSOutStream::overrun(size_t itemSize, size_t nItems)
|
||||
void TLSOutStream::overrun(size_t needed)
|
||||
{
|
||||
if (itemSize > bufSize)
|
||||
throw Exception("TLSOutStream overrun: max itemSize exceeded");
|
||||
if (needed > bufSize)
|
||||
throw Exception("TLSOutStream overrun: buffer size exceeded");
|
||||
|
||||
flush();
|
||||
|
||||
size_t nAvail;
|
||||
nAvail = (end - ptr) / itemSize;
|
||||
if (nAvail < nItems)
|
||||
return nAvail;
|
||||
|
||||
return nItems;
|
||||
}
|
||||
|
||||
size_t TLSOutStream::writeTLS(const U8* data, size_t length)
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace rdr {
|
||||
size_t length();
|
||||
|
||||
protected:
|
||||
size_t overrun(size_t itemSize, size_t nItems);
|
||||
virtual void overrun(size_t needed);
|
||||
|
||||
private:
|
||||
size_t writeTLS(const U8* data, size_t length);
|
||||
|
||||
@@ -24,41 +24,30 @@
|
||||
|
||||
using namespace rdr;
|
||||
|
||||
enum { DEFAULT_BUF_SIZE = 16384 };
|
||||
|
||||
ZlibInStream::ZlibInStream(size_t bufSize_)
|
||||
: underlying(0), bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0),
|
||||
zs(NULL), bytesIn(0)
|
||||
ZlibInStream::ZlibInStream()
|
||||
: underlying(0), zs(NULL), bytesIn(0)
|
||||
{
|
||||
ptr = end = start = new U8[bufSize];
|
||||
init();
|
||||
}
|
||||
|
||||
ZlibInStream::~ZlibInStream()
|
||||
{
|
||||
deinit();
|
||||
delete [] start;
|
||||
}
|
||||
|
||||
void ZlibInStream::setUnderlying(InStream* is, size_t bytesIn_)
|
||||
{
|
||||
underlying = is;
|
||||
bytesIn = bytesIn_;
|
||||
ptr = end = start;
|
||||
}
|
||||
|
||||
size_t ZlibInStream::pos()
|
||||
{
|
||||
return offset + ptr - start;
|
||||
skip(avail());
|
||||
}
|
||||
|
||||
void ZlibInStream::flushUnderlying()
|
||||
{
|
||||
ptr = end = start;
|
||||
|
||||
while (bytesIn > 0) {
|
||||
decompress(true);
|
||||
end = start; // throw away any data
|
||||
if (!check(1))
|
||||
throw Exception("ZlibInStream: failed to flush remaining stream data");
|
||||
skip(avail());
|
||||
}
|
||||
|
||||
setUnderlying(NULL, 0);
|
||||
@@ -96,47 +85,18 @@ void ZlibInStream::deinit()
|
||||
zs = NULL;
|
||||
}
|
||||
|
||||
size_t ZlibInStream::overrun(size_t itemSize, size_t nItems, bool wait)
|
||||
{
|
||||
if (itemSize > bufSize)
|
||||
throw Exception("ZlibInStream overrun: max itemSize exceeded");
|
||||
|
||||
if (end - ptr != 0)
|
||||
memmove(start, ptr, end - ptr);
|
||||
|
||||
offset += ptr - start;
|
||||
end -= ptr - start;
|
||||
ptr = start;
|
||||
|
||||
while ((size_t)(end - ptr) < itemSize) {
|
||||
if (!decompress(wait))
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t nAvail;
|
||||
nAvail = (end - ptr) / itemSize;
|
||||
if (nAvail < nItems)
|
||||
return nAvail;
|
||||
|
||||
return nItems;
|
||||
}
|
||||
|
||||
// decompress() calls the decompressor once. Note that this won't necessarily
|
||||
// generate any output data - it may just consume some input data. Returns
|
||||
// false if wait is false and we would block on the underlying stream.
|
||||
|
||||
bool ZlibInStream::decompress(bool wait)
|
||||
bool ZlibInStream::fillBuffer(size_t maxSize, bool wait)
|
||||
{
|
||||
if (!underlying)
|
||||
throw Exception("ZlibInStream overrun: no underlying stream");
|
||||
|
||||
zs->next_out = (U8*)end;
|
||||
zs->avail_out = start + bufSize - end;
|
||||
zs->avail_out = maxSize;
|
||||
|
||||
size_t n = underlying->check(1, 1, wait);
|
||||
size_t n = underlying->check(1, wait);
|
||||
if (n == 0) return false;
|
||||
zs->next_in = (U8*)underlying->getptr();
|
||||
zs->avail_in = underlying->getend() - underlying->getptr();
|
||||
zs->avail_in = underlying->avail();
|
||||
if (zs->avail_in > bytesIn)
|
||||
zs->avail_in = bytesIn;
|
||||
|
||||
|
||||
@@ -24,38 +24,32 @@
|
||||
#ifndef __RDR_ZLIBINSTREAM_H__
|
||||
#define __RDR_ZLIBINSTREAM_H__
|
||||
|
||||
#include <rdr/InStream.h>
|
||||
#include <rdr/BufferedInStream.h>
|
||||
|
||||
struct z_stream_s;
|
||||
|
||||
namespace rdr {
|
||||
|
||||
class ZlibInStream : public InStream {
|
||||
class ZlibInStream : public BufferedInStream {
|
||||
|
||||
public:
|
||||
|
||||
ZlibInStream(size_t bufSize=0);
|
||||
ZlibInStream();
|
||||
virtual ~ZlibInStream();
|
||||
|
||||
void setUnderlying(InStream* is, size_t bytesIn);
|
||||
void flushUnderlying();
|
||||
size_t pos();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
|
||||
void init();
|
||||
void deinit();
|
||||
|
||||
size_t overrun(size_t itemSize, size_t nItems, bool wait);
|
||||
bool decompress(bool wait);
|
||||
virtual bool fillBuffer(size_t maxSize, bool wait);
|
||||
|
||||
private:
|
||||
InStream* underlying;
|
||||
size_t bufSize;
|
||||
size_t offset;
|
||||
z_stream_s* zs;
|
||||
size_t bytesIn;
|
||||
U8* start;
|
||||
};
|
||||
|
||||
} // end of namespace rdr
|
||||
|
||||
@@ -30,9 +30,9 @@ using namespace rdr;
|
||||
|
||||
enum { DEFAULT_BUF_SIZE = 16384 };
|
||||
|
||||
ZlibOutStream::ZlibOutStream(OutStream* os, size_t bufSize_, int compressLevel)
|
||||
ZlibOutStream::ZlibOutStream(OutStream* os, int compressLevel)
|
||||
: underlying(os), compressionLevel(compressLevel), newLevel(compressLevel),
|
||||
bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
|
||||
bufSize(DEFAULT_BUF_SIZE), offset(0)
|
||||
{
|
||||
zs = new z_stream;
|
||||
zs->zalloc = Z_NULL;
|
||||
@@ -95,18 +95,18 @@ void ZlibOutStream::flush()
|
||||
ptr = start;
|
||||
}
|
||||
|
||||
size_t ZlibOutStream::overrun(size_t itemSize, size_t nItems)
|
||||
void ZlibOutStream::overrun(size_t needed)
|
||||
{
|
||||
#ifdef ZLIBOUT_DEBUG
|
||||
fprintf(stderr,"zos overrun\n");
|
||||
#endif
|
||||
|
||||
if (itemSize > bufSize)
|
||||
throw Exception("ZlibOutStream overrun: max itemSize exceeded");
|
||||
if (needed > bufSize)
|
||||
throw Exception("ZlibOutStream overrun: buffer size exceeded");
|
||||
|
||||
checkCompressionLevel();
|
||||
|
||||
while ((size_t)(end - ptr) < itemSize) {
|
||||
while (avail() < needed) {
|
||||
zs->next_in = start;
|
||||
zs->avail_in = ptr - start;
|
||||
|
||||
@@ -126,13 +126,6 @@ size_t ZlibOutStream::overrun(size_t itemSize, size_t nItems)
|
||||
ptr -= zs->next_in - start;
|
||||
}
|
||||
}
|
||||
|
||||
size_t nAvail;
|
||||
nAvail = (end - ptr) / itemSize;
|
||||
if (nAvail < nItems)
|
||||
return nAvail;
|
||||
|
||||
return nItems;
|
||||
}
|
||||
|
||||
void ZlibOutStream::deflate(int flush)
|
||||
@@ -148,7 +141,7 @@ void ZlibOutStream::deflate(int flush)
|
||||
do {
|
||||
underlying->check(1);
|
||||
zs->next_out = underlying->getptr();
|
||||
zs->avail_out = underlying->getend() - underlying->getptr();
|
||||
zs->avail_out = underlying->avail();
|
||||
|
||||
#ifdef ZLIBOUT_DEBUG
|
||||
fprintf(stderr,"zos: calling deflate, avail_in %d, avail_out %d\n",
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace rdr {
|
||||
|
||||
public:
|
||||
|
||||
ZlibOutStream(OutStream* os=0, size_t bufSize=0, int compressionLevel=-1);
|
||||
ZlibOutStream(OutStream* os=0, int compressionLevel=-1);
|
||||
virtual ~ZlibOutStream();
|
||||
|
||||
void setUnderlying(OutStream* os);
|
||||
@@ -45,7 +45,7 @@ namespace rdr {
|
||||
|
||||
private:
|
||||
|
||||
size_t overrun(size_t itemSize, size_t nItems);
|
||||
virtual void overrun(size_t needed);
|
||||
void deflate(int flush);
|
||||
void checkCompressionLevel();
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <rfb/Exception.h>
|
||||
#include <rfb/clipboardTypes.h>
|
||||
#include <rfb/fenceTypes.h>
|
||||
#include <rfb/CMsgReader.h>
|
||||
#include <rfb/CMsgWriter.h>
|
||||
@@ -42,7 +43,8 @@ CConnection::CConnection()
|
||||
: csecurity(0), is(0), os(0), reader_(0), writer_(0),
|
||||
shared(false),
|
||||
state_(RFBSTATE_UNINITIALISED), useProtocol3_3(false),
|
||||
framebuffer(NULL), decoder(this)
|
||||
framebuffer(NULL), decoder(this),
|
||||
serverClipboard(NULL), hasLocalClipboard(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -54,6 +56,7 @@ CConnection::~CConnection()
|
||||
reader_ = 0;
|
||||
delete writer_;
|
||||
writer_ = 0;
|
||||
strFree(serverClipboard);
|
||||
}
|
||||
|
||||
void CConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
|
||||
@@ -342,6 +345,79 @@ void CConnection::dataRect(const Rect& r, int encoding)
|
||||
decoder.decodeRect(r, encoding, framebuffer);
|
||||
}
|
||||
|
||||
void CConnection::serverCutText(const char* str)
|
||||
{
|
||||
hasLocalClipboard = false;
|
||||
|
||||
strFree(serverClipboard);
|
||||
serverClipboard = NULL;
|
||||
|
||||
serverClipboard = latin1ToUTF8(str);
|
||||
|
||||
handleClipboardAnnounce(true);
|
||||
}
|
||||
|
||||
void CConnection::handleClipboardCaps(rdr::U32 flags,
|
||||
const rdr::U32* lengths)
|
||||
{
|
||||
rdr::U32 sizes[] = { 0 };
|
||||
|
||||
CMsgHandler::handleClipboardCaps(flags, lengths);
|
||||
|
||||
writer()->writeClipboardCaps(rfb::clipboardUTF8 |
|
||||
rfb::clipboardRequest |
|
||||
rfb::clipboardPeek |
|
||||
rfb::clipboardNotify |
|
||||
rfb::clipboardProvide,
|
||||
sizes);
|
||||
}
|
||||
|
||||
void CConnection::handleClipboardRequest(rdr::U32 flags)
|
||||
{
|
||||
if (!(flags & rfb::clipboardUTF8))
|
||||
return;
|
||||
if (!hasLocalClipboard)
|
||||
return;
|
||||
handleClipboardRequest();
|
||||
}
|
||||
|
||||
void CConnection::handleClipboardPeek(rdr::U32 flags)
|
||||
{
|
||||
if (!hasLocalClipboard)
|
||||
return;
|
||||
if (cp.clipboardFlags() & rfb::clipboardNotify)
|
||||
writer()->writeClipboardNotify(rfb::clipboardUTF8);
|
||||
}
|
||||
|
||||
void CConnection::handleClipboardNotify(rdr::U32 flags)
|
||||
{
|
||||
strFree(serverClipboard);
|
||||
serverClipboard = NULL;
|
||||
|
||||
if (flags & rfb::clipboardUTF8) {
|
||||
hasLocalClipboard = false;
|
||||
handleClipboardAnnounce(true);
|
||||
} else {
|
||||
handleClipboardAnnounce(false);
|
||||
}
|
||||
}
|
||||
|
||||
void CConnection::handleClipboardProvide(rdr::U32 flags,
|
||||
const size_t* lengths,
|
||||
const rdr::U8* const* data)
|
||||
{
|
||||
if (!(flags & rfb::clipboardUTF8))
|
||||
return;
|
||||
|
||||
strFree(serverClipboard);
|
||||
serverClipboard = NULL;
|
||||
|
||||
serverClipboard = convertLF((const char*)data[0], lengths[0]);
|
||||
|
||||
// FIXME: Should probably verify that this data was actually requested
|
||||
handleClipboardData(serverClipboard);
|
||||
}
|
||||
|
||||
void CConnection::authSuccess()
|
||||
{
|
||||
}
|
||||
@@ -364,3 +440,53 @@ void CConnection::fence(rdr::U32 flags, unsigned len, const char data[])
|
||||
|
||||
writer()->writeFence(flags, len, data);
|
||||
}
|
||||
|
||||
void CConnection::handleClipboardRequest()
|
||||
{
|
||||
}
|
||||
|
||||
void CConnection::handleClipboardAnnounce(bool available)
|
||||
{
|
||||
}
|
||||
|
||||
void CConnection::handleClipboardData(const char* data)
|
||||
{
|
||||
}
|
||||
|
||||
void CConnection::requestClipboard()
|
||||
{
|
||||
if (serverClipboard != NULL) {
|
||||
handleClipboardData(serverClipboard);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cp.clipboardFlags() & rfb::clipboardRequest)
|
||||
writer()->writeClipboardRequest(rfb::clipboardUTF8);
|
||||
}
|
||||
|
||||
void CConnection::announceClipboard(bool available)
|
||||
{
|
||||
hasLocalClipboard = available;
|
||||
|
||||
if (cp.clipboardFlags() & rfb::clipboardNotify)
|
||||
writer()->writeClipboardNotify(available ? rfb::clipboardUTF8 : 0);
|
||||
else {
|
||||
if (available)
|
||||
handleClipboardRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void CConnection::sendClipboardData(const char* data)
|
||||
{
|
||||
if (cp.clipboardFlags() & rfb::clipboardProvide) {
|
||||
CharArray filtered(convertCRLF(data));
|
||||
size_t sizes[1] = { strlen(filtered.buf) + 1 };
|
||||
const rdr::U8* data[1] = { (const rdr::U8*)filtered.buf };
|
||||
writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data);
|
||||
} else {
|
||||
CharArray latin1(utf8ToLatin1(data));
|
||||
|
||||
writer()->writeClientCutText(latin1.buf, strlen(latin1.buf));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -107,6 +107,17 @@ namespace rfb {
|
||||
virtual void framebufferUpdateEnd();
|
||||
virtual void dataRect(const Rect& r, int encoding);
|
||||
|
||||
virtual void serverCutText(const char* str);
|
||||
|
||||
virtual void handleClipboardCaps(rdr::U32 flags,
|
||||
const rdr::U32* lengths);
|
||||
virtual void handleClipboardRequest(rdr::U32 flags);
|
||||
virtual void handleClipboardPeek(rdr::U32 flags);
|
||||
virtual void handleClipboardNotify(rdr::U32 flags);
|
||||
virtual void handleClipboardProvide(rdr::U32 flags,
|
||||
const size_t* lengths,
|
||||
const rdr::U8* const* data);
|
||||
|
||||
|
||||
// Methods to be overridden in a derived class
|
||||
|
||||
@@ -121,9 +132,43 @@ namespace rfb {
|
||||
// derived class must call on to CConnection::serverInit().
|
||||
virtual void serverInit();
|
||||
|
||||
// handleClipboardRequest() is called whenever the server requests
|
||||
// the client to send over its clipboard data. It will only be
|
||||
// called after the client has first announced a clipboard change
|
||||
// via announceClipboard().
|
||||
virtual void handleClipboardRequest();
|
||||
|
||||
// handleClipboardAnnounce() is called to indicate a change in the
|
||||
// clipboard on the server. Call requestClipboard() to access the
|
||||
// actual data.
|
||||
virtual void handleClipboardAnnounce(bool available);
|
||||
|
||||
// handleClipboardData() is called when the server has sent over
|
||||
// the clipboard data as a result of a previous call to
|
||||
// requestClipboard(). Note that this function might never be
|
||||
// called if the clipboard data was no longer available when the
|
||||
// server received the request.
|
||||
virtual void handleClipboardData(const char* data);
|
||||
|
||||
|
||||
// Other methods
|
||||
|
||||
// requestClipboard() will result in a request to the server to
|
||||
// transfer its clipboard data. A call to handleClipboardData()
|
||||
// will be made once the data is available.
|
||||
virtual void requestClipboard();
|
||||
|
||||
// announceClipboard() informs the server of changes to the
|
||||
// clipboard on the client. The server may later request the
|
||||
// clipboard data via handleClipboardRequest().
|
||||
virtual void announceClipboard(bool available);
|
||||
|
||||
// sendClipboardData() transfers the clipboard data to the server
|
||||
// and should be called whenever the server has requested the
|
||||
// clipboard via handleClipboardRequest().
|
||||
virtual void sendClipboardData(const char* data);
|
||||
|
||||
|
||||
CMsgReader* reader() { return reader_; }
|
||||
CMsgWriter* writer() { return writer_; }
|
||||
|
||||
@@ -190,6 +235,9 @@ namespace rfb {
|
||||
|
||||
ModifiablePixelBuffer* framebuffer;
|
||||
DecodeManager decoder;
|
||||
|
||||
char* serverClipboard;
|
||||
bool hasLocalClipboard;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -48,6 +48,7 @@ set(RFB_SOURCES
|
||||
Security.cxx
|
||||
SecurityServer.cxx
|
||||
SecurityClient.cxx
|
||||
SelfBench.cxx
|
||||
SSecurityPlain.cxx
|
||||
SSecurityStack.cxx
|
||||
SSecurityVncAuth.cxx
|
||||
@@ -63,6 +64,7 @@ set(RFB_SOURCES
|
||||
VNCServerST.cxx
|
||||
ZRLEEncoder.cxx
|
||||
ZRLEDecoder.cxx
|
||||
cpuid.cxx
|
||||
encodings.cxx
|
||||
util.cxx
|
||||
xxhash.c)
|
||||
@@ -96,6 +98,27 @@ if(GNUTLS_FOUND)
|
||||
)
|
||||
endif()
|
||||
|
||||
# SSE2
|
||||
|
||||
set(SSE2_SOURCES
|
||||
scale_sse2.cxx)
|
||||
|
||||
set(SCALE_DUMMY_SOURCES
|
||||
scale_dummy.cxx)
|
||||
|
||||
if(COMPILER_SUPPORTS_SSE2)
|
||||
set_source_files_properties(${SSE2_SOURCES} PROPERTIES COMPILE_FLAGS ${COMPILE_FLAGS} -msse2)
|
||||
set(RFB_SOURCES
|
||||
${RFB_SOURCES}
|
||||
${SSE2_SOURCES}
|
||||
)
|
||||
else()
|
||||
set(RFB_SOURCES
|
||||
${RFB_SOURCES}
|
||||
${SCALE_DUMMY_SOURCES}
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(rfb STATIC ${RFB_SOURCES})
|
||||
|
||||
target_link_libraries(rfb ${RFB_LIBRARIES})
|
||||
|
||||
@@ -92,3 +92,26 @@ void CMsgHandler::setLEDState(unsigned int state)
|
||||
{
|
||||
cp.setLEDState(state);
|
||||
}
|
||||
|
||||
void CMsgHandler::handleClipboardCaps(rdr::U32 flags, const rdr::U32* lengths)
|
||||
{
|
||||
cp.setClipboardCaps(flags, lengths);
|
||||
}
|
||||
|
||||
void CMsgHandler::handleClipboardRequest(rdr::U32 flags)
|
||||
{
|
||||
}
|
||||
|
||||
void CMsgHandler::handleClipboardPeek(rdr::U32 flags)
|
||||
{
|
||||
}
|
||||
|
||||
void CMsgHandler::handleClipboardNotify(rdr::U32 flags)
|
||||
{
|
||||
}
|
||||
|
||||
void CMsgHandler::handleClipboardProvide(rdr::U32 flags,
|
||||
const size_t* lengths,
|
||||
const rdr::U8* const* data)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace rfb {
|
||||
int w, int h,
|
||||
const ScreenSet& layout);
|
||||
virtual void setCursor(int width, int height, const Point& hotspot,
|
||||
const rdr::U8* data) = 0;
|
||||
const rdr::U8* data, const bool resizing = false) = 0;
|
||||
virtual void setPixelFormat(const PixelFormat& pf);
|
||||
virtual void setName(const char* name);
|
||||
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
|
||||
@@ -72,6 +72,15 @@ namespace rfb {
|
||||
|
||||
virtual void setLEDState(unsigned int state);
|
||||
|
||||
virtual void handleClipboardCaps(rdr::U32 flags,
|
||||
const rdr::U32* lengths);
|
||||
virtual void handleClipboardRequest(rdr::U32 flags);
|
||||
virtual void handleClipboardPeek(rdr::U32 flags);
|
||||
virtual void handleClipboardNotify(rdr::U32 flags);
|
||||
virtual void handleClipboardProvide(rdr::U32 flags,
|
||||
const size_t* lengths,
|
||||
const rdr::U8* const* data);
|
||||
|
||||
ConnParams cp;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,10 +18,14 @@
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <rdr/OutStream.h>
|
||||
#include <rdr/MemOutStream.h>
|
||||
#include <rdr/ZlibOutStream.h>
|
||||
|
||||
#include <rfb/msgTypes.h>
|
||||
#include <rfb/fenceTypes.h>
|
||||
#include <rfb/encodings.h>
|
||||
#include <rfb/qemuTypes.h>
|
||||
#include <rfb/clipboardTypes.h>
|
||||
#include <rfb/Exception.h>
|
||||
#include <rfb/PixelFormat.h>
|
||||
#include <rfb/Rect.h>
|
||||
@@ -57,7 +61,7 @@ void CMsgWriter::writeSetPixelFormat(const PixelFormat& pf)
|
||||
void CMsgWriter::writeSetEncodings(int nEncodings, rdr::U32* encodings)
|
||||
{
|
||||
startMsg(msgTypeSetEncodings);
|
||||
os->skip(1);
|
||||
os->pad(1);
|
||||
os->writeU16(nEncodings);
|
||||
for (int i = 0; i < nEncodings; i++)
|
||||
os->writeU32(encodings[i]);
|
||||
@@ -265,6 +269,104 @@ void CMsgWriter::writeClientCutText(const char* str, rdr::U32 len)
|
||||
endMsg();
|
||||
}
|
||||
|
||||
void CMsgWriter::writeClipboardCaps(rdr::U32 caps,
|
||||
const rdr::U32* lengths)
|
||||
{
|
||||
size_t i, count;
|
||||
|
||||
if (!(cp->clipboardFlags() & clipboardCaps))
|
||||
throw Exception("Server does not support clipboard \"caps\" action");
|
||||
|
||||
count = 0;
|
||||
for (i = 0;i < 16;i++) {
|
||||
if (caps & (1 << i))
|
||||
count++;
|
||||
}
|
||||
|
||||
startMsg(msgTypeClientCutText);
|
||||
os->pad(3);
|
||||
os->writeS32(-(4 + 4 * count));
|
||||
|
||||
os->writeU32(caps | clipboardCaps);
|
||||
|
||||
count = 0;
|
||||
for (i = 0;i < 16;i++) {
|
||||
if (caps & (1 << i))
|
||||
os->writeU32(lengths[count++]);
|
||||
}
|
||||
|
||||
endMsg();
|
||||
}
|
||||
|
||||
void CMsgWriter::writeClipboardRequest(rdr::U32 flags)
|
||||
{
|
||||
if (!(cp->clipboardFlags() & clipboardRequest))
|
||||
throw Exception("Server does not support clipboard \"request\" action");
|
||||
|
||||
startMsg(msgTypeClientCutText);
|
||||
os->pad(3);
|
||||
os->writeS32(-4);
|
||||
os->writeU32(flags | clipboardRequest);
|
||||
endMsg();
|
||||
}
|
||||
|
||||
void CMsgWriter::writeClipboardPeek(rdr::U32 flags)
|
||||
{
|
||||
if (!(cp->clipboardFlags() & clipboardPeek))
|
||||
throw Exception("Server does not support clipboard \"peek\" action");
|
||||
|
||||
startMsg(msgTypeClientCutText);
|
||||
os->pad(3);
|
||||
os->writeS32(-4);
|
||||
os->writeU32(flags | clipboardPeek);
|
||||
endMsg();
|
||||
}
|
||||
|
||||
void CMsgWriter::writeClipboardNotify(rdr::U32 flags)
|
||||
{
|
||||
if (!(cp->clipboardFlags() & clipboardNotify))
|
||||
throw Exception("Server does not support clipboard \"notify\" action");
|
||||
|
||||
startMsg(msgTypeClientCutText);
|
||||
os->pad(3);
|
||||
os->writeS32(-4);
|
||||
os->writeU32(flags | clipboardNotify);
|
||||
endMsg();
|
||||
}
|
||||
|
||||
void CMsgWriter::writeClipboardProvide(rdr::U32 flags,
|
||||
const size_t* lengths,
|
||||
const rdr::U8* const* data)
|
||||
{
|
||||
rdr::MemOutStream mos;
|
||||
rdr::ZlibOutStream zos;
|
||||
|
||||
int i, count;
|
||||
|
||||
if (!(cp->clipboardFlags() & clipboardProvide))
|
||||
throw Exception("Server does not support clipboard \"provide\" action");
|
||||
|
||||
zos.setUnderlying(&mos);
|
||||
|
||||
count = 0;
|
||||
for (i = 0;i < 16;i++) {
|
||||
if (!(flags & (1 << i)))
|
||||
continue;
|
||||
zos.writeU32(lengths[count]);
|
||||
zos.writeBytes(data[count], lengths[count]);
|
||||
count++;
|
||||
}
|
||||
|
||||
zos.flush();
|
||||
|
||||
startMsg(msgTypeClientCutText);
|
||||
os->pad(3);
|
||||
os->writeS32(-(4 + mos.length()));
|
||||
os->writeU32(flags | clipboardProvide);
|
||||
os->writeBytes(mos.data(), mos.length());
|
||||
endMsg();
|
||||
}
|
||||
|
||||
void CMsgWriter::startMsg(int type)
|
||||
{
|
||||
os->writeU8(type);
|
||||
|
||||
@@ -56,6 +56,13 @@ namespace rfb {
|
||||
void writePointerEvent(const Point& pos, int buttonMask);
|
||||
void writeClientCutText(const char* str, rdr::U32 len);
|
||||
|
||||
void writeClipboardCaps(rdr::U32 caps, const rdr::U32* lengths);
|
||||
void writeClipboardRequest(rdr::U32 flags);
|
||||
void writeClipboardPeek(rdr::U32 flags);
|
||||
void writeClipboardNotify(rdr::U32 flags);
|
||||
void writeClipboardProvide(rdr::U32 flags, const size_t* lengths,
|
||||
const rdr::U8* const* data);
|
||||
|
||||
protected:
|
||||
void startMsg(int type);
|
||||
void endMsg();
|
||||
|
||||
@@ -695,6 +695,8 @@ bool ComparingUpdateTracker::compare(bool skipScrollDetection, const Region &ski
|
||||
std::vector<Rect> rects;
|
||||
std::vector<Rect>::iterator i;
|
||||
|
||||
changedPerc = 100;
|
||||
|
||||
if (!enabled)
|
||||
return false;
|
||||
|
||||
@@ -749,8 +751,13 @@ bool ComparingUpdateTracker::compare(bool skipScrollDetection, const Region &ski
|
||||
for (i = rects.begin(); i != rects.end(); i++)
|
||||
totalPixels += i->area();
|
||||
newChanged.get_rects(&rects);
|
||||
for (i = rects.begin(); i != rects.end(); i++)
|
||||
unsigned newchangedarea = 0;
|
||||
for (i = rects.begin(); i != rects.end(); i++) {
|
||||
missedPixels += i->area();
|
||||
newchangedarea += i->area();
|
||||
}
|
||||
|
||||
changedPerc = newchangedarea * 100 / fb->area();
|
||||
|
||||
if (changed.equals(newChanged))
|
||||
return false;
|
||||
|
||||
@@ -48,6 +48,8 @@ namespace rfb {
|
||||
virtual void getUpdateInfo(UpdateInfo* info, const Region& cliprgn);
|
||||
virtual void clear();
|
||||
|
||||
rdr::U8 changedPerc;
|
||||
|
||||
private:
|
||||
void compareRect(const Rect& r, Region* newchanged, const Region &skipCursorArea);
|
||||
PixelBuffer* fb;
|
||||
|
||||
@@ -298,6 +298,11 @@ size_t Congestion::getBandwidth()
|
||||
return congWindow * 1000 / safeBaseRTT;
|
||||
}
|
||||
|
||||
unsigned Congestion::getPingTime() const
|
||||
{
|
||||
return safeBaseRTT;
|
||||
}
|
||||
|
||||
void Congestion::debugTrace(const char* filename, int fd)
|
||||
{
|
||||
#ifdef CONGESTION_TRACE
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user